aboutsummaryrefslogtreecommitdiff
path: root/docs/source/stubs.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/source/stubs.rst')
-rw-r--r--docs/source/stubs.rst1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/docs/source/stubs.rst b/docs/source/stubs.rst
new file mode 100644
index 0000000..ffd6c9b
--- /dev/null
+++ b/docs/source/stubs.rst
@@ -0,0 +1,1129 @@
+.. _stubs:
+
+**********
+Type Stubs
+**********
+
+Introduction
+============
+
+*type stubs*, also called *stub files*, provide type information for untyped
+Python packages and modules. Type stubs serve multiple purposes:
+
+* They are the only way to add type information to extension modules.
+* They can provide type information for packages that do not wish to
+ add them inline.
+* They can be distributed separately from the implementation.
+ This allows stubs to be developed at a different pace or by different
+ authors, which is especially useful when adding type annotations to
+ existing packages.
+* They can act as documentation, succinctly explaining the external
+ API of a package, without including the implementation or private
+ members.
+
+This document aims to give guidance to both authors of type stubs and developers
+of type checkers and other tools. It describes the constructs that can be used safely in type stubs,
+suggests a style guide for them, and lists constructs that type
+checkers are expected to support.
+
+Type stubs that only use constructs described in this document should work with
+all type checkers that also follow this document.
+Type stub authors can elect to use additional constructs, but
+must be prepared that some type checkers will not parse them as expected.
+
+A type checker that conforms to this document will parse a type stub that only uses
+constructs described here without error and will not interpret any
+construct in a contradictory manner. However, type checkers are not
+required to implement checks for all these constructs, and
+can elect to ignore unsupported ones. Additionally type checkers
+can support constructs not described in this document and tool authors are
+encouraged to experiment with additional features.
+
+Syntax
+======
+
+Type stubs are syntactically valid Python 3.7 files with a ``.pyi`` suffix.
+The Python syntax used for type stubs is independent from the Python
+versions supported by the implementation, and from the Python version the type
+checker runs under (if any). Therefore, type stub authors should use the
+latest available syntax features in stubs (up to Python 3.7), even if the
+implementation supports older, pre-3.7 Python versions.
+Type checker authors are encouraged to support syntax features from
+post-3.7 Python versions, although type stub authors should not use such
+features if they wish to maintain compatibility with all type checkers.
+
+For example, Python 3.7 added the ``async`` keyword (see PEP 492 [#pep492]_).
+Stub authors should use it to mark coroutines, even if the implementation
+still uses the ``@coroutine`` decorator. On the other hand, type stubs should
+not use the positional-only syntax from PEP 570 [#pep570]_, introduced in
+Python 3.8, although type checker authors are encouraged to support it.
+
+Stubs are treated as if ``from __future__ import annotations`` is enabled.
+In particular, built-in generics, pipe union syntax (``X | Y``), and forward
+references can be used.
+
+Starting with Python 3.8, the :py:mod:`ast` module from the standard library supports
+all syntax features required by this PEP. Older Python versions can use the
+`typed_ast <https://pypi.org/project/typed-ast/>`_ package from the
+Python Package Index, which also supports Python 3.7 syntax and ``# type``
+comments.
+
+Distribution
+============
+
+Type stubs can be distributed with or separately from the implementation;
+see PEP 561 [#pep561]_ for more information. The
+`typeshed <https://github.com/python/typeshed>`_ project
+includes stubs for Python's standard library and several third-party
+packages. The stubs for the standard library are usually distributed with type checkers and do not
+require separate installation. Stubs for third-party libraries are
+available on the `Python Package Index <https://pypi.org>`_. A stub package for
+a library called ``widget`` will be called ``types-widget``.
+
+Supported Constructs
+====================
+
+This sections lists constructs that type checkers will accept in type stubs.
+Type stub authors can safely use these constructs. If a
+construct is marked as "unspecified", type checkers may handle it
+as they best see fit or report an error. Linters should usually
+flag those constructs. Type stub authors should avoid using them to
+ensure compatibility across type checkers.
+
+Unless otherwise mentioned, type stubs support all features from the
+``typing`` module of the latest released Python version. If a stub uses
+typing features from a later Python version than what the implementation
+supports, these features can be imported from ``typing_extensions`` instead
+of ``typing``.
+
+For example, a stub could use ``Literal``, introduced in Python 3.8,
+for a library supporting Python 3.7+::
+
+ from typing_extensions import Literal
+
+ def foo(x: Literal[""]) -> int: ...
+
+Comments
+--------
+
+Standard Python comments are accepted everywhere Python syntax allows them.
+
+Two kinds of structured comments are accepted:
+
+* A ``# type: X`` comment at the end of a line that defines a variable,
+ declaring that the variable has type ``X``. However, PEP 526-style [#pep526]_
+ variable annotations are preferred over type comments.
+* A ``# type: ignore`` comment at the end of any line, which suppresses all type
+ errors in that line. The type checker mypy supports suppressing certain
+ type errors by using ``# type: ignore[error-type]``. This is not supported
+ by other type checkers and should not be used in stubs.
+
+Imports
+-------
+
+Type stubs distinguish between imports that are re-exported and those
+that are only used internally. Imports are re-exported if they use one of these
+forms:[#pep484]_
+
+* ``import X as X``
+* ``from Y import X as X``
+* ``from Y import *``
+
+Here are some examples of imports that make names available for internal use in
+a stub but do not re-export them::
+
+ import X
+ from Y import X
+ from Y import X as OtherX
+
+Type aliases can be used to re-export an import under a different name::
+
+ from foo import bar as _bar
+ new_bar = _bar # "bar" gets re-exported with the name "new_bar"
+
+Sub-modules are always exported when they are imported in a module.
+For example, consider the following file structure::
+
+ foo/
+ __init__.pyi
+ bar.pyi
+
+Then ``foo`` will export ``bar`` when one of the following constructs is used in
+``__init__.pyi``::
+
+ from . import bar
+ from .bar import Bar
+
+Stubs support customizing star import semantics by defining a module-level
+variable called ``__all__``. In stubs, this must be a string list literal.
+Other types are not supported. Neither is the dynamic creation of this
+variable (for example by concatenation).
+
+By default, ``from foo import *`` imports all names in ``foo`` that
+do not begin with an underscore. When ``__all__`` is defined, only those names
+specified in ``__all__`` are imported::
+
+ __all__ = ['public_attr', '_private_looking_public_attr']
+
+ public_attr: int
+ _private_looking_public_attr: int
+ private_attr: int
+
+Type checkers support cyclic imports in stub files.
+
+Built-in Generics
+-----------------
+
+PEP 585 [#pep585]_ built-in generics are supported and should be used instead
+of the corresponding types from ``typing``::
+
+ from collections import defaultdict
+
+ def foo(t: type[MyClass]) -> list[int]: ...
+ x: defaultdict[int]
+
+Using imports from ``collections.abc`` instead of ``typing`` is
+generally possible and recommended::
+
+ from collections.abc import Iterable
+
+ def foo(iter: Iterable[int]) -> None: ...
+
+Unions
+------
+
+Declaring unions with ``Union`` and ``Optional`` is supported by all
+type checkers. With a few exceptions [#ts-4819]_, the shorthand syntax
+is also supported::
+
+ def foo(x: int | str) -> int | None: ... # recommended
+ def foo(x: Union[int, str]) -> Optional[int]: ... # ok
+
+Module Level Attributes
+-----------------------
+
+Module level variables and constants can be annotated using either
+type comments or variable annotation syntax::
+
+ x: int # recommended
+ x: int = 0
+ x = 0 # type: int
+ x = ... # type: int
+
+The type of a variable is unspecified when the variable is unannotated or
+when the annotation
+and the assigned value disagree. As an exception, the ellipsis literal can
+stand in for any type::
+
+ x = 0 # type is unspecified
+ x = ... # type is unspecified
+ x: int = "" # type is unspecified
+ x: int = ... # type is int
+
+Classes
+-------
+
+Class definition syntax follows general Python syntax, but type checkers
+are only expected to understand the following constructs in class bodies:
+
+* The ellipsis literal ``...`` is ignored and used for empty
+ class bodies. Using ``pass`` in class bodies is undefined.
+* Instance attributes follow the same rules as module level attributes
+ (see above).
+* Method definitions (see below) and properties.
+* Method aliases.
+* Inner class definitions.
+
+More complex statements don't need to be supported::
+
+ class Simple: ...
+
+ class Complex(Base):
+ read_write: int
+ @property
+ def read_only(self) -> int: ...
+ def do_stuff(self, y: str) -> None: ...
+ doStuff = do_stuff
+
+The type of generic classes can be narrowed by annotating the ``self``
+argument of the ``__init__`` method::
+
+ class Foo(Generic[_T]):
+ @overload
+ def __init__(self: Foo[str], type: Literal["s"]) -> None: ...
+ @overload
+ def __init__(self: Foo[int], type: Literal["i"]) -> None: ...
+ @overload
+ def __init__(self, type: str) -> None: ...
+
+The class must match the class in which it is declared. Using other classes,
+including sub or super classes, will not work. In addition, the ``self``
+annotation cannot contain type variables.
+
+.. _supported-functions:
+
+Functions and Methods
+---------------------
+
+Function and method definition syntax follows general Python syntax.
+Unless an argument name is prefixed with two underscores (but not suffixed
+with two underscores), it can be used as a keyword argument [#pep484]_::
+
+ # x is positional-only
+ # y can be used positionally or as keyword argument
+ # z is keyword-only
+ def foo(__x, y, *, z): ...
+
+PEP 570 [#pep570]_ style positional-only parameters are currently not
+supported.
+
+If an argument or return type is unannotated, per PEP 484 [#pep484]_ its
+type is assumed to be ``Any``. It is preferred to leave unknown
+types unannotated rather than explicitly marking them as ``Any``, as some
+type checkers can optionally warn about unannotated arguments.
+
+If an argument has a literal or constant default value, it must match the implementation
+and the type of the argument (if specified) must match the default value.
+Alternatively, ``...`` can be used in place of any default value::
+
+ # The following arguments all have type Any.
+ def unannotated(a, b=42, c=...): ...
+ # The following arguments all have type int.
+ def annotated(a: int, b: int = 42, c: int = ...): ...
+ # The following default values are invalid and the types are unspecified.
+ def invalid(a: int = "", b: Foo = Foo()): ...
+
+For a class ``C``, the type of the first argument to a classmethod is
+assumed to be ``type[C]``, if unannotated. For other non-static methods,
+its type is assumed to be ``C``::
+
+ class Foo:
+ def do_things(self): ... # self has type Foo
+ @classmethod
+ def create_it(cls): ... # cls has type Type[Foo]
+ @staticmethod
+ def utility(x): ... # x has type Any
+
+But::
+
+ _T = TypeVar("_T")
+
+ class Foo:
+ def do_things(self: _T) -> _T: ... # self has type _T
+ @classmethod
+ def create_it(cls: _T) -> _T: ... # cls has type _T
+
+PEP 612 [#pep612]_ parameter specification variables (``ParamSpec``)
+are supported in argument and return types::
+
+ _P = ParamSpec("_P")
+ _R = TypeVar("_R")
+
+ def foo(cb: Callable[_P, _R], *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
+
+However, ``Concatenate`` from PEP 612 is not yet supported; nor is using
+a ``ParamSpec`` to parameterize a generic class.
+
+PEP 647 [#pep647]_ type guards are supported.
+
+Using a function or method body other than the ellipsis literal is currently
+unspecified. Stub authors may experiment with other bodies, but it is up to
+individual type checkers how to interpret them::
+
+ def foo(): ... # compatible
+ def bar(): pass # behavior undefined
+
+All variants of overloaded functions and methods must have an ``@overload``
+decorator::
+
+ @overload
+ def foo(x: str) -> str: ...
+ @overload
+ def foo(x: float) -> int: ...
+
+The following (which would be used in the implementation) is wrong in
+type stubs::
+
+ @overload
+ def foo(x: str) -> str: ...
+ @overload
+ def foo(x: float) -> int: ...
+ def foo(x: str | float) -> Any: ...
+
+Aliases and NewType
+-------------------
+
+Type checkers should accept module-level type aliases, optionally using
+``TypeAlias`` (PEP 613 [#pep613]_), e.g.::
+
+ _IntList = list[int]
+ _StrList: TypeAlias = list[str]
+
+Type checkers should also accept regular module-level or class-level aliases,
+e.g.::
+
+ def a() -> None: ...
+ b = a
+
+ class C:
+ def f(self) -> int: ...
+ g = f
+
+A type alias may contain type variables. As per PEP 484 [#pep484]_,
+all type variables must be substituted when the alias is used::
+
+ _K = TypeVar("_K")
+ _V = TypeVar("_V")
+ _MyMap: TypeAlias = dict[str, dict[_K, _V]]
+
+ # either concrete types or other type variables can be substituted
+ def f(x: _MyMap[str, _V]) -> _V: ...
+ # explicitly substitute in Any rather than using a bare alias
+ def g(x: _MyMap[Any, Any]) -> Any: ...
+
+Otherwise, type variables in aliases follow the same rules as type variables in
+generic class definitions.
+
+``typing.NewType`` is also supported in stubs.
+
+Decorators
+----------
+
+Type stubs may only use decorators defined in the ``typing`` module, plus a
+fixed set of additional ones:
+
+* ``classmethod``
+* ``staticmethod``
+* ``property`` (including ``.setter``)
+* ``abc.abstractmethod``
+* ``dataclasses.dataclass``
+* ``asyncio.coroutine`` (although ``async`` should be used instead)
+
+The behavior of other decorators should instead be incorporated into the types.
+For example, for the following function::
+
+ import contextlib
+ @contextlib.contextmanager
+ def f():
+ yield 42
+
+the stub definition should be::
+
+ from contextlib import AbstractContextManager
+ def f() -> AbstractContextManager[int]: ...
+
+Version and Platform Checks
+---------------------------
+
+Type stubs for libraries that support multiple Python versions can use version
+checks to supply version-specific type hints. Type stubs for different Python
+versions should still conform to the most recent supported Python version's
+syntax, as explain in the Syntax_ section above.
+
+Version checks are if-statements that use ``sys.version_info`` to determine the
+current Python version. Version checks should only check against the ``major`` and
+``minor`` parts of ``sys.version_info``. Type checkers are only required to
+support the tuple-based version check syntax::
+
+ if sys.version_info >= (3,):
+ # Python 3-specific type hints. This tuple-based syntax is recommended.
+ else:
+ # Python 2-specific type hints.
+
+ if sys.version_info >= (3, 5):
+ # Specific minor version features can be easily checked with tuples.
+
+ if sys.version_info < (3,):
+ # This is only necessary when a feature has no Python 3 equivalent.
+
+Type stubs should avoid checking against ``sys.version_info.major``
+directly and should not use comparison operators other than ``<`` and ``>=``.
+
+No::
+
+ if sys.version_info.major >= 3:
+ # Semantically the same as the first tuple check.
+
+ if sys.version_info[0] >= 3:
+ # This is also the same.
+
+ if sys.version_info <= (2, 7):
+ # This does not work because e.g. (2, 7, 1) > (2, 7).
+
+Some type stubs also may need to specify type hints for different platforms.
+Platform checks must be equality comparisons between ``sys.platform`` and the name
+of a platform as a string literal:
+
+Yes::
+
+ if sys.platform == 'win32':
+ # Windows-specific type hints.
+ else:
+ # Posix-specific type hints.
+
+No::
+
+ if sys.platform.startswith('linux'):
+ # Not necessary since Python 3.3.
+
+ if sys.platform in ['linux', 'cygwin', 'darwin']:
+ # Only '==' or '!=' should be used in platform checks.
+
+Version and platform comparisons can be chained using the ``and`` and ``or``
+operators::
+
+ if sys.platform == 'linux' and (sys.version_info < (3,) or sys,version_info >= (3, 7)): ...
+
+Enums
+-----
+
+Enum classes are supported in stubs, regardless of the Python version targeted by
+the stubs.
+
+Enum members may be specified just like other forms of assignments, for example as
+``x: int``, ``x = 0``, or ``x = ...``. The first syntax is preferred because it
+allows type checkers to correctly type the ``.value`` attribute of enum members,
+without providing unnecessary information like the runtime value of the enum member.
+
+Additional properties on enum members should be specified with ``@property``, so they
+do not get interpreted by type checkers as enum members.
+
+Yes::
+
+ from enum import Enum
+
+ class Color(Enum):
+ RED: int
+ BLUE: int
+ @property
+ def rgb_value(self) -> int: ...
+
+ class Color(Enum):
+ # discouraged; type checkers will not understand that Color.RED.value is an int
+ RED = ...
+ BLUE = ...
+ @property
+ def rgb_value(self) -> int: ...
+
+No::
+
+ from enum import Enum
+
+ class Color(Enum):
+ RED: int
+ BLUE: int
+ rgb_value: int # no way for type checkers to know that this is not an enum member
+
+Unsupported Features
+--------------------
+
+Currently, the following features are not supported by all type checkers
+and should not be used in stubs:
+
+* Positional-only argument syntax (PEP 570 [#pep570]_). Instead, use
+ the syntax described in the section :ref:`supported-functions`.
+ [#ts-4972]_
+
+Type Stub Content
+=================
+
+This section documents best practices on what elements to include or
+leave out of type stubs.
+
+Modules excluded fom stubs
+--------------------------
+
+Not all modules should be included into stubs.
+
+It is recommended to exclude:
+
+1. Implementation details, with `multiprocessing/popen_spawn_win32.py <https://github.com/python/cpython/blob/main/Lib/multiprocessing/popen_spawn_win32.py>`_ as a notable example
+2. Modules that are not supposed to be imported, such as ``__main__.py``
+3. Protected modules that start with a single ``_`` char. However, when needed protected modules can still be added (see :ref:`undocumented-objects` section below)
+
+Public Interface
+----------------
+
+Stubs should include the complete public interface (classes, functions,
+constants, etc.) of the module they cover, but it is not always
+clear exactly what is part of the interface.
+
+The following should always be included:
+
+* All objects listed in the module's documentation.
+* All objects included in ``__all__`` (if present).
+
+Other objects may be included if they are not prefixed with an underscore
+or if they are being used in practice. (See the next section.)
+
+.. _undocumented-objects:
+
+Undocumented Objects
+--------------------
+
+Undocumented objects may be included as long as they are marked with a comment
+of the form ``# undocumented``.
+
+Example::
+
+ def list2cmdline(seq: Sequence[str]) -> str: ... # undocumented
+
+Such undocumented objects are allowed because omitting objects can confuse
+users. Users who see an error like "module X has no attribute Y" will
+not know whether the error appeared because their code had a bug or
+because the stub is wrong. Although it may also be helpful for a type
+checker to point out usage of private objects, false negatives (no errors for
+wrong code) are preferable over false positives (type errors
+for correct code). In addition, even for private objects a type checker
+can be helpful in pointing out that an incorrect type was used.
+
+``__all__``
+------------
+
+A type stub should contain an ``__all__`` variable if and only if it also
+present at runtime. In that case, the contents of ``__all__`` should be
+identical in the stub and at runtime. If the runtime dynamically adds
+or removes elements (for example if certain functions are only available on
+some platforms), include all possible elements in the stubs.
+
+Stub-Only Objects
+-----------------
+
+Definitions that do not exist at runtime may be included in stubs to aid in
+expressing types. Sometimes, it is desirable to make a stub-only class available
+to a stub's users - for example, to allow them to type the return value of a
+public method for which a library does not provided a usable runtime type::
+
+ from typing import Protocol
+
+ class _Readable(Protocol):
+ def read(self) -> str: ...
+
+ def get_reader() -> _Readable: ...
+
+Structural Types
+----------------
+
+As seen in the example with ``_Readable`` in the previous section, a common use
+of stub-only objects is to model types that are best described by their
+structure. These objects are called protocols [#pep544]_, and it is encouraged
+to use them freely to describe simple structural types.
+
+It is `recommended <#private-definitions>`_ to prefix stubs-only object names with ``_``.
+
+Incomplete Stubs
+----------------
+
+Partial stubs can be useful, especially for larger packages, but they should
+follow the following guidelines:
+
+* Included functions and methods should list all arguments, but the arguments
+ can be left unannotated.
+* Do not use ``Any`` to mark unannotated arguments or return values.
+* Partial classes should include a ``__getattr__()`` method marked with an
+ ``# incomplete`` comment (see example below).
+* Partial modules (i.e. modules that are missing some or all classes,
+ functions, or attributes) should include a top-level ``__getattr__()``
+ function marked with an ``# incomplete`` comment (see example below).
+* Partial packages (i.e. packages that are missing one or more sub-modules)
+ should have a ``__init__.pyi`` stub that is marked as incomplete (see above).
+ A better alternative is to create empty stubs for all sub-modules and
+ mark them as incomplete individually.
+
+Example of a partial module with a partial class ``Foo`` and a partially
+annotated function ``bar()``::
+
+ def __getattr__(name: str) -> Any: ... # incomplete
+
+ class Foo:
+ def __getattr__(self, name: str) -> Any: # incomplete
+ x: int
+ y: str
+
+ def bar(x: str, y, *, z=...): ...
+
+The ``# incomplete`` comment is mainly intended as a reminder for stub
+authors, but can be used by tools to flag such items.
+
+Attribute Access
+----------------
+
+Python has several methods for customizing attribute access: ``__getattr__``,
+``__getattribute__``, ``__setattr__``, and ``__delattr__``. Of these,
+``__getattr__`` and ``__setattr___`` should sometimes be included in stubs.
+
+In addition to marking incomplete definitions, ``__getattr__`` should be
+included when a class or module allows any name to be accessed. For example, consider
+the following class::
+
+ class Foo:
+ def __getattribute__(self, name):
+ return self.__dict__.setdefault(name)
+
+An appropriate stub definition is::
+
+ from typing import Any
+ class Foo:
+ def __getattr__(self, name: str) -> Any | None: ...
+
+Note that only ``__getattr__``, not ``__getattribute__``, is guaranteed to be
+supported in stubs.
+
+On the other hand, ``__getattr__`` should be omitted even if the source code
+includes it, if only limited names are allowed. For example, consider this class::
+
+ class ComplexNumber:
+ def __init__(self, n):
+ self._n = n
+ def __getattr__(self, name):
+ if name in ("real", "imag"):
+ return getattr(self._n, name)
+ raise AttributeError(name)
+
+In this case, the stub should list the attributes individually::
+
+ class ComplexNumber:
+ @property
+ def real(self) -> float: ...
+ @property
+ def imag(self) -> float: ...
+ def __init__(self, n: complex) -> None: ...
+
+``__setattr___`` should be included when a class allows any name to be set and
+restricts the type. For example::
+
+ class IntHolder:
+ def __setattr__(self, name, value):
+ if isinstance(value, int):
+ return super().__setattr__(name, value)
+ raise ValueError(value)
+
+A good stub definition would be::
+
+ class IntHolder:
+ def __setattr__(self, name: str, value: int) -> None: ...
+
+``__delattr__`` should not be included in stubs.
+
+Finally, even in the presence of ``__getattr__`` and ``__setattr__``, it is
+still recommended to separately define known attributes.
+
+Constants
+---------
+
+When the value of a constant is important, annotate it using ``Literal``
+instead of its type.
+
+Yes::
+
+ TEL_LANDLINE: Literal["landline"]
+ TEL_MOBILE: Literal["mobile"]
+ DAY_FLAG: Literal[0x01]
+ NIGHT_FLAG: Literal[0x02]
+
+No::
+
+ TEL_LANDLINE: str
+ TEL_MOBILE: str
+ DAY_FLAG: int
+ NIGHT_FLAG: int
+
+Documentation or Implementation
+-------------------------------
+
+Sometimes a library's documented types will differ from the actual types in the
+code. In such cases, type stub authors should use their best judgment. Consider
+these two examples::
+
+ def print_elements(x):
+ """Print every element of list x."""
+ for y in x:
+ print(y)
+
+ def maybe_raise(x):
+ """Raise an error if x (a boolean) is true."""
+ if x:
+ raise ValueError()
+
+The implementation of ``print_elements`` takes any iterable, despite the
+documented type of ``list``. In this case, annotate the argument as
+``Iterable[Any]``, to follow this PEP's style recommendation of preferring
+abstract types.
+
+For ``maybe_raise``, on the other hand, it is better to annotate the argument as
+``bool`` even though the implementation accepts any object. This guards against
+common mistakes like unintentionally passing in ``None``.
+
+If in doubt, consider asking the library maintainers about their intent.
+
+Style Guide
+===========
+
+The recommendations in this section are aimed at type stub authors
+who wish to provide a consistent style for type stubs. Type checkers
+should not reject stubs that do not follow these recommendations, but
+linters can warn about them.
+
+Stub files should generally follow the Style Guide for Python Code (PEP 8)
+[#pep8]_. There are a few exceptions, outlined below, that take the
+different structure of stub files into account and are aimed to create
+more concise files.
+
+Maximum Line Length
+-------------------
+
+Type stubs should be limited to 130 characters per line.
+
+Blank Lines
+-----------
+
+Do not use empty lines between functions, methods, and fields, except to
+group them with one empty line. Use one empty line around classes, but do not
+use empty lines between body-less classes, except for grouping.
+
+Yes::
+
+ def time_func() -> None: ...
+ def date_func() -> None: ...
+
+ def ip_func() -> None: ...
+
+ class Foo:
+ x: int
+ y: int
+ def __init__(self) -> None: ...
+
+ class MyError(Exception): ...
+ class AnotherError(Exception): ...
+
+No::
+
+ def time_func() -> None: ...
+
+ def date_func() -> None: ... # do no leave unnecessary empty lines
+
+ def ip_func() -> None: ...
+
+
+ class Foo: # leave only one empty line above
+ x: int
+ class MyError(Exception): ... # leave an empty line between the classes
+
+Shorthand Syntax
+----------------
+
+Where possible, use shorthand syntax for unions instead of
+``Union`` or ``Optional``. ``None`` should be the last
+element of an union.
+
+Yes::
+
+ def foo(x: str | int) -> None: ...
+ def bar(x: str | None) -> int | None: ...
+
+No::
+
+ def foo(x: Union[str, int]) -> None: ...
+ def bar(x: Optional[str]) -> Optional[int]: ...
+ def baz(x: None | str) -> None: ...
+
+Module Level Attributes
+-----------------------
+
+Do not use an assignment for module-level attributes.
+
+Yes::
+
+ CONST: Literal["const"]
+ x: int
+
+No::
+
+ CONST = "const"
+ x: int = 0
+ y: float = ...
+ z = 0 # type: int
+ a = ... # type: int
+
+Type Aliases
+------------
+
+Use ``TypeAlias`` for type aliases (but not for regular aliases).
+
+Yes::
+
+ _IntList: TypeAlias = list[int]
+ g = os.stat
+ Path = pathlib.Path
+ ERROR = errno.EEXIST
+
+No::
+
+ _IntList = list[int]
+ g: TypeAlias = os.stat
+ Path: TypeAlias = pathlib.Path
+ ERROR: TypeAlias = errno.EEXIST
+
+Classes
+-------
+
+Classes without bodies should use the ellipsis literal ``...`` in place
+of the body on the same line as the class definition.
+
+Yes::
+
+ class MyError(Exception): ...
+
+No::
+
+ class MyError(Exception):
+ ...
+ class AnotherError(Exception): pass
+
+Instance attributes and class variables follow the same recommendations as
+module level attributes:
+
+Yes::
+
+ class Foo:
+ c: ClassVar[str]
+ x: int
+
+No::
+
+ class Foo:
+ c: ClassVar[str] = ""
+ d: ClassVar[int] = ...
+ x = 4
+ y: int = ...
+
+Functions and Methods
+---------------------
+
+Use the same argument names as in the implementation, because
+otherwise using keyword arguments will fail. Of course, this
+does not apply to positional-only arguments, which are marked with a double
+underscore.
+
+Use the ellipsis literal ``...`` in place of actual default argument
+values. Use an explicit ``X | None`` annotation instead of
+a ``None`` default.
+
+Yes::
+
+ def foo(x: int = ...) -> None: ...
+ def bar(y: str | None = ...) -> None: ...
+
+No::
+
+ def foo(x: int = 0) -> None: ...
+ def bar(y: str = None) -> None: ...
+ def baz(z: str | None = None) -> None: ...
+
+Do not annotate ``self`` and ``cls`` in method definitions, except when
+referencing a type variable.
+
+Yes::
+
+ _T = TypeVar("_T")
+ class Foo:
+ def bar(self) -> None: ...
+ @classmethod
+ def create(cls: type[_T]) -> _T: ...
+
+No::
+
+ class Foo:
+ def bar(self: Foo) -> None: ...
+ @classmethod
+ def baz(cls: type[Foo]) -> int: ...
+
+The bodies of functions and methods should consist of only the ellipsis
+literal ``...`` on the same line as the closing parenthesis and colon.
+
+Yes::
+
+ def to_int1(x: str) -> int: ...
+ def to_int2(
+ x: str,
+ ) -> int: ...
+
+No::
+
+ def to_int1(x: str) -> int:
+ return int(x)
+ def to_int2(x: str) -> int:
+ ...
+ def to_int3(x: str) -> int: pass
+
+.. _private-definitions:
+
+Private Definitions
+-------------------
+
+Type variables, type aliases, and other definitions that should not
+be used outside the stub should be marked as private by prefixing them
+with an underscore.
+
+Yes::
+
+ _T = TypeVar("_T")
+ _DictList = Dict[str, List[Optional[int]]
+
+No::
+
+ T = TypeVar("T")
+ DictList = Dict[str, List[Optional[int]]]
+
+Language Features
+-----------------
+
+Use the latest language features available as outlined
+in the Syntax_ section, even for stubs targeting older Python versions.
+Do not use quotes around forward references and do not use ``__future__``
+imports.
+
+Yes::
+
+ class Py35Class:
+ x: int
+ forward_reference: OtherClass
+ class OtherClass: ...
+
+No::
+
+ class Py35Class:
+ x = 0 # type: int
+ forward_reference: 'OtherClass'
+ class OtherClass: ...
+
+Types
+-----
+
+Generally, use ``Any`` when a type cannot be expressed appropriately
+with the current type system or using the correct type is unergonomic.
+
+Use ``float`` instead of ``int | float``.
+Use ``None`` instead of ``Literal[None]``.
+For argument types,
+use ``bytes`` instead of ``bytes | memoryview | bytearray``.
+
+Use ``Text`` in stubs that support Python 2 when something accepts both
+``str`` and ``unicode``. Avoid using ``Text`` in stubs or branches for
+Python 3 only.
+
+Yes::
+
+ if sys.version_info < (3,):
+ def foo(s: Text) -> None: ...
+ else:
+ def foo(s: str, *, i: int) -> None: ...
+ def bar(s: Text) -> None: ...
+
+No::
+
+ if sys.version_info < (3,):
+ def foo(s: unicode) -> None: ...
+ else:
+ def foo(s: Text, *, i: int) -> None: ...
+
+For arguments, prefer protocols and abstract types (``Mapping``,
+``Sequence``, ``Iterable``, etc.). If an argument accepts literally any value,
+use ``object`` instead of ``Any``.
+
+For return values, prefer concrete types (``list``, ``dict``, etc.) for
+concrete implementations. The return values of protocols
+and abstract base classes must be judged on a case-by-case basis.
+
+Yes::
+
+ def map_it(input: Iterable[str]) -> list[int]: ...
+ def create_map() -> dict[str, int]: ...
+ def to_string(o: object) -> str: ... # accepts any object
+
+No::
+
+ def map_it(input: list[str]) -> list[int]: ...
+ def create_map() -> MutableMapping[str, int]: ...
+ def to_string(o: Any) -> str: ...
+
+Maybe::
+
+ class MyProto(Protocol):
+ def foo(self) -> list[int]: ...
+ def bar(self) -> Mapping[str]: ...
+
+Avoid union return types, since they require ``isinstance()`` checks.
+Use ``Any`` or ``X | Any`` if necessary.
+
+Use built-in generics instead of the aliases from ``typing``,
+where possible. See the section `Built-in Generics`_ for cases,
+where it's not possible to use them.
+
+Yes::
+
+ from collections.abc import Iterable
+
+ def foo(x: type[MyClass]) -> list[str]: ...
+ def bar(x: Iterable[str]) -> None: ...
+
+No::
+
+ from typing import Iterable, List, Type
+
+ def foo(x: Type[MyClass]) -> List[str]: ...
+ def bar(x: Iterable[str]) -> None: ...
+
+NamedTuple and TypedDict
+------------------------
+
+Use the class-based syntax for ``typing.NamedTuple`` and
+``typing.TypedDict``, following the Classes section of this style guide.
+
+Yes::
+
+ from typing import NamedTuple, TypedDict
+ class Point(NamedTuple):
+ x: float
+ y: float
+
+ class Thing(TypedDict):
+ stuff: str
+ index: int
+
+No::
+
+ from typing import NamedTuple, TypedDict
+ Point = NamedTuple("Point", [('x', float), ('y', float)])
+ Thing = TypedDict("Thing", {'stuff': str, 'index': int})
+
+References
+==========
+
+PEPs
+----
+
+.. [#pep8] PEP 8 -- Style Guide for Python Code, van Rossum et al. (https://www.python.org/dev/peps/pep-0008/)
+.. [#pep484] PEP 484 -- Type Hints, van Rossum et al. (https://www.python.org/dev/peps/pep-0484)
+.. [#pep492] PEP 492 -- Coroutines with async and await syntax, Selivanov (https://www.python.org/dev/peps/pep-0492/)
+.. [#pep526] PEP 526 -- Syntax for Variable Annotations, Gonzalez et al. (https://www.python.org/dev/peps/pep-0526)
+.. [#pep544] PEP 544 -- Protocols: Structural Subtyping, Levkivskyi et al. (https://www.python.org/dev/peps/pep-0544)
+.. [#pep561] PEP 561 -- Distributing and Packaging Type Information, Smith (https://www.python.org/dev/peps/pep-0561)
+.. [#pep570] PEP 570 -- Python Positional-Only Parameters, Hastings et al. (https://www.python.org/dev/peps/pep-0570)
+.. [#pep585] PEP 585 -- Type Hinting Generics In Standard Collections, Langa (https://www.python.org/dev/peps/pep-0585)
+.. [#pep604] PEP 604 -- Allow writing union types as X | Y, Prados and Moss (https://www.python.org/dev/peps/pep-0604)
+.. [#pep612] PEP 612 -- Parameter Specification Variables, Mendoza (https://www.python.org/dev/peps/pep-0612)
+.. [#pep613] PEP 613 -- Explicit Type Aliases, Zhu (https://www.python.org/dev/peps/pep-0613)
+.. [#pep647] PEP 647 -- User-Defined Type Guards, Traut (https://www.python.org/dev/peps/pep-0647)
+.. [#pep3107] PEP 3107 -- Function Annotations, Winter and Lownds (https://www.python.org/dev/peps/pep-3107)
+
+Bugs
+----
+
+.. [#ts-4819] typeshed issue #4819 -- PEP 604 tracker (https://github.com/python/typeshed/issues/4819)
+.. [#ts-4972] typeshed issue #4972 -- PEP 570 tracker (https://github.com/python/typeshed/issues/4972)
+
+Copyright
+=========
+
+This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.