Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 804 – An external dependency registry and name mapping mechanism

Author:
Pradyun Gedam <pradyunsg at gmail.com>,Ralf Gommers <ralf.gommers at gmail.com>,Michał Górny <mgorny at quansight.com>,Jaime Rodríguez-Guerra <jaime.rogue at gmail.com>,Michael Sarahan <msarahan at gmail.com>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Packaging
Requires:
725
Created:
03-Sep-2025
Post-History:
22-Sep-2025

Table of Contents

Abstract

This PEP specifies a name mapping mechanism that allows packaging tools to mapexternal dependency identifiers (as introduced inPEP 725) to theircounterparts in other package repositories.

Motivation

Packages on PyPI often require build-time and runtime dependencies that are notpresent on PyPI.PEP 725 introduced metadata to expresssuch dependencies. Using concrete external dependency metadata fora Python package requires mapping the given dependency identifiers to the specifiersused in other ecosystems, which would allow to:

  • Enabling tools to automatically map external dependencies to packages in otherpackaging repositories/ecosystems,
  • Including the needed external dependencieswith the packagenames used by the relevant system package manager on the user’s system inerror messages emitted by Python package installers and build frontends,as well as allowing the user to query for those names directly to obtain installinstructions.

Packaging ecosystems like Linux distros, conda, Homebrew, Spack, and Nix needfull sets of dependencies for Python packages, and have tools likepyp2rpm(Fedora),Grayskull (conda), anddh_python (Debian) which attempt toautomatically generate dependency information from the metadata available inupstream Python packages. Before PEP 725, external dependencies were handled manually,because there was no metadata for this inpyproject.toml or any otherstandard metadata file. Enabling its automatic conversion is a key benefit ofthis PEP, making Python packaging easier and more reliable. In addition, theauthors envision other types of tools making use of this information; e.g.,dependency analysis tools likeRepology,Dependabot andlibraries.io.

Rationale

Prior art

The R language has aSystem Requirements for R packages with a centralregistry that knows how to translate external dependency metadata to installcommands for package managers likeapt-get. This registry centralises themappings for a series of Linux distributions, and also Windows. macOS is notpresent. The“Rule Coverage” of its READMEused to show that this system improves the chance of success of building packagesfrom CRAN from source. Across all CRAN packages,Ubuntu 18 improved from 78.1% to 95.8%, CentOS 7 from 77.8% to 93.7% and openSUSE15.0 from 78.2% to 89.7%. The chance of success depends on how well the registryis maintained, but the gain is significant: ~4x fewer packages fail to build onUbuntu and CentOS in a Docker container.

RPM-based distributions, like Fedora, can use arule-based implementation(NameConvertor) inpyp2rpm. The main rule is that the RPM name for a PyPI package isf"python-{pypi_package_name}". This seems to work quite well; there are afew variants like Python version specific names, where the prefix contains thePython major and minor version numbers (e.g.python311- instead ofpython-).

Gentoo follows a similar approach to naming Python packages, using thedev-python/category and somewell-specified rules.

Conda-forge has a more explicit name mapping, because the base names are thesame in conda-forge as on PyPI (e.g.,numpy maps tonumpy), but thereare many exceptions because of both name collisions and renames (e.g., the PyPIname for PyTorch istorch while in conda-forge it’spytorch). There areseveral name mappings efforts maintained by different teams. Conda-forge’s infrastructuregenerates one inregro/cf-graph-countyfair.Grayskull maintainsits own curated mapping.Prefix.dev created theparselmouth mappingsto support conda and PyPI integrations in their tooling. A more complete overview oftheir approaches, strengths and weaknesses can be found inconda/grayskull#564.

TheOpenStack ecosystem also needs to deal withsome mapping efforts. All of them focus on Linux distributions, exclusively.pkg-mapaccompaniesdiskimage-builder and provides a file format where the user definesarbitrary variable names and their corresponding names in the target distro(Red Hat, Debian, OpenSUSE, etc). Seeexample for PyYAML.bindep defines a filebindep.txt(seeexample)where users can write down dependencies that are not installable from PyPI. The format isline-based, with each line containing a dependency as found in the Debian ecosystem.For other distributions, it offers a “filters” syntax between square brackets where userscan indicate other target platforms, optional dependencies and extras.

The need for mappings is also found in other ecosystems likeSageMath,but also by end-users themselves who want to install PyPI packages with their systempackage manager of choice (example StackOverflow question).

Governance and maintenance costs of name mappings

