pyright is Microsoft's Python type checker (requires node). It has active support and deployment, is fast, and detects a lot of issues other type checkers miss. It improves on the python vscode extension with type-checking and the detection of invalid imports.
pylance is a VS Code language server extension that bundles pyright and other goodies like auto-imports, code completion and additional stubs (eg: pandas, matplotlib)
pyright.typeCheckingMode
(or python.analysis.typeCheckingMode
for pylance) can be:
off
= all type-checking rules are disabled, but Python syntax and semantic errors are still reported and in pylance auto-complete suggestions are madebasic
= use when easing into type checking on existing code-bases, or on code-bases that use libraries with poor quality stubs (eg: pandas). Doesn't check for some things that mypy does, like incompatible overrides.strict
= new code-bases with high quality stubs should use this. Will error withreportUnknownParameterType
when type hints are missing from functions. Finds a lot of things mypy doesn't.
See configOptions.ts for the specific rules turned on and their level (eg: warning/error) for each mode.
Strict mode can be enabled on a per file basis via a comment, and individual rules disabled, see #601.
A pyrightconfig.json file in the root configures settings for the project. This is recommended so that everyone working on the project uses the same settings.
VSCode settings.json configures the default rules.
Pyright applies rules settings in the following order:
- Default rule settings
- Individual overrides in the pyrightconfig.json file
- Strict (for all or for specific subdirectories)
- File-level comments
Example settings.json for Pylance, using basic mode and enabling additional rules:
"python.languageServer": "Pylance",
"python.analysis.typeCheckingMode": "basic",
"python.analysis.diagnosticSeverityOverrides": {
"reportIncompatibleMethodOverride": "error"
}
- See Configuration for pyrightconfig.json options
- See Settings for vscode settings
To mimic PyCharm as closely as possible, use basic typeCheckingMode and set "strictDictionaryInference": true
in pyrightconfig.json
By default, Pyright/Pylance adds the root directory of the workspace to the search path. It also adds src/
if it's present, since it's a common convention.
You can add additional subdirectories to the search path by modifying python.analysis.extraPaths
in .vscode/settings.json
, eg: to add ./awesome_app/
to the search path (ref):
{
"python.pythonPath": "/Users/tekumara/.virtualenvs/myapp/bin/python",
"python.analysis.extraPaths": ["awesome_app"]
}
Lists with mixed types (eg: [1, "a"]
):
- In basic mode with be inferred as
List[Unknown]
ie: ignored - If
strictListInference: "true"
, will be inferred as as the union of the elements' types, eg:List[int | str]
See List Expression
Unknown
is used whenever a type cannot be inferred. It is a special form of Any
and so will create blind spots in type checking. Its distinct from Any
so Pyright can warn when types are not declared when the reportUnknown*
diagnostics are enabled.
For more info see Understanding Type Inference.
pyright can narrow a type to a more specific type based on the code path taken. See Type narrowing.
Pyright locates .pyi stubs in several locations including typeshed stubs it vendors, your project workspace, and lib/site-packages. To find lib/site-packages pyright needs to run inside your virtualenv, or have the venv
and venvPath
configured in pyrightconfig.json.
Many libraries lack stubs. However their .py
files can contain partial or complete type annotation. To use annotations in .py
files, and infer any missing types, when stubs are missing:
- specify the
--lib
command-line argument - set
"python.analysis.useLibraryCodeForTypes": true
for the pyright vscode extension. In Pylance this defaults to true. - set
"useLibraryCodeForTypes": true
in pyrightconfig.json. NB: Setting this tofalse
will override Pylance.
useLibraryCodeForTypes
is a double-edged sword. On the one hand, it can avoid issues like:
12:32 - error: "client" is not a known member of module (reportGeneralTypeIssues)
12:26 - error: Type of "client" is unknown (reportUnknownMemberType)
But on the other hand, the type information is inferred and can be incorrect. Some of these problems can only be fixed by the third party library author, and/or a type stub. Inference from source files can also be slow and can result in a sluggish experience for complex libraries like tensorflow.
The feature was added to provide completion suggestions when using Pylance (see pyright/#945). Setting "useLibraryCodeForTypes": false
will prevent type errors from incorrectly typed libraries. But, it will also disable "Go to Definition" behaviour in Pylance (see pylance-release/#278).
As of pyright 1.1.303 useLibraryCodeForTypes
defaults to true.
When pyright is run in strict mode and type stubs are missing it will generate a reportMissingTypeStubs
error.
This can be fixed by generating draft type stubs which by default are stored in typings/, eg:
pyright --createstub botocore
These stubs are a first draft intended for type-checking and are meant to be manually improved. --createstub
emits a comment with the return type for functions if it can be inferred. Whilst these may be incorrect they can reduce the manual work needed (see #1916).
--createstub
differ from useLibraryCodeForTypes
which is intended to create low-quality type information that's usually insufficient for type checking but may be sufficient for completion suggestions. (ref)
Compared to stubgen from mypy:
--createstub
does a better job at inferring function return types- stubgen does a better job at inferring some function args
--createstub
includes docstrings in the generated stubs
Reference:
- See Type Stub Files
NB: .pyi
stubs in typings/ take precedence over the same stubs in the virtualenv.
pyright can be supplied a set of files on the the command line, in which case it will ignore pyrightconfig.json and use the default configuration. For this reason, when using pyright in a pre-commit hook you probably want to specify pass_filenames: false
.
Pylance bundles stubs for pandas, matplotlib and other libraries. This stubs are incomplete. If you encounter a type error using these libraries that looks incorrect, first check the open issues on microsoft/pylance-release before reporting it.
Python doesn't have an explicit export keyword. Instead conventions has arisen on how to specify which modules and symbols in a library are its public interface. These include the following in in __init__.py:
- specifying exported symbols via the
__all__
symbol - using a redundant module or symbol alias during the import, eg:
from . import box as box
. See PEP 484 and the example here in rich #1596.
pyright 1.1.168 and later errors with reportPrivateImportUsage
when trying to import symbols that it considers private (ie: haven't be declared as above) from a type stubs or a py.typed library.
For more info see this comment.
To ignore reportGeneralTypeIssues for the whole file:
# pyright: reportGeneralTypeIssues=false
To ignore on a specific line:
# pyright: ignore[reportOptionalMemberAccess,reportOptionalSubscript,reportArgumentType,reportPrivateImportUsage]
Pyre can't find modules (#279) without specifying the search_path
pointing to site-packages. It's slow (11 secs) and doesn't find any issues out-of-the-box.
Mypy has > 1k open issues.
Pyright strict mode detects the most errors. Issues in pyright are quickly addressed. One drawback is it requires node and doesn't have a pypi distribution #819.