Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 633 – Dependency specification in pyproject.toml using an exploded TOML table

Author:
Laurie Opperman <laurie_opperman at hotmail.com>,Arun Babu Neelicattu <arun.neelicattu at gmail.com>
Sponsor:
Brett Cannon <brett at python.org>
Discussions-To:
Discourse thread
Status:
Rejected
Type:
Standards Track
Topic:
Packaging
Created:
02-Sep-2020
Post-History:
02-Sep-2020
Resolution:
Discourse message

Table of Contents

Rejection Notice

This PEP has been rejected in favour ofPEP 631 due to its popularity,consistency with the existing usage ofPEP 508 strings, and compatibilitywith existing packaging tool suites.

Abstract

This PEP specifies how to write a project’s dependencies in apyproject.toml file for packaging-related tools to consume using the fieldsdefined inPEP 621, as an alternative to thePEP 508-based approachdefined inPEP 631.

Motivation

There are multiple benefits to using TOML tables and other data-types torepresent requirements rather thanPEP 508 strings:

  • Easy initial validation via the TOML syntax.
  • Easy secondary validation using a schema, for example aJSON Schema.
  • Potential for users to guess the keys of given features, rather thanmemorising a syntax.
  • Users of multiple other popular languages may already be familiar with theTOML syntax.
  • TOML directly represents the same data structures as in JSON, and therefore asub-set of Python literals, so users can understand the hierarchy and type ofvalue

Rationale

Most of this is taken from discussions in thePEP 621 dependencies topic.This has elements fromPipfile,Poetry,Dart’s dependencies andRust’s Cargo. Acomparison document shows advantages and disadvantagesbetween this format andPEP 508-style specifiers.

In the specification of multiple requirements with the same distribution name(where environment markers choose the appropriate dependency), the chosensolution is similar toPoetry’s, where an array of requirements is allowed.

The direct-reference keys closely align with and utilisePEP 610 andPEP 440 as to reduce differences in the packaging ecosystem and rely onprevious work in specification.

Specification

As inPEP 621, if metadata is improperly specified then tools MUST raise anerror. The metadata MUST conform to theTOML specification.

To reduce confusion with this document being a specification for specifyingdependencies, the word “requirement” is used to mean aPEP 508 dependencyspecification.

The following tables are added to theproject table specified inPEP 621.

dependencies

Format: table

The keys inside this table are the names of the required distribution. Thevalues can have one of the following types:

  • string: the requirement is defined only by a version requirement, with samespecification asversion in the requirement table, except allowing theempty string"" to place no restriction on the version.
  • table: a requirement table.
  • array: an array of requirement tables. It is an error to specify an emptyarray[] as a value.

Requirement table

The keys of the requirement table are as follows (all are optional):

  • version (string): aPEP 440 version specifier, which is acomma-delimited list of version specifier clauses. The string MUST benon-empty.
  • extras (array of strings): a list ofPEP 508 extras declarations forthe distribution. The list MUST be non-empty.
  • markers (string): aPEP 508 environment marker expression. The stringMUST be non-empty.
  • url (string): the URL of the artifact to install and satisfy therequirement. Note thatfile:// is the prefix used for packages to beretrieved from the local filesystem.
  • git,hg,bzr orsvn (string): the URL of a VCS repository(as specified inPEP 440)to clone, whose tree will be installed to satisfy the requirement. FurtherVCS keys will be added via amendments toPEP 610, however tools MAY opt tosupport other VCS’s using their command-line command prior to the acceptanceof the amendment.
  • revision (string): the identifier for a specific revision of thespecified VCS repository to check-out before installation. Users MUST onlyprovide this when one ofgit,hg,bzr,svn, or another VCSkey is used to identify the distribution to install. Revision identifiers aresuggested inPEP 610.

At most one of the following keys can be specified simultaneously, as theylogically conflict with each other in the requirement:version,url,git,hg,bzr,svn, and any other VCS key.

An empty requirement table{} places no restriction on the requirement, inaddition to the empty string"".

Any keys provided which are not specified in this document MUST cause an errorin parsing.

