peps/pep-0366/index.html

257 lines
18 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 366 Main module explicit relative imports | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0366/">
<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 366 Main module explicit relative imports | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0366/">
<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 366</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 366 Main module explicit relative imports</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Alyssa Coghlan &lt;ncoghlan&#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">01-May-2007</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.6, 3.0</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">01-May-2007, 04-Jul-2007, 07-Jul-2007, 23-Nov-2007</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="#proposed-change">Proposed Change</a></li>
<li><a class="reference internal" href="#rationale-for-change">Rationale for Change</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#alternative-proposals">Alternative Proposals</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>This PEP proposes a backwards compatible mechanism that permits
the use of explicit relative imports from executable modules within
packages. Such imports currently fail due to an awkward interaction
between <a class="pep reference internal" href="../pep-0328/" title="PEP 328 Imports: Multi-Line and Absolute/Relative">PEP 328</a> and <a class="pep reference internal" href="../pep-0338/" title="PEP 338 Executing modules as scripts">PEP 338</a>.</p>
<p>By adding a new module level attribute, this PEP allows relative imports
to work automatically if the module is executed using the <code class="docutils literal notranslate"><span class="pre">-m</span></code> switch.
A small amount of boilerplate in the module itself will allow the relative
imports to work when the file is executed by name.</p>
<p>Guido accepted the PEP in November 2007 <a class="footnote-reference brackets" href="#id10" id="id1">[5]</a>.</p>
</section>
<section id="proposed-change">
<h2><a class="toc-backref" href="#proposed-change" role="doc-backlink">Proposed Change</a></h2>
<p>The major proposed change is the introduction of a new module level
attribute, <code class="docutils literal notranslate"><span class="pre">__package__</span></code>. When it is present, relative imports will
be based on this attribute rather than the module <code class="docutils literal notranslate"><span class="pre">__name__</span></code>
attribute.</p>
<p>As with the current <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute, setting <code class="docutils literal notranslate"><span class="pre">__package__</span></code> will
be the responsibility of the <a class="pep reference internal" href="../pep-0302/" title="PEP 302 New Import Hooks">PEP 302</a> loader used to import a module.
Loaders which use <code class="docutils literal notranslate"><span class="pre">imp.new_module()</span></code> to create the module object will
have the new attribute set automatically to <code class="docutils literal notranslate"><span class="pre">None</span></code>. When the import
system encounters an explicit relative import in a module without
<code class="docutils literal notranslate"><span class="pre">__package__</span></code> set (or with it set to <code class="docutils literal notranslate"><span class="pre">None</span></code>), it will calculate and
store the correct value (<code class="docutils literal notranslate"><span class="pre">__name__.rpartition('.')[0]</span></code> for normal
modules and <code class="docutils literal notranslate"><span class="pre">__name__</span></code> for package initialisation modules). If
<code class="docutils literal notranslate"><span class="pre">__package__</span></code> has already been set then the import system will use
it in preference to recalculating the package name from the
<code class="docutils literal notranslate"><span class="pre">__name__</span></code> and <code class="docutils literal notranslate"><span class="pre">__path__</span></code> attributes.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">runpy</span></code> module will explicitly set the new attribute, basing it off
the name used to locate the module to be executed rather than the name
used to set the modules <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute. This will allow relative
imports to work correctly from main modules executed with the <code class="docutils literal notranslate"><span class="pre">-m</span></code>
switch.</p>
<p>When the main module is specified by its filename, then the
<code class="docutils literal notranslate"><span class="pre">__package__</span></code> attribute will be set to <code class="docutils literal notranslate"><span class="pre">None</span></code>. To allow
relative imports when the module is executed directly, boilerplate
similar to the following would be needed before the first relative
import statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span> <span class="ow">and</span> <span class="n">__package__</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">__package__</span> <span class="o">=</span> <span class="s2">&quot;expected.package.name&quot;</span>
</pre></div>
</div>
<p>Note that this boilerplate is sufficient only if the top level package
is already accessible via <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>. Additional code that manipulates
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code> would be needed in order for direct execution to work
without the top level package already being importable.</p>
<p>This approach also has the same disadvantage as the use of absolute
imports of sibling modules - if the script is moved to a different
package or subpackage, the boilerplate will need to be updated
manually. It has the advantage that this change need only be made
once per file, regardless of the number of relative imports.</p>
<p>Note that setting <code class="docutils literal notranslate"><span class="pre">__package__</span></code> to the empty string explicitly is
permitted, and has the effect of disabling all relative imports from
that module (since the import machinery will consider it to be a
top level module in that case). This means that tools like <code class="docutils literal notranslate"><span class="pre">runpy</span></code>
do not need to provide special case handling for top level modules
when setting <code class="docutils literal notranslate"><span class="pre">__package__</span></code>.</p>
</section>
<section id="rationale-for-change">
<h2><a class="toc-backref" href="#rationale-for-change" role="doc-backlink">Rationale for Change</a></h2>
<p>The current inability to use explicit relative imports from the main
module is the subject of at least one open SF bug report (#1510172) <a class="footnote-reference brackets" href="#id6" id="id2">[1]</a>,
and has most likely been a factor in at least a few queries on
comp.lang.python (such as Alan Isaacs question in <a class="footnote-reference brackets" href="#id7" id="id3">[2]</a>).</p>
<p>This PEP is intended to provide a solution which permits explicit
relative imports from main modules, without incurring any significant
costs during interpreter startup or normal module import.</p>
<p>The section in <a class="pep reference internal" href="../pep-0338/" title="PEP 338 Executing modules as scripts">PEP 338</a> on relative imports and the main module provides
further details and background on this problem.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>Rev 47142 in SVN implemented an early variant of this proposal
which stored the main modules real module name in the
<code class="docutils literal notranslate"><span class="pre">__module_name__</span></code> attribute. It was reverted due to the fact
that 2.5 was already in beta by that time.</p>
<p>Patch 1487 <a class="footnote-reference brackets" href="#id9" id="id4">[4]</a> is the proposed implementation for this PEP.</p>
</section>
<section id="alternative-proposals">
<h2><a class="toc-backref" href="#alternative-proposals" role="doc-backlink">Alternative Proposals</a></h2>
<p><a class="pep reference internal" href="../pep-3122/" title="PEP 3122 Delineation of the main module">PEP 3122</a> proposed addressing this problem by changing the way
the main module is identified. Thats a significant compatibility cost
to incur to fix something that is a pretty minor bug in the overall
scheme of things, and the PEP was rejected <a class="footnote-reference brackets" href="#id8" id="id5">[3]</a>.</p>
<p>The advantage of the proposal in this PEP is that its only impact on
normal code is the small amount of time needed to set the extra
attribute when importing a module. Relative imports themselves should
be sped up fractionally, as the package name is cached in the module
globals, rather than having to be worked out again for each relative
import.</p>
</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="id6" role="doc-footnote">
<dt class="label" id="id6">[<a href="#id2">1</a>]</dt>
<dd>Absolute/relative import not working?
(<a class="reference external" href="https://github.com/python/cpython/issues/43535">https://github.com/python/cpython/issues/43535</a>)</aside>
<aside class="footnote brackets" id="id7" role="doc-footnote">
<dt class="label" id="id7">[<a href="#id3">2</a>]</dt>
<dd>c.l.p. question about modules and relative imports
(<a class="reference external" href="http://groups.google.com/group/comp.lang.python/browse_thread/thread/c44c769a72ca69fa/">http://groups.google.com/group/comp.lang.python/browse_thread/thread/c44c769a72ca69fa/</a>)</aside>
<aside class="footnote brackets" id="id8" role="doc-footnote">
<dt class="label" id="id8">[<a href="#id5">3</a>]</dt>
<dd>Guidos rejection of PEP 3122
(<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2007-April/006793.html">https://mail.python.org/pipermail/python-3000/2007-April/006793.html</a>)</aside>
<aside class="footnote brackets" id="id9" role="doc-footnote">
<dt class="label" id="id9">[<a href="#id4">4</a>]</dt>
<dd>PEP 366 implementation patch
(<a class="reference external" href="https://github.com/python/cpython/issues/45828">https://github.com/python/cpython/issues/45828</a>)</aside>
<aside class="footnote brackets" id="id10" role="doc-footnote">
<dt class="label" id="id10">[<a href="#id1">5</a>]</dt>
<dd>Acceptance of the PEP
(<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2007-November/075475.html">https://mail.python.org/pipermail/python-dev/2007-November/075475.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-0366.rst">https://github.com/python/peps/blob/main/peps/pep-0366.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0366.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="#proposed-change">Proposed Change</a></li>
<li><a class="reference internal" href="#rationale-for-change">Rationale for Change</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#alternative-proposals">Alternative Proposals</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-0366.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>