Skip to content

Commit ea409bd

Browse files
committed
Reverted a recent change that extended the reportPrivateImportUsage check to enforce imports from submodules whose names begin with an underscore. This change was disruptive to users of the popular pandas library because it exports a submodule named _typing. This was originally intended to be experimental or private, but it was never fully addressed. The pandas maintainers will work to fix this issue (pandas-dev/pandas#55231) over the next year. I'm going to back out this change to pyright in the meantime.
1 parent cb3e2ba commit ea409bd

10 files changed

+18
-109
lines changed

packages/pyright-internal/src/analyzer/analyzerFileInfo.ts

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export interface AnalyzerFileInfo {
6161
isTypeshedStubFile: boolean;
6262
isBuiltInStubFile: boolean;
6363
isInPyTypedPackage: boolean;
64-
isModulePrivate: boolean;
6564
ipythonMode: IPythonMode;
6665
accessedSymbolSet: Set<number>;
6766
}

packages/pyright-internal/src/analyzer/binder.ts

+11-18
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export class Binder extends ParseTreeWalker {
272272

273273
this._addTypingImportAliasesFromBuiltinsScope();
274274

275-
const moduleScope = this._createNewScope(
275+
this._createNewScope(
276276
isBuiltInModule ? ScopeType.Builtin : ScopeType.Module,
277277
this._fileInfo.builtinsScope,
278278
/* proxyScope */ undefined,
@@ -310,24 +310,17 @@ export class Binder extends ParseTreeWalker {
310310
// Perform all analysis that was deferred during the first pass.
311311
this._bindDeferred();
312312

313-
if (this._fileInfo.isModulePrivate) {
314-
// All symbols in a private module are private outside of the package.
315-
moduleScope.symbolTable.forEach((symbol) => {
316-
symbol.setPrivatePyTypedImport();
317-
});
318-
} else {
319-
// Use the __all__ list to determine whether any potential private
320-
// symbols should be made externally hidden or private.
321-
this._potentialHiddenSymbols.forEach((symbol, name) => {
322-
if (!this._dunderAllNames?.some((sym) => sym === name)) {
323-
if (this._fileInfo.isStubFile) {
324-
symbol.setIsExternallyHidden();
325-
} else {
326-
symbol.setPrivatePyTypedImport();
327-
}
313+
// Use the __all__ list to determine whether any potential private
314+
// symbols should be made externally hidden or private.
315+
this._potentialHiddenSymbols.forEach((symbol, name) => {
316+
if (!this._dunderAllNames?.some((sym) => sym === name)) {
317+
if (this._fileInfo.isStubFile) {
318+
symbol.setIsExternallyHidden();
319+
} else {
320+
symbol.setPrivatePyTypedImport();
328321
}
329-
});
330-
}
322+
}
323+
});
331324

332325
this._potentialPrivateSymbols.forEach((symbol, name) => {
333326
if (!this._dunderAllNames?.some((sym) => sym === name)) {

packages/pyright-internal/src/analyzer/importResolver.ts

+2-28
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ export interface ModuleNameAndType {
4646
export interface ModuleImportInfo extends ModuleNameAndType {
4747
isTypeshedFile: boolean;
4848
isThirdPartyPyTypedPresent: boolean;
49-
isModulePrivate: boolean;
5049
}
5150

5251
export interface ModuleNameInfoFromPath {
@@ -936,7 +935,6 @@ export class ImportResolver {
936935
importType: ImportType.Local,
937936
isStubFile: false,
938937
isNativeLib: false,
939-
isModulePrivate: false,
940938
implicitImports: new Map<string, ImplicitImport>(),
941939
filteredImplicitImports: new Map<string, ImplicitImport>(),
942940
nonStubImportResult: undefined,
@@ -1120,7 +1118,6 @@ export class ImportResolver {
11201118
let importType = ImportType.BuiltIn;
11211119
let isLocalTypingsFile = false;
11221120
let isThirdPartyPyTypedPresent = false;
1123-
const isModulePrivate = false;
11241121
let isTypeshedFile = false;
11251122

11261123
const importFailureInfo: string[] = [];
@@ -1163,7 +1160,6 @@ export class ImportResolver {
11631160
isTypeshedFile: true,
11641161
isLocalTypingsFile,
11651162
isThirdPartyPyTypedPresent,
1166-
isModulePrivate,
11671163
};
11681164
}
11691165
}
@@ -1300,14 +1296,7 @@ export class ImportResolver {
13001296
}
13011297

13021298
if (moduleName) {
1303-
return {
1304-
moduleName,
1305-
importType,
1306-
isTypeshedFile,
1307-
isLocalTypingsFile,
1308-
isThirdPartyPyTypedPresent,
1309-
isModulePrivate,
1310-
};
1299+
return { moduleName, importType, isTypeshedFile, isLocalTypingsFile, isThirdPartyPyTypedPresent };
13111300
}
13121301

13131302
if (allowInvalidModuleName && moduleNameWithInvalidCharacters) {
@@ -1317,7 +1306,6 @@ export class ImportResolver {
13171306
importType,
13181307
isLocalTypingsFile,
13191308
isThirdPartyPyTypedPresent,
1320-
isModulePrivate,
13211309
};
13221310
}
13231311

@@ -1328,7 +1316,6 @@ export class ImportResolver {
13281316
importType: ImportType.Local,
13291317
isLocalTypingsFile,
13301318
isThirdPartyPyTypedPresent,
1331-
isModulePrivate,
13321319
};
13331320
}
13341321

@@ -1368,7 +1355,6 @@ export class ImportResolver {
13681355
let implicitImports = new Map<string, ImplicitImport>();
13691356
let packageDirectory: Uri | undefined;
13701357
let pyTypedInfo: PyTypedInfo | undefined;
1371-
let isModulePrivate = false;
13721358

13731359
// Handle the "from . import XXX" case.
13741360
if (moduleDescriptor.nameParts.length === 0) {
@@ -1393,12 +1379,7 @@ export class ImportResolver {
13931379
for (let i = 0; i < moduleDescriptor.nameParts.length; i++) {
13941380
const isFirstPart = i === 0;
13951381
const isLastPart = i === moduleDescriptor.nameParts.length - 1;
1396-
const namePart = moduleDescriptor.nameParts[i];
1397-
dirPath = dirPath.combinePaths(namePart);
1398-
1399-
if (SymbolNameUtils.isProtectedName(namePart)) {
1400-
isModulePrivate = true;
1401-
}
1382+
dirPath = dirPath.combinePaths(moduleDescriptor.nameParts[i]);
14021383

14031384
if (useStubPackage && isFirstPart) {
14041385
dirPath = dirPath.addPath(stubsSuffix);
@@ -1514,12 +1495,6 @@ export class ImportResolver {
15141495
importFound = resolvedPaths.length >= moduleDescriptor.nameParts.length;
15151496
}
15161497

1517-
// Modules are considered private only if they are stub files or located
1518-
// within a py.typed package.
1519-
if (!isStubFile && !pyTypedInfo) {
1520-
isModulePrivate = false;
1521-
}
1522-
15231498
return {
15241499
importName,
15251500
isRelative: false,
@@ -1536,7 +1511,6 @@ export class ImportResolver {
15361511
isNativeLib,
15371512
implicitImports,
15381513
pyTypedInfo,
1539-
isModulePrivate,
15401514
filteredImplicitImports: implicitImports,
15411515
packageDirectory,
15421516
};

packages/pyright-internal/src/analyzer/importResult.ts

-4
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,6 @@ export interface ImportResult {
9999
// from .py here.
100100
nonStubImportResult?: ImportResult | undefined;
101101

102-
// Are the target module or its containing directories named in a
103-
// manner that indicates the module should be treated as private?
104-
isModulePrivate: boolean;
105-
106102
// Is there a "py.typed" file (as described in PEP 561) present in
107103
// the package that was used to resolve the import?
108104
pyTypedInfo?: PyTypedInfo | undefined;

packages/pyright-internal/src/analyzer/program.ts

-16
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ interface UpdateImportInfo {
7373
isTypeshedFile: boolean;
7474
isThirdPartyImport: boolean;
7575
isPyTypedPresent: boolean;
76-
isModulePrivate: boolean;
7776
}
7877

7978
export type PreCheckCallback = (parserOutput: ParserOutput, evaluator: TypeEvaluator) => void;
@@ -348,7 +347,6 @@ export class Program {
348347
importName,
349348
isThirdPartyImport,
350349
isInPyTypedPackage,
351-
/* isModulePrivate */ false,
352350
this._editModeTracker,
353351
this._console,
354352
this._logTracker
@@ -377,7 +375,6 @@ export class Program {
377375
moduleImportInfo.moduleName,
378376
/* isThirdPartyImport */ false,
379377
moduleImportInfo.isThirdPartyPyTypedPresent,
380-
moduleImportInfo.isModulePrivate,
381378
this._editModeTracker,
382379
this._console,
383380
this._logTracker,
@@ -1365,30 +1362,22 @@ export class Program {
13651362
const getThirdPartyImportInfo = (importResult: ImportResult) => {
13661363
let isThirdPartyImport = false;
13671364
let isPyTypedPresent = false;
1368-
let isModulePrivate = false;
13691365

13701366
if (importResult.importType === ImportType.ThirdParty) {
13711367
isThirdPartyImport = true;
13721368
if (importResult.pyTypedInfo) {
13731369
isPyTypedPresent = true;
13741370
}
1375-
if (importResult.isModulePrivate) {
1376-
isModulePrivate = true;
1377-
}
13781371
} else if (sourceFileInfo.isThirdPartyImport && importResult.importType === ImportType.Local) {
13791372
isThirdPartyImport = true;
13801373
if (sourceFileInfo.isThirdPartyPyTypedPresent) {
13811374
isPyTypedPresent = true;
13821375
}
1383-
if (importResult.isModulePrivate) {
1384-
isModulePrivate = true;
1385-
}
13861376
}
13871377

13881378
return {
13891379
isThirdPartyImport,
13901380
isPyTypedPresent,
1391-
isModulePrivate,
13921381
};
13931382
};
13941383

@@ -1406,7 +1395,6 @@ export class Program {
14061395
isTypeshedFile: false,
14071396
isThirdPartyImport: false,
14081397
isPyTypedPresent: false,
1409-
isModulePrivate: false,
14101398
});
14111399
}
14121400
}
@@ -1424,7 +1412,6 @@ export class Program {
14241412
!!importResult.isStdlibTypeshedFile || !!importResult.isThirdPartyTypeshedFile,
14251413
isThirdPartyImport: thirdPartyTypeInfo.isThirdPartyImport,
14261414
isPyTypedPresent: thirdPartyTypeInfo.isPyTypedPresent,
1427-
isModulePrivate: thirdPartyTypeInfo.isModulePrivate,
14281415
});
14291416
}
14301417
}
@@ -1440,7 +1427,6 @@ export class Program {
14401427
!!importResult.isStdlibTypeshedFile || !!importResult.isThirdPartyTypeshedFile,
14411428
isThirdPartyImport: thirdPartyTypeInfo.isThirdPartyImport,
14421429
isPyTypedPresent: thirdPartyTypeInfo.isPyTypedPresent,
1443-
isModulePrivate: thirdPartyTypeInfo.isModulePrivate,
14441430
});
14451431
}
14461432
}
@@ -1510,7 +1496,6 @@ export class Program {
15101496
moduleImportInfo.moduleName,
15111497
importInfo.isThirdPartyImport,
15121498
importInfo.isPyTypedPresent,
1513-
importInfo.isModulePrivate,
15141499
this._editModeTracker,
15151500
this._console,
15161501
this._logTracker
@@ -1627,7 +1612,6 @@ export class Program {
16271612
moduleImportInfo.moduleName,
16281613
/* isThirdPartyImport */ false,
16291614
/* isInPyTypedPackage */ false,
1630-
/* isModulePrivate */ false,
16311615
this._editModeTracker,
16321616
this._console,
16331617
this._logTracker

packages/pyright-internal/src/analyzer/programTypes.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ConsoleInterface } from '../common/console';
99
import { LogTracker } from '../common/logTracker';
1010
import { ServiceProvider } from '../common/serviceProvider';
1111
import { Uri } from '../common/uri/uri';
12-
import { IPythonMode, SourceFile, SourceFileEditMode } from './sourceFile';
12+
import { SourceFileEditMode, IPythonMode, SourceFile } from './sourceFile';
1313

1414
export interface ISourceFileFactory {
1515
createSourceFile(
@@ -18,7 +18,6 @@ export interface ISourceFileFactory {
1818
moduleName: string,
1919
isThirdPartyImport: boolean,
2020
isThirdPartyPyTypedPresent: boolean,
21-
isModulePrivate: boolean,
2221
editMode: SourceFileEditMode,
2322
console?: ConsoleInterface,
2423
logTracker?: LogTracker,

packages/pyright-internal/src/analyzer/sourceFile.ts

-9
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,6 @@ export class SourceFile {
232232
// "py.typed" file.
233233
private readonly _isThirdPartyPyTypedPresent: boolean;
234234

235-
// Indicates that the file is a submodule within a stub
236-
// package or a py.typed package and is named such that it
237-
// is "private" or contained within a subdirectory that
238-
// is named such that it is "private".
239-
private readonly _isModulePrivate: boolean;
240-
241235
private readonly _editMode: SourceFileEditMode;
242236

243237
// Settings that control which diagnostics should be output. The rules
@@ -261,7 +255,6 @@ export class SourceFile {
261255
moduleName: string,
262256
isThirdPartyImport: boolean,
263257
isThirdPartyPyTypedPresent: boolean,
264-
isModulePrivate: boolean,
265258
editMode: SourceFileEditMode,
266259
console?: ConsoleInterface,
267260
logTracker?: LogTracker,
@@ -278,7 +271,6 @@ export class SourceFile {
278271
this._isStubFile = uri.hasExtension('.pyi');
279272
this._isThirdPartyImport = isThirdPartyImport;
280273
this._isThirdPartyPyTypedPresent = isThirdPartyPyTypedPresent;
281-
this._isModulePrivate = isModulePrivate;
282274
const fileName = uri.fileName;
283275
this._isTypingStubFile =
284276
this._isStubFile && (this._uri.pathEndsWith('stdlib/typing.pyi') || fileName === 'typing_extensions.pyi');
@@ -1353,7 +1345,6 @@ export class SourceFile {
13531345
isTypeshedStubFile: this._isTypeshedStubFile,
13541346
isBuiltInStubFile: this._isBuiltInStubFile,
13551347
isInPyTypedPackage: this._isThirdPartyPyTypedPresent,
1356-
isModulePrivate: this._isModulePrivate,
13571348
ipythonMode: this._ipythonMode,
13581349
accessedSymbolSet: new Set<number>(),
13591350
};

packages/pyright-internal/src/common/serviceProviderExtensions.ts

-2
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ const DefaultSourceFileFactory: ISourceFileFactory = {
118118
moduleName: string,
119119
isThirdPartyImport: boolean,
120120
isThirdPartyPyTypedPresent: boolean,
121-
isModulePrivate: boolean,
122121
editMode: SourceFileEditMode,
123122
console?: ConsoleInterface,
124123
logTracker?: LogTracker,
@@ -130,7 +129,6 @@ const DefaultSourceFileFactory: ISourceFileFactory = {
130129
moduleName,
131130
isThirdPartyImport,
132131
isThirdPartyPyTypedPresent,
133-
isModulePrivate,
134132
editMode,
135133
console,
136134
logTracker,

packages/pyright-internal/src/tests/fourslash/import.pytyped.privateSymbols.fourslash.ts

-19
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
// @filename: testLib/__init__.py
1313
// @library: true
1414
//// from .module1 import one as one, two, three
15-
//// from ._module2 import ten as ten
1615
//// four: int = two * two
1716
//// _five: int = two + three
1817
//// _six: int = 6
@@ -24,10 +23,6 @@
2423
//// two: int = 2
2524
//// three: int = 3
2625

27-
// @filename: testLib/_module2/__init__.py
28-
// @library: true
29-
//// ten: int = 10
30-
3126
// @filename: .src/test1.py
3227
//// # pyright: reportPrivateUsage=true, reportPrivateImportUsage=true
3328
//// from testLib import one
@@ -43,12 +38,6 @@
4338
//// testLib.four
4439
//// testLib.[|/*marker6*/_five|]
4540
//// testLib._six
46-
////
47-
//// from testLib._module2 import [|/*marker7*/ten|]
48-
//// from testLib import ten
49-
//// import testLib._module2
50-
//// testLib.ten
51-
//// testLib._module2.[|/*marker8*/ten|]
5241

5342
// @ts-ignore
5443
await helper.verifyDiagnostics({
@@ -73,12 +62,4 @@ await helper.verifyDiagnostics({
7362
category: 'error',
7463
message: `"_five" is private and used outside of the module in which it is declared`,
7564
},
76-
marker7: {
77-
category: 'error',
78-
message: `"ten" is not exported from module "testLib._module2"`,
79-
},
80-
marker8: {
81-
category: 'error',
82-
message: `"ten" is not exported from module "testLib._module2"`,
83-
},
8465
});

0 commit comments

Comments
 (0)