optional-dependencies

Format: table

The keys inside this table are the names of an extra’s required distribution.The values can have one of the following types:

  • table: a requirement table.
  • array: an array of requirement tables.

These requirement tables havethe same specification as above, with the addition ofthe following required key:

  • for-extra (string): the name of thePEP 508 extra that thisrequirement is required for.

Reference implementation

Tools will need to convert this format toPEP 508 requirement strings. Belowis an example implementation of that conversion (assuming validation is alreadyperformed):

defconvert_requirement_to_pep508(name,requirement):ifisinstance(requirement,str):requirement={"version":requirement}pep508=nameif"extras"inrequirement:pep508+=" ["+", ".join(requirement["extras"])+"]"if"version"inrequirement:pep508+=" "+requirement["version"]if"url"inrequirement:pep508+=" @ "+requirement["url"]forvcsin("git","hg","bzr","svn"):ifvcsinrequirement:pep508+=" @ "+vcs+"+"+requirement[vcs]if"revision"inrequirement:pep508+="@"+requirement["revision"]extra=Noneif"for-extra"inrequirement:extra=requirement["for-extra"]if"markers"inrequirement:markers=requirement["markers"]ifextra:markers="extra = '"+extra+"' and ("+markers+")"pep508+="; "+markersreturnpep508,extradefconvert_requirements_to_pep508(dependencies):pep508s=[]extras=set()forname,reqindependencies.items():ifisinstance(req,list):forsub_reqinreq:pep508,extra=convert_requirement_to_pep508(name,sub_req)pep508s.append(pep508)ifextra:extras.add(extra)else:pep508,extra=convert_requirement_to_pep508(name,req)pep508s.append(pep508)ifextra:extras.add(extra)returnpep508s,extrasdefconvert_project_requirements_to_pep508(project):reqs,_=convert_requirements_to_pep508(project.get("dependencies",{}))optional_reqs,extras=convert_requirements_to_pep508(project.get("optional-dependencies",{}))reqs+=optional_reqsreturnreqs,extras

JSON schema

For initial validation, a JSON-schema can be used. Not only does this helptools have a consistent validation, but it allows code editors to highlightvalidation errors as users are building the dependencies list.

{"$id":"spam","$schema":"http://json-schema.org/draft-07/schema#","title":"Project metadata","type":"object","definitions":{"requirementTable":{"title":"Full project dependency specification","type":"object","properties":{"extras":{"title":"Dependency extras","type":"array","items":{"title":"Dependency extra","type":"string"}},"markers":{"title":"Dependency environment markers","type":"string"}},"propertyNames":{"enum":["extras","markers","version","url","git","hg","bzr","svn","for-extra"]},"oneOf":[{"title":"Version requirement","properties":{"version":{"title":"Version","type":"string"}}},{"title":"URL requirement","properties":{"url":{"title":"URL","type":"string","format":"uri"}},"required":["url"]},{"title":"VCS requirement","properties":{"revision":{"title":"VCS repository revision","type":"string"}},"oneOf":[{"title":"Git repository","properties":{"git":{"title":"Git URL","type":"string","format":"uri"}},"required":["git"]},{"title":"Mercurial repository","properties":{"hg":{"title":"Mercurial URL","type":"string","format":"uri"}},"required":["hg"]},{"title":"Bazaar repository","properties":{"bzr":{"title":"Bazaar URL","type":"string","format":"uri"}},"required":["bzr"]},{"title":"Subversion repository","properties":{"svn":{"title":"Subversion URL","type":"string","format":"uri"}},"required":["svn"]}]}]},"requirementVersion":{"title":"Version project dependency specification","type":"string"},"requirement":{"title":"Project dependency specification","oneOf":[{"$ref":"#/definitions/requirementVersion"},{"$ref":"#/definitions/requirementTable"},{"title":"Multiple specifications","type":"array","items":{"$ref":"#/definitions/requirementTable"},"minLength":1}]},"optionalRequirementTable":{"title":"Project optional dependency specification table","allOf":[{"$ref":"#/definitions/requirementTable"},{"properties":{"for-extra":{"title":"Dependency's extra","type":"string"}},"required":["for-extra"]}]},"optionalRequirement":{"title":"Project optional dependency specification","oneOf":[{"$ref":"#/definitions/optionalRequirementTable"},{"title":"Multiple specifications","type":"array","items":{"$ref":"#/definitions/optionalRequirementTable"},"minLength":1}]}},"properties":{"dependencies":{"title":"Project dependencies","type":"object","additionalProperties":{"$ref":"#/definitions/requirement"}},"optional-dependencies":{"title":"Project dependencies","type":"object","additionalProperties":{"$ref":"#/definitions/optionalRequirement"}}}}

