Added dynamic path computation rationale, specification, and discussion.

This commit is contained in:
Eric V. Smith 2012-05-22 20:35:42 -04:00
parent bb6f79b4ad
commit eb2097eee6
1 changed files with 77 additions and 15 deletions

View File

@ -21,6 +21,7 @@ directories that make up the package. This PEP builds upon previous work,
documented in PEP 382 and PEP 402. Those PEPs have since been rejected in
favor of this one. An implementation of this PEP is at [1]_.
Terminology
===========
@ -43,6 +44,7 @@ Within this PEP:
This PEP defines a new type of package, the "namespace package".
Namespace packages today
========================
@ -78,9 +80,10 @@ setuptools allows declaring namespace packages in a distribution's
``setup.py``, so that distribution developers don't need to put the
magic ``__path__`` modification into ``__init__.py`` themselves.
See PEP 402's "The Problem" section [2]_ for more details on the
motivation for namespace packages. Note that PEP 402 has been
rejected, but the motivating use cases are still valid.
See PEP 402's "The Problem" section [2]_ for additional motivations
for namespace packages. Note that PEP 402 has been rejected, but the
motivating use cases are still valid.
Rationale
=========
@ -107,6 +110,36 @@ completely, and affected portions can be installed into a common
directory or split across multiple directories as distributions see
fit.
A namespace package will not be constrained by a fixed ``__path__``,
computed from the parent path at namespace package creation time.
Consider the standard library ``encodings`` package:
1. Suppose that ``encodings`` becomes a namespace package.
2. It sometimes gets imported during interpreter startup to
initialize the standard io streams.
3. An application modifies ``sys.path`` after startup and wants to
contribute additional encodings.
4. An attempt is made to import an ``encodings`` portion that is
found on a path added in step 3.
If the import system was restricted to only finding portions along the
value of ``sys.path`` that existed at the time the ``encodings``
namespace package was created, the additional paths added in step 3
would never be searched for the additional portions imported in step
4. In addition, if step 2 were sometimes skipped (due to some runtime
flag or other condition), then the path items added in step 3 would
indeed be used the first time a portion was imported. Thus this PEP
requires that the list of path entries be dynamically computed when
each portion is loaded. It is expected that the import machinery will
do this efficiently by caching ``__path__`` values and only refreshing
them when it detects that the parent path has changed. In the case of
a top-level package like ``encodings``, this parent path would be
``sys.path``.
Specification
=============
@ -161,16 +194,15 @@ between it and a regular package.
Dynamic path computation
------------------------
A namespace package's ``__path__`` will be recomputed if the value of
the parent path changes. In order for this feature to work, the parent
path must be modified in-place, not replaced with a new object. For
example, for top-level namespace packages, this will work::
The import machinery will behave as if a namespace package's
``__path__`` is recomputed before each portion is loaded.
sys.path.append('new-dir')
But this will not::
sys.path = sys.path + ['new-dir']
For performance reasons, it is expected that this will be achieved by
detecting that the parent path has changed. If no change has taken
place, then no ``__path__`` recomputation is required. The
implementation must ensure that changes to the contents of the parent
path are detected, as well as detecting the replacement of the parent
path with a new path entry list object.
Impact on import finders and loaders
------------------------------------
@ -354,6 +386,33 @@ implement the ``find_loader`` method, described above.
The use case for supporting multiple portions per ``find_loader`` call
is given in [7]_.
Dynamic path computation
------------------------
Guido raised a concern that automatic dynamic path computation was an
unnecessary feature [8]_. Later in that thread, Philip Eby and Nick
Coghlan presented arguments as to why dynamic computation would
minimize surprise to Python users. The conclusion of that discussion
has been included in this PEP's Rationale section.
An earlier version of this PEP required that dynamic path computation
could only take affect if the parent path object were modified
in-place. That is, this would work::
sys.path.append('new-dir')
But this would not::
sys.path = sys.path + ['new-dir']
In the same thread [8]_, it was pointed out that this restriction is
not required. If the parent path is looked up by name instead of by
holding a reference to it, then there is no restriction on how the
parent path is modified or replaced. For a top-level namespace
package, the lookup would be module ``sys`` then attribute ``path``.
For a namespace package nested inside a module ``foo``, the lookup
would be module ``foo`` then attribute ``__path__``.
Module reprs
============
@ -464,6 +523,9 @@ References
.. [7] Use case for multiple portions per ``find_loader`` call
(http://mail.python.org/pipermail/import-sig/2012-May/000585.html)
.. [8] Discussion about dynamic path computation
(http://mail.python.org/pipermail/python-dev/2012-May/119560.html)
Copyright
=========