diff --git a/README.md b/README.md index 42b4f481b..7de5992a8 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ To update to the latest version: * [Comments](/docs/comments.md) * [Type Inference](/docs/type-inference.md) * [Import Resolution](/docs/import-resolution.md) +* [Extending Builtins](/docs/builtins.md) * [Type Stubs](/docs/type-stubs.md) * [Types in Libraries](/docs/typed-libraries.md) * [Commands](/docs/commands.md) diff --git a/docs/builtins.md b/docs/builtins.md new file mode 100644 index 000000000..3aadb27ea --- /dev/null +++ b/docs/builtins.md @@ -0,0 +1,8 @@ +# Extending Builtins + +The Python interpreter implicitly adds a set of symbols that are available within every module even though they are not explicitly imported. These so-called “built in” symbols include commonly-used types and functions such as “list”, “dict”, “int”, “float”, “min”, and “len”. + +Pyright gains knowledge of which types are included in “builtins” scope through the type stub file `builtins.pyi`. This stub file comes from the typeshed github repo and is bundled with pyright, along with type stubs that describe other stdlib modules. + +Some Python environments are customized to include additional builtins symbols. If you are using such an environment, you may want to tell Pyright about these additional symbols that are available at runtime. To do so, you can add a local type stub file called `__builtins__.pyi`. This file can be placed at the root of your project directory or at the root of the subdirectory specified in the `stubPath` setting (which is named `typings` by default). + diff --git a/packages/pyright-internal/src/analyzer/program.ts b/packages/pyright-internal/src/analyzer/program.ts index a13397566..1bd271cc4 100644 --- a/packages/pyright-internal/src/analyzer/program.ts +++ b/packages/pyright-internal/src/analyzer/program.ts @@ -359,6 +359,15 @@ export class Program { filePaths.forEach((filePath) => { const sourceFileInfo = this._getSourceFileInfoFromPath(filePath); if (sourceFileInfo) { + const fileName = getFileName(filePath); + + // Handle builtins and __builtins__ specially. They are implicitly + // included by all source files. + if (fileName === 'builtins.pyi' || fileName === '__builtins__.pyi') { + this.markAllFilesDirty(evenIfContentsAreSame, indexingNeeded); + return; + } + // If !evenIfContentsAreSame, see if the on-disk contents have // changed. If the file is open, the on-disk contents don't matter // because we'll receive updates directly from the client. diff --git a/packages/pyright-internal/src/analyzer/sourceFile.ts b/packages/pyright-internal/src/analyzer/sourceFile.ts index f68be52a7..7cecac10d 100644 --- a/packages/pyright-internal/src/analyzer/sourceFile.ts +++ b/packages/pyright-internal/src/analyzer/sourceFile.ts @@ -1214,11 +1214,29 @@ export class SourceFile { const imports: ImportResult[] = []; // Always include an implicit import of the builtins module. - let builtinsImportResult: ImportResult | undefined = importResolver.resolveImport(this._filePath, execEnv, { - leadingDots: 0, - nameParts: ['builtins'], - importedSymbols: undefined, - }); + let builtinsImportResult: ImportResult | undefined; + + // If this is a project source file (not a stub), try to resolve + // the __builtins__ stub first. + if (!this._isThirdPartyImport && !this._isStubFile) { + builtinsImportResult = importResolver.resolveImport(this._filePath, execEnv, { + leadingDots: 0, + nameParts: ['__builtins__'], + importedSymbols: undefined, + }); + + if (builtinsImportResult && !builtinsImportResult.isImportFound) { + builtinsImportResult = undefined; + } + } + + if (!builtinsImportResult) { + builtinsImportResult = importResolver.resolveImport(this._filePath, execEnv, { + leadingDots: 0, + nameParts: ['builtins'], + importedSymbols: undefined, + }); + } // Avoid importing builtins from the builtins.pyi file itself. if ( diff --git a/packages/pyright-internal/src/tests/fourslash/completions.builtinOverride.fourslash.ts b/packages/pyright-internal/src/tests/fourslash/completions.builtinOverride.fourslash.ts new file mode 100644 index 000000000..384896f73 --- /dev/null +++ b/packages/pyright-internal/src/tests/fourslash/completions.builtinOverride.fourslash.ts @@ -0,0 +1,22 @@ +/// + +// @filename: test.py +//// Cust[|/*marker1*/|] +//// my_v[|/*marker2*/|] + +// @filename: __builtins__.pyi +//// class CustomClass: ... +//// my_var: int = ... + +// @ts-ignore +await helper.verifyCompletion('exact', 'markdown', { + marker1: { + completions: [ + { + label: 'CustomClass', + kind: Consts.CompletionItemKind.Class, + }, + ], + }, + marker2: { completions: [{ label: 'my_var', kind: Consts.CompletionItemKind.Variable }] }, +});