Examples

Full artificial example:

[project.dependencies]flask={}django={}requests={version=">= 2.8.1, == 2.8.*",extras=["security","tests"],markers="python_version < '2.7'"}pip={url="https://github.com/pypa/pip/archive/1.3.1.zip"}sphinx={git="ssh://git@github.com/sphinx-doc/sphinx.git"}numpy="~=1.18"pytest=[{version="<6",markers="python_version < '3.5'"},{version=">=6",markers="python_version >= '3.5'"},][project.optional-dependencies]pytest-timout={for-extra="dev"}pytest-mock=[{version="<6",markers="python_version < '3.5'",for-extra="dev"},{version=">=6",markers="python_version >= '3.5'",for-extra="dev"},]

In homage toPEP 631, the following is an equivalent dependenciesspecification fordocker-compose:

[project.dependencies]cached-property=">= 1.2.0, < 2"distro=">= 1.2.0, < 2"docker={extras=["ssh"],version=">= 4.2.2, < 5"}docopt=">= 0.6.1, < 1"jsonschema=">= 2.5.1, < 4"PyYAML=">= 3.10, < 6"python-dotenv=">= 0.13.0, < 1"requests=">= 2.20.0, < 3"texttable=">= 0.9.0, < 2"websocket-client=">= 0.32.0, < 1"# Conditional"backports.shutil_get_terminal_size"={version="== 1.0.0",markers="python_version < '3.3'"}"backports.ssl_match_hostname"={version=">= 3.5, < 4",markers="python_version < '3.5'"}colorama={version=">= 0.4, < 1",markers="sys_platform == 'win32'"}enum34={version=">= 1.0.4, < 2",markers="python_version < '3.4'"}ipaddress={version=">= 1.0.16, < 2",markers="python_version < '3.3'"}subprocess32={version=">= 3.5.4, < 4",markers="python_version < '3.2'"}[project.optional-dependencies]PySocks={version=">= 1.5.6, != 1.5.7, < 2",for-extra="socks"}ddt={version=">= 1.2.2, < 2",for-extra="tests"}pytest={version="< 6",for-extra="tests"}mock={version=">= 1.0.1, < 4",markers="python_version < '3.4'",for-extra="tests"}

Compatibility Examples

The authors of this PEP recognise that various tools need to both readfrom and write to this format for dependency specification. This sectionaims to provide direct comparison with and examples for translating to/fromthe currently used standard,PEP 508.

Note

For simplicity and clarity, various ways in which TOML allows you to specify eachspecification is not represented. These examples use the standard inline representation.

For example, while following are considered equivalent in TOML, we choose thesecond form for the examples in this section.

aiohttp.version="== 3.6.2"aiohttp={version="== 3.6.2"}

Version Constrained Dependencies

No Version Constraint

aiohttp
aiohttp={}

Simple Version Constraint

aiohttp>=3.6.2,<4.0.0
aiohttp={version=">= 3.6.2, < 4.0.0"}

Note

This can, for conciseness, be also represented as a string.

aiohttp=">= 3.6.2, < 4.0.0"

Direct Reference Dependencies

URL Dependency

