Skip to content

Commit 7433bcb

Browse files
committed
Add third-party stubs discussion outlined in #84. Reformat paragraphs to conform to 72 characters per line.
1 parent a83508d commit 7433bcb

File tree

1 file changed

+100
-53
lines changed

1 file changed

+100
-53
lines changed

pep-0484.txt

Lines changed: 100 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,10 @@ Generics can be parametrized by using a new factory available in
264264
In this case the contract is that the returned value is consistent with
265265
the elements held by the collection.
266266

267-
``TypeVar`` supports constraining parametric types to a fixed set of possible
268-
types. For example, we can define a type variable that ranges over just
269-
``str`` and ``bytes``. By default, a type variable ranges over all
270-
possible types. Example of constraining a type variable::
267+
``TypeVar`` supports constraining parametric types to a fixed set of
268+
possible types. For example, we can define a type variable that ranges
269+
over just ``str`` and ``bytes``. By default, a type variable ranges
270+
over all possible types. Example of constraining a type variable::
271271

272272
from typing import TypeVar
273273

@@ -305,11 +305,10 @@ This is equivalent to omitting the generic notation and just saying
305305
User-defined generic types
306306
--------------------------
307307

308-
You can include a ``Generic`` base class to define a user-defined class as generic.
309-
Example::
308+
You can include a ``Generic`` base class to define a user-defined class
309+
as generic. Example::
310310

311311
from typing import TypeVar, Generic
312-
...
313312

314313
T = TypeVar('T')
315314

@@ -330,21 +329,21 @@ Example::
330329
def log(self, message: str) -> None:
331330
self.logger.info('{}: {}'.format(self.name message))
332331

333-
``Generic[T]`` as a base class defines that the class ``LoggedVar`` takes a
334-
single type parameter ``T``. This also makes ``T`` valid as a type within
335-
the class body.
332+
``Generic[T]`` as a base class defines that the class ``LoggedVar``
333+
takes a single type parameter ``T``. This also makes ``T`` valid as
334+
a type within the class body.
336335

337-
The ``Generic`` base class uses a metaclass that defines ``__getitem__`` so
338-
that ``LoggedVar[t]`` is valid as a type::
336+
The ``Generic`` base class uses a metaclass that defines ``__getitem__``
337+
so that ``LoggedVar[t]`` is valid as a type::
339338

340339
from typing import Iterable
341340

342341
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
343342
for var in vars:
344343
var.set(0)
345344

346-
A generic type can have any number of type variables, and type variables may
347-
be constrained. This is valid::
345+
A generic type can have any number of type variables, and type variables
346+
may be constrained. This is valid::
348347

349348
from typing import TypeVar, Generic
350349
...
@@ -355,15 +354,15 @@ be constrained. This is valid::
355354
class Pair(Generic[T, S]):
356355
...
357356

358-
Each type variable argument to ``Generic`` must be distinct. This is thus
359-
invalid::
357+
Each type variable argument to ``Generic`` must be distinct. This is
358+
thus invalid::
360359

361360
from typing import TypeVar, Generic
362361
...
363362

364363
T = TypeVar('T')
365364

366-
class Pair(Generic[T, T]):
365+
class Pair(Generic[T, T]): # INVALID
367366
...
368367

369368
You can use multiple inheritance with ``Generic``::
@@ -379,12 +378,12 @@ You can use multiple inheritance with ``Generic``::
379378
Arbitrary generic types as base classes
380379
---------------------------------------
381380

382-
``Generic[T]`` is only valid as a base class -- it's not a proper
383-
type. However, user-defined generic types such as ``LinkedList[T]``
384-
from the above example and built-in generic types and ABCs such as
385-
``List[T]`` and ``Iterable[T]`` are valid both as types and as base
386-
classes. For example, we can define a subclass of ``Dict`` that
387-
specializes type arguments::
381+
``Generic[T]`` is only valid as a base class -- it's not a proper type.
382+
However, user-defined generic types such as ``LinkedList[T]`` from the
383+
above example and built-in generic types and ABCs such as ``List[T]``
384+
and ``Iterable[T]`` are valid both as types and as base classes. For
385+
example, we can define a subclass of ``Dict`` that specializes type
386+
arguments::
388387

