Skip to content

Commit 8ecc93f

Browse files
authored
Make library docs more FAQ-like (#1164)
1 parent d69aa1e commit 8ecc93f

File tree

1 file changed

+184
-66
lines changed

1 file changed

+184
-66
lines changed

docs/source/libraries.rst

Lines changed: 184 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,79 +4,200 @@
44
Typing Python Libraries
55
***********************
66

7-
Much of Pythons popularity can be attributed to the rich collection of
7+
Much of Python's popularity can be attributed to the rich collection of
88
Python libraries available to developers. Authors of these libraries
99
play an important role in improving the experience for Python
1010
developers. This document provides some recommendations and guidance for
1111
Python library authors.
1212

13-
These recommendations are intended to provide the following benefits:
14-
15-
1. Consumers of libraries should have a great coding experience with
16-
fast and accurate completion suggestions, class and function
17-
documentation, signature help (including parameter default values),
18-
hover text, and auto-imports. This should happen by default without
19-
needing to download extra packages and without any special
20-
configuration. These features should be consistent across the Python
21-
ecosystem regardless of a developer’s choice of editor, IDE, notebook
22-
environment, etc.
23-
2. Consumers of libraries should be able to rely on complete and
24-
accurate type information so static type checkers can detect and
25-
report type inconsistencies and other violations of the interface
26-
contract.
27-
3. Library authors should be able to specify a well-defined interface
28-
contract that is enforced by tools. This allows a library
29-
implementation to evolve and improve without breaking consumers of
30-
the library.
31-
4. Library authors should have the benefits of static type checking to
13+
Why provide type annotations?
14+
=============================
15+
16+
Providing type annotations has the following benefits:
17+
18+
1. Type annotations help provide users of libraries a better coding
19+
experience by enabling fast and accurate completion suggestions, class and
20+
function documentation, signature help, hover text, auto-imports, etc.
21+
2. Users of libraries are able to use static type checkers to detect issues
22+
with their use of libraries.
23+
3. Type annotations allow library authors to specify an interface contract that
24+
is enforced by tools. This lets the library implementation evolve with less
25+
fear that users are depending on implementation details. In the event of
26+
changes to the library interface, type checkers are able to warn users when
27+
their code is affected.
28+
4. Library authors are able to use static type checking themselves to help
3229
produce high-quality, bug-free implementations.
3330

34-
Inlined Type Annotations and Type Stubs
35-
=======================================
31+
How to provide type annotations?
32+
================================
3633

37-
`PEP 561 <https://www.python.org/dev/peps/pep-0561/>`__ documents
38-
several ways type information can be delivered for a library: inlined
39-
type annotations, type stub files included in the package, a separate
40-
companion type stub package, and type stubs in the typeshed repository.
41-
Some of these options fall short on delivering the benefits above. We
42-
therefore provide the following more specific guidance to library
43-
authors.
34+
:pep:`561` documents several ways type information can be provided for a
35+
library:
4436

45-
.. note::
46-
All libraries should include inlined type annotations for the
47-
functions, classes, methods, and constants that comprise the public
48-
interface for the library.
49-
50-
Inlined type annotations should be included directly within the source
51-
code that ships with the package. Of the options listed in PEP 561,
52-
inlined type annotations offer the most benefits. They typically require
53-
the least effort to add and maintain, they are always consistent with
54-
the implementation, and docstrings and default parameter values are
55-
readily available, allowing language servers to enhance the development
56-
experience.
57-
58-
There are cases where inlined type annotations are not possible — most
59-
notably when a library’s exposed functionality is implemented in a
60-
language other than Python.
37+
- inline type annotations (preferred)
38+
- type stub files included in the package
39+
- a separate companion type stub package
40+
- type stubs in the typeshed repository
41+
42+
Inline type annotations simply refers to the use of annotations within your
43+
``.py`` files. In contrast, with type stub files, type information lives in
44+
separate ``.pyi`` files; see :ref:`stubs` for more details.
45+
46+
..
47+
TODO: link to a guide for writing stubs above
48+
49+
We recommend using the inline type annotations approach, since it has the
50+
following benefits:
51+
52+
- Typically requires the least effort to add and maintain
53+
- Users don't have to download additional packages
54+
- Always remains consistent with the implementation
55+
- Allows library authors to type check their own code
56+
- Allows language servers to show users relevant details about the
57+
implementation, such as docstrings and default parameter values
58+
59+
However, there are cases where inlined type annotations are not possible — most
60+
notably when a library's functionality is implemented in a language
61+
other than Python.
62+
63+
If you are not interested in providing type annotations for your library, you
64+
could suggest users to contribute type stubs to the
65+
`typeshed <https://github.com/python/typeshed>`__ project.
66+
67+
Marking a package as providing type information
68+
-----------------------------------------------
69+
70+
As specified in :pep:`561`, tools will not treat your package as providing type
71+
information unless it includes a special ``py.typed`` marker file.
6172

6273
.. note::
63-
Libraries that expose symbols implemented in languages other than
64-
Python should include stub (``.pyi``) files that describe the types for
65-
those symbols. These stubs should also contain docstrings and default
66-
parameter values.
74+
Before marking a package as providing type information, it is best to ensure
75+
that the library's interface is fully annotated. See :ref:`type_completeness`
76+
for more details.
77+
78+
Inline type annotations
79+
^^^^^^^^^^^^^^^^^^^^^^^
80+
81+
A typical directory structure would look like:
82+
83+
.. code-block:: text
84+
85+
setup.py
86+
my_great_package/
87+
__init__.py
88+
stuff.py
89+
py.typed
90+
91+
It's important to ensure that the ``py.typed`` marker file is included in the
92+
distributed package. If using ``setuptools``, this can be achieved like so:
93+
94+
.. code-block:: python
95+
96+
from setuptools import setup
97+
98+
setup(
99+
name="my_great_distribution",
100+
version="0.1",
101+
package_data={"my_great_package": ["py.typed"]},
102+
packages=["my_great_package"],
103+
)
104+
105+
106+
Type stub files included in the package
107+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108+
109+
It's possible to include a mix of type stub files (``.pyi``) and inline type
110+
annotations (``.py``). One use case for including type stub files in your
111+
package is to provide types for extension modules in your library. A typical
112+
directory structure would look like:
113+
114+
.. code-block:: text
115+
116+
setup.py
117+
my_great_package/
118+
__init__.py
119+
stuff.py
120+
stuff.pyi
121+
py.typed
122+
123+
If using ``setuptools``, we can ensure the ``.pyi`` and ``py.typed`` files are
124+
included like so:
125+
126+
.. code-block:: python
127+
128+
from setuptools import setup
129+
130+
setup(
131+
name="my_great_distribution",
132+
version="0.1",
133+
package_data={"my_great_package": ["py.typed", "stuff.pyi"]},
134+
packages=["my_great_package"],
135+
)
67136
68-
In many existing type stubs (such as those found in typeshed), default
69-
parameter values are replaced with with ``...`` and all docstrings are
70-
removed. We recommend that default values and docstrings remain within
71-
the type stub file so language servers can display this information to
72-
developers.
137+
The presence of ``.pyi`` files does not affect the Python interpreter at runtime
138+
in any way. However, static type checkers will only look at the ``.pyi`` file and
139+
ignore the corresponding ``.py`` file.
73140

74-
Library Interface
75-
=================
141+
Companion type stub package
142+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
76143

77-
`PEP 561 <https://www.python.org/dev/peps/pep-0561/>`__ indicates that a
78-
``py.typed`` marker file must be included in the package if the author
79-
wishes to support type checking of their code.
144+
These are often referred to as "stub-only" packages. The name of the stub package
145+
should be the name of the runtime package suffixed with ``-stubs``. The ``py.typed``
146+
marker file is not necessary for stub-only packages. This approach can be useful
147+
to develop type stubs independently from your library.
148+
149+
For example:
150+
151+
.. code-block:: text
152+
153+
setup.py
154+
my_great_package-stubs/
155+
__init__.pyi
156+
stuff.pyi
157+
158+
159+
.. code-block:: python
160+
161+
from setuptools import setup
162+
163+
setup(
164+
name="my_great_package-stubs",
165+
version="0.1",
166+
package_data={"my_great_package-stubs": ["__init__.pyi", "stuff.pyi"]},
167+
packages=["my_great_package-stubs"]
168+
)
169+
170+
171+
Users are then able to install the stubs-only package separately to provide
172+
types for the original library.
173+
174+
Inclusion in sdist
175+
^^^^^^^^^^^^^^^^^^
176+
177+
Note that to ensure inclusion of ``.pyi`` and ``py.typed`` files in an sdist
178+
(.tar.gz archive), you may also need to modify the inclusion rules in your
179+
``MANIFEST.in`` (see the
180+
`packaging guide <https://packaging.python.org/en/latest/guides/using-manifest-in/>`__
181+
for more details on ``MANIFEST.in``). For example:
182+
183+
.. code-block:: text
184+
185+
global-include *.pyi
186+
global-include py.typed
187+
188+
.. _type_completeness:
189+
190+
How much of my library needs types?
191+
===================================
192+
193+
A "py.typed" library should aim to be type complete so that type
194+
checking and inspection can work to their full extent. Here we say that a
195+
library is “type complete” if all of the symbols
196+
that comprise its interface have type annotations that refer to types
197+
that are fully known. Private symbols are exempt.
198+
199+
Library interface (public and private symbols)
200+
----------------------------------------------
80201

81202
If a ``py.typed`` module is present, a type checker will treat all modules
82203
within that package (i.e. all files that end in ``.py`` or ``.pyi``) as
@@ -119,13 +240,7 @@ determine the value of ``__all__``.
119240
- ``__all__.remove('a')``
120241

121242
Type Completeness
122-
=================
123-
124-
A “py.typed” library should aim to be type complete so that type
125-
checking and inspection can work to their full extent. Here we say that a
126-
library is “type complete” if all of the symbols
127-
that comprise its interface have type annotations that refer to types
128-
that are fully known. Private symbols are exempt.
243+
-----------------
129244

130245
The following are best practice recommendations for how to define “type complete”:
131246

@@ -282,6 +397,9 @@ Examples of known and unknown types
282397
class DictSubclass(dict):
283398
pass
284399
400+
..
401+
TODO: consider moving best practices to their own page?
402+
285403
Best Practices for Inlined Types
286404
================================
287405

0 commit comments

Comments
 (0)