From a5ff559690b24b2e10c44e4d384e2c6f209103ae Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 10 Apr 2026 21:51:04 -0700 Subject: [PATCH 1/3] Several updates based on DPO feedback Specifically, we drop the `site.toml` file proposal in favor of an evolution of the `.pth` file format and the addition of `.start` files. Also, update the Discussions-To header and Post-History. --- peps/pep-0829.rst | 689 ++++++++++++++++++---------------------------- 1 file changed, 264 insertions(+), 425 deletions(-) diff --git a/peps/pep-0829.rst b/peps/pep-0829.rst index 34a8636c914..23f38e6470b 100644 --- a/peps/pep-0829.rst +++ b/peps/pep-0829.rst @@ -1,25 +1,35 @@ PEP: 829 -Title: Structured Startup Configuration via .site.toml Files +Title: Package Startup Configuration Files Author: Barry Warsaw -Discussions-To: Pending +Discussions-To: https://discuss.python.org/t/pep-829-structured-startup-configuration-via-site-toml-files/106789 Status: Draft Type: Standards Track -Topic: Packaging Created: 31-Mar-2026 Python-Version: 3.15 Post-History: + `01-Apr-2026 `_ Abstract ======== -This PEP proposes a TOML-based configuration file format to replace -the ``.pth`` file mechanism used by ``site.py`` during interpreter -startup. The new format, using files named ``.site.toml``, -provides structured configuration for extending ``sys.path`` and -executing package initialization code, replacing the current ad-hoc -``.pth`` format that conflates path configuration with arbitrary code -execution. +This PEP changes the way packages influence Python's startup process. +Previously controlled through legacy ``.pth`` files parsed and executed by the +``site.py`` file during interpreter startup, such files are used to extend +``sys.path`` and execute package initialization code before control is passed +to the first line of user code. + +``.pth`` files in their historical form have a `long history +`_ of proposed removal, +primarily because of the obtuse nature of the arbitrary code execution +feature. Recent `supply chain attacks +`_ +have used arbitrary code execution in ``.pth`` files as an attack vector. + +This PEP doesn't completely close this vector, but it does propose an +important and useful improvement, by narrowing the attack surface and enabling +a future policy mechanism for controlling which packages are allowed or +prevented from extending the path and executing start up code. Motivation @@ -28,16 +38,17 @@ Motivation Python's ``.pth`` files (processed by ``Lib/site.py`` at startup) support two functions: -* **Extending** ``sys.path`` -- Lines in this file (excluding - comments and lines that start with ``import``) name directories to - be appended to ``sys.path``. Relative paths are implicitly - anchored at the site-packages directory. +* **Extending** ``sys.path`` -- Lines in this file (excluding comments + and lines that start with ``import``) name directories to be + appended to ``sys.path``. Relative paths are implicitly anchored at + the site-packages directory. -* **Executing code** -- lines starting with ``import`` (or +* **Executing arbitrary code** -- lines starting with ``import`` (or ``import\\t``) are executed immediately by passing the source string to ``exec()``. -This design has several problems: +While there are valid use cases for each feature, the ``import`` lines +support are the most problematic because: * Code execution is a side effect of the implementation. Lines that start with ``import`` can be extended by separating multiple @@ -45,518 +56,346 @@ This design has several problems: executed appears on the same line, it all gets executed when the ``.pth`` file is processed. -* ``.pth`` files are essentially unstructured, leading to contents - which are difficult to reason about or validate, and are often even - difficult to read. It mixes two potentially useful features with - different security constraints, and no way to separate out these - concerns. - -* The lack of ``.pth`` file structure also means there's no way to - express metadata, no future-proofing of the format, and no defined - execution or processing order of the contents. +* ``import`` lines are executed using ``exec()`` during interpreter + startup, which opens a broad attack surface. -* Using ``exec()`` on the file contents during interpreter startup is - a broad attack surface. - -* There is no explicit concept of an entry point, which is an - established pattern in Python packaging. Packages that require - code execution and initialization at startup abuse ``import`` lines - rather than explicitly declaring entry points. +* There is no explicit concept of an entry point, which is an established + pattern in Python packaging. Packages that require code execution and + initialization at startup abuse ``import`` lines rather than explicitly + declaring entry points. Specification ============= -This PEP defines a new file format called ``.site.toml`` -which addresses all of the stated problems with ``.pth`` files. Like -``.pth`` files, ``.site.toml`` files are processed at Python -startup time by the ``site.py`` module, which means that the ``-S`` -option, which disables ``site.py`` also disables -``.site.toml`` files. - -The standard library ``tomllib`` package is used to read and process -``.site.toml`` files. - -The presence of a ``.site.toml`` file supersedes a parallel -``.pth`` file. This allows for both an easy migration path and -continued support for older Pythons in parallel. - -Any parsing errors cause the entire ``.site.toml`` file to be ignored -and not processed (but it still supersedes any parallel ``.pth`` -file). Any errors that occur when importing entry point modules or calling -entry point functions are reported but do not abort the Python executable. - - -File Naming and Discovery -------------------------- - -* As with ``.pth`` files, packages may optionally install a single - ``.site.toml``, just like the current ``.pth`` file - convention. - -* The file naming format is ``.site.toml``. The ``.site`` marker - distinguishes these from other TOML files that might exist in site-packages - and describes the file's purpose (processed by ``site.py``). - -* The ```` prefix should match the package name, but just - like with ``.pth`` files, the interpreter does not enforce this. - Build backends and installers :ref:`**MAY** ` impose - stricter constraints if they so choose. - -* The package name (i.e. the ```` prefix) **MUST** follow the - standard `name normalization rules - `_. - -* ``.site.toml`` files live in the same site-packages directories - where ``.pth`` files are found today. - -* The discovery rules for ``.site.toml`` files is the same as - ``.pth`` files today. File names that start with a single ``.`` - (e.g. ``.site.toml``) and files with OS-level hidden attributes (``UF_HIDDEN``, - ``FILE_ATTRIBUTE_HIDDEN``) are excluded. - -* The processing order is alphabetical by filename, matching ``.pth`` - behavior. - -* If both ``.site.toml`` and ``.pth`` exist in the same - directory, only the ``.site.toml`` file is processed. In other - words, the presence of a ``.site.toml`` file supersedes a parallel - ```` file, even if the format of the TOML file is invalid. +This PEP proposes the following: +* Keep the ``.pth`` file format, but deprecate ``import`` line + processing for three years, after which such lines will be + disallowed. -Processing Model ----------------- +* During the deprecation period, the presence of a ``.start`` file + matching a ``.pth`` file disables the execution of ``import`` lines in + favor of entry points. This provides a migration path straddling Python + versions which support this PEP and earlier versions which do not. See the + :ref:`teach` section for specific migration guidelines. -All ``.site.toml`` files in a given site-packages directory -are read and parsed into an intermediate data structure before any -processing (i.e. path extension or entry point execution) occurs. -This two-phase approach (read then process) enables: +* Keep the current ``sys.path`` extension feature of ``.pth`` files + unchanged. Specifically, absolute paths are used verbatim while + relative paths are anchored at the directory in which the ``.pth`` + file is located. -* A future **policy mechanism** that can inspect and modify the collected data - before execution (e.g., disabling entry points for specific packages or - enforcing path restrictions). **NOTE**: Such a policy framework is - explicitly out-of-scope for this PEP. +* A new file format called ``.start`` files are added which names entry points + conforming to the "colon-form" of :func:`pkgutil.resolve_name` arguments. -* Future finer-grained control over the processing of path extensions - and entry point execution. For example, one could imagine special - ``-X`` options, environment variables, or other types of - configuration that allow path extensions only, or can explicitly - manage allow or deny lists of entry points. **NOTE**: Such - configuration options are explicitly out-of-scope for this PEP. +``site.py`` start up code is divided into these explicit phases: -* Better error reporting. All parsing, format, and data type errors - can be surfaced before any processing occurs. +#. List all ``.pth`` files and sort in alphabetical order by filename. -Within each site-packages directory, the processing order is: +#. Parse ``.pth`` files in sorted order, keeping a global sorted list of all + path extensions, de-duplicating entries (first one wins). Record the + ``.pth`` file the extension is found in (data structure TBD but documented). -#. Discover and parse all ``.site.toml`` files, sorted alphabetically. -#. Process all ``[paths]`` entries from the parsed TOML files. -#. Execute all ``[entrypoints]`` entries from the parsed TOML files. -#. Process any remaining ``.pth`` files that are not superseded by a - ``.site.toml`` file. +#. *Future extension:* apply :ref:`global policy filter ` on sorted + list of path extensions. -This ensures that path extensions are in place before any entry point code -runs, and that ``.site.toml``-declared paths are available to both -entry point imports and ``.pth`` import lines. +#. Append path extensions in sorted order to ``sys.path``. +#. List all ``.start`` files and sort in alphabetical order by filename. -TOML file schema ----------------- +#. Parse ``.start`` files in sorted order, keeping a global sorted list of all + entry points, de-duplicating entries (first one wins). Record the + ``.start`` file the entry point is found in (data structure TBD but + documented). -A ``.site.toml`` file is defined to have three sections, all of which -are optional: +#. *Future extension:* :ref:`apply global policy filter ` on sorted + list of entry points. -.. code-block:: toml +#. For each entry point, use :func:`pkg.resolve_name` to resolve the entry + point into a callable. Call the entry point with no arguments. - [metadata] - schema_version = 1 +For both ``.pth`` files and ``.start`` files, comment lines (i.e. lines +beginning with ``#`` as the first non-whitespace character) and blank lines +are ignored. Any other parsing error causes the line to be ignored. - [paths] - dirs = ["../lib", "/opt/mylib", "{sitedir}/extra"] +.. _ep-syntax: - [entrypoints] - init = ["foo.startup:initialize", "foo.plugins"] +Entry point syntax +------------------ +:func:`pkgutil.resolve_name` is used to resolve an entry point specification +into a callable object. However, in Python 3.14 and earlier, this function +accepts two forms, described in the documentation with pseudo-regular +expressions: -The ``[metadata]`` section -'''''''''''''''''''''''''' +* ``W(.W)*`` - no colon form +* ``W(.W)*:(W(.W)*)?`` - colon form with optional callable suffix -This section contains package and/or file metadata. The only defined key is -the the optional ``schema_version`` key. +This PEP proposes to only allow ``pkg.mod:callable`` form of entry points, and +requires that the callable be specified. See the :ref:`open issues +` for further discussion. -``schema_version`` (integer, recommended) - The TOML file schema version number. Must be the integer ``1`` - for this specification. If present, Python guarantees - forward-compatible handling: future versions will either process - the file according to the declared schema or skip it with clear - diagnostics. If the ``schema_version`` is present but has an - unsupported value, the entire file is skipped. If - ``schema_version`` is omitted, the file is processed on a - best-effort basis with no forward-compatibility guarantees. -Additional keys are permitted and preserved, although they are ignored for the -purposes of this PEP. - - -The ``[paths]`` section -''''''''''''''''''''''' - -Defined keys: - -``dirs`` - A list of strings specifying directories to append to ``sys.path``. - -Path entries use a hybrid resolution scheme: - -* **Relative paths** are anchored at the site-packages directory (sitedir), - matching current ``.pth`` behavior. For example, ``../lib`` in a file under - ``/usr/lib/python3.15/site-packages/`` resolves to - ``/usr/lib/python3.15/lib``. - -* **Absolute paths** are preserved as-is. For example, ``/opt/mylib`` is used - exactly as written. - -* **Placeholder variables** are supported using ``{name}`` syntax. The - placeholder ``{sitedir}`` expands to the site-packages directory where the - ``.site.toml`` file was found. Thus ``{sitedir}/relpath`` and - ``relpath`` resolve to the same path with the placeholder version being the - explicit (and recommended) form of the relative path form. - -While only ``{sitedir}`` is defined in this PEP, additional -placeholder variables (e.g., ``{prefix}``, ``{exec_prefix}``, -``{userbase}``) may be defined in future PEPs. - -If ``dirs`` is not a list of strings, a warning is emitted (visible -with ``-v``) and the section is skipped. - -Directories that do not exist on the filesystem are silently skipped, matching -``.pth`` behavior. Paths are de-duplicated, also matching -``.pth`` behavior. - - -The ``[entrypoints]`` section -''''''''''''''''''''''''''''' +File Naming and Discovery +------------------------- -``init`` -- a list of strings specifying `entry point -`_ -references to execute at startup. Each item uses the standard Python -entry point syntax: ``package.module:callable``. +* Packages may optionally install zero or more files of the format + ``.pth`` and ``.start``. The ```` prefix is arbitrary and + need not match the package name or each other, although all else being + equal, it is recommended that they do match the package name for clarity. + The interpreter does not enforce any constraints on the prefix. -* The ``:callable`` portion is optional. If omitted (e.g., - ``package.module``), the module is imported via - ``importlib.import_module()`` but nothing is called. This covers the common - ``.pth`` pattern of ``import foo`` for side effects. +* Files are processed in alphabetical order. -* Callables are invoked with no arguments. +* ``.start`` files live in the same site-packages directories where + ``.pth`` files are found today. The ``.pth`` location stays the + same. -* Entries are executed in the listed order. +* The discovery rules for ``.site.toml`` files is the same as + ``.pth`` files today. File names that start with a single ``.`` + (e.g. ``.start``) and files with OS-level hidden attributes (``UF_HIDDEN``, + ``FILE_ATTRIBUTE_HIDDEN``) are excluded. -* The ``[extras]`` syntax from the packaging entry point spec is not - supported; it is installer metadata and has no meaning at - interpreter startup. +Error Handling +-------------- -General Schema Rules -'''''''''''''''''''' +Errors are handled differently depending on the phase: -* All three sections are optional. An empty ``.site.toml`` - file is a valid no-op. +Phase 1: Reading and Parsing + If a ``.pth`` or ``.start`` file cannot be opened or read, it + is skipped and processing continues to the next file. Errors are reported + only when ``-v`` (verbose) is given. -* Unknown tables are silently ignored, providing forward compatibility for - future extensions. +Phase 2: Execution + Invalid or nonexistent file system paths are ignored, with errors printed + to ``sys.stderr``. Processing continues to the next path entry. -* ``[paths]`` is always processed before ``[entrypoints]``, regardless of the - order the sections appear in the TOML file. + Invalid entry point specifications are skipped. Exceptions during + execution of the entry point are printed to ``sys.stderr``. Processing + continues to the next entry point. +Because of the 2-phase interpretation of ``.pth`` and ``.start`` +files, continued evaluation of paths and entry points is a deliberate +improvement over current ``.pth`` behavior, which aborts processing the +remainder of a file on the first error. -Error Handling --------------- -Errors are handled differently depending on the phase: +.. _future: -Phase 1: Reading and Parsing - If a ``.site.toml`` file cannot be opened, decoded, or parsed as - valid TOML, it is skipped and processing continues to the next file. - Errors are reported only when ``-v`` (verbose) is given. Importantly, - a ``.site.toml`` file that fails to parse **still supersedes** - its corresponding ``.pth`` file. The existence of the - ``.site.toml`` file is sufficient to suppress - ``.pth`` processing, regardless of whether the TOML file - parses successfully. This prevents confusing dual-execution - scenarios and ensures that a broken ``.site.toml`` is - noticed rather than silently masked by fallback to the - ``.pth`` file. +Future Improvements +------------------- -Phase 2: Execution - If a path entry or entry point raises an exception during processing, the - traceback is printed to ``sys.stderr``, the failing entry is skipped, and - processing continues with the remaining entries in that file and - subsequent files. +The introduction of 2-phase processing of ``.pth`` and ``.start`` files gives +us the ability to implement future improvements, where some global site policy +can be applied, providing finer grained control over both ``sys.path`` +extension and entry point execution. One could imagine that after parsing, a +policy could be applied to either allow or deny path extensions or entry +points based on a number of different criteria, such as the ```` prefix +used to specify the extension, the path locations, or the modules in which the +entry points are defined. -This is a deliberate improvement over ``.pth`` behavior, which aborts -processing the remainder of a file on the first error. +This PEP deliberately leaves the design of such a policy mechanism to a future +specification. Rationale ========= -TOML as the configuration format - TOML is already used by ``pyproject.toml`` and is familiar to the Python - packaging ecosystem. It is an easily human readable and writable format - that aids in validation and auditing. TOML files are structured and - typed, and can be easily reasoned about. TOML files allows for easy - future extensibility. The ``tomllib`` module is available in the standard - library since Python 3.11. - -The ``.site.toml`` naming convention - A double extension clearly communicates purpose: the ``.site`` marker - indicates this is a site-startup configuration file, while ``.toml`` - indicates the format. This avoids ambiguity with other TOML files that - might exist in site-packages now or in the future. The package name - prefix preserves the current ``.pth`` convention of a single - startup file per package. - -Hybrid path resolution - Implicit relative path joining (matching ``.pth`` behavior) - provides a smooth migration path, while ``{sitedir}`` and future - placeholder variables offer explicit, extensible alternatives. As with - ``.pth`` files, absolute paths are preserved and used verbatim. - -``importlib.import_module()`` instead of ``exec()`` - Using the standard import machinery is more predictable and auditable than - ``exec()``. It integrates with the import system's hooks and logging, and - the ``package.module:callable`` syntax is already well-established in the - Python packaging ecosystem (e.g., ``console_scripts``). Allowing for - optional ``:callable`` syntax preserves the import-side-effect - functionality of ``.pth`` files, making migration easier. - -Two-phase processing - Reading all configuration before executing any of it provides a natural - extension point for future policy mechanisms and makes error reporting - more predictable. - -Alphabetical ordering with no priority mechanism - Packages are installed independently, and there is no external arbiter of - priority. Alphabetical ordering matches ``.pth`` behavior and is - simple to reason about. Priority could be addressed by a future site-wide - policy configuration. - -``schema_version`` as recommended, not required - Requiring ``schema_version`` would make the simplest valid file more - verbose. Making it recommended strikes a balance: files that include it - get forward-compatibility guarantees, while simple files that omit it - still work on a best-effort basis. - -Continue on error rather than abort - The ``.pth`` behavior of aborting the rest of a file on the first - error is unnecessarily harsh. If a package declares three entry points - and one fails, the other two should still run. +A previous iteration of this PEP proposed the use of a unified +``.site.toml`` file with tables to specify metadata, a list of path +extensions, and a list of entry points. While the PEP author and several +discussion participants liked this structured approach, a number of detractors +expressed the opinion that TOML files were overkill for this proposal. The +PEP author believes that the processing overhead of TOML files was negligible +and that the structured approach was useful for readability and future +extensibility. Detractors countered with YAGNI. + +The two-file approach is a simple evolutionary improvement over the previous +``.pth`` file process. The first improvement is the deprecation and removal +of arbitrary code execution through ``exec()`` of ``import`` lines. Such +lines are a wide attack vector that even the :func:`exec` standard library +documentation strongly warns against. Replacing these lines with the narrower +invocation of entry point function inside modules indirectly reduces the +attack vector because functions inside modules are easier to audit, both by +humans and automatic vulnerability scanners. + +The second improvement is splitting ``sys.path`` extension from entry point +specification into two files, special purposed for the exact use case they +support. There's no co-mingling of purposes, no possible interleaving of +effects, more readable file formats, and clear processing rules. ``sys.path`` +extensions are processed first, setting up the ability to import modules, and +then entry points are processed. It's unambiguously clear which file format +supports which use case. + +The third improvement is the 2-phase approach to processing these files. +Parsing errors can be reported early and need not terminate the further +processing of lines in each file. The transition from processing to execution +for both ``sys.path`` extension and entry point invocation gives us a chance +(:ref:`in the future `) to design and implement global policies for +explicitly controlling which path extensions and entry points are allowed (and +by implication, deemed safe), without resorting to the heavy hammer of +`disabling site.py processing completely +`_. Backwards Compatibility ======================= -* ``.pth`` file processing is **not** deprecated or removed. Both - ``.pth`` and ``.site.toml`` files are discovered in - parallel within each site-packages directory. This preserves backward - compatibility for all existing (pre-migration) packages. Deprecation of - ``.pth`` files is out-of-scope for this PEP. - -* When ``.site.toml`` exists alongside ``.pth``, the - ``.site.toml`` takes precedence and the ``.pth`` file is - skipped, providing for a natural migration path and easy compatibility with - older versions of Python which are unaware of ``.site.toml`` files. - -* Within a site-packages directory, all ``.site.toml`` files - are fully processed (paths and entry points) before any remaining - ``.pth`` files. +This PEP proposes a 3 year deprecation period for processing of ``import`` +lines inside ``.pth`` files. ``sys.path`` extensions in ``.pth`` files remain +unchanged. -* The ``site.addsitedir()`` public API retains its existing signature - and continues to accept ``known_paths``. +There should always be a simple migration strategy for any packages which +utilize the ``import`` line arbitrary code execution feature of current +``.pth`` files. They can simply move the code into a callable inside an +importable module inside the package, and then name this callable in an entry +point specification inside a ``.start`` file. Security Implications ===================== -This PEP improves the security posture of interpreter startup: +This PEP improves the security posture of interpreter startup. -* ``.site.toml`` files replace ``exec()`` with - ``importlib.import_module()`` and explicit ``getattr()`` calls, - which are more constrained and auditable. +* The removal of arbitrary code execution by :func:`exec` with entry point + execution, which is more constrained and auditable. -* ``io.open_code()`` is used to read ``.site.toml`` files, ensuring - that audit hooks (:pep:`578`) can monitor file access. +* Python's import system is used to access and run the entry points, so the + standard audit hooks (:pep:`578`) can provide monitoring. -* The two-phase processing model creates a natural point where a future policy - mechanism could inspect and restrict what gets executed. +* The two-phase processing model creates a natural hook where a :ref:`future + ` policy mechanism could inspect and restrict what gets executed. -* The ``package.module:callable`` syntax limits execution to - importable modules and their attributes, unlike ``exec()`` which can - run arbitrary code. +* The ``package.module:callable`` syntax limits execution to callables within + importable modules. -The overall attack surface is not eliminated -- a malicious package -can still cause arbitrary code execution via ``init`` entrypoints, but -the mechanism proposed in this PEP is more structured, auditable, and -amenable to future policy controls. +The overall attack surface is not eliminated -- a malicious package can still +cause arbitrary code execution viaentry points, but the mechanism proposed in +this PEP is more structured, auditable, and amenable to future policy +controls. +.. _teach: + How to Teach This ================= -For package authors -------------------- - -If your package currently ships a ``.pth`` file, you can migrate to a -``.site.toml`` file. The equivalent of a ``.pth`` file -containing a directory name is: - -.. code-block:: toml - - [paths] - dirs = ["my_directory"] - -The equivalent of a ``.pth`` file containing ``import my_package`` -is: - -.. code-block:: toml - - [entrypoints] - init = ["my_package"] - -If your ``.pth`` file calls a specific function, use the -``module:callable`` syntax: - -.. code-block:: toml +The :mod:`site` module documentation will be updated to describe the operation +and best practices for ``.pth`` and ``.start`` files. The +following guidelines for package authors will be include: - [entrypoints] - init = ["my_package.startup:initialize"] +If your package currently ships a ``.pth`` file, analyze whether you are +using it for ``sys.path`` extension or start up code execution. You can keep +all the ``sys.path`` extension lines unchanged. -If your ``.pth`` file includes arbitrary code, put that code in a -start up function and use the ``module:callable`` syntax. +If you are using the code execution of ``import`` lines feature, create a +callable (taking zero arguments) within an importable module inside your +package. Name these as ``pkg.mod:callable`` entry points in a matching +``.start`` file. -Both ``.pth`` and ``.site.toml`` can coexist during -migration. If both exist for the same package, only the -``.site.toml`` is processed. Thus it is recommended that -packages compatible with older Pythons ship both files. +During the deprecation period, if your package has to straddle older Pythons +that don't support this PEP and newer Pythons that do, leave the ``import`` +lines in your ``.pth`` file for now. Older, non-supporting Pythons will +execute the ``import`` lines, and newer, supporting Pythons will ignore these +and use the entry points instead. -.. _tool-authors: - -For tool makers ---------------- - -Build backends and installers should generate ``.site.toml`` -files alongside or instead of ``.pth`` files, depending on -the package's Python support matrix. The TOML format is easy to -generate programmatically using ``tomllib`` (for reading) or string -formatting (for writing, since the schema is simple). - -Build backends **SHOULD** ensure that the ```` prefix matches -the package name. - -Installers **MAY** validate or enforce that the ```` prefix -matches the package name. +After the deprecation period, remove all ``import`` lines from your +``.pth`` file. Reference Implementation ========================= -A `reference implementation `_ -is provided as modifications to ``Lib/site.py``, adding the following: - -* ``_SiteTOMLData`` -- a ``__slots__`` class holding parsed data from - a single ``.site.toml`` file (metadata, dirs, init). +.. note:: -* ``_read_site_toml(sitedir, name)`` -- reads and parses a single - ``.site.toml`` file, validates types, and returns a - ``_SiteTOMLData`` instance or ``None`` on error. - -* ``_process_site_toml_paths(toml_data_list, known_paths)`` -- - processes ``[paths].dirs`` from all parsed files, expanding - placeholders and adding directories to ``sys.path`` as appropriate. - -* ``_process_site_toml_entrypoints(toml_data_list)`` -- executes - ``[entrypoints].init`` from all parsed files. - -* Modified ``addsitedir()`` -- orchestrates the three-phase flow: - discover and parse ``.site.toml`` files, process paths and - entry points, then process remaining ``.pth`` files. - -Tests are provided in ``Lib/test/test_site.py`` in the -``SiteTomlTests`` class. + The `reference implementation `_ + conformed to the previous draft of this PEP and has not yet been updated. Rejected Ideas ============== +Just add entry points to ``.pth`` files and leave the ``import`` lines alone + This is rejected on the basis of conflation of intent and the migration + path :ref:`described above `. The principle of separation of + concerns means that it's easy to understand which use case a package is + utilizing. + +``.site.toml`` files + This was the unified new file format proposed in a previous draft of this + PEP. It was generally felt that the structured format of the TOML file + was overkill, and the overhead of parsing a TOML file wasn't worth the + future extensibility benefit. + Single configuration file instead of per-package files - A single site-wide configuration file was considered but rejected - because it would require coordination between independently - installed packages and would not mirror the ``.pth`` - convention that tools already understand. - -JSON instead of TOML - JSON lacks comments and is less human-friendly. TOML is already - the standard configuration format in the Python ecosystem via - ``pyproject.toml``. - -YAML instead of TOML - There is no standard YAML parser in the standard library. - -Python instead of TOML - Python is imperative, TOML is declarative. Thus TOML files are - much more readily validated and reasoned about. - -``$schema`` URL reference - Unlike JSON, TOML has no standard ``$schema`` convention. A - simple integer ``schema_version`` is sufficient and - self-contained. - -Required ``schema_version`` - Requiring ``schema_version`` would make the simplest valid file - more verbose without significant benefit. The - recommended-but-optional - approach balances simplicity with future-proofing. - -Separate ``load`` and ``execute`` keys in ``[entrypoints]`` - Splitting import-only and callable entry points into separate lists - was considered but rejected because it complicates execution - ordering. A single ``init`` list with both forms keeps ordering - explicit. + A single site-wide configuration file was considered but rejected because + it would require coordination between independently installed packages and + would not mirror the ``.pth`` convention that tools already + understand. Priority or weight field for processing order Since packages are installed independently, there is no arbiter of - priority. Alphabetical ordering matches ``.pth`` - behavior. Priority could be addressed by a future site-wide - policy configuration file, not per-package metadata. + priority. Alphabetical ordering matches current ``.pth`` processing + order. Priority could be addressed by a future site-wide policy + configuration file, not per-package metadata. Passing arguments to callables - Callables are invoked with no arguments for simplicity and parity - with existing ``.pth`` import behavior. Future PEPs may - define an optional context argument (e.g., the parsed TOML data or - a site info object). + Callables are invoked with no arguments for simplicity and because there + are no obviously useful arguments to pass to the entry point. +.. _open-issues: Open Issues =========== -* Should a warning be emitted when both ``.pth`` and - ``.site.toml`` coexist? +* As described in the :ref:`entry point syntax ` section, this PEP + proposes to use a narrow definition of the acceptable object reference + syntax implemented by :func:`pkgutil.resolve_name`, i.e. specifically + requiring the ``pkg.mod:callable`` syntax. This is because a) we don't want + to encourage code execution by direct import side-effect (i.e. functionality + at module scope level). -* Should future ``-X`` options provide fine-grained control over - error reporting, unknown table warnings, and entry point execution? + Assuming this restriction is acceptable, how this is implemented is an open + question. ``site.py`` could enforce it directly, but then that sort of + defeats the purpose of using :func:`pkgutil.resolve_name`. The PEP author's + preference would be to add an optional keyword-only argument to + :func:`pkgutil.resolve_name`, i.e. ``strict`` defaulting to ``False`` for + backward compatibility. ``strict=True`` would narrow the acceptable inputs + to effectively ``W(.W)*:(W(.W)*)``, namely, rejecting the older, non-colon + form, and making the callable after the colon required. -* Should callables receive context (e.g., the path to the - ``.site.toml`` file, the parsed TOML data, or a site info object)? +* Should future ``-X`` options provide fine-grained control over error + reporting or entry point execution? -* What additional placeholder variables should be supported beyond - ``{sitedir}``? Candidates include ``{prefix}``, ``{exec_prefix}``, and - ``{userbase}``. +* This PEP does not address the use of ``._pth`` `files + `_ because + the purpose and behavior is completely different, despite the similar name. Change History ============== -None at this time. +XX-XXX-2026 + +* An evolution of the ``.pth`` file format and the addition of the ``.start`` + file for entry point specification is proposed instead of the ``site.toml`` + file from the previous draft. + + +Acknowledgments +=============== + +The PEP author thanks Paul Moore for the constructive and pleasant +conversation leading to the compromise from the first draft of this proposal +to its current form. Thanks also go to Emma Smith and Brett Cannon for their +feedback and encouragement. + + +Footnotes +========= + +None Copyright From ccbffa29b949fb0add8085d9444ce2d28edcdf9c Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 10 Apr 2026 22:06:42 -0700 Subject: [PATCH 2/3] Post-History syntax --- peps/pep-0829.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0829.rst b/peps/pep-0829.rst index 23f38e6470b..f97dfd32de1 100644 --- a/peps/pep-0829.rst +++ b/peps/pep-0829.rst @@ -7,7 +7,7 @@ Type: Standards Track Created: 31-Mar-2026 Python-Version: 3.15 Post-History: - `01-Apr-2026 `_ + `01-Apr-2026 `__ Abstract From 7d4b6d779f9adc8cb1a1cc63fbeb0e9c7f0880d8 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 10 Apr 2026 22:11:22 -0700 Subject: [PATCH 3/3] Fix a cross reference --- peps/pep-0829.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0829.rst b/peps/pep-0829.rst index f97dfd32de1..ffe3897641d 100644 --- a/peps/pep-0829.rst +++ b/peps/pep-0829.rst @@ -111,7 +111,7 @@ This PEP proposes the following: #. *Future extension:* :ref:`apply global policy filter ` on sorted list of entry points. -#. For each entry point, use :func:`pkg.resolve_name` to resolve the entry +#. For each entry point, use :func:`pkgutil.resolve_name` to resolve the entry point into a callable. Call the entry point with no arguments. For both ``.pth`` files and ``.start`` files, comment lines (i.e. lines