The maintenance cost of external dependency mappings to a large number of packagingecosystems is potentially high. We choose to define the registry in sucha way that:

  • A central authority maintains the list of recognized DepURLs and theknown ecosystem mappings.
  • The mappings themselves are maintained by the target packaging ecosystems.

Hence this system is opt-in for a given ecosystem, and the associatedmaintenance costs are distributed.

Generating package manager-specific install commands

Python package authors with external dependencies usually have installationinstructions for those external dependencies in their documentation. Theseinstructions are difficult to write and keep up-to-date, and are usually onlycovering one or at most a handful of platforms. As an example, here are SciPy’sinstructions for its external build dependencies (C/C++/Fortran compilers,OpenBLAS, pkg-config):

  • Debian/Ubuntu:sudoaptinstall-ygccg++gfortranlibopenblas-devliblapack-devpkg-configpython3-pippython3-dev
  • Fedora:sudodnfinstallgcc-gfortranpython3-developenblas-devellapack-develpkgconfig
  • CentOS/RHEL:sudoyuminstallgcc-gfortranpython3-developenblas-devellapack-develpkgconfig
  • Arch Linux:sudopacman-Sgcc-fortranopenblaspkgconf
  • Homebrew on macOS:brewinstallgfortranopenblaspkg-config

The package names vary a lot, and there are differences like some distrossplitting off headers and other build-time dependencies in a separate-dev/-devel package while others do not. With the registry in this PEP,this could be made both more comprehensive and easier to maintain through a toolcommand with semantics of“show this ecosystem’s preferred package managerinstall command for all external dependencies”. This may be done as astandalone tool, or as a new subcommand in any Python development workflow tool(e.g., Pip, Poetry, Hatch, PDM, uv).

To this end, each ecosystem mapping can provide a list of package managersknown to be compatible, with templated instructions on how to install and querypackages. The provided install command templates are paired with query command templatesso those tools can check whether the needed packages are already present withouthaving to attempt an install operation (which might be expensive and have unintendedside effects like version upgrades).

Registry design

The mapping infrastructure has been designed to present the following components and properties:

  • A central registry of PEP 725 identifiers (DepURLs), including at least thewell-known generic and virtual identifiers considered canonical.
  • A list of known ecosystems, where ecosystem maintainers can register their name mapping(s).
  • A standardized schema that defines how mappings should be structured. Each mapping canalso provide programmatic details about how their supported package manager(s) work.

The above documents are provided as JSON files validated by accompanying JSON schemas.A Python library and CLI is provided to query and utilize these resources. The user canconfigure which system package manager they prefer to use for the default package mappingsand command generation (e.g. a user on Ubuntu may preferconda,brew orspackinstead ofapt as their package manager of choice to provide external dependencies).

Specification

Three schemas are proposed:

  1. A central registry of known DepURLs, as introduced in PEP 725.
  2. A list of known ecosystems and the canonical URL for their mappings.
  3. The ecosystem-specific mappings of DepURLs to theircorresponding ecosystem specifiers, plus details of their package manager(s).

Central registry

The central registry defines which identifiers are recognized as canonical,plus known aliases. Each entry MUST provide a valid DepURL in thefieldid, with an optional free formdescription text. Additionallyan entry MAY refer to another entry via itsprovides field, which takesa string or a list of strings already defined asid in the registry. This is usefulfor both aliases (e.g.dep:generic/arrow anddep:github/apache/arrow) andconcrete implementations of adep:virtual/ entry (e.g.dep:generic/gccwould providedep:virtual/compiler/c). Entries withoutprovides contentor, if populated, only withdep:virtual/ identifiers, are consideredcanonical. Theprovides field MUST NOT be present indep:virtual/ definitions.

Having a central registry enables the validation of the[external] table.All involved tools MUST check that the provided identifiers are well formed.Additionally, some tools MAY check whether the identifiers in use are recognized ascanonical. More specifically:

  • Build backends, build frontends, and installers SHOULD NOT do any validationof identifiers being canonical by default.
  • Uploaders liketwine SHOULD validate if the identifiers are canonicaland warn or report an error to the user, with opt-out mechanisms. TheySHOULD suggest a canonical replacement, if available.
  • Index servers like PyPI MAY perform the same validation as the uploaders andreject the artifact if necessary.

This registry SHOULD also centralize authoritative decisions about itscontents, such as which entry of a collection of aliases is preferred ascanonical, or which versioning scheme applies to virtual DepURLs (see AppendixB). The corresponding answers are not given in this PEP; instead we delegatethat responsibility to the central registry maintainers.