aiohttp@https://files.pythonhosted.org/packages/97/d1/1cc7a1f84097d7abdc6c09ee8d2260366f081f8e82da36ebb22a25cdda9f/aiohttp-3.6.2-cp35-cp35m-macosx_10_13_x86_64.whl
aiohttp={url="https://files.pythonhosted.org/packages/97/d1/1cc7a1f84097d7abdc6c09ee8d2260366f081f8e82da36ebb22a25cdda9f/aiohttp-3.6.2-cp35-cp35m-macosx_10_13_x86_64.whl"}

VCS Dependency

aiohttp@git+ssh://git@github.com/aio-libs/aiohttp.git@master
aiohttp={git="ssh://git@github.com/aio-libs/aiohttp.git",revision="master"}

Environment Markers

aiohttp>=3.6.1;python_version>='3.8'
aiohttp={version=">= 3.6.1",markers="python_version >= '3.8'"}

A slightly extended example of the above, where a particular version ofaiohttp is required based on the interpreter version.

aiohttp>=3.6.1;python_version>='3.8'aiohttp>=3.0.0,<3.6.1;python_version<'3.8'
aiohttp=[{version=">= 3.6.1",markers="python_version >= '3.8'"},{version=">= 3.0.0, < 3.6.1",markers="python_version < '3.8'"}]

Package Extras

Specifying dependency for a package extra

aiohttp>=3.6.2;extra=='http'
aiohttp={version=">= 3.6.2",for-extra="http"}

Using extras from a dependency

aiohttp[speedups]>=3.6.2
aiohttp={version=">= 3.6.2",extras=["speedups"]}

Complex Examples

Version Constraint

aiohttp[speedups]>=3.6.2;python_version>='3.8'andextra=='http'
aiohttp={version=">= 3.6.2",extras=["speedups"],markers="python_version >= '3.8'",for-extra="http"}

Direct Reference (VCS)

aiohttp[speedups]@git+ssh://git@github.com/aio-libs/aiohttp.git@master;python_version>='3.8'andextra=='http'
aiohttp={git="ssh://git@github.com/aio-libs/aiohttp.git",revision="master",extras=["speedups"],markers="python_version >= '3.8'",for-extra="http"}

Rejected Ideas

Switch to an array fordependencies

Use an array instead of a table in order to have each element only be a table(with aname key) and no arrays of requirement tables. This was veryverbose and restrictive in the TOML format, and having multiple requirementsfor a given distribution isn’t very common.

Replaceoptional-dependencies withextras

Remove theoptional-dependencies table in favour of both including anoptional key in the requirement and anextras table which specifieswhich (optional) requirements are needed for a project’s extra. This reducesthe number of table with the same specification (to 1) and allows forrequirements to be specified once but used in multiple extras, but distancessome of the requirement’s properties (which extra(s) it belongs to), groupsrequired and optional dependencies together (possibly mixed), and there may notbe a simple way to choose a requirement when a distribution has multiplerequirements. This was rejected asoptional-dependencies has already beenused in thePEP 621 draft.

direct table in requirement

Include the direct-reference keys in adirect table, have the VCS specifiedas the value of avcs key. This was more explicit and easier to include ina JSON-schema validation, but was decided to be too verbose and not asreadable.

Include hash

Include hash in direct-reference requirements. This was only for packagelock-files, and didn’t really have a place in the project’s metadata.

Dependency tables for each extra

Have theoptional-dependencies be a table of dependency tables for eachextra, with the table name being the extra’s name. This madeoptional-dependencies a different type (table of tables of requirements)fromdependencies (table of requirements), which could be jarring for usersand harder to parse.

Environment marker keys

Make eachPEP 508 environment marker as a key (or child-table key) inthe requirement. This arguably increases readability and ease of parsing.Themarkers key would still be allowed for more advanced specification,with which the key-specified environment markers areand’d with theresult of. This was deferred as more design needs to be undertaken.

Multiple extras which one requirement can satisfy

Replace thefor-extra key withfor-extras, with the value being anarray of extras which the requirement satisfies. This reduces someduplication, but in this case that duplication makes explicit which extrashave which dependencies.

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-0633.rst

Last modified:2025-02-01 08:55:40 GMT


[8]ページ先頭

©2009-2025 Movatter.jp