peps/pep-0302/index.html

643 lines
60 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 302 New Import Hooks | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0302/">
<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 302 New Import Hooks | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0302/">
<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 302</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 302 New Import Hooks</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Just van Rossum &lt;just&#32;&#97;t&#32;letterror.com&gt;,
Paul Moore &lt;p.f.moore&#32;&#97;t&#32;gmail.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-Dec-2002</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.3</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">19-Dec-2002</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="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#use-cases">Use cases</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification-part-1-the-importer-protocol">Specification part 1: The Importer Protocol</a></li>
<li><a class="reference internal" href="#specification-part-2-registering-hooks">Specification part 2: Registering Hooks</a></li>
<li><a class="reference internal" href="#packages-and-the-role-of-path">Packages and the role of <code class="docutils literal notranslate"><span class="pre">__path__</span></code></a></li>
<li><a class="reference internal" href="#optional-extensions-to-the-importer-protocol">Optional Extensions to the Importer Protocol</a></li>
<li><a class="reference internal" href="#integration-with-the-imp-module">Integration with the imp module</a></li>
<li><a class="reference internal" href="#forward-compatibility">Forward Compatibility</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#references-and-footnotes">References and Footnotes</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>The language reference for import <a class="footnote-reference brackets" href="#id17" id="id1">[10]</a> and importlib documentation
<a class="footnote-reference brackets" href="#id18" id="id2">[11]</a> now supersede this PEP. This document is no longer updated
and provided for historical purposes only.</p>
</div>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP proposes to add a new set of import hooks that offer better
customization of the Python import mechanism. Contrary to the current
<code class="docutils literal notranslate"><span class="pre">__import__</span></code> hook, a new-style hook can be injected into the existing
scheme, allowing for a finer grained control of how modules are found and how
they are loaded.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>The only way to customize the import mechanism is currently to override the
built-in <code class="docutils literal notranslate"><span class="pre">__import__</span></code> function. However, overriding <code class="docutils literal notranslate"><span class="pre">__import__</span></code> has many
problems. To begin with:</p>
<ul class="simple">
<li>An <code class="docutils literal notranslate"><span class="pre">__import__</span></code> replacement needs to <em>fully</em> reimplement the entire
import mechanism, or call the original <code class="docutils literal notranslate"><span class="pre">__import__</span></code> before or after the
custom code.</li>
<li>It has very complex semantics and responsibilities.</li>
<li><code class="docutils literal notranslate"><span class="pre">__import__</span></code> gets called even for modules that are already in
<code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>, which is almost never what you want, unless youre writing
some sort of monitoring tool.</li>
</ul>
<p>The situation gets worse when you need to extend the import mechanism from C:
its currently impossible, apart from hacking Pythons <code class="docutils literal notranslate"><span class="pre">import.c</span></code> or
reimplementing much of <code class="docutils literal notranslate"><span class="pre">import.c</span></code> from scratch.</p>
<p>There is a fairly long history of tools written in Python that allow extending
the import mechanism in various way, based on the <code class="docutils literal notranslate"><span class="pre">__import__</span></code> hook. The
Standard Library includes two such tools: <code class="docutils literal notranslate"><span class="pre">ihooks.py</span></code> (by GvR) and
<code class="docutils literal notranslate"><span class="pre">imputil.py</span></code> <a class="footnote-reference brackets" href="#id10" id="id3">[1]</a> (Greg Stein), but perhaps the most famous is <code class="docutils literal notranslate"><span class="pre">iu.py</span></code> by
Gordon McMillan, available as part of his Installer package. Their usefulness
is somewhat limited because they are written in Python; bootstrapping issues
need to worked around as you cant load the module containing the hook with
the hook itself. So if you want the entire Standard Library to be loadable
from an import hook, the hook must be written in C.</p>
</section>
<section id="use-cases">
<h2><a class="toc-backref" href="#use-cases" role="doc-backlink">Use cases</a></h2>
<p>This section lists several existing applications that depend on import hooks.
Among these, a lot of duplicate work was done that could have been saved if
there had been a more flexible import hook at the time. This PEP should make
life a lot easier for similar projects in the future.</p>
<p>Extending the import mechanism is needed when you want to load modules that
are stored in a non-standard way. Examples include modules that are bundled
together in an archive; byte code that is not stored in a <code class="docutils literal notranslate"><span class="pre">pyc</span></code> formatted
file; modules that are loaded from a database over a network.</p>
<p>The work on this PEP was partly triggered by the implementation of <a class="pep reference internal" href="../pep-0273/" title="PEP 273 Import Modules from Zip Archives">PEP 273</a>,
which adds imports from Zip archives as a built-in feature to Python. While
the PEP itself was widely accepted as a must-have feature, the implementation
left a few things to desire. For one thing it went through great lengths to
integrate itself with <code class="docutils literal notranslate"><span class="pre">import.c</span></code>, adding lots of code that was either
specific for Zip file imports or <em>not</em> specific to Zip imports, yet was not
generally useful (or even desirable) either. Yet the <a class="pep reference internal" href="../pep-0273/" title="PEP 273 Import Modules from Zip Archives">PEP 273</a> implementation
can hardly be blamed for this: it is simply extremely hard to do, given the
current state of <code class="docutils literal notranslate"><span class="pre">import.c</span></code>.</p>
<p>Packaging applications for end users is a typical use case for import hooks,
if not <em>the</em> typical use case. Distributing lots of source or <code class="docutils literal notranslate"><span class="pre">pyc</span></code> files
around is not always appropriate (let alone a separate Python installation),
so there is a frequent desire to package all needed modules in a single file.
So frequent in fact that multiple solutions have been implemented over the
years.</p>
<p>The oldest one is included with the Python source code: Freeze <a class="footnote-reference brackets" href="#id11" id="id4">[2]</a>. It puts
marshalled byte code into static objects in C source code. Freezes “import
hook” is hard wired into <code class="docutils literal notranslate"><span class="pre">import.c</span></code>, and has a couple of issues. Later
solutions include Fredrik Lundhs Squeeze, Gordon McMillans Installer, and
Thomas Hellers py2exe <a class="footnote-reference brackets" href="#id12" id="id5">[3]</a>. MacPython ships with a tool called
<code class="docutils literal notranslate"><span class="pre">BuildApplication</span></code>.</p>
<p>Squeeze, Installer and py2exe use an <code class="docutils literal notranslate"><span class="pre">__import__</span></code> based scheme (py2exe
currently uses Installers <code class="docutils literal notranslate"><span class="pre">iu.py</span></code>, Squeeze used <code class="docutils literal notranslate"><span class="pre">ihooks.py</span></code>), MacPython
has two Mac-specific import hooks hard wired into <code class="docutils literal notranslate"><span class="pre">import.c</span></code>, that are
similar to the Freeze hook. The hooks proposed in this PEP enables us (at
least in theory; its not a short-term goal) to get rid of the hard coded
hooks in <code class="docutils literal notranslate"><span class="pre">import.c</span></code>, and would allow the <code class="docutils literal notranslate"><span class="pre">__import__</span></code>-based tools to get
rid of most of their <code class="docutils literal notranslate"><span class="pre">import.c</span></code> emulation code.</p>
<p>Before work on the design and implementation of this PEP was started, a new
<code class="docutils literal notranslate"><span class="pre">BuildApplication</span></code>-like tool for Mac OS X prompted one of the authors of
this PEP (JvR) to expose the table of frozen modules to Python, in the <code class="docutils literal notranslate"><span class="pre">imp</span></code>
module. The main reason was to be able to use the freeze import hook
(avoiding fancy <code class="docutils literal notranslate"><span class="pre">__import__</span></code> support), yet to also be able to supply a set
of modules at runtime. This resulted in issue #642578 <a class="footnote-reference brackets" href="#id13" id="id6">[4]</a>, which was
mysteriously accepted (mostly because nobody seemed to care either way ;-).
Yet it is completely superfluous when this PEP gets accepted, as it offers a
much nicer and general way to do the same thing.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>While experimenting with alternative implementation ideas to get built-in Zip
import, it was discovered that achieving this is possible with only a fairly
small amount of changes to <code class="docutils literal notranslate"><span class="pre">import.c</span></code>. This allowed to factor out the
Zip-specific stuff into a new source file, while at the same time creating a
<em>general</em> new import hook scheme: the one youre reading about now.</p>
<p>An earlier design allowed non-string objects on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>. Such an object
would have the necessary methods to handle an import. This has two
disadvantages: 1) it breaks code that assumes all items on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> are
strings; 2) it is not compatible with the <code class="docutils literal notranslate"><span class="pre">PYTHONPATH</span></code> environment variable.
The latter is directly needed for Zip imports. A compromise came from Jython:
allow string <em>subclasses</em> on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, which would then act as importer
objects. This avoids some breakage, and seems to work well for Jython (where
it is used to load modules from <code class="docutils literal notranslate"><span class="pre">.jar</span></code> files), but it was perceived as an
“ugly hack”.</p>
<p>This led to a more elaborate scheme, (mostly copied from McMillans
<code class="docutils literal notranslate"><span class="pre">iu.py</span></code>) in which each in a list of candidates is asked whether it can
handle the <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> item, until one is found that can. This list of
candidates is a new object in the <code class="docutils literal notranslate"><span class="pre">sys</span></code> module: <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code>.</p>
<p>Traversing <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code> for each path item for each new import can be
expensive, so the results are cached in another new object in the <code class="docutils literal notranslate"><span class="pre">sys</span></code>
module: <code class="docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code>. It maps <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> entries to importer
objects.</p>
<p>To minimize the impact on <code class="docutils literal notranslate"><span class="pre">import.c</span></code> as well as to avoid adding extra
overhead, it was chosen to not add an explicit hook and importer object for
the existing file system import logic (as <code class="docutils literal notranslate"><span class="pre">iu.py</span></code> has), but to simply fall
back to the built-in logic if no hook on <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code> could handle the
path item. If this is the case, a <code class="docutils literal notranslate"><span class="pre">None</span></code> value is stored in
<code class="docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code>, again to avoid repeated lookups. (Later we can
go further and add a real importer object for the built-in mechanism, for now,
the <code class="docutils literal notranslate"><span class="pre">None</span></code> fallback scheme should suffice.)</p>
<p>A question was raised: what about importers that dont need <em>any</em> entry on
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code>? (Built-in and frozen modules fall into that category.) Again,
Gordon McMillan to the rescue: <code class="docutils literal notranslate"><span class="pre">iu.py</span></code> contains a thing he calls the
<em>metapath</em>. In this PEPs implementation, its a list of importer objects
that is traversed <em>before</em> <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>. This list is yet another new object
in the <code class="docutils literal notranslate"><span class="pre">sys</span></code> module: <code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code>. Currently, this list is empty by
default, and frozen and built-in module imports are done after traversing
<code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code>, but still before <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>.</p>
</section>
<section id="specification-part-1-the-importer-protocol">
<h2><a class="toc-backref" href="#specification-part-1-the-importer-protocol" role="doc-backlink">Specification part 1: The Importer Protocol</a></h2>
<p>This PEP introduces a new protocol: the “Importer Protocol”. It is important
to understand the context in which the protocol operates, so here is a brief
overview of the outer shells of the import mechanism.</p>
<p>When an import statement is encountered, the interpreter looks up the
<code class="docutils literal notranslate"><span class="pre">__import__</span></code> function in the built-in name space. <code class="docutils literal notranslate"><span class="pre">__import__</span></code> is then
called with four arguments, amongst which are the name of the module being
imported (may be a dotted name) and a reference to the current global
namespace.</p>
<p>The built-in <code class="docutils literal notranslate"><span class="pre">__import__</span></code> function (known as <code class="docutils literal notranslate"><span class="pre">PyImport_ImportModuleEx()</span></code>
in <code class="docutils literal notranslate"><span class="pre">import.c</span></code>) will then check to see whether the module doing the import is
a package or a submodule of a package. If it is indeed a (submodule of a)
package, it first tries to do the import relative to the package (the parent
package for a submodule). For example, if a package named “spam” does “import
eggs”, it will first look for a module named “spam.eggs”. If that fails, the
import continues as an absolute import: it will look for a module named
“eggs”. Dotted name imports work pretty much the same: if package “spam” does
“import eggs.bacon” (and “spam.eggs” exists and is itself a package),
“spam.eggs.bacon” is tried. If that fails “eggs.bacon” is tried. (There are
more subtleties that are not described here, but these are not relevant for
implementers of the Importer Protocol.)</p>
<p>Deeper down in the mechanism, a dotted name import is split up by its
components. For “import spam.ham”, first an “import spam” is done, and only
when that succeeds is “ham” imported as a submodule of “spam”.</p>
<p>The Importer Protocol operates at this level of <em>individual</em> imports. By the
time an importer gets a request for “spam.ham”, module “spam” has already been
imported.</p>
<p>The protocol involves two objects: a <em>finder</em> and a <em>loader</em>. A finder object
has a single method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">finder</span><span class="o">.</span><span class="n">find_module</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
</pre></div>
</div>
<p>This method will be called with the fully qualified name of the module. If
the finder is installed on <code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code>, it will receive a second
argument, which is <code class="docutils literal notranslate"><span class="pre">None</span></code> for a top-level module, or <code class="docutils literal notranslate"><span class="pre">package.__path__</span></code>
for submodules or subpackages <a class="footnote-reference brackets" href="#id14" id="id7">[5]</a>. It should return a loader object if the
module was found, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if it wasnt. If <code class="docutils literal notranslate"><span class="pre">find_module()</span></code> raises an
exception, it will be propagated to the caller, aborting the import.</p>
<p>A loader object also has one method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">loader</span><span class="o">.</span><span class="n">load_module</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
</pre></div>
</div>
<p>This method returns the loaded module or raises an exception, preferably
<code class="docutils literal notranslate"><span class="pre">ImportError</span></code> if an existing exception is not being propagated. If
<code class="docutils literal notranslate"><span class="pre">load_module()</span></code> is asked to load a module that it cannot, <code class="docutils literal notranslate"><span class="pre">ImportError</span></code> is
to be raised.</p>
<p>In many cases the finder and loader can be one and the same object:
<code class="docutils literal notranslate"><span class="pre">finder.find_module()</span></code> would just return <code class="docutils literal notranslate"><span class="pre">self</span></code>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">fullname</span></code> argument of both methods is the fully qualified module name,
for example “spam.eggs.ham”. As explained above, when
<code class="docutils literal notranslate"><span class="pre">finder.find_module(&quot;spam.eggs.ham&quot;)</span></code> is called, “spam.eggs” has already
been imported and added to <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>. However, the <code class="docutils literal notranslate"><span class="pre">find_module()</span></code>
method isnt necessarily always called during an actual import: meta tools
that analyze import dependencies (such as freeze, Installer or py2exe) dont
actually load modules, so a finder shouldnt <em>depend</em> on the parent package
being available in <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">load_module()</span></code> method has a few responsibilities that it must fulfill
<em>before</em> it runs any code:</p>
<ul>
<li>If there is an existing module object named fullname in <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>,
the loader must use that existing module. (Otherwise, the <code class="docutils literal notranslate"><span class="pre">reload()</span></code>
builtin will not work correctly.) If a module named fullname does not
exist in <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>, the loader must create a new module object and
add it to <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>.<p>Note that the module object <em>must</em> be in <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> before the loader
executes the module code. This is crucial because the module code may
(directly or indirectly) import itself; adding it to <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>
beforehand prevents unbounded recursion in the worst case and multiple
loading in the best.</p>
<p>If the load fails, the loader needs to remove any module it may have
inserted into <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>. If the module was already in <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code>
then the loader should leave it alone.</p>
</li>
<li>The <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute must be set. This must be a string, but it may
be a dummy value, for example “&lt;frozen&gt;”. The privilege of not having a
<code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute at all is reserved for built-in modules.</li>
<li>The <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute must be set. If one uses <code class="docutils literal notranslate"><span class="pre">imp.new_module()</span></code>
then the attribute is set automatically.</li>
<li>If its a package, the <code class="docutils literal notranslate"><span class="pre">__path__</span></code> variable must be set. This must be a
list, but may be empty if <code class="docutils literal notranslate"><span class="pre">__path__</span></code> has no further significance to the
importer (more on this later).</li>
<li>The <code class="docutils literal notranslate"><span class="pre">__loader__</span></code> attribute must be set to the loader object. This is
mostly for introspection and reloading, but can be used for
importer-specific extras, for example getting data associated with an
importer.</li>
<li>The <code class="docutils literal notranslate"><span class="pre">__package__</span></code> attribute must be set (<a class="pep reference internal" href="../pep-0366/" title="PEP 366 Main module explicit relative imports">PEP 366</a>).<p>If the module is a Python module (as opposed to a built-in module or a
dynamically loaded extension), it should execute the modules code in the
modules global name space (<code class="docutils literal notranslate"><span class="pre">module.__dict__</span></code>).</p>
<p>Here is a minimal pattern for a <code class="docutils literal notranslate"><span class="pre">load_module()</span></code> method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Consider using importlib.util.module_for_loader() to handle</span>
<span class="c1"># most of these details for you.</span>
<span class="k">def</span> <span class="nf">load_module</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fullname</span><span class="p">):</span>
<span class="n">code</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
<span class="n">ispkg</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_package</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
<span class="n">mod</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">imp</span><span class="o">.</span><span class="n">new_module</span><span class="p">(</span><span class="n">fullname</span><span class="p">))</span>
<span class="n">mod</span><span class="o">.</span><span class="vm">__file__</span> <span class="o">=</span> <span class="s2">&quot;&lt;</span><span class="si">%s</span><span class="s2">&gt;&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span>
<span class="n">mod</span><span class="o">.</span><span class="n">__loader__</span> <span class="o">=</span> <span class="bp">self</span>
<span class="k">if</span> <span class="n">ispkg</span><span class="p">:</span>
<span class="n">mod</span><span class="o">.</span><span class="n">__path__</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">mod</span><span class="o">.</span><span class="n">__package__</span> <span class="o">=</span> <span class="n">fullname</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">mod</span><span class="o">.</span><span class="n">__package__</span> <span class="o">=</span> <span class="n">fullname</span><span class="o">.</span><span class="n">rpartition</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">exec</span><span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="n">mod</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>
<span class="k">return</span> <span class="n">mod</span>
</pre></div>
</div>
</li>
</ul>
</section>
<section id="specification-part-2-registering-hooks">
<h2><a class="toc-backref" href="#specification-part-2-registering-hooks" role="doc-backlink">Specification part 2: Registering Hooks</a></h2>
<p>There are two types of import hooks: <em>Meta hooks</em> and <em>Path hooks</em>. Meta
hooks are called at the start of import processing, before any other import
processing (so that meta hooks can override <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> processing, frozen
modules, or even built-in modules). To register a meta hook, simply add the
finder object to <code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code> (the list of registered meta hooks).</p>
<p>Path hooks are called as part of <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> (or <code class="docutils literal notranslate"><span class="pre">package.__path__</span></code>)
processing, at the point where their associated path item is encountered. A
path hook is registered by adding an importer factory to <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code> is a list of callables, which will be checked in sequence
to determine if they can handle a given path item. The callable is called
with one argument, the path item. The callable must raise <code class="docutils literal notranslate"><span class="pre">ImportError</span></code> if
it is unable to handle the path item, and return an importer object if it can
handle the path item. Note that if the callable returns an importer object
for a specific <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> entry, the builtin import machinery will not be
invoked to handle that entry any longer, even if the importer object later
fails to find a specific module. The callable is typically the class of the
import hook, and hence the class <code class="docutils literal notranslate"><span class="pre">__init__()</span></code> method is called. (This is
also the reason why it should raise <code class="docutils literal notranslate"><span class="pre">ImportError</span></code>: an <code class="docutils literal notranslate"><span class="pre">__init__()</span></code> method
cant return anything. This would be possible with a <code class="docutils literal notranslate"><span class="pre">__new__()</span></code> method in
a new style class, but we dont want to require anything about how a hook is
implemented.)</p>
<p>The results of path hook checks are cached in <code class="docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code>,
which is a dictionary mapping path entries to importer objects. The cache is
checked before <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code> is scanned. If it is necessary to force a
rescan of <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code>, it is possible to manually clear all or part of
<code class="docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code>.</p>
<p>Just like <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> itself, the new <code class="docutils literal notranslate"><span class="pre">sys</span></code> variables must have specific
types:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code> and <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code> must be Python lists.</li>
<li><code class="docutils literal notranslate"><span class="pre">sys.path_importer_cache</span></code> must be a Python dict.</li>
</ul>
<p>Modifying these variables in place is allowed, as is replacing them with new
objects.</p>
</section>
<section id="packages-and-the-role-of-path">
<h2><a class="toc-backref" href="#packages-and-the-role-of-path" role="doc-backlink">Packages and the role of <code class="docutils literal notranslate"><span class="pre">__path__</span></code></a></h2>
<p>If a module has a <code class="docutils literal notranslate"><span class="pre">__path__</span></code> attribute, the import mechanism will treat it
as a package. The <code class="docutils literal notranslate"><span class="pre">__path__</span></code> variable is used instead of <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> when
importing submodules of the package. The rules for <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> therefore
also apply to <code class="docutils literal notranslate"><span class="pre">pkg.__path__</span></code>. So <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code> is also consulted when
<code class="docutils literal notranslate"><span class="pre">pkg.__path__</span></code> is traversed. Meta importers dont necessarily use
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code> at all to do their work and may therefore ignore the value of
<code class="docutils literal notranslate"><span class="pre">pkg.__path__</span></code>. In this case it is still advised to set it to list, which
can be empty.</p>
</section>
<section id="optional-extensions-to-the-importer-protocol">
<h2><a class="toc-backref" href="#optional-extensions-to-the-importer-protocol" role="doc-backlink">Optional Extensions to the Importer Protocol</a></h2>
<p>The Importer Protocol defines three optional extensions. One is to retrieve
data files, the second is to support module packaging tools and/or tools that
analyze module dependencies (for example Freeze), while the last is to support
execution of modules as scripts. The latter two categories of tools usually
dont actually <em>load</em> modules, they only need to know if and where they are
available. All three extensions are highly recommended for general purpose
importers, but may safely be left out if those features arent needed.</p>
<p>To retrieve the data for arbitrary “files” from the underlying storage
backend, loader objects may supply a method named <code class="docutils literal notranslate"><span class="pre">get_data()</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">loader</span><span class="o">.</span><span class="n">get_data</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</pre></div>
</div>
<p>This method returns the data as a string, or raise <code class="docutils literal notranslate"><span class="pre">IOError</span></code> if the “file”
wasnt found. The data is always returned as if “binary” mode was used -
there is no CRLF translation of text files, for example. It is meant for
importers that have some file-system-like properties. The path argument is
a path that can be constructed by munging <code class="docutils literal notranslate"><span class="pre">module.__file__</span></code> (or
<code class="docutils literal notranslate"><span class="pre">pkg.__path__</span></code> items) with the <code class="docutils literal notranslate"><span class="pre">os.path.*</span></code> functions, for example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">d</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">__loader__</span><span class="o">.</span><span class="n">get_data</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="s2">&quot;logo.gif&quot;</span><span class="p">))</span>
</pre></div>
</div>
<p>The following set of methods may be implemented if support for (for example)
Freeze-like tools is desirable. It consists of three additional methods
which, to make it easier for the caller, each of which should be implemented,
or none at all:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">loader</span><span class="o">.</span><span class="n">is_package</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
<span class="n">loader</span><span class="o">.</span><span class="n">get_code</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
<span class="n">loader</span><span class="o">.</span><span class="n">get_source</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
</pre></div>
</div>
<p>All three methods should raise <code class="docutils literal notranslate"><span class="pre">ImportError</span></code> if the module wasnt found.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">loader.is_package(fullname)</span></code> method should return <code class="docutils literal notranslate"><span class="pre">True</span></code> if the
module specified by fullname is a package and <code class="docutils literal notranslate"><span class="pre">False</span></code> if it isnt.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">loader.get_code(fullname)</span></code> method should return the code object
associated with the module, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if its a built-in or extension
module. If the loader doesnt have the code object but it <em>does</em> have the
source code, it should return the compiled source code. (This is so that our
caller doesnt also need to check <code class="docutils literal notranslate"><span class="pre">get_source()</span></code> if all it needs is the code
object.)</p>
<p>The <code class="docutils literal notranslate"><span class="pre">loader.get_source(fullname)</span></code> method should return the source code for
the module as a string (using newline characters for line endings) or <code class="docutils literal notranslate"><span class="pre">None</span></code>
if the source is not available (yet it should still raise <code class="docutils literal notranslate"><span class="pre">ImportError</span></code> if
the module cant be found by the importer at all).</p>
<p>To support execution of modules as scripts (<a class="pep reference internal" href="../pep-0338/" title="PEP 338 Executing modules as scripts">PEP 338</a>),
the above three methods for
finding the code associated with a module must be implemented. In addition to
those methods, the following method may be provided in order to allow the
<code class="docutils literal notranslate"><span class="pre">runpy</span></code> module to correctly set the <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">loader</span><span class="o">.</span><span class="n">get_filename</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
</pre></div>
</div>
<p>This method should return the value that <code class="docutils literal notranslate"><span class="pre">__file__</span></code> would be set to if the
named module was loaded. If the module is not found, then <code class="docutils literal notranslate"><span class="pre">ImportError</span></code>
should be raised.</p>
</section>
<section id="integration-with-the-imp-module">
<h2><a class="toc-backref" href="#integration-with-the-imp-module" role="doc-backlink">Integration with the imp module</a></h2>
<p>The new import hooks are not easily integrated in the existing
<code class="docutils literal notranslate"><span class="pre">imp.find_module()</span></code> and <code class="docutils literal notranslate"><span class="pre">imp.load_module()</span></code> calls. Its questionable
whether its possible at all without breaking code; it is better to simply add
a new function to the <code class="docutils literal notranslate"><span class="pre">imp</span></code> module. The meaning of the existing
<code class="docutils literal notranslate"><span class="pre">imp.find_module()</span></code> and <code class="docutils literal notranslate"><span class="pre">imp.load_module()</span></code> calls changes from: “they
expose the built-in import mechanism” to “they expose the basic <em>unhooked</em>
built-in import mechanism”. They simply wont invoke any import hooks. A new
<code class="docutils literal notranslate"><span class="pre">imp</span></code> module function is proposed (but not yet implemented) under the name
<code class="docutils literal notranslate"><span class="pre">get_loader()</span></code>, which is used as in the following pattern:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">loader</span> <span class="o">=</span> <span class="n">imp</span><span class="o">.</span><span class="n">get_loader</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span>
<span class="k">if</span> <span class="n">loader</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">loader</span><span class="o">.</span><span class="n">load_module</span><span class="p">(</span><span class="n">fullname</span><span class="p">)</span>
</pre></div>
</div>
<p>In the case of a “basic” import, one the <code class="docutils literal notranslate"><span class="pre">imp.find_module()</span></code> function would
handle, the loader object would be a wrapper for the current output of
<code class="docutils literal notranslate"><span class="pre">imp.find_module()</span></code>, and <code class="docutils literal notranslate"><span class="pre">loader.load_module()</span></code> would call
<code class="docutils literal notranslate"><span class="pre">imp.load_module()</span></code> with that output.</p>
<p>Note that this wrapper is currently not yet implemented, although a Python
prototype exists in the <code class="docutils literal notranslate"><span class="pre">test_importhooks.py</span></code> script (the <code class="docutils literal notranslate"><span class="pre">ImpWrapper</span></code>
class) included with the patch.</p>
</section>
<section id="forward-compatibility">
<h2><a class="toc-backref" href="#forward-compatibility" role="doc-backlink">Forward Compatibility</a></h2>
<p>Existing <code class="docutils literal notranslate"><span class="pre">__import__</span></code> hooks will not invoke new-style hooks by magic, unless
they call the original <code class="docutils literal notranslate"><span class="pre">__import__</span></code> function as a fallback. For example,
<code class="docutils literal notranslate"><span class="pre">ihooks.py</span></code>, <code class="docutils literal notranslate"><span class="pre">iu.py</span></code> and <code class="docutils literal notranslate"><span class="pre">imputil.py</span></code> are in this sense not forward
compatible with this PEP.</p>
</section>
<section id="open-issues">
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
<p>Modules often need supporting data files to do their job, particularly in the
case of complex packages or full applications. Current practice is generally
to locate such files via <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> (or a <code class="docutils literal notranslate"><span class="pre">package.__path__</span></code> attribute).
This approach will not work, in general, for modules loaded via an import
hook.</p>
<p>There are a number of possible ways to address this problem:</p>
<ul class="simple">
<li>“Dont do that”. If a package needs to locate data files via its
<code class="docutils literal notranslate"><span class="pre">__path__</span></code>, it is not suitable for loading via an import hook. The
package can still be located on a directory in <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, as at present,
so this should not be seen as a major issue.</li>
<li>Locate data files from a standard location, rather than relative to the
module file. A relatively simple approach (which is supported by
distutils) would be to locate data files based on <code class="docutils literal notranslate"><span class="pre">sys.prefix</span></code> (or
<code class="docutils literal notranslate"><span class="pre">sys.exec_prefix</span></code>). For example, looking in
<code class="docutils literal notranslate"><span class="pre">os.path.join(sys.prefix,</span> <span class="pre">&quot;data&quot;,</span> <span class="pre">package_name)</span></code>.</li>
<li>Import hooks could offer a standard way of getting at data files relative
to the module file. The standard <code class="docutils literal notranslate"><span class="pre">zipimport</span></code> object provides a method
<code class="docutils literal notranslate"><span class="pre">get_data(name)</span></code> which returns the content of the “file” called <code class="docutils literal notranslate"><span class="pre">name</span></code>,
as a string. To allow modules to get at the importer object, <code class="docutils literal notranslate"><span class="pre">zipimport</span></code>
also adds an attribute <code class="docutils literal notranslate"><span class="pre">__loader__</span></code> to the module, containing the
<code class="docutils literal notranslate"><span class="pre">zipimport</span></code> object used to load the module. If such an approach is used,
it is important that client code takes care not to break if the
<code class="docutils literal notranslate"><span class="pre">get_data()</span></code> method is not available, so it is not clear that this
approach offers a general answer to the problem.</li>
</ul>
<p>It was suggested on python-dev that it would be useful to be able to receive a
list of available modules from an importer and/or a list of available data
files for use with the <code class="docutils literal notranslate"><span class="pre">get_data()</span></code> method. The protocol could grow two
additional extensions, say <code class="docutils literal notranslate"><span class="pre">list_modules()</span></code> and <code class="docutils literal notranslate"><span class="pre">list_files()</span></code>. The
latter makes sense on loader objects with a <code class="docutils literal notranslate"><span class="pre">get_data()</span></code> method. However,
its a bit unclear which object should implement <code class="docutils literal notranslate"><span class="pre">list_modules()</span></code>: the
importer or the loader or both?</p>
<p>This PEP is biased towards loading modules from alternative places: it
currently doesnt offer dedicated solutions for loading modules from
alternative file formats or with alternative compilers. In contrast, the
<code class="docutils literal notranslate"><span class="pre">ihooks</span></code> module from the standard library does have a fairly straightforward
way to do this. The Quixote project <a class="footnote-reference brackets" href="#id15" id="id8">[7]</a> uses this technique to import PTL
files as if they are ordinary Python modules. To do the same with the new
hooks would either mean to add a new module implementing a subset of
<code class="docutils literal notranslate"><span class="pre">ihooks</span></code> as a new-style importer, or add a hookable built-in path importer
object.</p>
<p>There is no specific support within this PEP for “stacking” hooks. For
example, it is not obvious how to write a hook to load modules from <code class="docutils literal notranslate"><span class="pre">tar.gz</span></code>
files by combining separate hooks to load modules from <code class="docutils literal notranslate"><span class="pre">.tar</span></code> and <code class="docutils literal notranslate"><span class="pre">.gz</span></code>
files. However, there is no support for such stacking in the existing hook
mechanisms (either the basic “replace <code class="docutils literal notranslate"><span class="pre">__import__</span></code>” method, or any of the
existing import hook modules) and so this functionality is not an obvious
requirement of the new mechanism. It may be worth considering as a future
enhancement, however.</p>
<p>It is possible (via <code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code>) to add hooks which run before
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code> is processed. However, there is no equivalent way of adding
hooks to run after <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> is processed. For now, if a hook is required
after <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> has been processed, it can be simulated by adding an
arbitrary “cookie” string at the end of <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, and having the required
hook associated with this cookie, via the normal <code class="docutils literal notranslate"><span class="pre">sys.path_hooks</span></code>
processing. In the longer term, the path handling code will become a “real”
hook on <code class="docutils literal notranslate"><span class="pre">sys.meta_path</span></code>, and at that stage it will be possible to insert
user-defined hooks either before or after it.</p>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>The <a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a> implementation has been integrated with Python as of 2.3a1. An
earlier version is available as patch #652586 <a class="footnote-reference brackets" href="#id16" id="id9">[9]</a>, but more interestingly,
the issue contains a fairly detailed history of the development and design.</p>
<p><a class="pep reference internal" href="../pep-0273/" title="PEP 273 Import Modules from Zip Archives">PEP 273</a> has been implemented using <a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a>s import hooks.</p>
</section>
<section id="references-and-footnotes">
<h2><a class="toc-backref" href="#references-and-footnotes" role="doc-backlink">References and Footnotes</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id10" role="doc-footnote">
<dt class="label" id="id10">[<a href="#id3">1</a>]</dt>
<dd>imputil module
<a class="reference external" href="http://docs.python.org/library/imputil.html">http://docs.python.org/library/imputil.html</a></aside>
<aside class="footnote brackets" id="id11" role="doc-footnote">
<dt class="label" id="id11">[<a href="#id4">2</a>]</dt>
<dd>The Freeze tool.
See also the <code class="docutils literal notranslate"><span class="pre">Tools/freeze/</span></code> directory in a Python source distribution</aside>
<aside class="footnote brackets" id="id12" role="doc-footnote">
<dt class="label" id="id12">[<a href="#id5">3</a>]</dt>
<dd>py2exe by Thomas Heller
<a class="reference external" href="http://www.py2exe.org/">http://www.py2exe.org/</a></aside>
<aside class="footnote brackets" id="id13" role="doc-footnote">
<dt class="label" id="id13">[<a href="#id6">4</a>]</dt>
<dd>imp.set_frozenmodules() patch
<a class="reference external" href="http://bugs.python.org/issue642578">http://bugs.python.org/issue642578</a></aside>
<aside class="footnote brackets" id="id14" role="doc-footnote">
<dt class="label" id="id14">[<a href="#id7">5</a>]</dt>
<dd>The path argument to <code class="docutils literal notranslate"><span class="pre">finder.find_module()</span></code> is there because the
<code class="docutils literal notranslate"><span class="pre">pkg.__path__</span></code> variable may be needed at this point. It may either come
from the actual parent module or be supplied by <code class="docutils literal notranslate"><span class="pre">imp.find_module()</span></code> or
the proposed <code class="docutils literal notranslate"><span class="pre">imp.get_loader()</span></code> function.</aside>
<aside class="footnote brackets" id="id15" role="doc-footnote">
<dt class="label" id="id15">[<a href="#id8">7</a>]</dt>
<dd>Quixote, a framework for developing Web applications
<a class="reference external" href="http://www.mems-exchange.org/software/quixote/">http://www.mems-exchange.org/software/quixote/</a></aside>
<aside class="footnote brackets" id="id16" role="doc-footnote">
<dt class="label" id="id16">[<a href="#id9">9</a>]</dt>
<dd>New import hooks + Import from Zip files
<a class="reference external" href="http://bugs.python.org/issue652586">http://bugs.python.org/issue652586</a></aside>
<aside class="footnote brackets" id="id17" role="doc-footnote">
<dt class="label" id="id17">[<a href="#id1">10</a>]</dt>
<dd>Language reference for imports
<a class="reference external" href="http://docs.python.org/3/reference/import.html">http://docs.python.org/3/reference/import.html</a></aside>
<aside class="footnote brackets" id="id18" role="doc-footnote">
<dt class="label" id="id18">[<a href="#id2">11</a>]</dt>
<dd>importlib documentation
<a class="reference external" href="http://docs.python.org/3/library/importlib.html#module-importlib">http://docs.python.org/3/library/importlib.html#module-importlib</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-0302.rst">https://github.com/python/peps/blob/main/peps/pep-0302.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0302.rst">2023-09-09 17:39:29 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="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#use-cases">Use cases</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification-part-1-the-importer-protocol">Specification part 1: The Importer Protocol</a></li>
<li><a class="reference internal" href="#specification-part-2-registering-hooks">Specification part 2: Registering Hooks</a></li>
<li><a class="reference internal" href="#packages-and-the-role-of-path">Packages and the role of <code class="docutils literal notranslate"><span class="pre">__path__</span></code></a></li>
<li><a class="reference internal" href="#optional-extensions-to-the-importer-protocol">Optional Extensions to the Importer Protocol</a></li>
<li><a class="reference internal" href="#integration-with-the-imp-module">Integration with the imp module</a></li>
<li><a class="reference internal" href="#forward-compatibility">Forward Compatibility</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#references-and-footnotes">References and Footnotes</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-0302.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>