From 08b2cb46988521b0193b04ad265dcc3540a06322 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Mon, 6 Mar 2023 18:10:33 -0700 Subject: [PATCH] Did a consistency pass on documentation markdown. --- docs/_sidebar.md | 8 +++--- docs/builtins.md | 2 +- docs/commands.md | 6 ++-- docs/comments.md | 8 +++--- docs/configuration.md | 4 +-- docs/faq.md | 2 +- docs/features.md | 2 +- docs/img/PyrightSmall.png | Bin 0 -> 12294 bytes docs/import-resolution.md | 16 +++++------ docs/mypy-comparison.md | 58 +++++++++++++++++++------------------- docs/settings.md | 2 +- docs/type-inference.md | 42 +++++++++++++-------------- docs/type-stubs.md | 12 ++++---- docs/typed-libraries.md | 52 +++++++++++++++++----------------- 14 files changed, 107 insertions(+), 107 deletions(-) create mode 100644 docs/img/PyrightSmall.png diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 2b0fabc9a..ad39152a9 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -1,16 +1,16 @@ -- Getting started +- Getting Started - [Installation](installation.md) - [Type Concepts](type-concepts.md) - - [Getting Started with Type Checking](getting-started.md) - - [Pyright Features](features.md) + - [Type Checking Your Code](getting-started.md) + - [Features](features.md) - [FAQ](faq.md) - Customization - [Continuous Integration (CI)](ci-integration.md) - [Configuration](configuration.md) - - [Configuration Options](configuration.md#main-pyright-config-options) + - [Configuration Options](configuration.md#main-configuration-options) - [Diagnostic Rules](configuration.md#type-check-diagnostics-settings) - [Execution Environments](configuration.md#execution-environment-options) - [Sample pyrightconfig.json](configuration.md#sample-config-file) diff --git a/docs/builtins.md b/docs/builtins.md index 3aadb27ea..090a4afd2 100644 --- a/docs/builtins.md +++ b/docs/builtins.md @@ -1,4 +1,4 @@ -# Extending Builtins +## 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”. diff --git a/docs/commands.md b/docs/commands.md index 5ca235c92..502887fb7 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,11 +1,11 @@ -# VS Code Commands +## VS Code Commands Pyright offers the following commands, which can be invoked from VS Code’s “Command Palette”, which can be accessed from the View menu or by pressing Cmd-Shift-P. -## Organize Imports +### Organize Imports This command reorders all imports found in the global (module-level) scope of the source file. As recommended in PEP8, imports are grouped into three groups, each separated by an empty line. The first group includes all built-in modules, the second group includes all third-party modules, and the third group includes all local modules. Within each group, imports are sorted alphabetically. And within each “from X import Y” statement, the imported symbols are sorted alphabetically. Pyright also rewraps any imports that don't fit within a single line, switching to multi-line formatting. -## Restart Server +### Restart Server This command forces the type checker to discard all of its cached type information and restart analysis. It is useful in cases where new type stubs or libraries have been installed. diff --git a/docs/comments.md b/docs/comments.md index e91f2b3c9..91886c1bb 100644 --- a/docs/comments.md +++ b/docs/comments.md @@ -1,8 +1,8 @@ -# Comments +## Comments Some behaviors of pyright can be controlled through the use of comments within the source file. -## Type Annotations +### Type Annotations Versions of Python prior to 3.6 did not support type annotations for variables. Pyright honors type annotations found within a comment at the end of the same line where a variable is assigned. ```python @@ -13,7 +13,7 @@ self._target = 3 # type: int | str Future versions of Python will likely deprecate support for type annotation comments. The “reportTypeCommentUsage” diagnostic will report usage of such comments so they can be replaced with inline type annotations. -## File-level Type Controls +### File-level Type Controls Strict type checking, where most supported type-checking switches generate errors, can be enabled for a file through the use of a special comment. Typically this comment is placed at or near the top of a code file on its own line. ```python @@ -38,7 +38,7 @@ Diagnostic levels are also supported. # pyright: reportPrivateUsage=warning, reportOptionalCall=error ``` -## Line-level Diagnostic Suppression +### Line-level Diagnostic Suppression PEP 484 defines a special comment `# type: ignore` that can be used at the end of a line to suppress all diagnostics emitted by a type checker on that line. Pyright supports this mechanism. diff --git a/docs/configuration.md b/docs/configuration.md index daa784a46..c7e949533 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,4 +1,4 @@ -# Pyright Configuration +## Pyright Configuration Pyright offers flexible configuration options specified in a JSON-formatted text configuration. By default, the file is called “pyrightconfig.json” and is located within the root directory of your project. Multi-root workspaces (“Add Folder to Workspace…”) are supported, and each workspace root can have its own “pyrightconfig.json” file. For a sample pyrightconfig.json file, see [below](configuration.md#sample-config-file). @@ -6,7 +6,7 @@ Pyright settings can also be specified in a `[tool.pyright]` section of a “pyp Relative paths specified within the config file are relative to the config file’s location. Paths with shell variables (including `~`) are not supported. Paths within a the config file should generally be relative paths so the config file can be shared by other developers who contribute to the project. -## Main Pyright Config Options +## Main Configuration Options **include** [array of paths, optional]: Paths of directories or files that should be included. If no paths are specified, pyright defaults to the directory that contains the config file. Paths may contain wildcard characters ** (a directory or multiple levels of directories), * (a sequence of zero or more characters), or ? (a single character). If no include paths are specified, the root path for the workspace is assumed. diff --git a/docs/faq.md b/docs/faq.md index 87b5a8b0c..d2fe4ea3f 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,4 +1,4 @@ -# Frequently Asked Questions +## Frequently Asked Questions **Q:** What is the difference between Pyright and [Pylance](https://github.com/microsoft/pylance-release)? diff --git a/docs/features.md b/docs/features.md index 53073f9ba..dbe27d571 100644 --- a/docs/features.md +++ b/docs/features.md @@ -1,4 +1,4 @@ -# Pyright Features +## Pyright Features ### Speed Pyright is a fast type checker meant for large Python source bases. It can run in a “watch” mode and performs fast incremental updates when files are modified. diff --git a/docs/img/PyrightSmall.png b/docs/img/PyrightSmall.png new file mode 100644 index 0000000000000000000000000000000000000000..043de771ea3303c4401a5f97444c803460670685 GIT binary patch literal 12294 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 literal 0 HcmV?d00001 diff --git a/docs/import-resolution.md b/docs/import-resolution.md index 5eaa66f64..e71b7194e 100644 --- a/docs/import-resolution.md +++ b/docs/import-resolution.md @@ -1,6 +1,6 @@ -# Import Resolution +## Import Resolution -## Resolution Order +### Resolution Order If the import is relative (the module name starts with one or more dots), it resolves the import relative to the path of the importing source file. For absolute (non-relative) imports, Pyright employs the following resolution order: @@ -28,7 +28,7 @@ For absolute (non-relative) imports, Pyright employs the following resolution or -## Configuring Your Python Environment +### Configuring Your Python Environment Pyright does not require a Python environment to be configured if all imports can be resolved using local files and type stubs. If a Python environment is configured, it will attempt to use the packages installed in the `site-packages` subdirectory during import resolution. Pyright uses the following mechanisms (in priority order) to determine which Python environment to use: @@ -39,7 +39,7 @@ Pyright uses the following mechanisms (in priority order) to determine which Pyt 3. As a fallback, use the default Python environment (i.e. the one that is invoked when typing `python` in the shell). -## Editable installs +### Editable installs [PEP 660](https://peps.python.org/pep-0660/) enables build backends (e.g. setuptools) to use import hooks to direct the [import machinery](https://docs.python.org/3/reference/import.html) @@ -55,21 +55,21 @@ the editable install to use `.pth` files instead of import hooks. See your build documentation for details on how to do this. We have provided some basic information for common build backends below. -### Setuptools +#### Setuptools Setuptools currently supports two ways to request: [“compat mode”](https://setuptools.pypa.io/en/latest/userguide/development_mode.html#legacy-behavior) where a `.pth` file will be used -- a config setting and an environment variable. Another option is [“strict mode”](https://setuptools.pypa.io/en/latest/userguide/development_mode.html#strict-editable-installs) which uses symlinks instead. -### Hatch/Hatchling +#### Hatch/Hatchling [Hatchling](https://hatch.pypa.io/latest/config/build/#dev-mode) uses `.pth` files by default. It will only use import hooks if you set `dev-mode-exact` to `true`. -### PDM +#### PDM [PDM](https://pdm.fming.dev/latest/pyproject/build/#editable-build-backend) uses `.pth` files by default. It will only use import hooks if you set `editable-backend` to `"editables"`. -## Debugging Import Resolution Problems +### Debugging Import Resolution Problems The import resolution mechanisms in Python are complicated, and Pyright offers many configuration options. If you are encountering problems with import resolution, Pyright provides additional logging that may help you identify the cause. To enable verbose logging, pass `--verbose` as a command-line argument or add the following entry to the config file `"verboseOutput": true`. If you are using the Pyright VS Code extension, the additional logging will appear in the Output tab (select “Pyright” from the menu). Please include this verbose logging when reporting import resolution bugs. diff --git a/docs/mypy-comparison.md b/docs/mypy-comparison.md index 3baf91380..2c32971e5 100644 --- a/docs/mypy-comparison.md +++ b/docs/mypy-comparison.md @@ -1,18 +1,18 @@ -# Differences Between Pyright and Mypy +## Differences Between Pyright and Mypy -## What is Mypy? +### What is Mypy? Mypy is the “OG” in the world of Python type checkers. It was started by Jukka Lehtosalo in 2012 with contributions from Guido van Rossum, Ivan Levkivskyi, and many others over the years. For a detailed history, refer to [this documentation](http://mypy-lang.org/about.html). The code for mypy can be found in [this github project](https://github.com/python/mypy). -## Why Does Pyright’s Behavior Differ from Mypy’s? +### Why Does Pyright’s Behavior Differ from Mypy’s? Mypy served as a reference implementation of [PEP 484](https://www.python.org/dev/peps/pep-0484/), which defines standard behaviors for Python static typing. Although PEP 484 spells out many type checking behaviors, it intentionally leaves many other behaviors undefined. This approach has allowed different type checkers to innovate and differentiate. Pyright generally adheres to the type checking behaviors spelled out in PEP 484 and follow-on typing PEPs (526, 544, 586, 589, etc.). For behaviors that are not explicitly spelled out in these standards, pyright generally tries to adhere to mypy’s behavior unless there is a compelling justification for deviating. This document discusses these differences and provides the reasoning behind each design choice. -## Design Goals +### Design Goals Pyright was designed with performance in mind. It is not unusual for pyright to be 3x to 5x faster than mypy when type checking large code bases. Some of its design decisions were motivated by this goal. @@ -23,21 +23,21 @@ To achieve these design goals, pyright is implemented as a “lazy” or “just Pyright implements its own parser, which recovers gracefully from syntax errors and continues parsing the remainder of the source file. By comparison, mypy uses the parser built in to the Python interpreter, and it does not support recovery after a syntax error. -## Type Checking Unannotated Code +### Type Checking Unannotated Code By default, pyright performs type checking for all code regardless of whether it contains type annotations. This is important for language server features. It is also important for catching bugs in code that is unannotated. By default, mypy skips all functions or methods that do not have type annotations. This is a common source of confusion for mypy users who are surprised when type violations in unannotated functions go unreported. If the option `--check-untyped-defs` is enabled, mypy performs type checking for all functions and methods. -## Inferred Return Types +### Inferred Return Types If a function or method lacks a return type annotation, pyright infers the return type from `return` and `yield` statements within the function’s body (including the implied `return None` at the end of the function body). This is important for supporting completion suggestions. It also improves type checking coverage and eliminates the need for developers to needlessly supply return type annotations for trivial return types. By comparison, mypy never infers return types and assumes that functions without a return type annotation have a return type of `Any`. This was an intentional design decision by mypy developers and is explained in [this thread](https://github.com/python/mypy/issues/10149). -## Unions vs Joins +### Unions vs Joins When merging two types during code flow analysis or widening types during constraint solving, pyright always uses a union operation. Mypy typically (but not always) uses a “join” operation, which merges types by finding a common supertype. The use of joins discards valuable type information and leads to many false positive errors that are [well documented within the mypy issue tracker](https://github.com/python/mypy/issues?q=is%3Aissue+is%3Aopen+label%3Atopic-join-v-union). @@ -61,7 +61,7 @@ def func2(condition: bool, val1: str, val2: int): ``` -## Variable Type Declarations +### Variable Type Declarations Pyright treats variable type annotations as type declarations. If a variable is not annotated, pyright allows any value to be assigned to that variable, and its type is inferred to be the union of all assigned types. @@ -90,7 +90,7 @@ def func3(condition: bool): Pyright’s behavior is more consistent, is conceptually simpler and more natural for Python developers, leads to fewer false positives, and eliminates the need for many otherwise-necessary variable type annotations. -## Class and Instance Variable Inference +### Class and Instance Variable Inference Pyright handles instance and class variables consistently with local variables. If a type annotation is provided for an instance or class variable (either within the class or one of its base classes), pyright treats this as a type declaration and enforces it accordingly. If a class implementation does not provide a type annotation for an instance or class variable and its base classes likewise do not provide a type annotation, the variable’s type is inferred from all assignments within the class implementation. @@ -110,7 +110,7 @@ a.x = 3.0 # Pyright treats this as an error because the type of `x` is `int | st ``` -## Class and Instance Variable Enforcement +### Class and Instance Variable Enforcement Pyright distinguishes between “pure class variables”, “regular class variables”, and “pure instance variable”. For a detailed explanation, refer to [this documentation](type-concepts.md#class-and-instance-variables). @@ -130,7 +130,7 @@ print(A.z) # pyright: error, mypy: no error ``` -## Assignment-based Type Narrowing +### Assignment-based Type Narrowing Pyright applies type narrowing for variable assignments. This is done regardless of whether the assignment statement includes a variable type annotation. Mypy skips assignment-based type narrowing when the target variable includes a type annotation. The consensus of the typing community is that mypy’s behavior here is inconsistent, and there are [plans to eliminate this inconsistency](https://github.com/python/mypy/issues/2008). @@ -144,7 +144,7 @@ reveal_type(v2) # mypy reveals `Sequence[int]` rather than `list[int]` ``` -## Type Guards +### Type Guards Pyright supports several built-in type guards that mypy does not currently support. For a full list of type guard expression forms supported by pyright, refer to [this documentation](type-concepts.md#type-guards). @@ -156,12 +156,12 @@ The following expression forms are not currently supported by mypy as type guard * `bool(x)` (where x is any expression that is statically verifiable to be truthy or falsey in all cases) -## Aliased Conditional Expressions +### Aliased Conditional Expressions Pyright supports the [aliasing of conditional expressions](type-concepts.md#aliased-conditional-expression) used for type guards. Mypy does not currently support this, but it is a frequently-requested feature. -## Narrowing for Implied Else +### Narrowing for Implied Else Pyright supports a feature called [type narrowing for implied else](type-concepts.md#narrowing-for-implied-else) in cases where an `if` or `elif` clause has no associated `else` clause. This feature allows pyright to determine that all cases have already been handled by the `if` or `elif` statement and that the "implied else" would never be executed if it were present. This eliminates certain false positive errors. Mypy currently does not support this. @@ -178,7 +178,7 @@ def is_red(color: Color) -> bool: # mypy reports error: Missing return statement ``` -## Narrowing Any +### Narrowing Any Pyright never narrows `Any` when performing type narrowing for assignments. Mypy is inconsistent about when it applies type narrowing to `Any` type arguments. @@ -194,7 +194,7 @@ reveal_type(b) # pyright: list[Any], mypy: list[int] ``` -## Inference of List, Set, and Dict Expressions +### Inference of List, Set, and Dict Expressions Pyright’s inference rules for [list, set and dict expressions](type-inference.md#list-expressions) differ from mypy’s when values with heterogeneous types are used. Mypy uses a join operator to combine the types. Pyright uses either an `Unknown` or a union depending on configuration settings. A join operator often produces a type that is not what was intended, and this leads to false positive errors. @@ -215,7 +215,7 @@ def func(one: Literal[1]): ``` -## Inference of Tuple Expressions +### Inference of Tuple Expressions Pyright’s inference rules for [tuple expressions](type-inference.md#tuple-expressions) differ from mypy’s when tuple entries contain literals. Pyright retains these literal types, but mypy widens the types to their non-literal type. Pyright retains the literal types in this case because tuples are immutable, and more precise (narrower) types are almost always beneficial in this situation. @@ -227,7 +227,7 @@ y: Literal["stop", "go"] = x[1] # mypy: type error ``` -## Assignment-Based Narrowing for Literals +### Assignment-Based Narrowing for Literals When assigning a literal value to a variable, pyright narrows the type to reflect the literal. Mypy does not. Pyright retains the literal types in this case because more precise (narrower) types are typically beneficial and have little or no downside. @@ -250,19 +250,19 @@ def func2(): ``` -## Type Narrowing for Asymmetric Descriptors +### Type Narrowing for Asymmetric Descriptors When pyright evaluates a write to a class variable that contains a descriptor object (including properties), it normally applies assignment-based type narrowing. However, when the descriptor is asymmetric — that is, its “getter” type is different from its “setter” type, pyright refrains from applying assignment-based type narrowing. For a full discussion of this, refer to [this issue](https://github.com/python/mypy/issues/3004). Mypy has not yet implemented the agreed-upon behavior, so its type narrowing behavior may differ from pyright’s in this case. -## Parameter Type Inference +### Parameter Type Inference Mypy infers the type of `self` and `cls` parameters in methods but otherwise does not infer any parameter types. Pyright implements several parameter type inference techniques that improve type checking and language service features in the absence of explicit parameter type annotations. For details, refer to [this documentation](type-inference.md#parameter-type-inference). -## Constraint Solver Behaviors +### Constraint Solver Behaviors When evaluating a call expression that invokes a generic class constructor or a generic function, a type checker performs a process called “constraint solving” to solve the type variables found within the target function signature. The solved type variables are then applied to the return type of that function to determine the final type of the call expression. This process is called “constraint solving” because it takes into account various constraints that are specified for each type variable. These constraints include variance rules and type variable bounds. @@ -322,7 +322,7 @@ def func2(x: list[int], y: list[str] | int): ``` -## Constrained Type Variables +### Constrained Type Variables When mypy analyzes a class or function that has in-scope constrained TypeVars, it analyzes the class or function multiple times, once for each constraint. This can produce multiple errors. @@ -337,7 +337,7 @@ def func(a: AnyStr, b: T): Pyright cannot use the same multi-pass technique as mypy in this case. It needs to produce a single type for any given identifier to support language server features. Pyright instead uses a mechanism called [conditional types](type-concepts.md#constrained-type-variables-and-conditional-types). This approach allows pyright to handle some constrained TypeVar use cases that mypy cannot, but there are conversely other use cases that mypy can handle and pyright cannot. -## “Unknown” Type and Strict Mode +### “Unknown” Type and Strict Mode Pyright differentiates between explicit and implicit forms of `Any`. The implicit form is referred to as [`Unknown`](type-inference.md#unknown-type). For example, if a parameter is annotated as `list[Any]`, that is a use of an explicit `Any`, but if a parameter is annotated as `list`, that is an implicit `Any`, so pyright refers to this type as `list[Unknown]`. Pyright implements several checks that are enabled in “strict” type-checking modes that report the use of an `Unknown` type. Such uses can mask type errors. @@ -346,12 +346,12 @@ Mypy does not track the difference between explicit and implicit `Any` types, bu Pyright’s approach gives developers more control. It provides a way to be explicit about `Any` where that is the intent. When an `Any` is implicitly produced due to an missing type argument or some other condition that produces an `Any` within the type checker logic, the developer is alerted to that condition. -## Overload Resolution +### Overload Resolution Overload resolution rules are under-specified in PEP 484. Pyright and mypy apply similar rules, but there are likely some complex edge cases where different results will be produced. For full documentation of pyright’s overload behaviors, refer to [this documentation](type-concepts.md#overloads). -## Import Statements +### Import Statements Pyright intentionally does not model implicit side effects of the Python import loading mechanism. In general, such side effects cannot be modeled statically because they depend on execution order. Dependency on such side effects leads to fragile code, so pyright treats these as errors. For more details, refer to [this documentation](import-statements.md). @@ -362,14 +362,14 @@ import collections.abc collections.deque() # Pyright produces an error here because the `collections` module wasn't explicitly imported ``` -## Ellipsis in Function Body +### Ellipsis in Function Body If Pyright encounters a function body whose implementation is `...`, it does not enforce the return type annotation. The `...` semantically means “this is a code placeholder” — a convention established in type stubs, protocol definitions, and elsewhere. Mypy treats `...` function bodies as though they are executable and enforces the return type annotation. This was a recent change in mypy — made long after Pyright established a different behavior. Prior to mypy’s recent change, it did not enforce return types for function bodies consisting of either `...` or `pass`. Now it enforces both. -## Circular References +### Circular References Because mypy is a multi-pass analyzer, it is able to deal with certain forms of circular references that pyright cannot handle. Here are several examples of circularities that mypy resolves without errors but pyright does not. @@ -398,12 +398,12 @@ def my_decorator(x: Callable[..., "A"]) -> Callable[..., "A"]: class A: ... ``` -## Class Decorator Evaluation +### Class Decorator Evaluation Pyright honors class decorators. Mypy largely ignores them. See [this issue](https://github.com/python/mypy/issues/3135) for details. -## Support for Type Comments +### Support for Type Comments Versions of Python prior to 3.0 did not have a dedicated syntax for supplying type annotations. Annotations therefore needed to be supplied using “type comments” of the form `# type: `. Python 3.6 added the ability to supply type annotations for variables. diff --git a/docs/settings.md b/docs/settings.md index 130148ef0..cc9b6c39a 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -1,4 +1,4 @@ -# Pyright Settings +## Pyright Settings The Pyright language server honors the following settings. diff --git a/docs/type-inference.md b/docs/type-inference.md index f0bc4d146..63c3d55bb 100644 --- a/docs/type-inference.md +++ b/docs/type-inference.md @@ -1,6 +1,6 @@ -# Understanding Type Inference +## Understanding Type Inference -## Symbols and Scopes +### Symbols and Scopes In Python, a _symbol_ is any name that is not a keyword. Symbols can represent classes, functions, methods, variables, parameters, modules, type aliases, type variables, etc. @@ -13,7 +13,7 @@ The following constructs within Python define a scope: 4. Each function and lambda defines its own scope. The function’s parameters are symbols within its scope, as are any variables defined within the function. 5. List comprehensions define their own scope. -## Type Declarations +### Type Declarations A symbol can be declared with an explicit type. The “def” and “class” keywords, for example, declare a symbol as a function or a class. Other symbols in Python can be introduced into a scope with no declared type. Newer versions of Python have introduced syntax for declaring the types of input parameters, return parameters, and variables. @@ -43,17 +43,17 @@ var3 | Variable | func1 | Note that once a symbol’s type is declared, it cannot be redeclared to a different type. -## Type Inference +### Type Inference Some languages require every symbol to be explicitly typed. Python allows a symbol to be bound to different values at runtime, so its type can change over time. A symbol’s type doesn’t need to be declared statically. When Pyright encounters a symbol with no type declaration, it attempts to _infer_ the type based on the values assigned to it. As we will see below, type inference cannot always determine the correct (intended) type, so type annotations are still required in some cases. Furthermore, type inference can require significant computation, so it is much less efficient than when type annotations are provided. -## “Unknown” Type +### “Unknown” Type If a symbol’s type cannot be inferred, Pyright sets its type to “Unknown”, which is a special form of “Any”. The “Unknown” type allows Pyright to optionally warn when types are not declared and cannot be inferred, thus leaving potential “blind spots” in type checking. -### Single-Assignment Type Inference +#### Single-Assignment Type Inference The simplest form of type inference is one that involves a single assignment to a symbol. The inferred type comes from the type of the source expression. Examples include: @@ -66,7 +66,7 @@ for var5 in [3, 4]: ... # Inferred type is int var6 = [p for p in [1, 2, 3]] # Inferred type is list[int] ``` -### Multi-Assignment Type Inference +#### Multi-Assignment Type Inference When a symbol is assigned values in multiple places within the code, those values may have different types. The inferred type of the variable is the union of all such types. @@ -86,11 +86,11 @@ else: var2 = Foo() ``` -### Ambiguous Type Inference +#### Ambiguous Type Inference In some cases, an expression’s type is ambiguous. For example, what is the type of the expression `[]`? Is it `list[None]`, `list[int]`, `list[Any]`, `Sequence[Any]`, `Iterable[Any]`? These ambiguities can lead to unintended type violations. Pyright uses several techniques for reducing these ambiguities based on contextual information. In the absence of contextual information, heuristics are used. -### Bidirectional Type Inference (Expected Types) +#### Bidirectional Type Inference (Expected Types) One powerful technique Pyright uses to eliminate type inference ambiguities is _bidirectional inference_. This technique makes use of an “expected type”. @@ -109,7 +109,7 @@ var5 = (3,) # Type is assumed to be tuple[Literal[3]] var6: tuple[float, ...] = (3,) # Type of RHS is now tuple[float, ...] ``` -### Empty list and Dictionary Type Inference +#### Empty list and Dictionary Type Inference It is common to initialize a local variable or instance variable to an empty list (`[]`) or empty dictionary (`{}`) on one code path but initialize it to a non-empty list or dictionary on other code paths. In such cases, Pyright will infer the type based on the non-empty list or dictionary and suppress errors about a “partially unknown type”. @@ -123,7 +123,7 @@ reveal_type(my_list) # list[str] ``` -### Return Type Inference +#### Return Type Inference As with variable assignments, function return types can be inferred from the `return` statements found within that function. The returned type is assumed to be the union of all types returned from all `return` statements. If a `return` statement is not followed by an expression, it is assumed to return `None`. Likewise, if the function does not end in a `return` statement, and the end of the function is reachable, an implicit `return None` is assumed. @@ -140,7 +140,7 @@ def func1(val: int): return True ``` -### NoReturn return type +#### NoReturn return type If there is no code path that returns from a function (e.g. all code paths raise an exception), Pyright infers a return type of `NoReturn`. As an exception to this rule, if the function is decorated with `@abstractmethod`, the return type is not inferred as `NoReturn` even if there is no return. This accommodates a common practice where an abstract method is implemented with a `raise NotImplementedError()` statement. @@ -156,11 +156,11 @@ class Foo: raise NotImplementedError() ``` -### Generator return types +#### Generator return types Pyright can infer the return type for a generator function from the `yield` statements contained within that function. -### Call-site Return Type Inference +#### Call-site Return Type Inference It is common for input parameters to be unannotated. This can make it difficult for Pyright to infer the correct return type for a function. For example: @@ -191,7 +191,7 @@ def func2(p_int: int, p_str: str, p_flt: float): var2 = func1(p_str, p_flt, p_int) ``` -### Parameter Type Inference +#### Parameter Type Inference Input parameters for functions and methods typically require type annotations. There are several cases where Pyright may be able to infer a parameter’s type if it is unannotated. @@ -225,7 +225,7 @@ def func(a, b=0, c=None): reveal_type(func) # (a: Unknown, b: int, c: Unknown | None) -> None ``` -### Literals +#### Literals Python 3.8 introduced support for _literal types_. This allows a type checker like Pyright to track specific literal values of str, bytes, int, bool, and enum values. As with other types, literal types can be declared. @@ -249,7 +249,7 @@ When Pyright is performing type inference, it generally does not infer literal t var1 = [4] ``` -### Tuple Expressions +#### Tuple Expressions When inferring the type of a tuple expression (in the absence of bidirectional inference hints), Pyright assumes that the tuple has a fixed length, and each tuple element is typed as specifically as possible. @@ -267,7 +267,7 @@ def func1(a: int): var3: tuple[int, ...] = (a, a) ``` -### List Expressions +#### List Expressions When inferring the type of a list expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics: @@ -293,7 +293,7 @@ var4: list[float] = [1, 3.4] # Infer list[float] ``` -### Set Expressions +#### Set Expressions When inferring the type of a set expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics: @@ -316,7 +316,7 @@ var3: set[float] = {1, 3.4} # Infer set[float] ``` -### Dictionary Expressions +#### Dictionary Expressions When inferring the type of a dictionary expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics: @@ -340,7 +340,7 @@ var3 = {"a": 3, "b": 3.4} # Infer dict[str, int | float] (on) var4: dict[str, float] = {"a": 3, "b": 3.4} ``` -### Lambdas +#### Lambdas Lambdas present a particular challenge for a Python type checker because there is no provision in the Python syntax for annotating the types of a lambda’s input parameters. The types of these parameters must therefore be inferred based on context using bidirectional type inference. Absent this context, a lambda’s input parameters (and often its return type) will be unknown. diff --git a/docs/type-stubs.md b/docs/type-stubs.md index beb01d257..6a9343814 100644 --- a/docs/type-stubs.md +++ b/docs/type-stubs.md @@ -1,8 +1,8 @@ -# Type Stub Files +## Type Stub Files Type stubs are “.pyi” files that specify the public interface for a library. They use a variant of the Python syntax that allows for “...” to be used in place of any implementation details. Type stubs define the public contract for the library. -## Importance of Type Stub Files +### Importance of Type Stub Files Regardless of the search path, Pyright always attempts to resolve an import with a type stub (“.pyi”) file before falling back to a python source (“.py”) file. If a type stub cannot be located for an external import, Pyright will try to use inline type information if the module is part of a package that contains a “py.typed” file (defined in [PEP 561](https://www.python.org/dev/peps/pep-0561/)). If the module is part of a package that doesn’t contain a “py.typed” file, Pyright will treat all of the symbols imported from these modules will be of type “Unknown”, and wildcard imports (of the form `from foo import *`) will not populate the module’s namespace with specific symbol names. @@ -16,12 +16,12 @@ Why does Pyright not attempt (by default) to determine types from imported pytho If you’re serious about static type checking for your Python source base, it’s highly recommended that you consume “py.typed” packages or use type stub files for all external imports. If you are unable to find a type stub for a particular library, the recommended approach is to create a custom type stub file that defines the portion of that module’s interface used by your code. More library maintainers have started to provide inlined types or type stub files. -## Generating Type Stubs +### Generating Type Stubs If you use only a few classes, methods or functions within a library, writing a type stub file by hand is feasible. For large libraries, this can become tedious and error-prone. Pyright can generate “draft” versions of type stub files for you. To generate a type stub file from within VS Code, enable the reportMissingTypeStubs” setting in your pyrightconfig.json file or by adding a comment `# pyright: reportMissingTypeStubs=true` to individual source files. Make sure you have the target library installed in the python environment that pyright is configured to use for import resolution. Optionally specify a “stubPath” in your pyrightconfig.json file. This is where pyright will generate your type stub files. By default, the stubPath is set to "./typings". -### Generating Type Stubs in VS Code +#### Generating Type Stubs in VS Code If “reportMissingTypeStubs” is enabled, pyright will highlight any imports that have no type stub. Hover over the error message, and you will see a “Quick Fix” link. Clicking on this link will reveal a popup menu item titled “Create Type Stub For XXX”. The example below shows a missing typestub for the `django` library. ![Pyright](img/CreateTypeStub1.png) @@ -30,13 +30,13 @@ Click on the menu item to create the type stub. Depending on the size of the lib ![Pyright](img/CreateTypeStub2.png) -### Generating Type Stubs from Command Line +#### Generating Type Stubs from Command Line The command-line version of pyright can also be used to generate type stubs. As with the VS Code version, it must be run within the context of your configured project. Then type `pyright --createstub [import-name]`. For example: `pyright --createstub django` -### Cleaning Up Generated Type Stubs +#### Cleaning Up Generated Type Stubs Pyright can give you a head start by creating type stubs, but you will typically need to clean up the first draft, fixing various errors and omissions that pyright was not able to infer from the original library code. A few common situations that need to be cleaned up: diff --git a/docs/typed-libraries.md b/docs/typed-libraries.md index 47139e4da..6f86b510c 100644 --- a/docs/typed-libraries.md +++ b/docs/typed-libraries.md @@ -1,4 +1,4 @@ -# Typing Guidance for Python Libraries +## Typing Guidance for Python Libraries Much of Python’s popularity can be attributed to the rich collection of Python libraries available to developers. Authors of these libraries play an important role in improving the experience for Python developers. This document provides some recommendations and guidance for Python library authors. @@ -10,7 +10,7 @@ These recommendations are intended to provide the following benefits: 4. Library authors should have the benefits of static type checking to produce high-quality, bug-free implementations. -## Inlined Type Annotations and Type Stubs +### Inlined Type Annotations and Type Stubs [PEP 561](https://www.python.org/dev/peps/pep-0561/) documents several ways type information can be delivered for a library: inlined type annotations, type stub files included in the package, a separate companion type stub package, and type stubs in the typeshed repository. Some of these options fall short on delivering the benefits above. We therefore provide the following more specific guidance to library authors. All libraries should include inlined type annotations for the functions, classes, methods, and constants that comprise the public interface for the library. @@ -22,7 +22,7 @@ There are cases where inlined type annotations are not possible — most notably In many existing type stubs (such as those found in typeshed), default parameter values are replaced with with “...” and all docstrings are removed. We recommend that default values and docstrings remain within the type stub file so language servers can display this information to developers. -## Library Interface +### Library Interface [PEP 561](https://www.python.org/dev/peps/pep-0561/) indicates that a “py.typed” marker file must be included in the package if the author wishes to support type checking of their code. If a “py.typed” module is present, a type checker will treat all modules within that package (i.e. all files that end in “.py” or “.pyi”) as importable unless the module is marked private. There are two ways to mark a module private: (1) the module's filename begins with an underscore; (2) the module is inside a sub-package marked private. For example: @@ -50,7 +50,7 @@ The following idioms are supported for defining the values contained within `__a * `__all__.remove('a')` -## Type Completeness +### Type Completeness A “py.typed” library is said to be “type complete” if all of the symbols that comprise its interface have type annotations that refer to types that are fully known. Private symbols are exempt. A “known type” is defined as follows: @@ -86,14 +86,14 @@ Type annotations can be omitted in a few specific cases where the type is obviou * A variable is assigned in only one location using a simple assignment expression and the right-hand side of the assignment is a literal value (e.g. `1`, `3.14`, `"hi"`, or `MyEnum.Value`) or an identifier that has a known type that doesn't depend on type narrowing logic. -### Ambiguous Types +#### Ambiguous Types When a symbol is missing a type annotation, a type checker may be able to infer its type based on contextual information. However, type inference rules are not standardized and differ between type checkers. A symbol is said to have an “ambiguous type” if its type may be inferred differently between different Python type checkers. This can lead to a bad experience for consumers of the library. Ambiguous types can be avoided by providing explicit type annotations. -### Examples of known, ambiguous and unknown types +#### Examples of known, ambiguous and unknown types ```python # Variable with known type (unambiguous because it uses a literal assignment) @@ -206,7 +206,7 @@ class DictSubclass(dict): ``` -## Verifying Type Completeness +### Verifying Type Completeness Pyright provides a feature that allows library authors to verify type completeness for a “py.typed” package. To use this feature, create a clean Python environment and install your package along with all of the other dependent packages. Run the CLI version of pyright with the `--verifytypes` option. `pyright --verifytypes ` @@ -222,7 +222,7 @@ The `--verifytypes` feature can be integrated into a continuous integration (CI) If the `--verifytypes` option is combined with `--ignoreexternal`, any incomplete types that are imported from other external packages are ignored. This allows library authors to focus on adding type annotations for the code that is directly under their control. -### Improving Type Completeness +#### Improving Type Completeness Here are some tips for increasing the type completeness score for your library: @@ -232,19 +232,19 @@ Here are some tips for increasing the type completeness score for your library: * If your package exposes types from other libraries, work with the maintainers of these other libraries to achieve type completeness. -## Best Practices for Inlined Types +### Best Practices for Inlined Types -### Wide vs. Narrow Types +#### Wide vs. Narrow Types In type theory, when comparing two types that are related to each other, the “wider” type is the one that is more general, and the “narrower” type is more specific. For example, `Sequence[str]` is a wider type than `list[str]` because all `list` objects are also `Sequence` objects, but the converse is not true. A subclass is narrower than a class it derives from. A union of types is wider than the individual types that comprise the union. In general, a function input parameter should be annotated with the widest possible type supported by the implementation. For example, if the implementation requires the caller to provide an iterable collection of strings, the parameter should be annotated as `Iterable[str]`, not as `list[str]`. The latter type is narrower than necessary, so if a user attempts to pass a tuple of strings (which is supported by the implementation), a type checker will complain about a type incompatibility. As a specific application of the “use the widest type possible” rule, libraries should generally use immutable forms of container types instead of mutable forms (unless the function needs to modify the container). Use `Sequence` rather than `list`, `Mapping` rather than `dict`, etc. Immutable containers allow for more flexibility because their type parameters are covariant rather than invariant. A parameter that is typed as `Sequence[str | int]` can accept a `list[str | int]`, `list[int]`, `Sequence[str]`, and a `Sequence[int]`. But a parameter typed as `list[str | int]` is much more restrictive and accepts only a `list[str | int]`. -### Overloads +#### Overloads If a function or method can return multiple different types and those types can be determined based on the presence or types of certain parameters, use the `@overload` mechanism defined in [PEP 484](https://www.python.org/dev/peps/pep-0484/#id45). When overloads are used within a “.py” file, they must appear prior to the function implementation, which should not have an `@overload` decorator. -### Keyword-only Parameters +#### Keyword-only Parameters If a function or method is intended to take parameters that are specified only by name, use the keyword-only separator ("*"). ```python @@ -252,7 +252,7 @@ def create_user(age: int, *, dob: date | None = None): ... ``` -### Positional-only Parameters +#### Positional-only Parameters If a function or method is intended to take parameters that are specified only by position, use the positional-only separator ("/") as documented in [PEP 570](https://peps.python.org/pep-0570/). If your library needs to run on versions of Python prior to 3.8, you can alternatively name the positional-only parameters with an identifier that begins with a double underscore. ```python @@ -288,10 +288,10 @@ def complex_decorator(*, mode: str) -> Callable[[_F], _F]: Decorators that mutate the signature of the decorated function present challenges for type annotations. The `ParamSpec` and `Concatenate` mechanisms described in [PEP 612](https://www.python.org/dev/peps/pep-0612/) provide some help here, but these are available only in Python 3.10 and newer. More complex signature mutations may require type annotations that erase the original signature, thus blinding type checkers and other tools that provide signature assistance. As such, library authors are discouraged from creating decorators that mutate function signatures in this manner. -### Generic Classes and Functions +#### Generic Classes and Functions Classes and functions that can operate in a generic manner on various types should declare themselves as generic using the mechanisms described in [PEP 484](https://www.python.org/dev/peps/pep-0484/). This includes the use of `TypeVar` symbols. Typically, a `TypeVar` should be private to the file that declares it, and should therefore begin with an underscore. -### Type Aliases +#### Type Aliases Type aliases are symbols that refer to other types. Generic type aliases (those that refer to unspecialized generic classes) are supported by most type checkers. Pyright also provides support for recursive type aliases. [PEP 613](https://www.python.org/dev/peps/pep-0613/) provides a way to explicitly designate a symbol as a type alias using the new TypeAlias annotation. @@ -310,7 +310,7 @@ TreeNode = LeafNode | list["TreeNode"] StrOrInt: TypeAlias = str | int ``` -### Abstract Classes and Methods +#### Abstract Classes and Methods Classes that must be subclassed should derive from `ABC`, and methods or properties that must be overridden should be decorated with the `@abstractmethod` decorator. This allows type checkers to validate that the required methods have been overridden and provide developers with useful error messages when they are not. It is customary to implement an abstract method by raising a `NotImplementedError` exception. ```python @@ -329,13 +329,13 @@ class Hashable(ABC): raise NotImplementedError() ``` -### Final Classes and Methods +#### Final Classes and Methods Classes that are not intended to be subclassed should be decorated as `@final` as described in [PEP 591](https://www.python.org/dev/peps/pep-0591/). The same decorator can also be used to specify methods that cannot be overridden by subclasses. -### Literals +#### Literals Type annotations should make use of the Literal type where appropriate, as described in [PEP 586](https://www.python.org/dev/peps/pep-0586/). Literals allow for more type specificity than their non-literal counterparts. -### Constants +#### Constants Constant values (those that are read-only) can be specified using the Final annotation as described in [PEP 591](https://www.python.org/dev/peps/pep-0591/). Type checkers will also typically treat variables that are named using all upper-case characters as constants. @@ -358,7 +358,7 @@ ColorFormatRgb: Final[Literal["rgb"]] = "rgb" LATEST_VERSION: Final[tuple[int, int]] = (4, 5) ``` -### Typed Dictionaries, Data Classes, and Named Tuples +#### Typed Dictionaries, Data Classes, and Named Tuples If a library runs only on newer versions of Python, it can use some of the new type-friendly classes. NamedTuple (described in [PEP 484](https://www.python.org/dev/peps/pep-0484/)) is preferred over namedtuple. @@ -368,10 +368,10 @@ Data classes (described in [PEP 557](https://www.python.org/dev/peps/pep-0557/)) TypedDict (described in [PEP 589](https://www.python.org/dev/peps/pep-0589/)) is preferred over untyped dictionaries. -## Compatibility with Older Python Versions +### Compatibility with Older Python Versions Each new version of Python from 3.5 onward has introduced new typing constructs. This presents a challenge for library authors who want to maintain runtime compatibility with older versions of Python. This section documents several techniques that can be used to add types while maintaining backward compatibility. -### Quoted Annotations +#### Quoted Annotations Type annotations for variables, parameters, and return types can be placed in quotes. The Python interpreter will then ignore them, whereas a type checker will interpret them as type annotations. ```python @@ -410,20 +410,20 @@ class Foo: ... ``` -### typing_extensions +#### typing_extensions New type features that require runtime support are typically included in the stdlib `typing` module. Where possible, these new features are back-ported to a runtime library called `typing_extensions` that works with older Python runtimes. -### TYPE_CHECKING +#### TYPE_CHECKING The `typing` module exposes a variable called `TYPE_CHECKING` which has a value of False within the Python runtime but a value of True when the type checker is performing its analysis. This allows type checking statements to be conditionalized. Care should be taken when using `TYPE_CHECKING` because behavioral changes between type checking and runtime could mask problems that the type checker would otherwise catch. -## Non-Standard Type Behaviors +### Non-Standard Type Behaviors Type annotations provide a way to annotate typical type behaviors, but some classes implement specialized, non-standard behaviors that cannot be described using standard type annotations. For now, such types need to be annotated as Any, which is unfortunate because the benefits of static typing are lost. -## Docstrings +### Docstrings It is recommended that docstrings be provided for all classes, functions, and methods in the interface. They should be formatted according to [PEP 257](https://www.python.org/dev/peps/pep-0257/). There is currently no single agreed-upon standard for function and method docstrings, but several common variants have emerged. We recommend using one of these variants.