peps/pep-0420/index.html

738 lines
61 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 420 Implicit Namespace Packages | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0420/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 420 Implicit Namespace Packages | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0420/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 420</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 420 Implicit Namespace Packages</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Eric V. Smith &lt;eric&#32;&#97;t&#32;trueblade.com&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">19-Apr-2012</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.3</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
<dt class="field-odd">Resolution<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2012-May/119651.html">Python-Dev message</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#terminology">Terminology</a></li>
<li><a class="reference internal" href="#namespace-packages-today">Namespace packages today</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#dynamic-path-computation">Dynamic path computation</a></li>
<li><a class="reference internal" href="#impact-on-import-finders-and-loaders">Impact on import finders and loaders</a></li>
<li><a class="reference internal" href="#differences-between-namespace-packages-and-regular-packages">Differences between namespace packages and regular packages</a></li>
<li><a class="reference internal" href="#namespace-packages-in-the-standard-library">Namespace packages in the standard library</a></li>
<li><a class="reference internal" href="#migrating-from-legacy-namespace-packages">Migrating from legacy namespace packages</a></li>
</ul>
</li>
<li><a class="reference internal" href="#packaging-implications">Packaging Implications</a></li>
<li><a class="reference internal" href="#examples">Examples</a><ul>
<li><a class="reference internal" href="#nested-namespace-packages">Nested namespace packages</a></li>
<li><a class="reference internal" href="#id2">Dynamic path computation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#discussion">Discussion</a><ul>
<li><a class="reference internal" href="#find-module-versus-find-loader"><code class="docutils literal notranslate"><span class="pre">find_module</span></code> versus <code class="docutils literal notranslate"><span class="pre">find_loader</span></code></a></li>
<li><a class="reference internal" href="#id8">Dynamic path computation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#module-reprs">Module reprs</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Namespace packages are a mechanism for splitting a single Python package
across multiple directories on disk. In current Python versions, an algorithm
to compute the packages <code class="docutils literal notranslate"><span class="pre">__path__</span></code> must be formulated. With the enhancement
proposed here, the import machinery itself will construct the list of
directories that make up the package. This PEP builds upon previous work,
documented in <a class="pep reference internal" href="../pep-0382/" title="PEP 382 Namespace Packages">PEP 382</a> and <a class="pep reference internal" href="../pep-0402/" title="PEP 402 Simplified Package Layout and Partitioning">PEP 402</a>. Those PEPs have since been rejected in
favor of this one. An implementation of this PEP is at <a class="footnote-reference brackets" href="#id11" id="id1">[1]</a>.</p>
</section>
<section id="terminology">
<h2><a class="toc-backref" href="#terminology" role="doc-backlink">Terminology</a></h2>
<p>Within this PEP:</p>
<ul class="simple">
<li>“package” refers to Python packages as defined by Pythons import
statement.</li>
<li>“distribution” refers to separately installable sets of Python
modules as stored in the Python package index, and installed by
distutils or setuptools.</li>
<li>“vendor package” refers to groups of files installed by an
operating systems packaging mechanism (e.g. Debian or Redhat
packages install on Linux systems).</li>
<li>“regular package” refers to packages as they are implemented in
Python 3.2 and earlier.</li>
<li>“portion” refers to a set of files in a single directory (possibly
stored in a zip file) that contribute to a namespace package.</li>
<li>“legacy portion” refers to a portion that uses <code class="docutils literal notranslate"><span class="pre">__path__</span></code>
manipulation in order to implement namespace packages.</li>
</ul>
<p>This PEP defines a new type of package, the “namespace package”.</p>
</section>
<section id="namespace-packages-today">
<h2><a class="toc-backref" href="#namespace-packages-today" role="doc-backlink">Namespace packages today</a></h2>
<p>Python currently provides <code class="docutils literal notranslate"><span class="pre">pkgutil.extend_path</span></code> to denote a package
as a namespace package. The recommended way of using it is to put:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pkgutil</span> <span class="kn">import</span> <span class="n">extend_path</span>
<span class="n">__path__</span> <span class="o">=</span> <span class="n">extend_path</span><span class="p">(</span><span class="n">__path__</span><span class="p">,</span> <span class="vm">__name__</span><span class="p">)</span>
</pre></div>
</div>
<p>in the packages <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>. Every distribution needs to provide
the same contents in its <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>, so that <code class="docutils literal notranslate"><span class="pre">extend_path</span></code> is
invoked independent of which portion of the package gets imported
first. As a consequence, the packages <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> cannot
practically define any names as it depends on the order of the package
fragments on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> to determine which portion is imported
first. As a special feature, <code class="docutils literal notranslate"><span class="pre">extend_path</span></code> reads files named
<code class="docutils literal notranslate"><span class="pre">&lt;packagename&gt;.pkg</span></code> which allows declaration of additional portions.</p>
<p>setuptools provides a similar function named
<code class="docutils literal notranslate"><span class="pre">pkg_resources.declare_namespace</span></code> that is used in the form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pkg_resources</span>
<span class="n">pkg_resources</span><span class="o">.</span><span class="n">declare_namespace</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
</pre></div>
</div>
<p>In the portions <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>, no assignment to <code class="docutils literal notranslate"><span class="pre">__path__</span></code> is
necessary, as <code class="docutils literal notranslate"><span class="pre">declare_namespace</span></code> modifies the package <code class="docutils literal notranslate"><span class="pre">__path__</span></code>
through <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>. As a special feature, <code class="docutils literal notranslate"><span class="pre">declare_namespace</span></code>
also supports zip files, and registers the package name internally so
that future additions to <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> by setuptools can properly add
additional portions to each package.</p>
<p>setuptools allows declaring namespace packages in a distributions
<code class="docutils literal notranslate"><span class="pre">setup.py</span></code>, so that distribution developers dont need to put the
magic <code class="docutils literal notranslate"><span class="pre">__path__</span></code> modification into <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> themselves.</p>
<p>See <a class="pep reference internal" href="../pep-0402/" title="PEP 402 Simplified Package Layout and Partitioning">PEP 402</a>s <a class="pep reference internal" href="../pep-0402/#the-problem" title="PEP 402 Simplified Package Layout and Partitioning § The Problem">“The Problem”</a>
section for additional motivations
for namespace packages. Note that <a class="pep reference internal" href="../pep-0402/" title="PEP 402 Simplified Package Layout and Partitioning">PEP 402</a> has been rejected, but the
motivating use cases are still valid.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>The current imperative approach to namespace packages has led to
multiple slightly-incompatible mechanisms for providing namespace
packages. For example, pkgutil supports <code class="docutils literal notranslate"><span class="pre">*.pkg</span></code> files; setuptools
doesnt. Likewise, setuptools supports inspecting zip files, and
supports adding portions to its <code class="docutils literal notranslate"><span class="pre">_namespace_packages</span></code> variable,
whereas pkgutil doesnt.</p>
<p>Namespace packages are designed to support being split across multiple
directories (and hence found via multiple <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> entries). In
this configuration, it doesnt matter if multiple portions all provide
an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file, so long as each portion correctly initializes
the namespace package. However, Linux distribution vendors (amongst
others) prefer to combine the separate portions and install them all
into the <em>same</em> file system directory. This creates a potential for
conflict, as the portions are now attempting to provide the <em>same</em>
file on the target system - something that is not allowed by many
package managers. Allowing implicit namespace packages means that the
requirement to provide an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file can be dropped
completely, and affected portions can be installed into a common
directory or split across multiple directories as distributions see
fit.</p>
<p>A namespace package will not be constrained by a fixed <code class="docutils literal notranslate"><span class="pre">__path__</span></code>,
computed from the parent path at namespace package creation time.
Consider the standard library <code class="docutils literal notranslate"><span class="pre">encodings</span></code> package:</p>
<ol class="arabic simple">
<li>Suppose that <code class="docutils literal notranslate"><span class="pre">encodings</span></code> becomes a namespace package.</li>
<li>It sometimes gets imported during interpreter startup to
initialize the standard io streams.</li>
<li>An application modifies <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> after startup and wants to
contribute additional encodings from new path entries.</li>
<li>An attempt is made to import an encoding from an <code class="docutils literal notranslate"><span class="pre">encodings</span></code>
portion that is found on a path entry added in step 3.</li>
</ol>
<p>If the import system was restricted to only finding portions along the
value of <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> that existed at the time the <code class="docutils literal notranslate"><span class="pre">encodings</span></code>
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 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> values and only refreshing
them when it detects that the parent path has changed. In the case of
a top-level package like <code class="docutils literal notranslate"><span class="pre">encodings</span></code>, this parent path would be
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code>.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>Regular packages will continue to have an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> and will
reside in a single directory.</p>
<p>Namespace packages cannot contain an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>. As a
consequence, <code class="docutils literal notranslate"><span class="pre">pkgutil.extend_path</span></code> and
<code class="docutils literal notranslate"><span class="pre">pkg_resources.declare_namespace</span></code> become obsolete for purposes of
namespace package creation. There will be no marker file or directory
for specifying a namespace package.</p>
<p>During import processing, the import machinery will continue to
iterate over each directory in the parent path as it does in Python
3.2. While looking for a module or package named “foo”, for each
directory in the parent path:</p>
<ul class="simple">
<li>If <code class="docutils literal notranslate"><span class="pre">&lt;directory&gt;/foo/__init__.py</span></code> is found, a regular package is
imported and returned.</li>
<li>If not, but <code class="docutils literal notranslate"><span class="pre">&lt;directory&gt;/foo.{py,pyc,so,pyd}</span></code> is found, a module
is imported and returned. The exact list of extension varies by
platform and whether the -O flag is specified. The list here is
representative.</li>
<li>If not, but <code class="docutils literal notranslate"><span class="pre">&lt;directory&gt;/foo</span></code> is found and is a directory, it is
recorded and the scan continues with the next directory in the
parent path.</li>
<li>Otherwise the scan continues with the next directory in the parent
path.</li>
</ul>
<p>If the scan completes without returning a module or package, and at
least one directory was recorded, then a namespace package is created.
The new namespace package:</p>
<ul class="simple">
<li>Has a <code class="docutils literal notranslate"><span class="pre">__path__</span></code> attribute set to an iterable of the path strings
that were found and recorded during the scan.</li>
<li>Does not have a <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute.</li>
</ul>
<p>Note that if “import foo” is executed and “foo” is found as a
namespace package (using the above rules), then “foo” is immediately
created as a package. The creation of the namespace package is not
deferred until a sub-level import occurs.</p>
<p>A namespace package is not fundamentally different from a regular
package. It is just a different way of creating packages. Once a
namespace package is created, there is no functional difference
between it and a regular package.</p>
<section id="dynamic-path-computation">
<h3><a class="toc-backref" href="#dynamic-path-computation" role="doc-backlink">Dynamic path computation</a></h3>
<p>The import machinery will behave as if a namespace packages
<code class="docutils literal notranslate"><span class="pre">__path__</span></code> is recomputed before each portion is loaded.</p>
<p>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 <code class="docutils literal notranslate"><span class="pre">__path__</span></code> 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.</p>
</section>
<section id="impact-on-import-finders-and-loaders">
<h3><a class="toc-backref" href="#impact-on-import-finders-and-loaders" role="doc-backlink">Impact on import finders and loaders</a></h3>
<p><a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a> defines “finders” that are called to search path elements.
These finders <code class="docutils literal notranslate"><span class="pre">find_module</span></code> methods return either a “loader” object
or <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
<p>For a finder to contribute to namespace packages, it must implement a
new <code class="docutils literal notranslate"><span class="pre">find_loader(fullname)</span></code> method. <code class="docutils literal notranslate"><span class="pre">fullname</span></code> has the same
meaning as for <code class="docutils literal notranslate"><span class="pre">find_module</span></code>. <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> always returns a
2-tuple of <code class="docutils literal notranslate"><span class="pre">(loader,</span> <span class="pre">&lt;iterable-of-path-entries&gt;)</span></code>. <code class="docutils literal notranslate"><span class="pre">loader</span></code> may
be <code class="docutils literal notranslate"><span class="pre">None</span></code>, in which case <code class="docutils literal notranslate"><span class="pre">&lt;iterable-of-path-entries&gt;</span></code> (which may
be empty) is added to the list of recorded path entries and path
searching continues. If <code class="docutils literal notranslate"><span class="pre">loader</span></code> is not <code class="docutils literal notranslate"><span class="pre">None</span></code>, it is immediately
used to load a module or regular package.</p>
<p>Even if <code class="docutils literal notranslate"><span class="pre">loader</span></code> is returned and is not <code class="docutils literal notranslate"><span class="pre">None</span></code>,
<code class="docutils literal notranslate"><span class="pre">&lt;iterable-of-path-entries&gt;</span></code> must still contain the path entries for
the package. This allows code such as <code class="docutils literal notranslate"><span class="pre">pkgutil.extend_path()</span></code> to
compute path entries for packages that it does not load.</p>
<p>Note that multiple path entries per finder are allowed. This is to
support the case where a finder discovers multiple namespace portions
for a given <code class="docutils literal notranslate"><span class="pre">fullname</span></code>. Many finders will support only a single
namespace package portion per <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> call, in which case this
iterable will contain only a single string.</p>
<p>The import machinery will call <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> if it exists, else fall
back to <code class="docutils literal notranslate"><span class="pre">find_module</span></code>. Legacy finders which implement
<code class="docutils literal notranslate"><span class="pre">find_module</span></code> but not <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> will be unable to contribute
portions to a namespace package.</p>
<p>The specification expands <a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a> loaders to include an optional method called
<code class="docutils literal notranslate"><span class="pre">module_repr()</span></code> which if present, is used to generate module object reprs.
See the section below for further details.</p>
</section>
<section id="differences-between-namespace-packages-and-regular-packages">
<h3><a class="toc-backref" href="#differences-between-namespace-packages-and-regular-packages" role="doc-backlink">Differences between namespace packages and regular packages</a></h3>
<p>Namespace packages and regular packages are very similar. The
differences are:</p>
<ul class="simple">
<li>Portions of namespace packages need not all come from the same
directory structure, or even from the same loader. Regular packages
are self-contained: all parts live in the same directory hierarchy.</li>
<li>Namespace packages have no <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute.</li>
<li>Namespace packages <code class="docutils literal notranslate"><span class="pre">__path__</span></code> attribute is a read-only iterable
of strings, which is automatically updated when the parent path is
modified.</li>
<li>Namespace packages have no <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> module.</li>
<li>Namespace packages have a different type of object for their
<code class="docutils literal notranslate"><span class="pre">__loader__</span></code> attribute.</li>
</ul>
</section>
<section id="namespace-packages-in-the-standard-library">
<h3><a class="toc-backref" href="#namespace-packages-in-the-standard-library" role="doc-backlink">Namespace packages in the standard library</a></h3>
<p>It is possible, and this PEP explicitly allows, that parts of the
standard library be implemented as namespace packages. When and if
any standard library packages become namespace packages is outside the
scope of this PEP.</p>
</section>
<section id="migrating-from-legacy-namespace-packages">
<h3><a class="toc-backref" href="#migrating-from-legacy-namespace-packages" role="doc-backlink">Migrating from legacy namespace packages</a></h3>
<p>As described above, prior to this PEP <code class="docutils literal notranslate"><span class="pre">pkgutil.extend_path()</span></code> was
used by legacy portions to create namespace packages. Because it is
likely not practical for all existing portions of a namespace package
to be migrated to this PEP at once, <code class="docutils literal notranslate"><span class="pre">extend_path()</span></code> will be modified
to also recognize <a class="pep reference internal" href="../pep-0420/" title="PEP 420 Implicit Namespace Packages">PEP 420</a> namespace packages. This will allow some
portions of a namespace to be legacy portions while others are
migrated to <a class="pep reference internal" href="../pep-0420/" title="PEP 420 Implicit Namespace Packages">PEP 420</a>. These hybrid namespace packages will not have
the dynamic path computation that normal namespace packages have,
since <code class="docutils literal notranslate"><span class="pre">extend_path()</span></code> never provided this functionality in the past.</p>
</section>
</section>
<section id="packaging-implications">
<h2><a class="toc-backref" href="#packaging-implications" role="doc-backlink">Packaging Implications</a></h2>
<p>Multiple portions of a namespace package can be installed into the
same directory, or into separate directories. For this section,
suppose there are two portions which define “foo.bar” and “foo.baz”.
“foo” itself is a namespace package.</p>
<p>If these are installed in the same location, a single directory “foo”
would be in a directory that is on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>. Inside “foo” would
be two directories, “bar” and “baz”. If “foo.bar” is removed (perhaps
by an OS package manager), care must be taken not to remove the
“foo/baz” or “foo” directories. Note that in this case “foo” will be
a namespace package (because it lacks an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>), even though
all of its portions are in the same directory.</p>
<p>Note that “foo.bar” and “foo.baz” can be installed into the same “foo”
directory because they will not have any files in common.</p>
<p>If the portions are installed in different locations, two different
“foo” directories would be in directories that are on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>.
“foo/bar” would be in one of these sys.path entries, and “foo/baz”
would be in the other. Upon removal of “foo.bar”, the “foo/bar” and
corresponding “foo” directories can be completely removed. But
“foo/baz” and its corresponding “foo” directory cannot be removed.</p>
<p>It is also possible to have the “foo.bar” portion installed in a
directory on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, and have the “foo.baz” portion provided in
a zip file, also on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>.</p>
</section>
<section id="examples">
<h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2>
<section id="nested-namespace-packages">
<h3><a class="toc-backref" href="#nested-namespace-packages" role="doc-backlink">Nested namespace packages</a></h3>
<p>This example uses the following directory structure:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Lib</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">namespace_pkgs</span>
<span class="n">project1</span>
<span class="n">parent</span>
<span class="n">child</span>
<span class="n">one</span><span class="o">.</span><span class="n">py</span>
<span class="n">project2</span>
<span class="n">parent</span>
<span class="n">child</span>
<span class="n">two</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>Here, both parent and child are namespace packages: Portions of them
exist in different directories, and they do not have <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>
files.</p>
<p>Here we add the parent directories to <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, and show that the
portions are correctly found:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sys</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">+=</span> <span class="p">[</span><span class="s1">&#39;Lib/test/namespace_pkgs/project1&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project2&#39;</span><span class="p">]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">parent.child.one</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">parent</span><span class="o">.</span><span class="n">__path__</span>
<span class="go">_NamespacePath([&#39;Lib/test/namespace_pkgs/project1/parent&#39;, &#39;Lib/test/namespace_pkgs/project2/parent&#39;])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">parent</span><span class="o">.</span><span class="n">child</span><span class="o">.</span><span class="n">__path__</span>
<span class="go">_NamespacePath([&#39;Lib/test/namespace_pkgs/project1/parent/child&#39;, &#39;Lib/test/namespace_pkgs/project2/parent/child&#39;])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">parent.child.two</span>
<span class="gp">&gt;&gt;&gt;</span>
</pre></div>
</div>
</section>
<section id="id2">
<h3><a class="toc-backref" href="#id2" role="doc-backlink">Dynamic path computation</a></h3>
<p>This example uses a similar directory structure, but adds a third
portion:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Lib</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">namespace_pkgs</span>
<span class="n">project1</span>
<span class="n">parent</span>
<span class="n">child</span>
<span class="n">one</span><span class="o">.</span><span class="n">py</span>
<span class="n">project2</span>
<span class="n">parent</span>
<span class="n">child</span>
<span class="n">two</span><span class="o">.</span><span class="n">py</span>
<span class="n">project3</span>
<span class="n">parent</span>
<span class="n">child</span>
<span class="n">three</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>We add <code class="docutils literal notranslate"><span class="pre">project1</span></code> and <code class="docutils literal notranslate"><span class="pre">project2</span></code> to <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, then import
<code class="docutils literal notranslate"><span class="pre">parent.child.one</span></code> and <code class="docutils literal notranslate"><span class="pre">parent.child.two</span></code>. Then we add the
<code class="docutils literal notranslate"><span class="pre">project3</span></code> to <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> and when <code class="docutils literal notranslate"><span class="pre">parent.child.three</span></code> is
imported, <code class="docutils literal notranslate"><span class="pre">project3/parent</span></code> is automatically added to
<code class="docutils literal notranslate"><span class="pre">parent.__path__</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># add the first two parent paths to sys.path</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">sys</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">+=</span> <span class="p">[</span><span class="s1">&#39;Lib/test/namespace_pkgs/project1&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project2&#39;</span><span class="p">]</span>
<span class="c1"># parent.child.one can be imported, because project1 was added to sys.path:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">parent.child.one</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">parent</span><span class="o">.</span><span class="n">__path__</span>
<span class="n">_NamespacePath</span><span class="p">([</span><span class="s1">&#39;Lib/test/namespace_pkgs/project1/parent&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project2/parent&#39;</span><span class="p">])</span>
<span class="c1"># parent.child.__path__ contains project1/parent/child and project2/parent/child, but not project3/parent/child:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">parent</span><span class="o">.</span><span class="n">child</span><span class="o">.</span><span class="n">__path__</span>
<span class="n">_NamespacePath</span><span class="p">([</span><span class="s1">&#39;Lib/test/namespace_pkgs/project1/parent/child&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project2/parent/child&#39;</span><span class="p">])</span>
<span class="c1"># parent.child.two can be imported, because project2 was added to sys.path:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">parent.child.two</span>
<span class="c1"># we cannot import parent.child.three, because project3 is not in the path:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">parent.child.three</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="n">File</span> <span class="s2">&quot;&lt;stdin&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
<span class="n">File</span> <span class="s2">&quot;&lt;frozen importlib._bootstrap&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1286</span><span class="p">,</span> <span class="ow">in</span> <span class="n">_find_and_load</span>
<span class="n">File</span> <span class="s2">&quot;&lt;frozen importlib._bootstrap&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1250</span><span class="p">,</span> <span class="ow">in</span> <span class="n">_find_and_load_unlocked</span>
<span class="ne">ImportError</span><span class="p">:</span> <span class="n">No</span> <span class="n">module</span> <span class="n">named</span> <span class="s1">&#39;parent.child.three&#39;</span>
<span class="c1"># now add project3 to sys.path:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;Lib/test/namespace_pkgs/project3&#39;</span><span class="p">)</span>
<span class="c1"># and now parent.child.three can be imported:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">parent.child.three</span>
<span class="c1"># project3/parent has been added to parent.__path__:</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">parent</span><span class="o">.</span><span class="n">__path__</span>
<span class="n">_NamespacePath</span><span class="p">([</span><span class="s1">&#39;Lib/test/namespace_pkgs/project1/parent&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project2/parent&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project3/parent&#39;</span><span class="p">])</span>
<span class="c1"># and project3/parent/child has been added to parent.child.__path__</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">parent</span><span class="o">.</span><span class="n">child</span><span class="o">.</span><span class="n">__path__</span>
<span class="n">_NamespacePath</span><span class="p">([</span><span class="s1">&#39;Lib/test/namespace_pkgs/project1/parent/child&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project2/parent/child&#39;</span><span class="p">,</span> <span class="s1">&#39;Lib/test/namespace_pkgs/project3/parent/child&#39;</span><span class="p">])</span>
<span class="o">&gt;&gt;&gt;</span>
</pre></div>
</div>
</section>
</section>
<section id="discussion">
<h2><a class="toc-backref" href="#discussion" role="doc-backlink">Discussion</a></h2>
<p>At PyCon 2012, we had a discussion about namespace packages at which
<a class="pep reference internal" href="../pep-0382/" title="PEP 382 Namespace Packages">PEP 382</a> and <a class="pep reference internal" href="../pep-0402/" title="PEP 402 Simplified Package Layout and Partitioning">PEP 402</a> were rejected, to be replaced by this PEP <a class="footnote-reference brackets" href="#id12" id="id3">[3]</a>.</p>
<p>There is no intention to remove support of regular packages. If a
developer knows that her package will never be a portion of a
namespace package, then there is a performance advantage to it being a
regular package (with an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code>). Creation and loading of a
regular package can take place immediately when it is located along
the path. With namespace packages, all entries in the path must be
scanned before the package is created.</p>
<p>Note that an ImportWarning will no longer be raised for a directory
lacking an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file. Such a directory will now be
imported as a namespace package, whereas in prior Python versions an
ImportWarning would be raised.</p>
<p>Alyssa (Nick) Coghlan presented a list of her objections to this proposal <a class="footnote-reference brackets" href="#id13" id="id4">[4]</a>.
They are:</p>
<ol class="arabic simple">
<li>Implicit package directories go against the Zen of Python.</li>
<li>Implicit package directories pose awkward backwards compatibility
challenges.</li>
<li>Implicit package directories introduce ambiguity into file system
layouts.</li>
<li>Implicit package directories will permanently entrench current
newbie-hostile behavior in <code class="docutils literal notranslate"><span class="pre">__main__</span></code>.</li>
</ol>
<p>Alyssa later gave a detailed response to her own objections <a class="footnote-reference brackets" href="#id14" id="id5">[5]</a>, which
is summarized here:</p>
<ol class="arabic simple">
<li>The practicality of this PEP wins over other proposals and the
status quo.</li>
<li>Minor backward compatibility issues are okay, as long as they are
properly documented.</li>
<li>This will be addressed in <a class="pep reference internal" href="../pep-0395/" title="PEP 395 Qualified Names for Modules">PEP 395</a>.</li>
<li>This will also be addressed in <a class="pep reference internal" href="../pep-0395/" title="PEP 395 Qualified Names for Modules">PEP 395</a>.</li>
</ol>
<p>The inclusion of namespace packages in the standard library was
motivated by Martin v. Löwis, who wanted the <code class="docutils literal notranslate"><span class="pre">encodings</span></code> package to
become a namespace package <a class="footnote-reference brackets" href="#id15" id="id6">[6]</a>. While this PEP allows for standard
library packages to become namespaces, it defers a decision on
<code class="docutils literal notranslate"><span class="pre">encodings</span></code>.</p>
<section id="find-module-versus-find-loader">
<h3><a class="toc-backref" href="#find-module-versus-find-loader" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">find_module</span></code> versus <code class="docutils literal notranslate"><span class="pre">find_loader</span></code></a></h3>
<p>An early draft of this PEP specified a change to the <code class="docutils literal notranslate"><span class="pre">find_module</span></code>
method in order to support namespace packages. It would be modified
to return a string in the case where a namespace package portion was
discovered.</p>
<p>However, this caused a problem with existing code outside of the
standard library which calls <code class="docutils literal notranslate"><span class="pre">find_module</span></code>. Because this code would
not be upgraded in concert with changes required by this PEP, it would
fail when it would receive unexpected return values from
<code class="docutils literal notranslate"><span class="pre">find_module</span></code>. Because of this incompatibility, this PEP now
specifies that finders that want to provide namespace portions must
implement the <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> method, described above.</p>
<p>The use case for supporting multiple portions per <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> call
is given in <a class="footnote-reference brackets" href="#id16" id="id7">[7]</a>.</p>
</section>
<section id="id8">
<h3><a class="toc-backref" href="#id8" role="doc-backlink">Dynamic path computation</a></h3>
<p>Guido raised a concern that automatic dynamic path computation was an
unnecessary feature <a class="footnote-reference brackets" href="#id17" id="id9">[8]</a>. Later in that thread, PJ Eby and Alyssa
Coghlan presented arguments as to why dynamic computation would
minimize surprise to Python users. The conclusion of that discussion
has been included in this PEPs Rationale section.</p>
<p>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:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;new-dir&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>But this would not:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span> <span class="o">+</span> <span class="p">[</span><span class="s1">&#39;new-dir&#39;</span><span class="p">]</span>
</pre></div>
</div>
<p>In the same thread <a class="footnote-reference brackets" href="#id17" id="id10">[8]</a>, 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 the module named <code class="docutils literal notranslate"><span class="pre">&quot;sys&quot;</span></code> then its
attribute <code class="docutils literal notranslate"><span class="pre">&quot;path&quot;</span></code>. For a namespace package nested inside a package
<code class="docutils literal notranslate"><span class="pre">foo</span></code>, the lookup would be for the module named <code class="docutils literal notranslate"><span class="pre">&quot;foo&quot;</span></code> then its
attribute <code class="docutils literal notranslate"><span class="pre">&quot;__path__&quot;</span></code>.</p>
</section>
</section>
<section id="module-reprs">
<h2><a class="toc-backref" href="#module-reprs" role="doc-backlink">Module reprs</a></h2>
<p>Previously, module reprs were hard coded based on assumptions about a modules
<code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute. If this attribute existed and was a string, it was
assumed to be a file system path, and the module objects repr would include
this in its value. The only exception was that <a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a> reserved missing
<code class="docutils literal notranslate"><span class="pre">__file__</span></code> attributes to built-in modules, and in CPython, this assumption
was baked into the module objects implementation. Because of this
restriction, some modules contained contrived <code class="docutils literal notranslate"><span class="pre">__file__</span></code> values that did not
reflect file system paths, and which could cause unexpected problems later
(e.g. <code class="docutils literal notranslate"><span class="pre">os.path.join()</span></code> on a non-path <code class="docutils literal notranslate"><span class="pre">__file__</span></code> would return gibberish).</p>
<p>This PEP relaxes this constraint, and leaves the setting of <code class="docutils literal notranslate"><span class="pre">__file__</span></code> to
the purview of the loader producing the module. Loaders may opt to leave
<code class="docutils literal notranslate"><span class="pre">__file__</span></code> unset if no file system path is appropriate. Loaders may also
set additional reserved attributes on the module if useful. This means that
the definitive way to determine the origin of a module is to check its
<code class="docutils literal notranslate"><span class="pre">__loader__</span></code> attribute.</p>
<p>For example, namespace packages as described in this PEP will have no
<code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute because no corresponding file exists. In order to
provide flexibility and descriptiveness in the reprs of such modules, a new
optional protocol is added to <a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a> loaders. Loaders can implement a
<code class="docutils literal notranslate"><span class="pre">module_repr()</span></code> method which takes a single argument, the module object.
This method should return the string to be used verbatim as the repr of the
module. The rules for producing a module repr are now standardized as:</p>
<ul class="simple">
<li>If the module has an <code class="docutils literal notranslate"><span class="pre">__loader__</span></code> and that loader has a <code class="docutils literal notranslate"><span class="pre">module_repr()</span></code>
method, call it with a single argument, which is the module object. The
value returned is used as the modules repr.</li>
<li>If an exception occurs in <code class="docutils literal notranslate"><span class="pre">module_repr()</span></code>, the exception is
caught and discarded, and the calculation of the modules repr
continues as if <code class="docutils literal notranslate"><span class="pre">module_repr()</span></code> did not exist.</li>
<li>If the module has an <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute, this is used as part of the
modules repr.</li>
<li>If the module has no <code class="docutils literal notranslate"><span class="pre">__file__</span></code> but does have an <code class="docutils literal notranslate"><span class="pre">__loader__</span></code>, then the
loaders repr is used as part of the modules repr.</li>
<li>Otherwise, just use the modules <code class="docutils literal notranslate"><span class="pre">__name__</span></code> in the repr.</li>
</ul>
<p>Here is a snippet showing how namespace module reprs are calculated
from its loader:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">NamespaceLoader</span><span class="p">:</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">module_repr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">&quot;&lt;module &#39;</span><span class="si">{}</span><span class="s2">&#39; (namespace)&gt;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">module</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
</pre></div>
</div>
<p>Built-in module reprs would no longer need to be hard-coded, but
instead would come from their loader as well:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BuiltinImporter</span><span class="p">:</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">module_repr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">&quot;&lt;module &#39;</span><span class="si">{}</span><span class="s2">&#39; (built-in)&gt;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">module</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
</pre></div>
</div>
<p>Here are some example reprs of different types of modules with
different sets of the related attributes:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">email</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">email</span>
<span class="go">&lt;module &#39;email&#39; from &#39;/home/barry/projects/python/pep-420/Lib/email/__init__.py&#39;&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">email</span><span class="p">)(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span>
<span class="go">&lt;module &#39;foo&#39;&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="vm">__file__</span> <span class="o">=</span> <span class="s1">&#39;zippy:/de/do/dah&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span>
<span class="go">&lt;module &#39;foo&#39; from &#39;zippy:/de/do/dah&#39;&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Loader</span><span class="p">:</span> <span class="k">pass</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">__loader__</span> <span class="o">=</span> <span class="n">Loader</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">m</span><span class="o">.</span><span class="vm">__file__</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span>
<span class="go">&lt;module &#39;foo&#39; (&lt;class &#39;__main__.Loader&#39;&gt;)&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">NewLoader</span><span class="p">:</span>
<span class="gp">... </span> <span class="nd">@classmethod</span>
<span class="gp">... </span> <span class="k">def</span> <span class="nf">module_repr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">module</span><span class="p">):</span>
<span class="gp">... </span> <span class="k">return</span> <span class="s1">&#39;&lt;mystery module!&gt;&#39;</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">__loader__</span> <span class="o">=</span> <span class="n">NewLoader</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span>
<span class="go">&lt;mystery module!&gt;</span>
<span class="gp">&gt;&gt;&gt;</span>
</pre></div>
</div>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id11" role="doc-footnote">
<dt class="label" id="id11">[<a href="#id1">1</a>]</dt>
<dd>PEP 420 branch (<a class="reference external" href="http://hg.python.org/features/pep-420">http://hg.python.org/features/pep-420</a>)</aside>
<aside class="footnote brackets" id="id12" role="doc-footnote">
<dt class="label" id="id12">[<a href="#id3">3</a>]</dt>
<dd>PyCon 2012 Namespace Package discussion outcome
(<a class="reference external" href="https://mail.python.org/pipermail/import-sig/2012-March/000421.html">https://mail.python.org/pipermail/import-sig/2012-March/000421.html</a>)</aside>
<aside class="footnote brackets" id="id13" role="doc-footnote">
<dt class="label" id="id13">[<a href="#id4">4</a>]</dt>
<dd>Alyssa Coghlans objection to the lack of marker files or directories
(<a class="reference external" href="https://mail.python.org/pipermail/import-sig/2012-March/000423.html">https://mail.python.org/pipermail/import-sig/2012-March/000423.html</a>)</aside>
<aside class="footnote brackets" id="id14" role="doc-footnote">
<dt class="label" id="id14">[<a href="#id5">5</a>]</dt>
<dd>Alyssa Coghlans response to her initial objections
(<a class="reference external" href="https://mail.python.org/pipermail/import-sig/2012-April/000464.html">https://mail.python.org/pipermail/import-sig/2012-April/000464.html</a>)</aside>
<aside class="footnote brackets" id="id15" role="doc-footnote">
<dt class="label" id="id15">[<a href="#id6">6</a>]</dt>
<dd>Martin v. Löwiss suggestion to make <code class="docutils literal notranslate"><span class="pre">encodings</span></code> a namespace
package
(<a class="reference external" href="https://mail.python.org/pipermail/import-sig/2012-May/000540.html">https://mail.python.org/pipermail/import-sig/2012-May/000540.html</a>)</aside>
<aside class="footnote brackets" id="id16" role="doc-footnote">
<dt class="label" id="id16">[<a href="#id7">7</a>]</dt>
<dd>Use case for multiple portions per <code class="docutils literal notranslate"><span class="pre">find_loader</span></code> call
(<a class="reference external" href="https://mail.python.org/pipermail/import-sig/2012-May/000585.html">https://mail.python.org/pipermail/import-sig/2012-May/000585.html</a>)</aside>
<aside class="footnote brackets" id="id17" role="doc-footnote">
<dt class="label" id="id17">[8]<em> (<a href='#id9'>1</a>, <a href='#id10'>2</a>) </em></dt>
<dd>Discussion about dynamic path computation
(<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2012-May/119560.html">https://mail.python.org/pipermail/python-dev/2012-May/119560.html</a>)</aside>
</aside>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0420.rst">https://github.com/python/peps/blob/main/peps/pep-0420.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0420.rst">2023-10-11 12:05:51 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#terminology">Terminology</a></li>
<li><a class="reference internal" href="#namespace-packages-today">Namespace packages today</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#dynamic-path-computation">Dynamic path computation</a></li>
<li><a class="reference internal" href="#impact-on-import-finders-and-loaders">Impact on import finders and loaders</a></li>
<li><a class="reference internal" href="#differences-between-namespace-packages-and-regular-packages">Differences between namespace packages and regular packages</a></li>
<li><a class="reference internal" href="#namespace-packages-in-the-standard-library">Namespace packages in the standard library</a></li>
<li><a class="reference internal" href="#migrating-from-legacy-namespace-packages">Migrating from legacy namespace packages</a></li>
</ul>
</li>
<li><a class="reference internal" href="#packaging-implications">Packaging Implications</a></li>
<li><a class="reference internal" href="#examples">Examples</a><ul>
<li><a class="reference internal" href="#nested-namespace-packages">Nested namespace packages</a></li>
<li><a class="reference internal" href="#id2">Dynamic path computation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#discussion">Discussion</a><ul>
<li><a class="reference internal" href="#find-module-versus-find-loader"><code class="docutils literal notranslate"><span class="pre">find_module</span></code> versus <code class="docutils literal notranslate"><span class="pre">find_loader</span></code></a></li>
<li><a class="reference internal" href="#id8">Dynamic path computation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#module-reprs">Module reprs</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0420.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>