389388
from typing import Dict, List, Optional
390389

@@ -402,8 +401,7 @@ specializes type arguments::
402401
nodes = self.get(name)
403402
if nodes:
404403
return nodes[-1]
405-
else:
406-
return None
404+
return None
407405

408406
``SymbolTable`` is a subclass of ``dict`` and a subtype of ``Dict[str,
409407
List[Node]]``.
@@ -463,9 +461,9 @@ The local and global namespace in which it is evaluated should be the
463461
same namespaces in which default arguments to the same function would
464462
be evaluated.
465463

466-
Moreover, the expression should be parseable as a valid type hint,
467-
i.e., it is constrained by the rules from the section ``Acceptable
468-
type hints`` above.
464+
Moreover, the expression should be parseable as a valid type hint, i.e.,
465+
it is constrained by the rules from the section `Acceptable type hints`_
466+
above.
469467

470468
It is allowable to use string literals as *part* of a type hint, for
471469
example::
@@ -527,7 +525,7 @@ When the type of a value is ``object``, the type checker will reject
527525
almost all operations on it, and assigning it to a variable (or using
528526
it as a return value) of a more specialized type is a type error. On
529527
the other hand, when a value has type ``Any``, the type checker will
530-
allow all operations on it, and a value of type `Any`` can be assigned
528+
allow all operations on it, and a value of type ``Any`` can be assigned
531529
to a variable (or used as a return value) of a more constrained type.
532530

533531

@@ -654,12 +652,12 @@ Compatibility with other uses of function annotations
654652
=====================================================
655653

656654
A number of existing or potential use cases for function annotations
657-
exist, which are incompatible with type hinting. These may confuse a
658-
static type checker. However, since type hinting annotations have no
659-
runtime behavior (other than evaluation of the annotation expression
660-
and storing annotations in the ``__annotations__`` attribute of the
661-
function object), this does not make the program incorrect -- it just
662-
may cause a type checker to emit spurious warnings or errors.
655+
exist, which are incompatible with type hinting. These may confuse
656+
a static type checker. However, since type hinting annotations have no
657+
runtime behavior (other than evaluation of the annotation expression and
658+
storing annotations in the ``__annotations__`` attribute of the function
659+
object), this does not make the program incorrect -- it just may cause
660+
a type checker to emit spurious warnings or errors.
663661

664662
To mark portions of the program that should not be covered by type
665663
hinting, you can use one or more of the following:
@@ -674,10 +672,10 @@ hinting, you can use one or more of the following:
674672
For more details see later sections.
675673

676674
In order for maximal compatibility with offline type checking it may
677-
eventually be a good idea to change interfaces that rely on
678-
annotations to switch to a different mechanism, for example a
679-
decorator. In Python 3.5 there is no pressure to do this, however.
680-
See also the longer discussion under "Rejected alternatives" below.
675+
eventually be a good idea to change interfaces that rely on annotations
676+
to switch to a different mechanism, for example a decorator. In Python
677+
3.5 there is no pressure to do this, however. See also the longer
678+
discussion under `Rejected alternatives`_ below.
681679

682680

683681
Type comments
@@ -744,12 +742,11 @@ the type of ``x`` is ``t``. At runtime a cast always returns the
744742
expression unchanged -- it does not check the type, and it does not
745743
convert or coerce the value.
746744

747-
Casts differ from type comments (see the previous section). When
748-
using a type comment, the type checker should still verify that the
749-
inferred type is consistent with the stated type. When using a cast,
750-
the type checker should blindly believe the programmer. Also, casts
751-
can be used in expressions, while type comments only apply to
752-
assignments.
745+
Casts differ from type comments (see the previous section). When using
746+
a type comment, the type checker should still verify that the inferred
747+
type is consistent with the stated type. When using a cast, the type
748+
checker should blindly believe the programmer. Also, casts can be used
749+
in expressions, while type comments only apply to assignments.
753750

754751

755752
Stub Files
@@ -761,23 +758,25 @@ stub files:
761758

762759
* Extension modules
763760

764-
* 3rd party modules whose authors have not yet added type hints
761+
* Third-party modules whose authors have not yet added type hints
765762

766-
* Standard library modules for which type hints have not yet been written
763+
* Standard library modules for which type hints have not yet been
764+
written
767765

768766
* Modules that must be compatible with Python 2 and 3
769767

770768
* Modules that use annotations for other purposes
771769

772-
Stub files have the same syntax as regular Python modules. There is
773-
one feature of the ``typing`` module that may only be used in stub
774-
files: the ``@overload`` decorator described below.
770+
Stub files have the same syntax as regular Python modules. There is one
771+
feature of the ``typing`` module that may only be used in stub files:
772+
the ``@overload`` decorator described below.
775773

776774
The type checker should only check function signatures in stub files;
777-
function bodies in stub files should just be a single ``pass`` statement.
775+
function bodies in stub files should just be a single ``pass``
776+
statement.
778777

779-
The type checker should have a configurable search path for stub
780-
files. If a stub file is found the type checker should not read the
778+
The type checker should have a configurable search path for stub files.
779+
If a stub file is found the type checker should not read the
781780
corresponding "real" module.
782781

783782
While stub files are syntactically valid Python modules, they use the
@@ -850,6 +849,54 @@ satisfactory multiple dispatch design, but we don't want such a design
850849
to be constrained by the overloading syntax defined for type hints in
851850
stub files.
852851

852+
Storing and distributing stub files
853+
-----------------------------------
854+
855+
The easiest form of stub file storage and distribution is to put them
856+
alongside Python modules in the same directory. This makes them easy to
857+
find by both programmers and the tools. However, since package
858+
maintainers are free not to add type hinting to their packages,
859+
third-party stubs installable by ``pip`` from PyPI are also supported.
860+
In this case we have to consider three issues: naming, versioning,
861+
installation path.
862+
863+
This PEP does not provide a recommendation on a naming scheme that
864+
should be used for third-party stub file packages. Discoverability will
865+
hopefully be based on package popularity, like with Django packages for
866+
example.
867+
868+
Third-party stubs have to be versioned using the lowest version of the
869+
source package that is compatible. Example: FooPackage has versions
870+
1.0, 1.1, 1.2, 1.3, 2.0, 2.1, 2.2. There are API changes in versions
871+
1.1, 2.0 and 2.2. The stub file package maintainer is free to release
872+
stubs for all versions but at least 1.0, 1.1, 2.0 and 2.2 are required
873+
to enable the end user type check all versions. This is because the
874+
user knows that the closest *lower or equal* version of stubs is
875+
compatible. In the provided example, for FooPackage 1.3 the user would
876+
choose stubs version 1.1.
877+
878+
Note that if the user decides to use the "latest" available source
879+
package, using the "latest" stub files should generally also work if
880+
they're updated often.
881+
882+
Third-party stub packages can use any location for stub storage. The
883+
type checker will search for them using PYTHONPATH. A default fallback
884+
directory that is always checked is ``shared/typehints/python3.5/`` (or
885+
3.6, etc.). Since there can only be one package installed for a given
886+
Python version per environment, no additional versioning is performed
887+
under that directory (just like bare directory installs by ``pip`` in
888+
site-packages). Stub file package authors might use the following
889+
snippet in ``setup.py``::
890+
891+
...
892+
data_files=[
893+
(
894+
'shared/typehints/python{}.{}'.format(*sys.version_info[:2]),
895+
pathlib.Path(SRC_PATH).glob('**/*.pyi'),
896+
),
897+
],
898+
...
899+
853900

854901
Exceptions
855902
==========

0 commit comments

Comments
 (0)