Distributing type information

Stub files

(Originally specified inPEP 484.)

Stub files, also calledtype stubs, provide type information for untypedPython packages and modules. Stub files 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 toadd them inline.

  • They can be distributed separately from the package or module that theyprovide types for. The latter is referred to as theimplementation.This allows stubs to be developed at a different pace or by differentauthors, which is especially useful when adding type annotations toexisting packages.

  • They can act as documentation, succinctly explaining the externalAPI of a package, without including implementation details or privatemembers.

Stub files use a subset of the constructs used in Python source files, asdescribed inSupported Constructs below. Type checkers shouldparse a stub that uses only such constructs without error and not interpret anyconstruct in a manner contradictory to this specification. However, typecheckers are not required to implement checks for all of these constructs andcan elect to ignore unsupported ones. Additionally, type checkers can supportconstructs not described here.

If a stub file is found for a module, the type checker should not read thecorresponding “real” module. SeeImport resolution ordering for more information.

Syntax

Stub files are syntactically valid Python files with a.pyi suffix. Theyshould be parseable (e.g., withast.parse()) in all Python versionsthat are supported by the implementation and that are still supportedby the CPython project. For example, defining a type alias using thetype keyword is only accepted by the Python parser in Python 3.12 and later,so stubs supporting Python 3.11 or earlier versions should not use this syntax.This allows type checkers implemented in Python to parse stub files usingfunctionality from the standard library.Type checkers may choose to support syntactic features from newer Python versionsin stub files, but stubs that rely on such features may not be portable to alltype checkers. Type checkers may also choose to support Python versions thatare no longer supported by CPython; if so, they cannot rely on standard libraryfunctionality to parse stub files.

Type checkers should evaluate allannotation expressions as if they are quoted.Consequently, forward references do not need to be quoted, and type systemfeatures that do not depend on Python syntax changes are supported in stubs regardlessof the Python version supported. For example, the use of the| operatorto create unions (X|Y) was introduced in Python 3.10, but may be usedeven in stubs that support Python 3.9 and older versions.

Supported Constructs