Mappings

The mappings specify which ecosystem-specific identifiers provide the canonicalentries available in the central registry. A mapping mainly consists of a listof dictionaries, in which each entry consists of:

  • anid field with the canonical DepURL.
  • an optional free formdescription text.
  • aspecs field whose value MUST be one of:
    • a dictionary with three keys (build,host,run). The valuesMUST be a string or list of strings representing the ecosystem-specific packageidentifiers as needed as build-, host- and runtime dependencies (see PEP 725 fordetails on these definitions).
    • for convenience, a string or a list of strings are also accepted as ashorthand form. In this case, the identifier(s) will be used to populatethe three categories mentioned in the item above.
    • an empty list, which is understood as the ecosystem not having packages toprovide such dependency.
  • aspecs_from field whose value is a DepURL from which thespecsfield will be imported. Eitherspecs orspecs_from MUST be present.
  • an optionalurls field whose value MUST be a URL, a list of URLs, or adictionary that maps a string to a URL. This is useful to link to externalresources that provide more information about the mapped packages.

The mappings SHOULD also specify another sectionpackage_managers, reportingwhich package managers are available in the ecosystem and how to use them. This field MUSTtake a list of dictionaries, with each of them reporting the following fields:

  • name (string), unique identifier for this package manager. Usually, the executable name.
  • commands (list of dictionaries), the commands to run to install the mapped package(s) andcheck whether they are already installed.
  • specifier_syntax: instructions on how to map a subset of PEP 440 specifiers tothe target package manager. Three levels of support are offered: name-only, exact-version-only,and version-range compatibility (with per-operator translations).

Each mapping MUST have a canonical URL for online retrieval. These mappingsMAY also be packaged for offline distribution in each platform. The authorsrecommend placing in the standard location for data artifacts in each operatingsystem; e.g.$XDG_DATA_DIRS on Linux and others,~/Library/ApplicationSupport onmacOS, and%LOCALAPPDATA% for Windows. The subdirectory identifier MUSTbeexternal-packaging-metadata-mappings. This data directory SHOULD onlycontain mapping documents named{ecosystem-identifier}.mapping.json. The centralregistry and known ecosystem documents MAY also be distributed in this directory,asregistry.json andknown-ecosystems.json, respectively.

Known ecosystems

The list of known ecosystems has two roles:

  1. Reporting the canonical URL for its mapping.
  2. Assigning a short identifier to each ecosystem. This is the identifierthat MUST be used in the mapping filenames mentioned above so they can befound in the local filesystem.

For ecosystems corresponding to Linux distributions, the identifier MUST be theone reported by theiros-releaseID parameter. For other ecosystems, it MUST be decided during the submission tothe list of known ecosystems document. It MUST only use the characters allowed inos-release’sID field, as per this regex[a-z0-9\-_.]+.

Schema details

Three JSON Schema documents are provided to fully standardize the registries and mappings.

Central registry schema

The central registry is specified by the followingJSON schema:

$schema
Typestring
DescriptionURL of the definition list schema in use for the document.
RequiredFalse
schema_version
Typeinteger
RequiredFalse
definitions
Typearray
DescriptionList of DepURLs currently recognized.
RequiredTrue

Each entry in this list is defined as:

FieldTypeDescriptionRequired
idDepURLField (string matching regex^dep:.+$)DepURLTrue
descriptionstringFree-form field to add some details about the package. Allows Markdown.False
providesDepURLField|list[DepURLField]List of identifiers this entry connects to.Useful to annotate aliases or virtual package implementations.False
urlsAnyUrl|list[AnyUrl]|dict[NonEmptyString,AnyUrl]Hyperlinks to web locations that provide more information about the definition.False

Known ecosystems schema

The known ecosystems list is specified by the followingJSON Schema:

$schema
Typestring
DescriptionURL of the mappings schema in use for the document.
RequiredFalse
schema_version
Typeinteger
RequiredFalse
ecosystems
Typedict
DescriptionEcosystems names and their corresponding details.
RequiredTrue

This dictionary maps non-empty string keys referring to the ecosystem identifiersto a sub-dictionary defined as:

KeyValue typeValue descriptionRequired
Literal['mapping']AnyURLURL to the mapping for this ecosystemTrue

Mappings schema

The mappings are specified by the followingJSON Schema:

