python-peps/pep-0648/index.html

703 lines
54 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 648 Extensible customizations of the interpreter at startup | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0648/">
<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 648 Extensible customizations of the interpreter at startup | peps.python.org'>
<meta property="og:description" content="This PEP proposes supporting extensible customization of the interpreter by allowing users to install files that will be executed at startup.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0648/">
<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="This PEP proposes supporting extensible customization of the interpreter by allowing users to install files that will be executed at startup.">
<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 648</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 648 Extensible customizations of the interpreter at startup</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Mario Corchero &lt;mariocj89&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Pablo Galindo</dd>
<dt class="field-odd">Discussions-To<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/pep-648-extensible-customizations-of-the-interpreter-at-startup/6403">Discourse thread</a></dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</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">30-Dec-2020</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.11</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">16-Dec-2020, 18-Dec-2020</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="#pep-rejection">PEP Rejection</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
<li><a class="reference internal" href="#limitations-of-pth-files">Limitations of <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></li>
<li><a class="reference internal" href="#limitations-of-sitecustomize-py">Limitations of <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#why-sitecustomize">Why <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></li>
<li><a class="reference internal" href="#discovering-the-new-sitecustomize-directories">Discovering the new <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories</a></li>
<li><a class="reference internal" href="#time-of-sitecustomize-discovery">Time of <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> discovery</a></li>
<li><a class="reference internal" href="#order-of-execution-within-sitecustomize">Order of execution within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></li>
<li><a class="reference internal" href="#interaction-with-pth-files">Interaction with <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></li>
<li><a class="reference internal" href="#execution-of-files-within-sitecustomize">Execution of files within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></li>
<li><a class="reference internal" href="#failure-handling">Failure handling</a></li>
<li><a class="reference internal" href="#interaction-with-virtual-environments">Interaction with virtual environments</a></li>
<li><a class="reference internal" href="#interaction-with-sitecustomize-py-and-usercustomize-py">Interaction with <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> and <code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code></a></li>
<li><a class="reference internal" href="#identifying-all-installed-files">Identifying all installed files</a></li>
<li><a class="reference internal" href="#files-naming-convention">Files naming convention</a></li>
<li><a class="reference internal" href="#disabling-start-files">Disabling start files</a></li>
<li><a class="reference internal" href="#support-in-build-backends">Support in build backends</a></li>
<li><a class="reference internal" href="#impact-on-startup-time">Impact on startup time</a></li>
<li><a class="reference internal" href="#audit-event">Audit Event</a></li>
<li><a class="reference internal" href="#security-implications">Security implications</a></li>
</ul>
</li>
<li><a class="reference internal" href="#how-to-teach-this">How to teach this</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward compatibility</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#do-nothing">Do nothing</a></li>
<li><a class="reference internal" href="#formalize-using-pth-files">Formalize using <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></li>
<li><a class="reference internal" href="#making-sitecustomize-a-namespace-package">Making <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> a namespace package</a></li>
<li><a class="reference internal" href="#support-for-shutdown-customization">Support for shutdown customization</a></li>
<li><a class="reference internal" href="#using-entry-points">Using entry_points</a></li>
</ul>
</li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</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 supporting extensible customization of the interpreter by
allowing users to install files that will be executed at startup.</p>
</section>
<section id="pep-rejection">
<h2><a class="toc-backref" href="#pep-rejection" role="doc-backlink">PEP Rejection</a></h2>
<p>PEP 648 was rejected <a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/message/UHODNOGISLYUKX2K2JCCBYMZFEWZDSPO/">by the steering council</a>
as it has a limited number of use cases and further complicates the startup sequence.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>System administrators, tools that repackage the interpreter and some
libraries need to customize aspects of the interpreter at startup time.</p>
<p>This is usually achieved via <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> for system administrators
whilst libraries rely on exploiting <code class="docutils literal notranslate"><span class="pre">pth</span></code> files. This PEP proposes a way of
achieving the same functionality in a more user-friendly and structured way.</p>
<section id="limitations-of-pth-files">
<h3><a class="toc-backref" href="#limitations-of-pth-files" role="doc-backlink">Limitations of <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></h3>
<p>If a library needs to perform any customization before an import or that
relates to the general working of the interpreter, they often rely on the
fact that <code class="docutils literal notranslate"><span class="pre">pth</span></code> files, which are loaded at startup and implemented via the
site module <a class="footnote-reference brackets" href="#site" id="id1">[7]</a>, can include Python code that will be executed when the
<code class="docutils literal notranslate"><span class="pre">pth</span></code> file is evaluated.</p>
<p>Note that <code class="docutils literal notranslate"><span class="pre">pth</span></code> files were originally developed to just add additional
directories to <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, but they may also contain lines which start
with “import”, which will be passed to <code class="docutils literal notranslate"><span class="pre">exec()</span></code>. Users have exploited this
feature to allow the customizations that they needed. See setuptools
<a class="footnote-reference brackets" href="#setuptools" id="id2">[4]</a> or betterexceptions <a class="footnote-reference brackets" href="#betterexceptions" id="id3">[5]</a> as examples.</p>
<p>Using <code class="docutils literal notranslate"><span class="pre">pth</span></code> files for this purpose is far from ideal for library developers,
as they need to inject code into a single line preceded by an import, making
it rather unreadable. Library developers following that practice will usually
create a module that performs all actions on import, as done by
betterexceptions <a class="footnote-reference brackets" href="#betterexceptions" id="id4">[5]</a>, but the approach is still not really
user friendly.</p>
<p>Additionally, it is also non-ideal for users of the interpreter if they want
to inspect what is being executed at Python startup as they need to review
all the <code class="docutils literal notranslate"><span class="pre">pth</span></code> files for potential code execution which can be spread across
all site paths. Most of those <code class="docutils literal notranslate"><span class="pre">pth</span></code> files will be “legitimate” <code class="docutils literal notranslate"><span class="pre">pth</span></code>
files that just modify the path, answering the question of “what is changing
my interpreter at startup” a rather complex one.</p>
<p>Lastly, there have been multiple suggestions for removing code execution from
<code class="docutils literal notranslate"><span class="pre">pth</span></code> files, see <a class="footnote-reference brackets" href="#bpo-24534" id="id5">[1]</a> and <a class="footnote-reference brackets" href="#bpo-33944" id="id6">[2]</a>.</p>
</section>
<section id="limitations-of-sitecustomize-py">
<h3><a class="toc-backref" href="#limitations-of-sitecustomize-py" role="doc-backlink">Limitations of <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code></a></h3>
<p>Whilst sitecustomize is an acceptable solution, it assumes a single person is
in charge of the system and the interpreter. If both the system administrator
and the responsibility of provisioning the interpreter want to add
customizations at the interpreter startup they need to agree on the contents
of the file and combine all the changes. This is not a major limitation
though, and it is not the main driver of this change. Should the change
happen, it will also improve the situation for these users, as rather than
having a <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> which performs all those actions, they can have
custom isolated files named after the features they want to enhance. As an
example, Ubuntu could change their current <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> to just be
<code class="docutils literal notranslate"><span class="pre">ubuntu_apport_python_hook</span></code>. This not only better represents its intent but
also gives users of the interpreter a better understanding of the
modifications happening on their interpreter.</p>
</section>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>This PEP proposes supporting extensible customization of the interpreter at
startup by executing all files discovered in directories named
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> in sitepackages <a class="footnote-reference brackets" href="#sitepackages-api" id="id7">[8]</a> or
usersitepackages <a class="footnote-reference brackets" href="#usersitepackages-api" id="id8">[9]</a> at startup time.</p>
<section id="why-sitecustomize">
<h3><a class="toc-backref" href="#why-sitecustomize" role="doc-backlink">Why <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></h3>
<p>The name aims to follow the already existing concept of <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>.
As the directory will be within <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, given that it is located in
site paths, we choose to use double underscore around its name, to prevent
colliding with the already existing <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>.</p>
</section>
<section id="discovering-the-new-sitecustomize-directories">
<h3><a class="toc-backref" href="#discovering-the-new-sitecustomize-directories" role="doc-backlink">Discovering the new <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories</a></h3>
<p>The Python interpreter will look at startup for directory named
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> within any of the standard site-packages path.</p>
<p>These are commonly the Python system location and the user location, but are
ultimately defined by the site module logic.</p>
<p>Users can use <code class="docutils literal notranslate"><span class="pre">site.sitepackages</span></code> <a class="footnote-reference brackets" href="#sitepackages-api" id="id9">[8]</a> and
<code class="docutils literal notranslate"><span class="pre">site.usersitepackages</span></code> <a class="footnote-reference brackets" href="#usersitepackages-api" id="id10">[9]</a> to know the paths where
the interpreter can discover <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories.</p>
</section>
<section id="time-of-sitecustomize-discovery">
<h3><a class="toc-backref" href="#time-of-sitecustomize-discovery" role="doc-backlink">Time of <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> discovery</a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories will be discovered exactly after <code class="docutils literal notranslate"><span class="pre">pth</span></code>
files are discovered in a site-packages path as part of <code class="docutils literal notranslate"><span class="pre">site.addsitedir</span></code>
<a class="footnote-reference brackets" href="#siteaddsitedir" id="id11">[10]</a>.</p>
<p>These is repeated for each of the site-packages path in the exact same order
that is being followed today for <code class="docutils literal notranslate"><span class="pre">pth</span></code> files.</p>
</section>
<section id="order-of-execution-within-sitecustomize">
<h3><a class="toc-backref" href="#order-of-execution-within-sitecustomize" role="doc-backlink">Order of execution within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></h3>
<p>The implementation will execute the files within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> by
sorting them by name when discovering each of the <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code>
directories. We discourage users to rely on the order of execution though.</p>
<p>We considered executing them in random order, but that could result in
different results depending on how the interpreter chooses to pick up those
files. So even if it wont be a good practice to rely on other files being
executed, we think that is better than having randomly different results on
interpreter startup. We chose to run the files after the <code class="docutils literal notranslate"><span class="pre">pth</span></code> files in
case a user needs to add items to the path before running a files.</p>
</section>
<section id="interaction-with-pth-files">
<h3><a class="toc-backref" href="#interaction-with-pth-files" role="doc-backlink">Interaction with <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">pth</span></code> files can be used to add paths into <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>, but this should not
affect the <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> discovery process, as those directories are
looked up exclusively in site-packages paths.</p>
</section>
<section id="execution-of-files-within-sitecustomize">
<h3><a class="toc-backref" href="#execution-of-files-within-sitecustomize" role="doc-backlink">Execution of files within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></h3>
<p>When a <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory is discovered, all of the files that
have a <code class="docutils literal notranslate"><span class="pre">.py</span></code> extension within it will be read with <code class="docutils literal notranslate"><span class="pre">io.open_code</span></code> and
executed by using <code class="docutils literal notranslate"><span class="pre">exec</span></code> <a class="footnote-reference brackets" href="#exec" id="id12">[11]</a>.</p>
<p>An empty dictionary will be passed as <code class="docutils literal notranslate"><span class="pre">globals</span></code> to the <code class="docutils literal notranslate"><span class="pre">exec</span></code> function
to prevent unexpected interactions between different files.</p>
</section>
<section id="failure-handling">
<h3><a class="toc-backref" href="#failure-handling" role="doc-backlink">Failure handling</a></h3>
<p>Any error on the execution of any of the files will not be logged unless the
interpreter is run in verbose mode and it should not stop the evaluation of
other files. The user will receive a message in stderr saying that the file
failed to be executed and that verbose mode can be used to get more
information. This behaviour mimics the one existing for <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>.</p>
</section>
<section id="interaction-with-virtual-environments">
<h3><a class="toc-backref" href="#interaction-with-virtual-environments" role="doc-backlink">Interaction with virtual environments</a></h3>
<p>The customizations applied to an interpreter via the new
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> solutions will continue to work when a user creates a
virtual environment the same way that <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>
interact with virtual environments.</p>
<p>This is a difference when compared to <code class="docutils literal notranslate"><span class="pre">pth</span></code> files, which are not propagated
into virtual environments unless <code class="docutils literal notranslate"><span class="pre">include-system-site-packages</span></code> is enabled.</p>
<p>If library maintainers have features installed via <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> that
they do not want to propagate into virtual environments, they should detect
if they are running within a virtual environment by checking <code class="docutils literal notranslate"><span class="pre">sys.prefix</span> <span class="pre">==</span>
<span class="pre">sys.base_prefix</span></code>. This behavior is similar to packages that modify the global
<code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>.</p>
</section>
<section id="interaction-with-sitecustomize-py-and-usercustomize-py">
<h3><a class="toc-backref" href="#interaction-with-sitecustomize-py-and-usercustomize-py" role="doc-backlink">Interaction with <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> and <code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code></a></h3>
<p>Until removed, <code class="docutils literal notranslate"><span class="pre">sitecustomize</span></code> and <code class="docutils literal notranslate"><span class="pre">usercustomize</span></code> will be executed after
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> similar to pth files. See the Backward compatibility
section for information on removal plans for <code class="docutils literal notranslate"><span class="pre">sitecustomize</span></code> and
<code class="docutils literal notranslate"><span class="pre">usercustomize</span></code>.</p>
</section>
<section id="identifying-all-installed-files">
<h3><a class="toc-backref" href="#identifying-all-installed-files" role="doc-backlink">Identifying all installed files</a></h3>
<p>To facilitate debugging of the Python startup, if the site module is invoked
it will print the <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories that will be discovered
on startup.</p>
</section>
<section id="files-naming-convention">
<h3><a class="toc-backref" href="#files-naming-convention" role="doc-backlink">Files naming convention</a></h3>
<p>Packages will be encouraged to include the name of the package within the
name of the file to avoid collisions between packages. But the only
requirement on the filename is that it ends in <code class="docutils literal notranslate"><span class="pre">.py</span></code> for the interpreter to
execute them.</p>
</section>
<section id="disabling-start-files">
<h3><a class="toc-backref" href="#disabling-start-files" role="doc-backlink">Disabling start files</a></h3>
<p>In some scenarios, like when the startup time is key, it might be desired to
disable this option altogether. The already existing flag <code class="docutils literal notranslate"><span class="pre">-S</span></code> <a class="footnote-reference brackets" href="#s-flag" id="id13">[3]</a>
will disable all <code class="docutils literal notranslate"><span class="pre">site</span></code>-related manipulation, including this new feature.
If the flag is passed in, <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories will not be
discovered.</p>
<p>Additionally, to allow for starting the interpreter disabling only this new
feature a new option will be added under <code class="docutils literal notranslate"><span class="pre">-X</span></code>: <code class="docutils literal notranslate"><span class="pre">disablesitecustomize</span></code>,
which will disable the discovery of <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> exclusively.</p>
<p>Lastly, the user can disable the discovery of <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code>
directories only in the user site by disabling the user site via any of the
multiple options in the <code class="docutils literal notranslate"><span class="pre">site.py</span></code> module.</p>
</section>
<section id="support-in-build-backends">
<h3><a class="toc-backref" href="#support-in-build-backends" role="doc-backlink">Support in build backends</a></h3>
<p>Whilst build backends can choose to provide an option to facilitate the
installation of these files into a <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory, this
PEP does not address that directly. Similar to <code class="docutils literal notranslate"><span class="pre">pth</span></code> files, build backends
can choose to not provide an easy-to-configure mechanism for
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> files and let users hook into the installation
process to include such files. We do not think build backends enhanced
support as a requirement for this PEP.</p>
</section>
<section id="impact-on-startup-time">
<h3><a class="toc-backref" href="#impact-on-startup-time" role="doc-backlink">Impact on startup time</a></h3>
<p>A concern in this implementation is how Python interpreter startup time can
be affected by this addition. We expect the performance impact to be highly
coupled to the logic in the files that a user or sysadmin installs in the
Python environment being tested.</p>
<p>If the interpreter has any files in their <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory,
the file execution time plus a call reading the code will be added to the
startup time. This is similar to how code execution is impacting startup time
through <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>, <code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code> and code in <code class="docutils literal notranslate"><span class="pre">pth</span></code> files.
We will therefore focus here on comparing this solution against those three,
as otherwise the actual time added to startup is highly dependent on the code
that is being executed in those files.</p>
<p>Results were gathered by running “./python.exe -c pass” with perf on 50
iterations, repeating 50 times the command on each iteration and getting the
geometric mean of all the results. The file used to run those benchmarks is
checked in in the reference implementation <a class="footnote-reference brackets" href="#id18" id="id14">[6]</a>.</p>
<p>The benchmark was run with 3.10 alpha 7 compiled with PGO and LTO with the
following parameters and system state:</p>
<ul class="simple">
<li>Perf event: Max sample rate set to 1 per second</li>
<li>CPU Frequency: Minimum frequency of CPU 17,35 set to the maximum frequency</li>
<li>Turbo Boost (MSR): Turbo Boost disabled on CPU 17: MSR 0x1a0 set to 0x4000850089</li>
<li>IRQ affinity: Set default affinity to CPU 0-16,18-34</li>
<li>IRQ affinity: Set affinity of IRQ 1,3-16,21,25-31,56-59,68-85,87,89-90,92-93,95-104 to CPU 0-16,18-34</li>
<li>CPU: use 2 logical CPUs: 17,35</li>
<li>Perf event: Maximum sample rate: 1 per second</li>
<li>ASLR: Full randomization</li>
<li>Linux scheduler: Isolated CPUs (2/36): 17,35</li>
<li>Linux scheduler: RCU disabled on CPUs (2/36): 17,35</li>
<li>CPU Frequency: 0-16,18-34=min=1200 MHz, max=3600 MHz; 17,35=min=max=3600 MHz</li>
<li>Turbo Boost (MSR): CPU 17,35: disabled</li>
</ul>
<p>The code placed to be executed in <code class="docutils literal notranslate"><span class="pre">pth</span></code> files, <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>,
<code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code> and files within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> is the following:</p>
<blockquote>
<div>import time; x = time.time() ** 5</div></blockquote>
<p>The file is aimed at execution a simple operation but still expected to be
negligible. This is to put the experiment in a situation where we make
visible any hit on performance due to the mechanism whilst still making it
relatively realistic. Additionally, it starts with an import and is a single
line to be able to be used in <code class="docutils literal notranslate"><span class="pre">pth</span></code> files.</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head">Test</th>
<th class="head" colspan="4"># of files</th>
<th class="head" colspan="2">Time (us)</th>
</tr>
<tr class="row-even"><th class="head">#</th>
<th class="head"><code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code></th>
<th class="head"><code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code></th>
<th class="head"><code class="docutils literal notranslate"><span class="pre">pth</span></code></th>
<th class="head"><code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></th>
<th class="head">Run 1</th>
<th class="head">Run 2</th>
</tr>
</thead>
<tbody>
<tr class="row-odd"><td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>Dir not created</td>
<td>13884</td>
<td>13897</td>
</tr>
<tr class="row-even"><td>2</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>13871</td>
<td>13818</td>
</tr>
<tr class="row-odd"><td>3</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>13964</td>
<td>13924</td>
</tr>
<tr class="row-even"><td>4</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>13940</td>
<td>13939</td>
</tr>
<tr class="row-odd"><td>5</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>13990</td>
<td>13993</td>
</tr>
<tr class="row-even"><td>6</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>2 (system + user)</td>
<td>14063</td>
<td>14040</td>
</tr>
<tr class="row-odd"><td>7</td>
<td>0</td>
<td>0</td>
<td>50</td>
<td>0</td>
<td>16011</td>
<td>16014</td>
</tr>
<tr class="row-even"><td>8</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>50</td>
<td>15456</td>
<td>15448</td>
</tr>
</tbody>
</table>
<p>Results can be reproduced with <code class="docutils literal notranslate"><span class="pre">run-benchmark.py</span></code> script provided in the
reference implementation <a class="footnote-reference brackets" href="#id18" id="id15">[6]</a>.</p>
<p>We interpret the following from these results:</p>
<ul class="simple">
<li>Using two <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> scripts compared to <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>
and <code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code> slows down the interpreter by 0.3%. We expect this
slowdown until <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> and <code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code> are removed in
a future release as even if the user does not create the files, the
interpreter will still attempt to import them.</li>
<li>With the arbitrary 50 pth files with code tested, moving those to
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> produces a speedup of ~3.5% in startup. Which is likely
related to the simpler logic to evaluate <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> files compared
to <code class="docutils literal notranslate"><span class="pre">pth</span></code> file execution.</li>
<li>In general all measurements show that there is a low impact on startup time
with this addition.</li>
</ul>
</section>
<section id="audit-event">
<h3><a class="toc-backref" href="#audit-event" role="doc-backlink">Audit Event</a></h3>
<p>A new audit event will be added and triggered on <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code>
execution to facilitate security inspection by calling <code class="docutils literal notranslate"><span class="pre">sys.audit</span></code>
<a class="footnote-reference brackets" href="#sysaudit" id="id16">[12]</a> with “sitecustimze.exec_file” as name and the filename as
argument.</p>
</section>
<section id="security-implications">
<h3><a class="toc-backref" href="#security-implications" role="doc-backlink">Security implications</a></h3>
<p>This PEP aims to move all code execution from <code class="docutils literal notranslate"><span class="pre">pth</span></code> files to files within a
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory. We think this is an improvement to system admins
for the following reasons:</p>
<ul class="simple">
<li>Allows to quickly identify the code being executed at startup time by the
interpreter by looking into a single directory rather than having to scan
all <code class="docutils literal notranslate"><span class="pre">pth</span></code> files.</li>
<li>Allows to track usage of this feature through the new proposed audit event.</li>
<li>Gives finer grain control by allowing to tune permissions on the
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory, potentially allowing users to install only
packages that does not change the interpreter startup.</li>
</ul>
<p>In short, whilst this allows for a malicious users to drop a file that will
be executed at startup, its an improvement compared to the existing <code class="docutils literal notranslate"><span class="pre">pth</span></code>
files.</p>
</section>
</section>
<section id="how-to-teach-this">
<h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to teach this</a></h2>
<p>This can be documented and taught as simple as saying that the interpreter
will try to look for the <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory at startup in its
site paths and if it finds any files with <code class="docutils literal notranslate"><span class="pre">.py</span></code> extension, it will then
execute it one by one.</p>
<p>For system administrators and tools that package the interpreter, we can now
recommend placing files in <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> as they used to place
<code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>. Being more comfortable on that their content wont be
overridden by the next person, as they can provide with specific files to
handle the logic they want to customize.</p>
<p>Library developers should be able to specify a new argument on tools like
setuptools that will inject those new files. Something like
<code class="docutils literal notranslate"><span class="pre">sitecustomize_files=[&quot;scripts/betterexceptions.py&quot;]</span></code>, which allows them to
add those. Should the build backend not support that, they can manually
install them as they used to do with <code class="docutils literal notranslate"><span class="pre">pth</span></code> files. We will recommend them to
include the name of the package as part of the files name.</p>
</section>
<section id="backward-compatibility">
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward compatibility</a></h2>
<p>This PEP adds a deprecation warning on <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code>,
<code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code> and <code class="docutils literal notranslate"><span class="pre">pth</span></code> code execution in 3.11, 3.12 and 3.13. With
plans on removing those features by 3.14. The migration from those solutions
to <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> should ideally be just moving the logic into a
different file.</p>
<p>Whilst the existing <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> mechanism was created targeting
System Administrators that placed it in a site path, the file could be
actually placed anywhere in the path at the time that the interpreter was
starting up. The new mechanism does not allow for users to place
<code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories anywhere in the path, but only in site
paths. System administrators can recover a similar behavior to
<code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> by adding a custom file in <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> which
just imports <code class="docutils literal notranslate"><span class="pre">sitecustomize</span></code> as a migration path.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>An initial implementation that passes the CPython test suite is available for
evaluation <a class="footnote-reference brackets" href="#id18" id="id17">[6]</a>.</p>
<p>This implementation is just for the reviewer to play with and check potential
issues that this PEP could generate.</p>
</section>
<section id="rejected-ideas">
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
<section id="do-nothing">
<h3><a class="toc-backref" href="#do-nothing" role="doc-backlink">Do nothing</a></h3>
<p>Whilst the current status “works” it presents the issues listed in the
motivation. After analyzing the impact of this change, we believe it is worth
it, given the enhanced experience it brings.</p>
</section>
<section id="formalize-using-pth-files">
<h3><a class="toc-backref" href="#formalize-using-pth-files" role="doc-backlink">Formalize using <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></h3>
<p>Another option would be to just glorify and document the usage of <code class="docutils literal notranslate"><span class="pre">pth</span></code> files
to inject code at startup code, but that is a suboptimal experience for users
as listed in the motivation.</p>
</section>
<section id="making-sitecustomize-a-namespace-package">
<h3><a class="toc-backref" href="#making-sitecustomize-a-namespace-package" role="doc-backlink">Making <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> a namespace package</a></h3>
<p>We considered making the directory a namespace package and just import all
the modules within it, which allowed searching across all paths in
<code class="docutils literal notranslate"><span class="pre">sys.path</span></code> at initialization time and provided a way to declare
dependencies between files by importing each other. This was rejected for
multiple reasons:</p>
<ol class="arabic simple">
<li>This was unnecessarily broadening the list of paths where arbitrary files
are executed.</li>
<li>The logic brought additional complexity, like what to do if a package were
to install an <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file in one of the locations.</li>
<li>Its cheaper to search for <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> as we are looking for
<code class="docutils literal notranslate"><span class="pre">pth</span></code> files already in the site paths compared to performing an actual
import of a namespace package.</li>
</ol>
</section>
<section id="support-for-shutdown-customization">
<h3><a class="toc-backref" href="#support-for-shutdown-customization" role="doc-backlink">Support for shutdown customization</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">init.d</span></code> users might be tempted to implement this feature in a way that users
could also add code at shutdown, but extra support for that is not needed, as
Python users can already do that via <code class="docutils literal notranslate"><span class="pre">atexit</span></code>.</p>
</section>
<section id="using-entry-points">
<h3><a class="toc-backref" href="#using-entry-points" role="doc-backlink">Using entry_points</a></h3>
<p>We considered extending the use of entry points to allow specifying files
that should be executed at startup but we discarded that solution due to two
main reasons. The first one being impact on startup time. This approach will
require scanning all packages distribution information to just execute a
handful of files. This has an impact on performance even if the user is not
using the feature and such impact growths linearly with the number of packages
installed in the environment. The second reason was that the proposed
implementation in this PEP offers a single solution for startup customization
for packages and system administrators. Additionally, if the main objective of
entry points is to make it easy for libraries to install files at startup,
that can still be added and make the build backends just install the files
within the <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directory.</p>
</section>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document is placed in the public domain or under the CC0-1.0-Universal
license, whichever is more permissive.</p>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>Thanks Pablo Galindo for contributing to this PEP and offering his PC to run
the benchmark.</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="bpo-24534" role="doc-footnote">
<dt class="label" id="bpo-24534">[<a href="#id5">1</a>]</dt>
<dd><a class="reference external" href="https://bugs.python.org/issue24534">https://bugs.python.org/issue24534</a></aside>
<aside class="footnote brackets" id="bpo-33944" role="doc-footnote">
<dt class="label" id="bpo-33944">[<a href="#id6">2</a>]</dt>
<dd><a class="reference external" href="https://bugs.python.org/issue33944">https://bugs.python.org/issue33944</a></aside>
<aside class="footnote brackets" id="s-flag" role="doc-footnote">
<dt class="label" id="s-flag">[<a href="#id13">3</a>]</dt>
<dd><a class="reference external" href="https://docs.python.org/3/using/cmdline.html#id3">https://docs.python.org/3/using/cmdline.html#id3</a></aside>
<aside class="footnote brackets" id="setuptools" role="doc-footnote">
<dt class="label" id="setuptools">[<a href="#id2">4</a>]</dt>
<dd><a class="reference external" href="https://github.com/pypa/setuptools/blob/b6bbe236ed0689f50b5148f1172510b975687e62/setup.py#L100">https://github.com/pypa/setuptools/blob/b6bbe236ed0689f50b5148f1172510b975687e62/setup.py#L100</a></aside>
<aside class="footnote brackets" id="betterexceptions" role="doc-footnote">
<dt class="label" id="betterexceptions">[5]<em> (<a href='#id3'>1</a>, <a href='#id4'>2</a>) </em></dt>
<dd><a class="reference external" href="https://github.com/Qix-/better-exceptions/blob/7b417527757d555faedc354c86d3b6fe449200c2/better_exceptions_hook.pth#L1">https://github.com/Qix-/better-exceptions/blob/7b417527757d555faedc354c86d3b6fe449200c2/better_exceptions_hook.pth#L1</a></aside>
<aside class="footnote brackets" id="id18" role="doc-footnote">
<dt class="label" id="id18">[6]<em> (<a href='#id14'>1</a>, <a href='#id15'>2</a>, <a href='#id17'>3</a>) </em></dt>
<dd><a class="reference external" href="https://github.com/mariocj89/cpython/tree/pu/__sitecustomize__">https://github.com/mariocj89/cpython/tree/pu/__sitecustomize__</a></aside>
<aside class="footnote brackets" id="site" role="doc-footnote">
<dt class="label" id="site">[<a href="#id1">7</a>]</dt>
<dd><a class="reference external" href="https://docs.python.org/3/library/site.html">https://docs.python.org/3/library/site.html</a></aside>
<aside class="footnote brackets" id="sitepackages-api" role="doc-footnote">
<dt class="label" id="sitepackages-api">[8]<em> (<a href='#id7'>1</a>, <a href='#id9'>2</a>) </em></dt>
<dd><a class="reference external" href="https://docs.python.org/3/library/site.html?highlight=site#site.getsitepackages">https://docs.python.org/3/library/site.html?highlight=site#site.getsitepackages</a></aside>
<aside class="footnote brackets" id="usersitepackages-api" role="doc-footnote">
<dt class="label" id="usersitepackages-api">[9]<em> (<a href='#id8'>1</a>, <a href='#id10'>2</a>) </em></dt>
<dd><a class="reference external" href="https://docs.python.org/3/library/site.html?highlight=site#site.getusersitepackages">https://docs.python.org/3/library/site.html?highlight=site#site.getusersitepackages</a></aside>
<aside class="footnote brackets" id="siteaddsitedir" role="doc-footnote">
<dt class="label" id="siteaddsitedir">[<a href="#id11">10</a>]</dt>
<dd><a class="reference external" href="https://github.com/python/cpython/blob/5787ba4a45492e232f5470c7d2e93763198e4b22/Lib/site.py#L207">https://github.com/python/cpython/blob/5787ba4a45492e232f5470c7d2e93763198e4b22/Lib/site.py#L207</a></aside>
<aside class="footnote brackets" id="exec" role="doc-footnote">
<dt class="label" id="exec">[<a href="#id12">11</a>]</dt>
<dd><a class="reference external" href="https://docs.python.org/3/library/functions.html#exec">https://docs.python.org/3/library/functions.html#exec</a></aside>
<aside class="footnote brackets" id="sysaudit" role="doc-footnote">
<dt class="label" id="sysaudit">[<a href="#id16">12</a>]</dt>
<dd><a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.audit">https://docs.python.org/3/library/sys.html#sys.audit</a></aside>
</aside>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0648.rst">https://github.com/python/peps/blob/main/peps/pep-0648.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0648.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="#pep-rejection">PEP Rejection</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
<li><a class="reference internal" href="#limitations-of-pth-files">Limitations of <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></li>
<li><a class="reference internal" href="#limitations-of-sitecustomize-py">Limitations of <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#why-sitecustomize">Why <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></li>
<li><a class="reference internal" href="#discovering-the-new-sitecustomize-directories">Discovering the new <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> directories</a></li>
<li><a class="reference internal" href="#time-of-sitecustomize-discovery">Time of <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> discovery</a></li>
<li><a class="reference internal" href="#order-of-execution-within-sitecustomize">Order of execution within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></li>
<li><a class="reference internal" href="#interaction-with-pth-files">Interaction with <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></li>
<li><a class="reference internal" href="#execution-of-files-within-sitecustomize">Execution of files within <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code></a></li>
<li><a class="reference internal" href="#failure-handling">Failure handling</a></li>
<li><a class="reference internal" href="#interaction-with-virtual-environments">Interaction with virtual environments</a></li>
<li><a class="reference internal" href="#interaction-with-sitecustomize-py-and-usercustomize-py">Interaction with <code class="docutils literal notranslate"><span class="pre">sitecustomize.py</span></code> and <code class="docutils literal notranslate"><span class="pre">usercustomize.py</span></code></a></li>
<li><a class="reference internal" href="#identifying-all-installed-files">Identifying all installed files</a></li>
<li><a class="reference internal" href="#files-naming-convention">Files naming convention</a></li>
<li><a class="reference internal" href="#disabling-start-files">Disabling start files</a></li>
<li><a class="reference internal" href="#support-in-build-backends">Support in build backends</a></li>
<li><a class="reference internal" href="#impact-on-startup-time">Impact on startup time</a></li>
<li><a class="reference internal" href="#audit-event">Audit Event</a></li>
<li><a class="reference internal" href="#security-implications">Security implications</a></li>
</ul>
</li>
<li><a class="reference internal" href="#how-to-teach-this">How to teach this</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward compatibility</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#do-nothing">Do nothing</a></li>
<li><a class="reference internal" href="#formalize-using-pth-files">Formalize using <code class="docutils literal notranslate"><span class="pre">pth</span></code> files</a></li>
<li><a class="reference internal" href="#making-sitecustomize-a-namespace-package">Making <code class="docutils literal notranslate"><span class="pre">__sitecustomize__</span></code> a namespace package</a></li>
<li><a class="reference internal" href="#support-for-shutdown-customization">Support for shutdown customization</a></li>
<li><a class="reference internal" href="#using-entry-points">Using entry_points</a></li>
</ul>
</li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0648.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>