Type checkers should fully support these constructs:

  • All features from thetyping module of the latest released Python versionthat usesupported syntax

  • Comments, including type declaration (#type:X) and error suppression(#type:ignore) comments

  • Import statements, including the standardImport Conventions and cyclicimports

  • Aliases, including type aliases, at both the module and class level

  • Simple version and platform checks

The constructs in the following subsections may be supported in a more limitedfashion, as described below.

Value Expressions

In locations where value expressions can appear, such as the right-hand side ofassignment statements and function parameter defaults, type checkers shouldsupport the following expressions:

  • The ellipsis literal,..., which can stand in for any value

  • Any value that is alegal parameter for typing.Literal

  • Floating point literals, such as3.14

  • Complex literals, such as1+2j

Module Level Attributes

Type checkers should support module-level variable annotations, with and withoutassignments:

x:intx:int=0x=0# type: intx=...# type: int

TheLiteral shortcut using Final should besupported:

x:Final=0# type is Literal[0]

When the type of a variable is omitted or disagrees from the assigned value,type checker behavior is undefined:

x=0# behavior undefinedx:Final=...# behavior undefinedx:int=""# behavior undefined

Classes

Class definition syntax follows general Python syntax, but type checkersare expected to understand only the following constructs in class bodies:

  • The ellipsis literal... is used for empty class bodies. Usingpass inclass bodies is undefined.

  • Instance attributes follow the same rules as module level attributes(see above).

  • Method definitions (see below) and properties.

  • Aliases.

  • Inner class definitions.

Yes:

classSimple:...classComplex(Base):read_write:int@propertydefread_only(self)->int:...defdo_stuff(self,y:str)->None:...doStuff=do_stuffIntList:TypeAlias=list[int]classInner:...

Functions and Methods

Function and method definition follows general Python syntax. Using a functionor method body other than the ellipsis literal is undefined:

deffoo():...# compatibledefbar():pass# behavior undefined

Decorators

Type checkers are expected to understand the effects of all decorators definedin thetyping module, plus these additional ones:

  • classmethod

  • staticmethod

  • property (including.setter and.deleter)

  • abc.abstractmethod

  • dataclasses.dataclass

  • warnings.deprecated

  • functions decorated with@typing.dataclass_transform

The Typeshed Project

Thetypeshed project contains typestubs for the standard library (vendored or handled specially by type checkers)and type stubs for third-party libraries that don’t ship their own type information(typically distributed via PyPI). Policies regarding thestubs collected there are decided separately and described in the project’sdocumentation.

Type information in libraries

(Originally specified inPEP 561.)

There are several motivations and methods of supporting typing in a package.This specification recognizes three types of packages that users of typing wish tocreate:

  1. The package maintainer would like to add type information inline.

  2. The package maintainer would like to add type information via stubs.

  3. A third party or package maintainer would like to share stub files fora package, but the maintainer does not want to include them in the sourceof the package.

This specification aims to support all three scenarios and make them simple to add topackaging and deployment.

The two major parts of this specification are the packaging specificationsand the resolution order for resolving module type information.

Packaging Type Information

In order to make packaging and distributing type information as simple andeasy as possible, packaging and distribution is done through existingframeworks.

Package maintainers who wish to support type checking of their code MUST adda marker file namedpy.typed to their package supporting typing. This marker appliesrecursively: if a top-level package includes it, all its sub-packages MUST supporttype checking as well.

To have this file including with the package, maintainers can use existing packagingoptions such aspackage_data insetuptools. For more details, seethe guide to providing type annotations.

For namespace packages (seePEP 420), thepy.typed file should be in thesubmodules of the namespace, to avoid conflicts and for clarity.

This specification does not support distributing typing information as part ofmodule-only distributions or single-file modules within namespace packages.

The single-file module should be refactored into a packageand indicate that the package supports typing as describedabove.

Stub-only Packages

For package maintainers wishing to ship stub files containing all of theirtype information, it is preferred that the*.pyi stubs are alongside thecorresponding*.py files. However, the stubs can also be put in a separatepackage and distributed separately. Third parties can also find this methoduseful if they wish to distribute stub files. The name of the stub packageMUST follow the schemefoopkg-stubs for type stubs for the package namedfoopkg.

Note the name of the distribution (i.e. the project name on PyPI) containingthe package MAY be different than the mandated*-stubs package name.The name of the distribution SHOULD NOT betypes-*, since this isconventionally used for stub-only packages provided by typeshed.

For stub-only packages adding apy.typed marker is notneeded since the name*-stubs is enough to indicate it is a source of typinginformation.

Third parties seeking to distribute stub files are encouraged to contact themaintainer of the package about distribution alongside the package. If themaintainer does not wish to maintain or package stub files or type informationinline, then a third party stub-only package can be created.

In addition, stub-only distributions MAY indicate which version(s)of the runtime package are targeted by indicating the runtime distribution’sversion(s) through normal dependency data. For example, thestub packageflyingcircus-stubs can indicate the versions of theruntimeflyingcircus distribution it supports throughdependenciesfield inpyproject.toml.

For namespace packages (seePEP 420), stub-only packages shoulduse the-stubs suffix on only the root namespace package.All stub-only namespace packages should omit__init__.pyi files.py.typedmarker files are not necessary for stub-only packages, but similarlyto packages with inline types, if used, they should be in submodules of the namespace toavoid conflicts and for clarity.

For example, if thepentagon andhexagon are separate distributionsinstalling within the namespace packageshapes.polygonsThe corresponding types-only distributions should produce packageslaid out as follows:

shapes-stubs└── polygons    └── pentagon        └── __init__.pyishapes-stubs└── polygons    └── hexagon        └── __init__.pyi

Partial Stub Packages

Many stub packages will only have part of the type interface for librariescompleted, especially initially. For the benefit of type checking and codeeditors, packages can be “partial”. This means modules not found in the stubpackage SHOULD be searched for in parts five and six of the module resolutionorder below, namelyinline packages and any third-party stubs the typechecker chooses to vendor.

Type checkers should merge the stub package and runtime packagedirectories. This can be thought of as the functional equivalent of copying thestub package into the same directory as the corresponding runtime packageand type checking the combined directory structure. Thus typecheckers MUST maintain the normal resolution order of checking*.pyi before*.py files.

If a stub package distribution is partial it MUST includepartial\n in apy.typed file. For stub-packages distributing within a namespacepackage (seePEP 420), thepy.typed file should be in thesubmodules of the namespace.

Type checkers should treat namespace packages within stub-packages asincomplete since multiple distributions may populate them.Regular packages within namespace packages in stub-package distributionsare considered complete unless apy.typed withpartial\n is included.

Import resolution ordering

The following is the order in which type checkers supporting this specification SHOULDresolve modules containing type information:

  1. Stubs or Python source manually put in the beginning of the path. Typecheckers SHOULD provide this to allow the user complete control of whichstubs to use, and to patch broken stubs orinline types from packages.In mypy the$MYPYPATH environment variable can be used for this.

  2. User code - the files the type checker is running on.

  3. Typeshed stubs for the standard library. These will usually be vendored bytype checkers, but type checkers SHOULD provide an option for users toprovide a path to a directory containing a custom or modified version oftypeshed; if this option is provided, type checkers SHOULD use this as thecanonical source for standard-library types in this step.

  4. Stub packages - these packages SHOULD supersede any installed inlinepackage. They can be found in directories namedfoopkg-stubs forpackagefoopkg.

  5. Packages with apy.typed marker file - if there is nothing overridingthe installed package,and it opts into type checking, the typesbundled with the package SHOULD be used (be they in.pyi typestub files or inline in.py files).

  6. If the type checker chooses to additionally vendor any third-party stubs(from typeshed or elsewhere), these SHOULD come last in the moduleresolution order.

If typecheckers identify a stub-only namespace package without the desired modulein step 4, they should continue to step 5/6. Typecheckers should identify namespace packagesby the absence of__init__.pyi. This allows different subpackages toindependently opt for inline vs stub-only.

Type checkers that check a different Python version than the version they runon MUST find the type information in thesite-packages/dist-packagesof that Python version. This can be queried e.g.pythonX.Y-c'importsite;print(site.getsitepackages())'. It is also recommendedthat the type checker allow for the user to point to a particular Pythonbinary, in case it is not in the path.

Library interface (public and private symbols)

If apy.typed module is present, a type checker will treat all moduleswithin that package (i.e. all files that end in.py or.pyi) asimportable unless the file name begins with an underscore. These modulescomprise the supported interface for the library.

Each module exposes a set of symbols. Some of these symbols areconsidered “private” — implementation details that are not part of thelibrary’s interface. Type checkers can use the following rulesto determine which symbols are visible outside of the package.

  • Symbols whose names begin with an underscore (but are not dundernames) are considered private.

  • Imported symbols are considered private by default. A fixed set ofimport forms re-export imported symbols.

  • A module can expose an__all__ symbol at the module level thatprovides a list of names that are considered part of the interface.This overrides all other rules above, allowing imported symbols orsymbols whose names begin with an underscore to be included in theinterface.

  • Local variables within a function (including nested functions) arealways considered private.

The following idioms are supported for defining the values containedwithin__all__. These restrictions allow type checkers to staticallydetermine the value of__all__.

  • __all__=('a','b')

  • __all__=['a','b']

  • __all__+=['a','b']

  • __all__+=submodule.__all__

  • __all__.extend(['a','b'])

  • __all__.extend(submodule.__all__)

  • __all__.append('a')

  • __all__.remove('a')

Import Conventions

By convention, certain import forms indicate to type checkers that an importedsymbol is re-exported and should be considered part of the importing module’spublic interface. All other imported symbols are considered private by default.

The following import forms re-export symbols:

  • importXasX (a redundant module alias): re-exportsX.

  • fromYimportXasX (a redundant symbol alias): re-exportsX.

  • fromYimport*: ifY defines a module-level__all__ list,re-exports all names in__all__; otherwise, re-exports all public symbolsinY’s global scope.