$schema
Typestring
DescriptionURL of the mappings schema in use for the document.
RequiredFalse
schema_version
Typeinteger
RequiredFalse
name
Typestring
DescriptionName of the schema
RequiredTrue
description
Typestring|None
DescriptionFree-form field to add information this mapping. AllowsMarkdown.
RequiredFalse
mappings
Typearray
DescriptionList of DepURL-to-specs mappings.
RequiredTrue

Each entry in this list is defined as:

FieldTypeDescriptionRequired
idDepURLField (string matching regex^dep:.+$)DepURL, as provided in the central registryTrue
descriptionstringFree-form field to add some details about the package. Allows Markdown.False
urlsAnyUrl|list[AnyUrl]|dict[NonEmptyString,AnyUrl]Hyperlinks to web locations that provide more information about the definition.False
specsstring|list[string]|dict[Literal['build','host','run'],string|list[string]]Ecosystem-specific identifiers for this package. The full form is a dictionarythat maps the categoriesbuild,host andrun to their correspondingpackage identifiers. As a shorthand, a single string or a list of strings can beprovided, in which case will be used to populate the three categories identically.Eitherspecs orspecs_from MUST be present.
specs_fromDepURLField (string matching regex^dep:.+$)Take specs from another mapping entry.Eitherspecs orspecs_from MUST be present.
extra_metadatadict[NonEmptyString,Any]Free-form key-value store for arbitrary metadata.False
package_managers
Typearray
DescriptionList of tools that can be used to install packages in thisecosystem.
RequiredTrue

Each entry in this list is defined as a dictionary with these fields:

FieldTypeDescriptionRequired
namestringShort identifier for this package manager (usually the command name)True
commandsdict[Literal['install','query'],dict[Literal['command','requires_elevation','multiple_specifiers'],list[str]|bool|Literal['always','name-only','never']]]Commands used to install or query the given package(s). Only two keysare allowed:install andquery. Their value is a dictionarywith:
  • a required keycommand that takes a list of strings(as expected bysubprocess.run).
  • an optionalrequires_elevation boolean (False by default)to indicate whether the command must run with elevated permissions(e.g. administrator on Windows, superuser on Linux and macOS).
  • an enummultiple_specifiers that determines whether the commandaccepts multiple package specifiers at the same time, accepting one of:
    • always, default ininstall.
    • name-only, the command only accepts multiple specifiers if they donot contain version constraints.
    • never, default inquery.

Exactly one of thecommand items MUST include a{} placeholder,which will be replaced by the mapped package identifier(s). Theinstall command SHOULD support the placeholder being replaced bymultiple identifiers,query MUST only receive a single identifierper command.

