-dev or-devel suffixeshost-requires key under[build-system]Requires-External field in Core MetadataThis PEP specifies how to write a project’s external, or non-PyPI, build andruntime dependencies in apyproject.toml file for packaging-related toolsto consume.
This PEP proposes to add an[external] table topyproject.toml withseven keys. “build-requires”, “host-requires” and “dependencies”are for specifying three types ofrequired dependencies:
build-requires, build tools to run on the build machinehost-requires, build dependencies needed for the host machine but also needed at build time.dependencies, needed at runtime on the host machine but not needed at build time.These three keys also have theiroptionalexternal counterparts (optional-build-requires,optional-host-requires,optional-dependencies), which have the same role thatproject.optional-dependencies plays forproject.dependencies. Finally,dependency-groups offers the same functionality asPEP 735 but for externaldependencies.
Cross compilation is taken into account by distinguishing between build and host dependencies.Optional build-time and runtime dependencies are supported too, in a manner analogousto how that is supported in the[project] table.
Python packages may have dependencies on build tools, libraries, command-linetools, or other software that is not present on PyPI. Currently there is no wayto express those dependencies in standardized metadata[1],[2]. Key motivators forthis PEP are to:
Packaging ecosystems like Linux distros, conda, Homebrew, Spack, and Nix needfull sets of dependencies for Python packages, and have tools likepyp2spec(Fedora),Grayskull (conda), anddh_python (Debian) which attempt toautomatically generate dependency metadata for their own package managers from the metadata inupstream Python packages. External dependencies are currently handled manually,because there is no metadata for this inpyproject.toml or any otherstandard location. Other tools resort to extracting dependencies from extensionmodules and shared libraries inside Python packages, likeelfdeps (Fedora).Enabling automating this type of conversion by only using explicitly annotated metadatais a key benefit of this PEP, making packaging Python packages for distros easierand more reliable. In addition, the authors envision other types of toolsmaking use of this information, e.g., dependency analysis tools likeRepology,Dependabot andlibraries.io.
Software bill of materials (SBOM) generation tools may also be able to use thisinformation, e.g. for flagging that external dependencies listed inpyproject.toml but not contained in wheel metadata are likely vendoredwithin the wheel.PEP 770, which standardizes how SBOMs are included inwheels, contains an instructive section on how that PEP differs from this one.
Packages with external dependencies are typically hard to build from source,and error messages from build failures tend to be hard to decipher for endusers. Missing external dependencies on the end user’s system are the mostlikely cause of build failures. If installers can show the required externaldependencies as part of their error message, this may save users a lot of time.
At the moment, information on external dependencies is only captured ininstallation documentation of individual packages. It is hard to maintain forpackage authors and tends to go out of date. It’s also hard for users anddistro packagers to find it. Having a canonical place to record this dependencyinformation will improve this situation.
This PEP is not trying to specify how the external dependencies should be used,nor a mechanism to implement a name mapping from names of individual packagesthat are canonical for Python projects published on PyPI to those of otherpackaging ecosystems. Canonical names and a name mapping mechanism are addressedinPEP 804.
Multiple types of external dependencies can be distinguished:
Concrete packages are straightforward to understand, and are a concept presentin every package management system. Virtual packages are a conceptalso present in a number of packaging systems – but not always, and thedetails of their implementation vary.
Cross compilation is not yet (as of September 2025) well-supported by stdlibmodules andpyproject.toml metadata. It is however important whentranslating external dependencies to those of other packaging systems (withtools likepyp2spec). Introducing support for cross compilation immediatelyin this PEP is much easier than extending[external] in the future, hencethe authors choose to include this now.
This PEP uses the following terminology:
Note that this terminology is not consistent across build and packaging tools,so care must be taken when comparing build/host dependencies inpyproject.toml to dependencies from other package managers.
Note that “target machine” or “target dependency” are not used in this PEP. Thatis typically only relevant for cross-compiling a compiler or other such advancedscenarios[3],[4] – this is out of scope forthis PEP.
Finally, note that while “dependency” is the term most widely used for packagesneeded at build time, the existing key inpyproject.toml for PyPIbuild-time dependencies isbuild-requires. Hence this PEP uses the keysbuild-requires andhost-requires under[external] for consistency.
Clear separation of metadata associated with the definition of build and hostplatforms, rather than assuming that build and host platform will always bethe same, is important[5].
Build dependencies are typically run during the build process - they may becompilers, code generators, or other such tools. In case the use of a builddependency implies a runtime dependency, that runtime dependency does not haveto be declared explicitly. For example, when compiling Fortran code withgfortran into a Python extension module, the package likely incurs adependency on thelibgfortran runtime library. The rationale for notexplicitly listing such runtime dependencies is two-fold: (1) it may depend oncompiler/linker flags or details of the build environment whether thedependency is present, and (2) these runtime dependencies can be detected andhandled automatically by tools likeauditwheel.
Host dependencies are typically not run during the build process, but only usedfor linking against. This is not a rule though – it may be possible ornecessary to run a host dependency under an emulator, or through a custom toollikecrossenv. When host dependencies imply a runtime dependency, that runtimedependency also does not have to be declared, just like for build dependencies.
When host dependencies are declared and a tool which is executing an actionunrelated to cross-compiling, it may decide to merge thehost-requires listintobuild-requires - whether this is useful is context-dependent.
A “Package URL” orPURL is a widely used URL string for identifying packagesthat is meant to be portable across packaging ecosystems. Its design is:
scheme:type/namespace/name@version?qualifiers#subpath
Thescheme component is a fixed string,pkg, and of the othercomponents onlytype andname are required.
Since external dependencies are likely to be typed by hand, we propose a PURLderivative that, in the name of ergonomics and user-friendliness, introduces anumber of changes (further discussed below):
virtual type.version field.In this derivative, we replace thepkg scheme withdep. Hence,we will refer to them as DepURLs.
As an example, a DepURL for therequests package on PyPI would be:
dep:pypi/requests# equivalent to pkg:pypi/requests
Adopting PURL-compatible strings to specify external dependencies inpyproject.toml solves a number of problems at once, and there are alreadyimplementations of the specification in Python and multiple other languages. PURL isalso already supported by dependency-related tooling like SPDX (seeExternal Repository Identifiers in the SPDX 2.3 spec),theOpen Source Vulnerability format,and theSonatype OSS Index;not having to wait years before support in such tooling arrives is valuable.DepURLs are very easily transformed into PURLs, with the exception ofdep:virtual which doesn’t have an equivalent inPURL.
For concrete packages without a canonical package manager to refer to, eitherdep:generic/dep-name can be used, or a direct reference to the VCS systemthat the package is maintained in (e.g.,dep:github/user-or-org-name/dep-name). Which of these is more appropriateis situation-dependent. This PEP recommends usingdep:generic when thepackage name is unambiguous and well-known (e.g.,dep:generic/git ordep:generic/openblas), and using the VCS as the type otherwise. Which nameis chosen as canonical for any given package, as well as the process to makeand record such choices, is the topic ofPEP 804.
PURL does not offer support for virtual or virtual dependency specification yet.Aproposal to add a virtual typeis being discussed for revision 1.1.
In the meantime, we propose adding a newtype to ourdep: derivative, thevirtualtype, which can take twonamespaces (extensible through the process given inPEP 804):
interface: for components such as BLAS or MPI.compiler: for compiled languages like C or Rust.Thename should be the most common name for the interface or language, lowercased.Some examples include:
dep:virtual/compiler/cdep:virtual/compiler/cxxdep:virtual/compiler/rustdep:virtual/interface/blasdep:virtual/interface/lapack
Since there are a limited number of such dependencies, it seems like it will beunderstandable and map well to Linux distros with virtual packages and to thelikes of conda and Spack.
PURLs support fixed versions via the@ component of the URL. For example,numpy===2.0 can be expressed aspkg:pypi/numpy@2.0.
Support in PURL for version expressions and ranges beyond a fixed version isavailable viavers URIs (see specification):
vers:type/version-constraint|version-constraint|...
Users are supposed to couple apkg: URL with avers: URL. For example,to expressnumpy>=2.0, the PURL equivalent would bepkg:pypi/numpy plusvers:pypi/>=2.0. This can be done with:
["pkg:pypi/numpy","vers:pypi/>=2.0"].pkg:pypi/numpy?vers=vers:pypi%2F%3E%3D2.0.Since none of these options are very ergonomic, we chose instead for DepURLsto accept version range specifiers too with semantics that are a subset ofPEP 440 semantics. The allowed operators are those that are widely availableacross package managers (e.g.,==,> and>= are common, while~= isn’t).
Some examples:
dep:pypi/numpy@2.0:numpy pinned at exactly version 2.0.dep:pypi/numpy@>=2.0:numpy with version greater or equal than 2.0.dep:virtual/interface/lapack@>=3.7.1: any package implementing theLAPACK interface for version greater or equal than3.7.1.The versioning scheme for particular virtual packages, in case that isn’tunambiguously defined by an upstream project or standard, will be defined inthe Central Registry (seePEP 804).
Regular environment markers (as originally defined inPEP 508) maybe used behind DepURLs. PURL qualifiers, which use? followed by a packagetype-specific dependency specifier component, should not be used for thepurposes for which environment markers suffice. The reason for this ispragmatic: environment markers are already used for other metadata inpyproject.toml, hence any tooling that is used withpyproject.toml islikely to already have a robust implementation to parse it. And we do notexpect to need the extra possibilities that PURL qualifiers provide (e.g., tospecify a Conan or conda channel, or a RubyGems platform).
We name the combination of a DepURL and environment markers as “externaldependency specifiers”, analogously to the existingdependency specifiers.
-dev(el) split packagesIt is fairly common, but far from universal, for distros to split a packageinto two or more packages. In particular, runtime components are oftenseparately installable from development components (headers, pkg-config andCMake files, etc.). The latter then typically has a name with-dev or-devel appended to the project/library name. Also, larger packages aresometimes split into multiple separate packages to keep install sizesmanageable. More often than not, such package splits are not defined orrecognized by the maintainers of a package, and it’s therefore ambiguous whatany split would mean. Hence, such splits should not be reflected in the[external] table. It is not possible to specify this in a reasonable waythat works across distros, hence only the canonical name should be used in[external].
The intended meaning of using a DepURL is “the full package with the namespecified”. I.e., including all installable artifacts that are part of thepackage. It will depend on the context in which the metadata is used whether apackage split is relevant. For example, iflibffi is a hostdependency and a tool wants to prepare an environment for building a wheel,then if a distro has split off the headers forlibffi into alibffi-devel package then the tool has to install bothlibffi andlibffi-devel.
For defining what canonical package names are and how package splits arehandled in practice when tools attempt to use[external] for installationpurposes, we refer toPEP 804.
Python headers and other build support files may also be split. This is thesame situation as in the section above (because Python is simply a regularpackage in distros).However, apython-dev|devel dependency is special becauseinpyproject.toml Python itself is an implicit rather than an explicitdependency. Hence a choice needs to be made here - addpython-dev implicitly,or make each package author add it explicitly under[external]. Forconsistency between Python dependencies and external dependencies, we choose toadd it implicitly. Python development headers must be assumed to be necessarywhen an[external] table contains one or more compiler packages.
Two new Core Metadata fields are proposed:
Requires-External-Dep. An external requirement. Mimics the transitionfromRequires toRequires-Dist. We chose the-Dep suffix toemphasize that the value is not a regular Python specifier (distribution),but an external dependency specifier containing a DepURL.Provides-External-Extra. Anextra group that carries external dependencies(as found inRequires-External-Dep) only.Since the Core Metadata specification does not contain fields for any metadata inpyproject.toml’s[build-system] table, thebuild-requiresandhost-requires content do not need to be reflected in existing coremetadata fields.
Additionally, this PEP also proposes to deprecate theRequires-External field.The reasons being:
pyproject.toml metadata.setuptools (seepypa/setuptools#4220),hatch (seepypa/hatch#1712),flit (seepypa/flit#353), orpoetrydo not offer ways to specify it or require a plugin (e.g.poetry-external-dependencies).maturin does seem to support it since 0.7.0 (seePyO3/maturin@5b0e4808),but it’s not directly documented. Other backends likescikit-build-core ormeson-python returned no results forExternal-Requires.A wheel may vendor its external dependencies. This happens in particular whendistributing wheels on PyPI or other Python package indexes – and tools likeauditwheel,delvewheel anddelocate automate this process. As a result, aRequires-External-Dep entry in an sdist may disappear from a wheel built fromthat sdist with a tool likecibuildwheel. It is also possible that aRequires-External-Dep entry remains in a wheel, either unchanged or withnarrower constraints.auditwheel does not vendor certain allow-listeddependencies, such as OpenGL, by default. In addition,auditwheel anddelvewheel allow a user to manually exclude dependencies via a--exclude or--no-dll command-line flag. This is used to avoidvendoring large shared libraries, for example those from CUDA.
Requires-External-Dep entries generated from external dependencies inpyproject.toml can therefore differ between an sdist and its correspondingwheel(s) depending on the build/distribution process.
Note that this does not imply that the field must be marked as Dynamic, sincethis distinction only applies to wheels built from an sdist by a build backend.In particular, wheels built from other wheels do not need to satisfy thisconstraint.
This PEP has chosen to include thePEP 735 keydependency-groups underthe[external] table too. This decision is motivated by the need of havingsimilar functionality for external metadata. The top-level table cannot be usedfor external dependencies because it’s expected to have PEP 508 strings (and tablesfor group includes), while we have chosen to rely ondep: URLs for the externaldependencies. Conflating both would raise significant backwards compatibilityissues with existing usage.
Strictly speaking, thedependency-groups schema allows us to define externaldependencies in per-group sub-tables:
[dependency-groups]dev=["pytest",{external=["dep:cargo/ripgrep"]},]
However, this has the same problem: we are mixing different types of dependencyspecifiers in the same data structure. We believe it’s cleaner to separate concernsin different top-level tables, hence why we still prefer to haveexternal.dependency-groups.
The rationale for havingexternal.dependency-groups is identical for therationale given inPEP 735 for introducing[dependency-groups]. Theintended usage and semantics of inclusion/exclusion into Core Metadatais thus identical to[dependency-groups].
external.optional-dependencies will show up in Core Metadata.external.dependency-groups will not.
If metadata is improperly specified then tools MUST raise an error to notifythe user about their mistake.
A DepURL implements a scheme for identifying packages that is meant to beportable across packaging ecosystems. Its design is:
dep:type/namespace/name@version?qualifiers#subpath
dep: is a fixed string, and always present.type andname arerequired, other components are optional. All components apply for both PURLand virtualtype’s, and have these requirements:
type (required): MUST be either aPURLtype, orvirtual.namespace (optional): MUST be aPURLnamespace, or a namespace inthe DepURL central registry (seePEP 804).name (required): MUST be a name that parses as a validPURLname.Tools MAY warn or error if a name is not present in the DepURL centralregistry (seePEP 804).version (optional): MUST be a regularversion specifier (PEP 440semantics) as a single version or version range, with the restriction thatonly the following operators may be used:>=,>,<,<=,==,,.qualifiers (optional): MUST parse as a validPURLqualifier.subpath (optional): MUST parse as a validPURLsubpath.External dependency specifiers MUST contain a DepURL, and MAY containenvironment markers with the same syntax as used in regulardependencyspecifiers (as originally specified inPEP 508).
TheExternal-Requires Core Metadata field will be marked asobsolete and itsusage will be discouraged.
Two new fields are added to Core Metadata:
Requires-External-Dep. An external requirement expressed as an externaldependency specifier string.Provides-External-Extra. Anextra group that carries external dependencies(as found inRequires-External-Dep) only.Given that the proposed changes are purely additive, the Core Metadataversion will be bumped to 2.6.
This will only impact PyPI and tools that want to support external runtime dependencies,and require no changes otherwise.
pyproject.tomlNote thatpyproject.toml content is in the same format as inPEP 621.
Tools MUST specify fields defined by this PEP in a table named[external].No tools may add fields to this table which are not defined by this PEP orsubsequent PEPs. The lack of an[external] table means the package eitherdoes not have any external dependencies, or the ones it does have are assumedto be present on the system already.
build-requires/optional-build-requiresbuild-requires) and atable with values of arrays of external dependency specifiers(optional-build-requires)The (optional) external build requirements needed to build the project.
Forbuild-requires, it is a key whose value is an array of strings. Eachstring represents a build requirement of the project and MUST be formatted asa valid external dependency specifier.
Foroptional-build-requires, it is a table where each key specifies anextra set of build requirements and whose value is an array of strings. Thestrings of the arrays MUST be valid external dependency specifiers.
host-requires/optional-host-requireshost-requires) and atable with values of arrays of external dependency specifiers(optional-host-requires) -Core metadata: N/AThe (optional) external host requirements needed to build the project.
Forhost-requires, it is a key whose value is an array of strings. Eachstring represents a host requirement of the project and MUST be formatted asa valid external dependency specifier.
Foroptional-host-requires, it is a table where each key specifies anextra set of host requirements and whose value is an array of strings. Thestrings of the arrays MUST be valid external dependency specifiers.
dependencies/optional-dependenciesdependencies) and atable with values of arrays of external dependency specifiers(optional-dependencies)Requires-External-Dep,Provides-External-ExtraThe (optional) runtime dependencies of the project.
Fordependencies, it is a key whose value is an array of strings. Eachstring represents a dependency of the project and MUST be formatted as a validexternal dependency specifier. Each string must be added toCore Metadata asaRequires-External-Dep field.
Foroptional-dependencies, it is a table where each key specifies anextraand whose value is an array of strings. The strings of the arrays MUST be validexternal dependency specifiers. For eachoptional-dependencies group:
Provides-External-Extra field.Requires-External-Dep field, with the corresponding;extra=='name' environment marker.dependency-groupsPEP 735 -style dependency groups, but using external dependency specifiersinstead of PEP 508 strings. Every other detail (e.g. group inclusion, namenormalization) follows the officialdependency groups specification.
These examples show what the[external] table content for a number ofpackages, and the correspondingPKG-INFO/METADATA content (if any) isexpected to be.
pyproject.toml content:
[external]build-requires=["dep:virtual/compiler/c","dep:virtual/compiler/rust","dep:generic/pkg-config",]host-requires=["dep:generic/openssl","dep:generic/libffi",]
PKG-INFO /METADATA content: N/A.
pyproject.toml content:
[external]build-requires=["dep:virtual/compiler/c","dep:virtual/compiler/cpp","dep:virtual/compiler/fortran","dep:generic/ninja","dep:generic/pkg-config",]host-requires=["dep:virtual/interface/blas","dep:virtual/interface/lapack@>=3.7.1",]
PKG-INFO /METADATA content: N/A.
pyproject.toml content:
[external]build-requires=["dep:virtual/compiler/c",]host-requires=["dep:generic/libjpeg","dep:generic/zlib",][external.optional-host-requires]extra=["dep:generic/lcms2","dep:generic/freetype","dep:generic/libimagequant","dep:generic/libraqm","dep:generic/libtiff","dep:generic/libxcb","dep:generic/libwebp","dep:generic/openjpeg@>=2.0","dep:generic/tk",]
PKG-INFO /METADATA content: N/A.
pyproject.toml content:
[project.optional-dependencies]r=["rpy2"][external]build-requires=["dep:generic/XCB; platform_system=='Linux'",][external.optional-dependencies]nat=["dep:cran/nat","dep:cran/nat.nblast",]
PKG-INFO /METADATA content:
Provides-External-Extra:natRequires-External-Dep:dep:cran/nat;extra=='nat'Requires-External-Dep:dep:cran/nat.nblast;extra=='nat'
pyproject.toml content:
[external]dependencies=["dep:cargo/ripgrep","dep:cargo/tree-sitter-cli","dep:golang/github.com/junegunn/fzf",]
PKG-INFO /METADATA content:
Requires-External-Dep:dep:cargo/ripgrepRequires-External-Dep:dep:cargo/tree-sitter-cliRequires-External-Dep:dep:golang/github.com/junegunn/fzf
pyproject.toml content:
[external]dependencies=["dep:generic/git",][external.optional-build-requires]dev=["dep:generic/nodejs",]
PKG-INFO /METADATA content:
Requires-External-Dep:dep:generic/git
pyproject.toml content:
[external]dependencies=[# libenchant is needed on all platforms but vendored into wheels# distributed on PyPI for Windows. Hence choose to encode that in# the metadata. Note: there is no completely unambiguous way to do# this; another choice is to leave out the environment marker in the# source distribution and either live with the unnecessary ``METADATA``# entry in the distributed Windows wheels, or to apply a patch to this# metadata when building those wheels."dep:github/AbiWord/enchant; platform_system!='Windows'",]
PKG-INFO /METADATA content:
Requires-External-Dep:dep:github/AbiWord/enchant;platform_system!="Windows"
pyproject.toml content:
[external.dependency-groups]dev=["dep:generic/catch2","dep:generic/valgrind",]
PKG-INFO /METADATA content: N/A.
There is no impact on backwards compatibility, as this PEP only adds new,optional metadata. In the absence of such metadata, nothing changes for packageauthors or packaging tooling.
The only change introduced in this PEP that has impact on existing projects is thedeprecation of theExternal-Requires Core Metadata field. We estimate the impactof this deprecation to be negligible, given the its low penetration in the ecosystem(see Rationale).
The field will still be recognized by existing tools such assetuptools-extbut its usage will be discouraged in thePython Packaging User Guide, similar towhat is done for obsolete fields likeRequires (deprecated in favor ofRequires-Dist).
There are no direct security concerns as this PEP covers how to staticallydefine metadata for external dependencies. Any security issues would stem fromhow tools consume the metadata and choose to act upon it.
External dependencies and if and how those external dependencies are vendoredare topics that are typically not understood in detail by Python packageauthors. We intend to start from how an external dependency is defined, thedifferent ways it can be depended on—from runtime-only withctypes or asubprocess call to it being a build dependency that’s linked against—before going into how to declare external dependencies in metadata. Thedocumentation should make explicit what is relevant for package authors, andwhat for distro packagers.
Material on this topic will be added to the most relevant packaging tutorials,primarily thePython Packaging User Guide. In addition, we expect that anybuild backend that adds support for external dependencies metadata will includeinformation about that in its documentation, as will tools likeauditwheel.
This PEP contains a metadata specification, rather that a code feature - hencethere will not be code implementing the metadata spec as a whole. However,there are parts that do have a reference implementation:
[external] table has to be valid TOML and therefore can be loadedwithtomllib. This table can be further processed with thepyproject-external package, demonstrated below.There are multiple possible consumers and use cases of this metadata, oncethat metadata gets added to Python packages. Tested metadata for all of thetop 150 most-downloaded packages from PyPI with published platform-specificwheels can be found inrgommers/external-deps-build. This metadata hasbeen validated by using it to build wheels from sdists patched with thatmetadata in clean Docker containers.
Given apyproject.toml with this[external] table:
[external]build-requires=["dep:virtual/compiler/c","dep:virtual/compiler/rust","dep:generic/pkg-config",]host-requires=["dep:generic/openssl","dep:generic/libffi",]
You can usepyproject_external.External to parse it and manipulate it:
>>>frompyproject_externalimportExternal>>>external=External.from_pyproject_path("./pyproject.toml")>>>external.validate()>>>external.to_dict(){'external': {'build_requires': ['dep:virtual/compiler/c', 'dep:virtual/compiler/rust', 'dep:generic/pkg-config'], 'host_requires': ['dep:generic/openssl', 'dep:generic/libffi']}}>>>external.build_requires[DepURL(type='virtual', namespace='compiler', name='c', version=None, qualifiers={}, subpath=None), DepURL(type='virtual', namespace='compiler', name='rust', version=None, qualifiers={}, subpath=None), DepURL(type='generic', namespace=None, name='pkg-config', version=None, qualifiers={}, subpath=None)]>>>external.build_requires[0]DepURL(type='virtual', namespace='compiler', name='c', version=None, qualifiers={}, subpath=None)
Note the proposed[external] table was well-formed. With invalid contents such as:
[external]build-requires=["dep:this-is-missing-the-type","pkg:not-a-dep-url"]
You would fail the validation:
>>>external=External.from_pyproject_data( { "external": { "build_requires": [ "dep:this-is-missing-the-type", "pkg:not-a-dep-url" ] } })ValueError: purl is missing the required type component: 'dep:this-is-missing-the-type'.
There are non-Python packages which are packaged on PyPI, such as Ninja,patchelf and CMake. What is typically desired is to use the system version ofthose, and if it’s not present on the system then install the PyPI package forit. The authors believe that specific support for this scenario is notnecessary (or at least, too complex to justify such support); a dependencyprovider for external dependencies can treat PyPI as one possible source forobtaining the package. An example mapping for this use case is proposed inPEP 804.
A previous draft PEP (“External dependencies” (2015))proposed using specific library and header names as external dependencies. Thisis both too granular, and insufficient (e.g., headers are often unversioned;multiple packages may provide the same header or library). Using package namesis a well-established pattern across packaging ecosystems and should bepreferred.
-dev or-devel suffixesThis convention is not consistent across packaging ecosystems, nor commonlyaccepted by upstream package authors. Since the need for explicit control(e.g., installing headers when a package is used as a runtime rather than abuild-time dependency) is quite niche and we don’t want to add designcomplexity without enough clear use cases, we have chosen to rely solely on thebuild,host andrun category split, with tools being in charge ofwhich category applies to each case in a context-dependent way.
If this proves to be insufficient, a future PEP could use the URL qualifierfeatures present in the PURL schema (?key=value) to implement the necessaryadjustments. This can be done in a backwards compatible fashion.
Some ecosystems exhibit methods to select packages based on parametrizedfunctions likecmake("dependency") orcompiler("language"), whichreturn package names based on some additional context or configuration. Thisfeature is arguably not very common and, even when present, rarely used.Additionally, its dynamic nature makes it prone to changing meaning over time,and relying on specific build systems for the name resolution is in general nota good idea.
The authors prefer static identifiers that can be mapped explicitly via wellknown metadata (e.g., as proposed inPEP 804).
Ecosystems that do implement these indirections can use them to support theinfrastructure designed to generate the mappings proposed inPEP 804.
host-requires key under[build-system]Addinghost-requires for host dependencies that are on PyPI in order tobetter support name mapping to other packaging systems with support forcross-compiling seems useful in principle, for the same reasons as this PEPadds ahost-requires under the[external] table. However, it isn’tnecessary to include in this PEP, and hence the authors prefer to keep thescope of this PEP limited - a future PEP on cross compilation may want totackle this.This issuecontains more arguments in favor and against addinghost-requires under[build-system] as part of this PEP.
Requires-External field in Core MetadataTheCore Metadata specification contains one relevant field, namelyRequires-External. While at first sight it would be a good candidate torecord theexternal.dependencies table, the authors have decided to notre-use this field to propagate the external runtime dependencies metadata.
TheRequires-External field has very loosely defined semantics as ofversion 2.4. Essentially:name[(version)][;environmentmarker] (withsquare brackets denoting optional fields). It is not defined what valid stringsforname are; the example in the specification uses both “C” as a languagename, and “libpng” as a package name. Tightening up the semantics would bebackwards incompatible, and leaving it as is seems unsatisfactory. DepURLswould need to be decomposed to fit in this syntax.
There are cases, in particular when dealing with pre-releases, where PEP 440semantics for version comparisons don’t quite work. For example,1.2.3a mayindicate a release subsequent to1.2.3 rather than an alpha version. Tohandle such cases correctly, it would be necessary to allow arbitraryversioning schemes. The authors of this PEP consider the added value ofallowing that is not justified by the additional complexity. If desired, apackage author can use either a code comment or thequalifier field of aDepURL (see the Versioning section under Rationale) to capture this level ofdetail.
None at this time.
pkgconfig specification as analternative toctypes.util.find_library” thread (2023, Discourse):https://discuss.python.org/t/pkgconfig-specification-as-an-alternative-to-ctypes-util-find-library/31379This 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-0725.rst
Last modified:2025-09-29 13:22:31 GMT