Changed import resolution order to more closely match PEP 561. Typeshed stdlib type stubs are now resolved later in the import resolution process, after all local modules and modules within the python environment.

This commit is contained in:
Eric Traut 2022-01-27 22:57:30 -08:00
parent 58428a69bd
commit a03acb0f41
2 changed files with 43 additions and 44 deletions

View File

@ -5,11 +5,9 @@ If the import is relative (the module name starts with one or more dots), it res
For absolute (non-relative) imports, Pyright employs the following resolution order:
1. Try to resolve using a **stdlib typeshed stub**. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Pyright. This allows for the use of a newer or a patched version of the typeshed stdlib stubs.
1. Try to resolve using the **stubPath** as defined in the `stubPath` config entry or the `python.analysis.stubPath` setting.
2. Try to resolve using the **stubPath** as defined in the `stubPath` config entry or the `python.analysis.stubPath` setting.
3. Try to resolve using **code within the workspace**.
2. Try to resolve using **code within the workspace**.
* Try to resolve relative to the **root directory** of the execution environment. If no execution environments are specified in the config file, use the root of the workspace. For more information about execution environments, refer to the [configuration documentation](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#execution-environment-options).
@ -17,16 +15,17 @@ For absolute (non-relative) imports, Pyright employs the following resolution or
* If no execution environment or extraPaths are configured, try to resolve using the **local directory `src`**. It is common for Python projects to place local source files within a directory of this name.
4. Try to resolve using **stubs or inlined types found within installed packages**. Pyright uses the configured Python environment to determine whether a package has been installed. For more details about how to configure your Python environment for Pyright, see below. If a Python environment is configured, Pyright looks in the `lib/site-packages`, `Lib/site-packages`, or `python*/site-packages` subdirectory. If no site-packages directory can be found, Pyright attempts to run the configured Python interpreter and ask it for its search paths. If no Python environment is configured, Pyright will use the default Python interpreter by invoking `python`.
3. Try to resolve using **stubs or inlined types found within installed packages**. Pyright uses the configured Python environment to determine whether a package has been installed. For more details about how to configure your Python environment for Pyright, see below. If a Python environment is configured, Pyright looks in the `lib/site-packages`, `Lib/site-packages`, or `python*/site-packages` subdirectory. If no site-packages directory can be found, Pyright attempts to run the configured Python interpreter and ask it for its search paths. If no Python environment is configured, Pyright will use the default Python interpreter by invoking `python`.
* For a given package, try to resolve first using a **stub package**. Stub packages, as defined in [PEP 561](https://www.python.org/dev/peps/pep-0561/#type-checker-module-resolution-order), are named the same as the original package but with “-stubs” appended.
* Try to resolve using an **inline stub**, a “.pyi” file that ships within the package.
* If the package contains a “py.typed” file as described in [PEP 561](https://www.python.org/dev/peps/pep-0561/), use inlined type annotations provided in “.py” files within the package.
* If the `python.analysis.useLibraryCodeForTypes` setting is set to true (or the `--lib` command-line argument was specified), try to resolve using the **library implementation** (“.py” file). Some “.py” files may contain partial or complete type annotations. Pyright will use type annotations that are provided and do its best to infer any missing type information. If you are using Pyright, `python.analysis.useLibraryCodeForTypes` is false by default. If you are using Pylance, it is true.
4. Try to resolve using a **stdlib typeshed stub**. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Pyright. This allows for the use of a newer or a patched version of the typeshed stdlib stubs.
5. Try to resolve using a **third-party typeshed** stub. If the `typeshedPath` is configured, use this instead of the typeshed stubs that are packaged with Pyright. This allows for the use of a newer or a patched version of the typeshed third-party stubs.
6. If the `python.analysis.useLibraryCodeForTypes` setting is set to true (or the `--lib` command-line argument was specified), try to resolve using the **library implementation** (“.py” file). Some “.py” files may contain partial or complete type annotations. Pyright will use type annotations that are provided and do its best to infer any missing type information. If you are using Pyright, `python.analysis.useLibraryCodeForTypes` is false by default. If you are using Pylance, it is true.
## Configuring Your Python Environment

View File

@ -1193,44 +1193,27 @@ export class ImportResolver {
const importName = this.formatImportName(moduleDescriptor);
const importFailureInfo: string[] = [];
// First check for a stdlib typeshed file.
if (allowPyi && moduleDescriptor.nameParts.length > 0) {
const builtInImport = this._findTypeshedPath(
// Check for a local stub file using stubPath.
if (allowPyi && this._configOptions.stubPath) {
importFailureInfo.push(`Looking in stubPath '${this._configOptions.stubPath}'`);
const typingsImport = this.resolveAbsoluteImport(
this._configOptions.stubPath,
execEnv,
moduleDescriptor,
importName,
/* isStdLib */ true,
importFailureInfo
importFailureInfo,
/* allowPartial */ undefined,
/* allowNativeLib */ false,
/* useStubPackage */ true,
allowPyi,
/* lookForPyTyped */ false
);
if (builtInImport) {
builtInImport.isTypeshedFile = true;
return builtInImport;
}
}
if (allowPyi) {
// Check for a local stub file using stubPath.
if (this._configOptions.stubPath) {
importFailureInfo.push(`Looking in stubPath '${this._configOptions.stubPath}'`);
const typingsImport = this.resolveAbsoluteImport(
this._configOptions.stubPath,
execEnv,
moduleDescriptor,
importName,
importFailureInfo,
/* allowPartial */ undefined,
/* allowNativeLib */ false,
/* useStubPackage */ true,
allowPyi,
/* lookForPyTyped */ false
);
if (typingsImport.isImportFound) {
// We will treat typings files as "local" rather than "third party".
typingsImport.importType = ImportType.Local;
typingsImport.isLocalTypingsFile = true;
return typingsImport;
}
if (typingsImport.isImportFound) {
// We will treat typings files as "local" rather than "third party".
typingsImport.importType = ImportType.Local;
typingsImport.isLocalTypingsFile = true;
return typingsImport;
}
}
@ -1308,13 +1291,14 @@ export class ImportResolver {
// If a library is fully py.typed, then we have found the best match,
// unless the execution environment is typeshed itself, in which case
// we don't want to favor py.typed libraries the typeshed lookup below.
// we don't want to favor py.typed libraries. Use the typeshed lookup below.
if (execEnv.root !== this._getTypeshedRoot(execEnv, importFailureInfo)) {
if (bestResultSoFar?.pyTypedInfo && !bestResultSoFar.isPartlyResolved) {
return bestResultSoFar;
}
}
// Call the extensibility hook for subclasses.
const extraResults = this.resolveImportEx(
sourceFilePath,
execEnv,
@ -1323,13 +1307,29 @@ export class ImportResolver {
importFailureInfo,
allowPyi
);
if (extraResults !== undefined) {
if (extraResults) {
return extraResults;
}
if (allowPyi) {
if (allowPyi && moduleDescriptor.nameParts.length > 0) {
// Check for a stdlib typeshed file.
importFailureInfo.push(`Looking for typeshed stdlib path`);
const typeshedStdlibImport = this._findTypeshedPath(
execEnv,
moduleDescriptor,
importName,
/* isStdLib */ true,
importFailureInfo
);
if (typeshedStdlibImport) {
typeshedStdlibImport.isTypeshedFile = true;
return typeshedStdlibImport;
}
// Check for a third-party typeshed file.
importFailureInfo.push(`Looking for typeshed path`);
importFailureInfo.push(`Looking for typeshed third-party path`);
const typeshedImport = this._findTypeshedPath(
execEnv,
moduleDescriptor,