True
specifier_syntaxdict[Literal['name_only','exact_version','version_ranges'],None|list[str]|dict[Literal['and','equal','greater_than','greater_than_equal','less_than','less_than_equal','not_equal','syntax'],None|str|list[str]]Mapping of allowed PEP440 version specifiers to the syntax used in thispackage manager. Three top-level keys are expected and required:
  • name_only MUST take a list of strings as the syntax used for specifiersthat do not contain any version information; it MUST include the placeholder{name}.
  • exact_version MUST beNone or a list of strings that describethe syntax used for specifiers that only express exact versionconstraints; in the latter case, the placeholders{name}and{version} MUST be present in at least one of the strings(although not necessary the same string for both).
  • version_ranges MUST beNone or a dictionary with thefollowing required keys:
    • the keysyntax takes a list of strings where at least one MUSTinclude the{ranges} placeholder (to be replaced by themaybe-joined version constraints, as determined by the value ofand). They MAY also include the{name} placeholder.
    • the keysequal,greater_than,greater_than_equal,less_than,less_than_equal, andnot_equal take a stringif the operator is supported,None otherwise. In the former case,the value MUST include the{version} placeholder, and MAY include{name}.
    • the key{and} takes a string used to join multiple versionconstraints in a single token, orNone if only a singleconstraint can be used per token. In the latter case, the differentconstraints will be “exploded” into several tokens using thesyntax template.

    Whenexact_version orversion_ranges are set toNone, itindicates that the respective types of specifiers are not supportedby the package manager.

True

Examples

Registry, known ecosystems and mappings

A simplified registry would look like this:

{"$schema":"https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/central-registry.schema.json","schema_version":1,"definitions":[{"id":"dep:generic/zlib","description":"A Massively Spiffy Yet Delicately Unobtrusive Compression Library"},{"id":"dep:generic/libwebp","description":"WebP codec is a library to encode and decode images in WebP format. This package contains the library that can be used in other programs to add WebP support"},{"id":"dep:generic/clang","description":"Language front-end and tooling infrastructure for languages in the C language family for the LLVM project."}]}

A minimal list of known ecosystems with a single entry would look like this:

{"$schema":"https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/known-ecosystems.schema.json","schema_version":1,"ecosystems":{"conda-forge":{"mapping":"https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/refs/heads/main/data/conda-forge.mapping.json"}}

That hypothetical conda-forge mapping (conda-forge.mapping.json), with only a couple entriesfor brevity, could look like:

{"schema_version":1,"name":"conda-forge","description":"Mapping for the conda-forge ecosystem","mappings":[{"id":"dep:generic/zlib","description":"zlib data compression library for the next generation systems. From zlib-ng/zlib-ng.","specs":"zlib-ng",// Simplest form"urls":{"feedstock":"https://github.com/conda-forge/zlib-ng-feedstock"}},{"id":"dep:generic/libwebp","description":"WebP image library. libwebp-base ships libraries; libwebp ships the binaries.","specs":{// expanded form with single spec per category"build":"libwebp","host":"libwebp-base","run":"libwebp"},"urls":{"feedstock":"https://github.com/conda-forge/libwebp-feedstock"}},{"id":"dep:generic/clang","description":"Development headers and libraries for Clang","specs":{// expanded form with specs list"build":["clang","clangxx"],"host":["clangdev"],"run":["clang","clangxx","clang-format","clang-tools"]},"urls":{"feedstock":"https://github.com/conda-forge/clangdev-feedstock"}},],"package_managers":[{"name":"conda","commands":{"install":{"command":["conda","install","{}"],"multiple_specifiers":"always","requires_elevation":false,},"query":{"command":["conda","list","-f","{}"],"multiple_specifiers":"never","requires_elevation":false,}},"specifier_syntax":{"exact_version":["{name}=={version}"],"name_only":["{name}"],"version_ranges":{"and":",","equal":"={version}","greater_than":">{version}","greater_than_equal":">={version}","less_than":"<{version}","less_than_equal":"<={version}","not_equal":"!={version}","syntax":["{name}{ranges}"]}}}]}

The following repository provides examples of how these schemascould look like in real cases.They are not meant to be prescriptive, but just illustrative of how to apply these schemas:

pyproject-external CLI

The following examples illustrate how the name mapping mechanism may be used.They use the CLI implemented as part of thepyproject-external package.

Say we have cloned the source of a Python package namedmy-cxx-pkg with asingle extension module, implemented in C++, linking tozlib, usingpybind11,plusmeson-python as the build backend:

[build-system]build-backend='mesonpy'requires=["meson-python>=0.13.1","pybind11>=2.10.4",][external]build-requires=["dep:virtual/compiler/cxx",]host-requires=["dep:generic/zlib",]

With complete name mappings forapt on Ubuntu, this may then show thefollowing:

# show all external dependencies as DepURLs$python-mpyproject_externalshow.[external]build-requires=["dep:virtual/compiler/cxx",]host-requires=["dep:generic/zlib",]# show all external dependencies, but mapped to the autodetected ecosystem$python-mpyproject_externalshow--output=mapped.[external]build_requires=["g++","python3",]host_requires=["zlib1g","zlib1g-dev",]# show how to install external dependencies$python-mpyproject_externalshow--output=command.sudoaptinstall--yesg++zlib1gzlib1g-devpython3

We have not yet run those install commands, so the external dependency may bemissing. If we get a build failure, the output may look like:

$ pip install ....× Encountered error while generating package metadata.╰─> See above for output.note: This is an issue with the package mentioned above, not pip.This package has the following external dependencies, if those are missingon your system they are likely to be the cause of this build failure:  dep:virtual/compiler/cxx  dep:generic/zlib

If Pip has implemented support for querying the name mapping registry, the endof that message could improve to:

Thefollowingexternaldependenciesareneededtoinstallthepackagementionedabove.Youmayneedtoinstallthemwith`apt`:g++zlib1gzlib1g-dev

If the user wants to use conda packages and themamba package manager toinstall external dependencies, they may specify that in their~/.config/pyproject-external/config.toml (or equivalent) file:

preferred_package_manager="mamba"

This will then change the output ofpyproject-external:

$python-mpyproject_externalshow--outputcommand.mambainstall--yes--channel=conda-forge--channel-priority=strictcxx-compilerzlibpython

Thepyproject-external CLI also provides a simple way to perform[external] table validation against the central registry to checkwhether the identifiers are considered canonical or not:

$python-mpyproject_externalshow--validategrpcio-1.71.0.tar.gzWARNINGDepURL'dep:virtual/compiler/cpp'isnotrecognizedinthecentralregistry.Didyoumeananyof['dep:virtual/compiler/c','dep:virtual/compiler/cxx','dep:virtual/compiler/cuda','dep:virtual/compiler/go','dep:virtual/compiler/c-sharp']?[external]build-requires=["dep:virtual/compiler/c","dep:virtual/compiler/cpp",]

pyproject-external API

Thepyproject-external Python API also allows users to do these operations programmatically:

>>>frompyproject_externalimportExternal>>>external=External.from_pyproject_data(      {        "external": {          "build-requires": [            "dep:virtual/compiler/c",            "dep:virtual/compiler/cpp",          ]        }      }    )>>>external.validate()Dep URL 'dep:virtual/compiler/cpp' is not recognized in the central registry. Did youmean any of ['dep:virtual/compiler/c', 'dep:virtual/compiler/cxx','dep:virtual/compiler/cuda', 'dep:virtual/compiler/go', 'dep:virtual/compiler/c-sharp']?>>>external=External.from_pyproject_data(      {        "external": {          "build-requires": [            "dep:virtual/compiler/c",            "dep:virtual/compiler/cxx",  # fixed          ]        }      }    )>>>external.validate()>>>external.to_dict(){'external': {'build_requires': ['dep:virtual/compiler/c', 'dep:virtual/compiler/cxx']}}>>>frompyproject_externalimportdetect_ecosystem_and_package_manager>>>ecosystem,package_manager=detect_ecosystem_and_package_manager()>>>ecosystem'conda-forge'>>>package_manager'pixi'>>>external.to_dict(mapped_for=ecosystem,package_manager=package_manager){'external': {'build_requires': ['c-compiler', 'cxx-compiler', 'python']}}>>>external.install_command(ecosystem,package_manager=package_manager)# {"command": ["pixi", "add", "{}"]}['pixi', 'add', 'c-compiler', 'cxx-compiler', 'python']>>>external.query_commands(ecosystem,package_manager=package_manager)# {"command": ["pixi", "list", "{}"]}[  ['pixi', 'list', 'c-compiler'],  ['pixi', 'list', 'cxx-compiler'],  ['pixi', 'list', 'python'],]

Grayskull

A prototype proof of concept implementation was contributed to Grayskull, a conda recipe generator forPython packages, viaconda/grayskull#518.

In order to use the name mappings for the recipe generator of our package, wecan now runGrayskull:

$ grayskull pypi my-cxx-pkg#### Initializing recipe for my-cxx-pkg (pypi) ####Recovering metadata from pypi...Starting the download of the sdist package my-cxx-pkgmy-cxx-pkg 100% Time:  0:00:10   5.3 MiB/s|###########|Checking for pyproject.toml...Build requirements:  - python                                 # [build_platform != target_platform]  - cross-python_{{ target_platform }}     # [build_platform != target_platform]  - meson-python >= 0.13.1                 # [build_platform != target_platform]  - pybind11 >= 2.10.4                     # [build_platform != target_platform]  - ninja                                  # [build_platform != target_platform]  - libboost-devel                         # [build_platform != target_platform]  - {{ compiler('cxx') }}Host requirements:  - python  - meson-python >=0.13.1  - pybind11 >=2.10.4  - ninja  - libboost-develRun requirements:  - python#### Recipe generated on /path/to/recipe/dir for my-cxx-pkg ####

Backwards Compatibility

There is no impact on backwards compatibility.

Security Implications

This proposal does not impose any security implications on existing projects.The proposed schemas, registries and mappings are available resources for downstreamtooling to use at their own will, in whatever way they find suitable.

We do have some recommendations for future implementors. The mapping schemaproposes fields to encode instructions for command execution(package_managers[].commands). A tampered mapping may change theseinstructions into something else. Hence, tools should not rely on internetconnectivity to fetch the mappings from their online sources. Instead:

  • they should vendor the relevant documents in the distributed packages,
  • or depend on prepackaged, offline distributions of these documents,
  • or implement best-practices for authenticity verification of the fetched documents.

The install commands have the potential to modify the system configuration of the user.When available, tools should prefer creating ephemeral, isolated environments for theinstallation of external dependencies. If the ecosystem lacks that feature natively,other solutions like containerization may be used. At the very least, informative messagingof the impact of the operation should be provided.

How to Teach This

There are at least four audiences that may need to get familiar with the contents of this PEP:

  1. Central registry maintainers, who are responsible for curating the list ofwell-known DepURLs and mapped ecosystems.
  2. Packaging ecosystem maintainers, who are responsible for keeping themapping for their ecosystem up-to-date.
  3. Maintainers of Python projects that require external dependencies.
  4. End users of packages that have external dependency metadata.

Central DepURL registry maintainers

Central DepURL registry maintainers curate the collection of DepURLs and theknown ecosystems. These contributors need to be able to refer to clearlydefined rules for when a new DepURL can be defined. It is undesirable to beloose with canonical DepURL definitions, because each definition added increasesmaintenance effort in the mappings in the target ecosystems.

The central registry maintainers should agree on the ground rules and write themdown as part of the repository documentation, perhaps supported by additionalaffordances like issue and pull request templates, or linting tools.

Package ecosystem maintainers usage

Missing mapping entries will result in the absence tailored error messages andother UX affordances for end users of the impacted ecosystems. It is thusrecommended that each package ecosystem keeps their mappings up-to-date withthe central registry. The key to this will be automation, like linting scripts(see example atexternal-metadata-mappings),or periodic notifications via issues or draft submissions.

Establishing the initial mapping is likely to involve a lot of work, but ideally the maintenance on an ongoing basis effort should require smaller effort.

As best practices are discovered and agreed on, they should get documentedin the central registry repository as learning materials for the mappingmaintainers.

Maintainers of Python projects

A package maintainer’s responsibility is to decide the DepURL that bestrepresents the external dependency that their package needs. This is coveredinPEP 725; the interactive mappings browser demo located atexternal-metadata-mappings.streamlit.appmay come handy. The central registry documentation may include examples andfrequently asked questions to guide newcomers with their decisions.

If no suitable DepURL is available for a given dependency, maintainers mayconsider submitting a request in the central registry. Instructions on how to dothis should be provided as part of the central registry documentation.

End user package consumers

There will be no change in the user experience by default. This is particularlytrue if the user only relies on wheels, since the only impact will be driven byexternal runtime dependencies (expected to be rare), and even in those casesthey need to opt-in by installing a compatible tool.

Users that do opt-in may find missing entries in for their target ecosystems, forwhich they should obtain informative error messages that point to the relevantdocumentation sections. This will allow them to get acquainted with the natureof the issue and its potential solutions.

We hope that this results in a subset of them reporting the missing entries,submitting a fix to the affected mapping or, if totally absent, even decidingto maintain a new one on their own. To that end, they should get familiar withthe responsibilties of mapping maintainers (discussed above).

Reference Implementation

A reference implementation should include three components:

  1. A central registry that captures at a minimum a DepURL and its description. This registry MUSTNOT contain specifics of package ecosystem mappings.
  2. A standard specification for a collection of mappings. JSON Schema is widely used for schemain many text editors, and would be a natural choice for expression of the standard specification.
  3. An implementation of (2), providing mappings from the contents of the centralregistry to the ecosystem-specific package names.

For (1), the JSON Schema is defined atcentral-registry.schema.json.An example registry can be found atregistry.json.For (2), the JSON Schema is defined atexternal-mapping.schema.json.A collection of example mappings for a sample of packages can be found atexternal-metadata-mappings.For (3), the JSON Schema is defined atknown-ecosystems.schema.json.An example list can be found atknown-ecosystems.json.The JSON Schemas are created withthese Pydantic models.

The reference CLI and Python API to consume the different JSON documents and[external] tablescan be found inpyproject-external.

Rejected Ideas

Centralized mappings governed by the same body

While a central authority for the registry is useful, the maintenance burdenof handling the mappings for multiple ecosystems is unfeasible at the scale of PyPI.Hence, we propose that the central authority only governs the central registry andthe list of known ecosystems, while the maintenance of the mappings themselves is handledby the target ecosystems.

Allowing ecosystem-specific variants of packages

Some ecosystems have their own variants of known packages; e.g. Debian’slibsymspg2-dev. While an identifier such asdep:debian/libsymspg2-devis syntactically valid, the central registry should not recognize it as awell-known identifier, preferring itsgeneric counterpart instead. Usersmay still choose to use it, but tools may warn about it and suggest using thegeneric one. This is meant to encourage ecosystem-agnostic metadata wheneverpossible to facilitate adoption across platforms and operating systems.

Adding more package metadata to the central registry

A central registry should only contain a list of DepURLs and aminimal set of metadata fields to facilitate its identification (a free-formtext description, and one or more URLs to relevant locations).

We have chosen to leave additional details out of the central registry, and insteadsuggest external contributors to maintain their own mappings where they canannotate the identifiers with extra metadata via the free-formextra_metadata field.

The reasons include:

  • The existing fields should be sufficient to identify the project home,where that extra metadata can be obtained (e.g. the repository at the URL will likelyinclude details about authorship and licensing).
  • These details can also be obtained from the actual target ecosystems. In somecases this might even be preferable; e.g., for licenses, where downstream packagingcan actually affect it by unvendoring dependencies or adjusting optional bits.
  • Those details may change over the lifetime of the project, and keeping themup-to-date would increase the maintenance burden on the governance body.
  • Centralizing additional metadata would hence introduce ambiguities anddiscrepancies across target ecosystems, where different versions may beavailable or required.

Mapping PyPI projects to repackaged counterparts in target ecosystems

It is common that other ecosystems redistribute Python projects with their ownpackaging system. While this is required for packages with compiled extensions, itis theoretically unnecessary for pure Python wheels; the only need for this seems tobe metadata translation. SeeWanting a singular packaging tool/vision #68,Wanting a singular packaging tool/vision #103,andspack/spack#28282for examples of discussions in this direction.

The proposals in this PEP do not consider PyPI ->ecosystem mappings, butthe same schemas can be repurposed to that end. After all, it is trivial to build a PURL orDepURL from a PyPI name (e.g.numpy becomespkg:pypi/numpy). A hypotheticalmapping maintainer could annotate their repackaging efforts with the source PURL identifier,and then use that metadata to generate compatible mappings, such as:

{"$schema":"https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/external-mapping.schema.json","schema_version":1,"name":"PyPI packages in Ubuntu 24.04","description":"PyPI mapping for the Ubuntu 24.04 LTS (Noble) distro","mappings":[{"id":"dep:pypi/numpy","description":"The fundamental package for scientific computing with Python","specs":["python3-numpy"],"urls":{"home":"https://numpy.org/"}}]}

Such a mapping would allow downstream redistribution efforts to focus on thecompiled packages and instead delegate pure wheels to Python packagingsolutions directly.

Strict validation of identifiers

The central registry provides a list of canonical identifiers, which may temptimplementors into ensuring that all supplied identifiers are indeed canonical. Wehave decided to onlyrecommend this practice for some tool categories, but in nocaserequire such checks.

It is expected that as the[external] metadata tables are adopted by thepackaging community, thecanonical identifier list grows to accommodate therequirements found in different projects. For example, a new C++ library or anew language compiler are introduced.

If validation is made too strict and rejects unknown identifiers, this wouldintroduce unnecessary friction in the external metadata adoption, and requirehuman interaction to review and accept the newly requested identifiers ina time-critical manner, potentially blocking publication of the packagethat needs a new identifier added to the central registry.

We suggest simply checking that the provided identifiers are well-formed. Futurework may choose to also enforce that the identifiers are recognized as canonical,once the central registry has matured with significant adoption.

Open Issues

None at this time.

References

Appendix A: Operational suggestions

In contrast with the ecosystem mappings, the central registry and the list of knownecosystems need to be maintained by a central authority. The authors propose to:

  • Host theexternal-metadata-mappings andpyproject-external repositories under thePyPAGitHub organization (or equivalent as perPEP 772).
  • Create a maintainers team for these two repositories, seeded with the authors of this PEP andregulated as perPEP 772.

Appendix B: Virtual versioning proposal

While virtual dependencies can be versioned with the same syntax as non-virtualdependencies, its meaning can be ambiguous (e.g. there can be multipleimplementations, and virtual interfaces may not be unambiguously versioned).Below we provide some suggestions for the central registry maintainers toconsider when standardizing such meaning:

  • OpenMP: has regularMAJOR.MINOR versions of its standard, so would looklike>=4.5.
  • BLAS/LAPACK: should use the versioning used byReference LAPACK, whichdefines what the standard APIs are. UsesMAJOR.MINOR.MICRO, so would looklike>=3.10.0.
  • Compilers: these implement language standards. For C, C++ and Fortran theseare versioned by year. In order for versions to sort correctly, we recommendusing the full year (four digits). So “at least C99” would be>=1999, andselecting C++14 or Fortran 77 would be==2014 or==1977 respectively.Other languages may use different versioning schemes. These should bedescribed somewhere before they are used inpyproject.toml.

Copyright

This document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.


Source:https://github.com/python/peps/blob/main/peps/pep-0804.rst

Last modified:2025-09-29 13:54:43 GMT


[8]ページ先頭

©2009-2025 Movatter.jp