From d31806fe1e045e5fb2d92df38c510685f2595035 Mon Sep 17 00:00:00 2001 From: CAM Gerlach Date: Tue, 2 Aug 2022 22:43:25 -0500 Subject: [PATCH] PEP 639: Further update per discussion, w/flat license key, etc. (#2705) Substantive content changes: * Instead of adding a new top-level `license-expression` key for the license expression in the `[project]` table of the `pyproject.toml` source metadata, the PEP now specifies using the top-level string value of the `license` key for this purpose, which PEP 621 (PEP-621) reserved it for, and updates the `license-expression` and `license` key specs, and the examples, rejected ideas and other sections accordingly. * Since this makes it not possible to convert a legacy `license` key to the new `License-Expression` field at build time, and that's not really advisable anyway, it drastically simplifies the normative Converting Legacy Metadata section to just a single normative statement, and updates/removes other mentions of it accordingly, and the (already rather unhelpful) example * Likewise, it simplifies and refines the guidance in the Mapping classifiers to SPDX identifiers section to be more general and less focused on build time, and also allows tools to ignore redundant parent classifiers (Note: This section will be moved to an external appendix in the next PR, but I didn't move it here for ease of review) * The `license_files` directory was renamed to `licenses` at the request of @brettcannon and to simplify things a touch * The specified handling of the `license.file` key was a bit confused by a (apparently quite common) misunderstanding about how the specified file is used (to inject its text directly under the `License` field in core metadata, rather than included in distribution archives or its path specified in metadata) due to it being rather underspecified in PEP 621, which this revision corrects. * Bump the core metadata version to reflect acceptance of PEP 685 as Metadata 2.3 * Bump the SPDX license list version to be up to date Significant non-normative/editorial changes: * Mention implementation of drafts of this PEP in Hatch and Setuptools, and also describes previous efforts in Setuptools and Wheel that this PEP builds on more clearly, as suggested on the discussion thread * Reference the canonical project [source] metadata PyPA spec instead of PEP 621, use clearer language surrounding that, and update a few references to other PEPs * Revise the Motivations and Rationale to be less duplicative/redundant, more balanced and focused more specifically on their respective areas (providing some background and describing the problem, and introducing and justifying the proposed solution, respectively) * Add a short blurb making explicit the use of RFC 2119 terminology (MUST, SHOULD, etc) * Update PEP headers * Various other minor revisions to correct typos and other issues, clarify and simply the text, and improve source formatting. --- pep-0639.rst | 753 +++++++++++++++++++++++++-------------------------- 1 file changed, 367 insertions(+), 386 deletions(-) diff --git a/pep-0639.rst b/pep-0639.rst index 39c9f6931..183017a72 100644 --- a/pep-0639.rst +++ b/pep-0639.rst @@ -2,7 +2,6 @@ PEP: 639 Title: Improving License Clarity with Better Package Metadata Author: Philippe Ombredanne , C.A.M. Gerlach , -Sponsor: Paul Moore PEP-Delegate: Brett Cannon Discussions-To: https://discuss.python.org/t/12622 Status: Draft @@ -11,7 +10,7 @@ Topic: Packaging Content-Type: text/x-rst Created: 15-Aug-2019 Post-History: `15-Aug-2019 `__, - `17-Dec-2021 `__ + `17-Dec-2021 `__, .. _639-abstract: @@ -38,7 +37,7 @@ The PEP also: and ``license ::`` :ref:`classifiers <639-spec-field-classifier>`. - :ref:`Adds and deprecates <639-spec-source-metadata>` the corresponding keys - in the :pep:`621` project source metadata format. + in the ``pyproject.toml`` ``[project]`` table. - :ref:`Provides clear guidance <639-spec-converting-metadata>` for authors and tools converting legacy license metadata, adding license files and @@ -53,8 +52,8 @@ The PEP also: :ref:`other ecosystems <639-license-doc-other-projects>`. The changes in this PEP will update the -:`core metadata `__ to version 2.3, modify the -`PEP 621 project metadata specification `__, +`core metadata `__ to version 2.4, modify the +`project (source) metadata specification `__, and make minor additions to the `source distribution (sdist) `__, `built distribution (wheel) `__ and `installed project `__ standards. @@ -122,8 +121,10 @@ binary distribution packages don't have :ref:`the same licenses Motivation ========== -All software is licensed, and providing accurate license information to Python -package users is an important matter. Today, there are multiple fields where +Software must be licensed in order for anyone other than its creator to +download, use, share and modify it, so providing accurate license information +to Python package users is an important matter. +Today, there are multiple fields where licenses are documented in core metadata, and there are limitations to what can be expressed in each of them. This often leads to confusion and a lack of clarity, both for package authors and end users. @@ -138,6 +139,30 @@ including on `outdated and ambiguous PyPI classifiers `__, `limited support for license files in the Wheel project `__, and `the lack of clear, precise and standardized license metadata `__. +The current license classifiers address some common cases, and could +be extended to include the full range of current SPDX identifiers +while deprecating the many ambiguous classifiers +(including some popular and problematic ones, +such as ``License :: OSI Approved :: BSD License``). +However, this requires a substantial amount of effort +to duplicate the SPDX license list and keep it in sync. +Furthermore, it is effectively a hard break in backward compatibility, +forcing a huge proportion of package authors to immediately update to new +classifiers (in most cases, with many possible choices that require closely +examining the project's license) immediately when PyPI deprecates the old ones. + +Furthermore, this only covers simple packages entirely under a single license; +it doesn't address the substantial fraction of common projects that vendor +dependencies (e.g. Setuptools), offer a choice of licenses (e.g. Packaging) +or were relicensed, adapt code from other projects or contain fonts, images, +examples, binaries or other assets under other licenses. It also requires +both authors and tools understand and implement the PyPI-specific bespoke +classifier system, rather than using short, easy to add and standardized +SPDX identifiers in a simple text field, as increasingly widely adopted by +most other packaging systems to reduce the overall burden on the ecosystem. +Finally, this does not provide as clear an indicator that a package +has adopted the new system, and should be treated accordingly. + On average, Python packages tend to have more ambiguous and missing license information than other common ecosystems (such as npm, Maven or Gem). This is supported by the `statistics page `__ of the @@ -159,7 +184,8 @@ and license documentation in a variety of other packaging systems, Linux distros, languages ecosystems and applications is surveyed in :ref:`another appendix <639-license-doc-other-projects>`. -There are a few takeaways from the survey: +There are a few takeaways from the survey, which have guided the design +and recommendations of this PEP: - Most package formats use a single ``License`` field. @@ -175,31 +201,6 @@ There are a few takeaways from the survey: Open Source Software licenses require package authors to include their full text in a distribution. -These considerations have guided the design and recommendations of this PEP. - -The current license classifiers cover some common cases, and could -theoretically be extended to include the full range of current SPDX -identifiers while deprecating the many ambiguous classifiers (including some -extremely popular and particularly problematic ones, such as -``License :: OSI Approved :: BSD License``). However, this both requires a -substantial amount of effort to duplicate the SPDX license list and keep -it in sync, and is effectively a hard break in backward compatibility, -forcing a huge proportion of package authors to immediately update to new -classifiers (in most cases, with many possible choices that require closely -examining the project's license) immediately when PyPI deprecates the old ones. - -Furthermore, this only covers simple packages entirely under a single license; -it doesn't address the substantial fraction of common projects that vendor -dependencies (e.g. Setuptools), offer a choice of licenses (e.g. Packaging) -or were relicensed, adapt code from other projects or contain fonts, images, -examples, binaries or other assets under other licenses. It also requires -both authors and tools understand and implement the PyPI-specific bespoke -classifier system, rather than using short, easy to add and standardized -SPDX identifiers in a simple text field, as increasingly widely adopted by -most other packaging systems to reduce the overall burden on the ecosystem. -Finally, this does not provide as clear an indicator that a package -has adopted the new system, and should be treated accordingly. - The use of a new ``License-Expression`` field will provide an intuitive, structured and unambiguous way to express the license of a package using a well-defined syntax and well-known license identifiers. @@ -208,6 +209,15 @@ way to ensure that the full text of the license(s) are included with the package when distributed, as legally required, and allows other tools consuming the core metadata to unambiguously locate a distribution's license files. +While dramatically simplifying and improving the present Python license +metadata story, this specification standardizes and builds upon +existing practice in the `Setuptools `__ and +`Wheel `__ projects. +Furthermore, an up-to-date version of the current draft of this PEP is +`already successfully implemented `__ in the popular +PyPA `Hatch `__ packaging tool, and an earlier draft of the +license files portion is `implemented in Setuptools `__. + Over time, encouraging the use of these fields and deprecating the ambiguous, duplicative and confusing legacy alternatives will help Python software publishers improve the clarity, accuracy and portability of their licensing @@ -224,7 +234,7 @@ This PEP seeks to clearly define the terms it uses, given that some have multiple established meanings (e.g. import vs. distribution package, wheel *format* vs. Wheel *project*); are related and often used interchangeably, but have critical distinctions in meaning -(e.g. :pep:`621` *key* vs. core metadata *field*); are existing concepts +(e.g. ``[project]`` *key* vs. core metadata *field*); are existing concepts that don't have formal terms/definitions (e.g. project/source metadata vs. distribution/built metadata, build vs. publishing tools), or are new concepts introduced here (e.g. license expression/identifier). @@ -235,6 +245,10 @@ This PEP also uses terms defined in the *project* and *source distribution*), and by the `SPDX Project `__ (*license identifier*, *license expression*). +The keywords "MUST", "MUST NOT", "REQUIRED", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" +in this document are to be interpreted as described in :rfc:`2119`. + Terms are listed here in their full versions; related words (``Rel:``) are in parenthesis, including short forms (``Short:``), sub-terms (``Sub:``) and common synonyms @@ -252,8 +266,8 @@ for the purposes of this PEP (``Syn:``). **Core Metadata Field** *(Short: Metadata Field/Field)* A single key-value pair, or sequence of such with the same key, as defined - by the core metadata specification. Notably, *not* a :pep:`621` project - metadata format key. + by the `core metadata specification `__. + Notably, distinct from a ``pyproject.toml`` ``[project]`` table *key*. **Distribution Package** *(Sub: Package, Distribution Archive)* (`See PyPUG `__) @@ -262,8 +276,10 @@ for the purposes of this PEP (``Syn:``). specifically references the physical **distribution archive**. **License Classifier** - A `PyPI Trove classifier `__ (as originally defined in - :pep:`301`) which begins with ``License ::``, currently used to indicate + A `PyPI Trove classifier `__ + (as `described in the core metadata specification + `__) + which begins with ``License ::``, currently used to indicate a project's license status by including it as a ``Classifier`` in the core metadata. @@ -286,26 +302,29 @@ for the purposes of this PEP (``Syn:``). project takes once installed from a distribution, as `specified by PyPA `__. -**Project Source Metadata** *(Sub: PEP 621 Metadata, Key, Subkey)* +**Project Source Metadata** *(Sub: Project Table Metadata, Key, Subkey)* Core metadata defined by the package author in the project source tree, - as top-level keys in the ``[project]`` table of a :pep:`621` ``pyproject.toml``, + as top-level keys in the ``[project]`` table of a ``pyproject.toml`` file, in the ``[metadata]`` table of ``setup.cfg``, or the equivalent for other build tools. - The **PEP 621 metadata** refers specifically to the former, as defined by the - `PyPA Declaring Project Metadata specification `__. - A **PEP 621 metadata key**, or an unqualified *key* refers specifically to - a top-level ``[project]`` key (notably, *not* a core metadata *field*), + The **Project Table Metadata**, or ``pyproject.toml`` ``[project]`` metadata, + refers specifically to the former, as defined by the + `PyPA Declaring Project Metadata specification `__ + and originally specified in :pep:`621`. + A **Project Table Key**, or an unqualified *key* refers specifically to + a top-level ``[project]`` key + (notably, distinct from a core metadata *field*), while a **subkey** refers to a second-level key in a table-valued - :pep:`621` key. + ``[project]`` key. **Root License Directory** *(Short: License Directory)* The directory under which license files are stored in a project/distribution and the root directory that their paths, as recorded under the ``License-File`` core metadata fields, are relative to. Defined here to be the project root directory for source trees and source - distributions, and a subdirectory named ``license_files`` of the directory - containing the core metadata (i.e., the ``.dist-info/license_files`` + distributions, and a subdirectory named ``licenses`` of the directory + containing the core metadata (i.e., the ``.dist-info/licenses`` directory) for built distributions and installed projects. **Tool** *(Sub: Packaging Tool, Build Tool, Install Tool, Publishing Tool)* @@ -330,7 +349,7 @@ for the purposes of this PEP (``Syn:``). **Wheel** *(Short: wheel, Rel: wheel format, Wheel project)* Here, **wheel**, the standard built distribution format introduced in - :pep:`427` and `specified by PyPA `__, will be referred to in + :pep:`427` and `specified by the PyPA `__, will be referred to in lowercase, while the `Wheel project `__, its reference implementation, will be referred to as such with **Wheel** in Title Case. @@ -345,7 +364,8 @@ this PEP include those in both :ref:`distribution package metadata <639-spec-core-metadata>`, as defined in the `core metadata specification `__, and :ref:`author-provided project source metadata <639-spec-source-metadata>`, -as originally defined in :pep:`621`. +as defined in the `project source metadata specification <_pep621spec>`__ +(and originally introduced in :pep:`621`). Further, :ref:`minor additions <639-spec-project-formats>` to the source distribution (sdist), built distribution (wheel) and installed project @@ -381,7 +401,7 @@ publishing tools; end-user-facing install tools MAY be more lenient than mentioned here when encountering malformed metadata that does not conform to this specification. -As it adds new fields, this PEP updates the core metadata to version 2.3. +As it adds new fields, this PEP updates the core metadata to version 2.4. .. _639-spec-field-license-expression: @@ -407,7 +427,7 @@ the SPDX license expression definition, a license expression can use the following license identifiers: - Any SPDX-listed license short-form identifiers that are published in the - `SPDX License List `__, version 3.15 or any later compatible + `SPDX License List `__, version 3.17 or any later compatible version. Note that the SPDX working group never removes any license identifiers; instead, they may choose to mark an identifier as "deprecated". @@ -487,7 +507,7 @@ if a built distribution's metadata contains no ``License-File`` entries, and publishing tools MAY but build tools MUST NOT raise an error. For all newly-uploaded distribution packages that include one or more -``License-File`` fields and declare a ``Metadata-Version`` of ``2.3`` or +``License-File`` fields and declare a ``Metadata-Version`` of ``2.4`` or higher, PyPI SHOULD validate that the specified files are present in all uploaded distributions, and MUST reject uploads that do not validate. @@ -521,8 +541,8 @@ Deprecate license classifiers ''''''''''''''''''''''''''''' Using license `classifiers `__ in the ``Classifier`` field -(described in :pep:`301`) is deprecated and replaced by the more precise -``License-Expression`` field. +(`described in the core metadata specification `__) +is deprecated and replaced by the more precise ``License-Expression`` field. If the ``License-Expression`` field is present, build tools SHOULD and publishing tools MUST raise an error if one or more license classifiers @@ -554,38 +574,37 @@ Project source metadata As originally introduced in :pep:`621`, the `PyPA Declaring Project Metadata specification `__ defines how to declare a project's source -metadata in a ``[project]`` table in the ``pyproject.toml`` file for +metadata under a ``[project]`` table in the ``pyproject.toml`` file for build tools to consume and output distribution core metadata. -This PEP :ref:`adds <639-spec-key-license-expression>` the ``license-expression`` -key, :ref:`adds <639-spec-key-license-files>` the ``license-files`` key and -:ref:`deprecates <639-spec-key-license>` the ``license`` key. +This PEP :ref:`adds <639-spec-key-license-expression>` +a top-level string value for the ``license`` key, +:ref:`adds <639-spec-key-license-files>` the new ``license-files`` key +and :ref:`deprecates <639-spec-key-license>` +the table value for the ``license`` key +along with its corresponding table subkeys, ``text`` and ``file``. .. _639-spec-key-license-expression: -Add ``license-expression`` key -'''''''''''''''''''''''''''''' +Add string value to ``license`` key +''''''''''''''''''''''''''''''''''' -A new ``license-expression`` key is added to the ``project`` table, which has -a string value that is a valid SPDX license expression, as -:ref:`defined previously <639-license-expression-definition>`. +A top-level string value is defined +for the ``license`` key in the ``[project]`` table, +which is specified to be a valid SPDX license expression, +as :ref:`defined previously <639-license-expression-definition>`. Its value maps to the ``License-Expression`` field in the core metadata. Build tools SHOULD validate the expression as described in the -:ref:`639-spec-field-license-expression` section, outputting -an error or warning as specified. When generating the core metadata, tools -MUST perform case normalization. +:ref:`639-spec-field-license-expression` section, +outputting an error or warning as specified. +When generating the core metadata, tools MUST perform case normalization. -If and only if the ``license-expression`` key is listed as ``dynamic`` -(and is not specified), tools MAY infer a value for the ``License-Expression`` -field if they can do so unambiguously, but MUST follow the provisions in the -:ref:`639-spec-converting-metadata` section. - -If the ``license-expression`` key is present and valid (and the ``license`` -key is not specified), for purposes of backward compatibility, tools MAY -back-fill the ``License`` core metadata field with the case-normalized value -of the ``license-expression`` key. +If a top-level string value for the ``license`` key is present and valid, +for purposes of backward compatibility +tools MAY back-fill the ``License`` core metadata field +with the normalized value of the ``license`` key. .. _639-spec-key-license-files: @@ -593,7 +612,7 @@ of the ``license-expression`` key. Add ``license-files`` key ''''''''''''''''''''''''' -A new ``license-files`` key is added to the ``project`` table for specifying +A new ``license-files`` key is added to the ``[project]`` table for specifying paths in the project source tree relative to ``pyproject.toml`` to file(s) containing licenses and other legal notices to be distributed with the package. It corresponds to the ``License-File`` fields in the core metadata. @@ -674,37 +693,39 @@ user has explicitly specified their own. .. _639-spec-key-license: -Deprecate ``license`` key -''''''''''''''''''''''''' +Deprecate ``license`` key table subkeys +''''''''''''''''''''''''''''''''''''''' -The ``license`` key in the ``project`` table is now deprecated. -It MUST NOT be used or listed as ``dynamic`` if either of the new -``license-expression`` or ``license-files`` keys are defined, -and build tools MUST raise an error if either is the case. +Table values for the ``license`` key in the ``[project]`` table, +including the ``text`` and ``file`` table subkeys, are now deprecated. +If the new ``license-files`` key is present, +build tools MUST raise an error if the ``license`` key is defined +and has a value other than a single top-level string. -Otherwise, if the ``text`` subkey is present in the ``license`` table, tools -SHOULD issue a warning informing users it is deprecated and recommending the -``license-expression`` key instead. +If the new ``license-files`` key is not present +and the ``text`` subkey is present in a ``license`` table, +tools SHOULD issue a warning informing users it is deprecated +and recommending a license expression as a top-level string key instead. -Likewise, if the ``file`` subkey is present in the ``license`` table, tools -SHOULD issue a warning informing users it is deprecated and recommending -the ``license-files`` key instead. However, if the file is present in the -source, build tools SHOULD still use it to fill the ``License-File`` field -in the core metadata, and if so, MUST include the specified file in any -distribution archives for the project. If the file does not exist at the -specified path, tools SHOULD issue a warning, and MUST NOT fill it in a -``License-File`` field. +Likewise, if the new ``license-files`` key is not present +and the ``file`` subkey is present in the ``license`` table, +tools SHOULD issue a warning informing users it is deprecated and recommending +the ``license-files`` key instead. -For backwards compatibility, to preserve consistent behavior with current tools -and ensure that users do not unknowingly create packages that are not legally -distributable, tools MUST assume the -:ref:`specified default value <639-default-patterns>` for the -``license-files`` key and also include, in addition to the license file -specified under this ``file`` subkey, any license files that match the -specified list of patterns. +If the specified license ``file`` is present in the source tree, +build tools SHOULD use it to fill the ``License-File`` field +in the core metadata, and MUST include the specified file +as if it were specified in a ``license-file.paths`` field. +If the file does not exist at the specified path, +tools MUST raise an informative error as previously specified. +However, tools MUST also still assume the +:ref:`specified default value <639-default-patterns>` +for the ``license-files`` key and also include, +in addition to a license file specified under the ``license.file`` subkey, +any license files that match the specified list of patterns. -The ``license`` key may be removed from a new version of the specification -in a future PEP. +Table values for the ``license`` key MAY be removed +from a new version of the specification in a future PEP. .. _639-spec-project-formats: @@ -728,26 +749,26 @@ each format, per the :ref:`639-spec-field-license-file` section. **Source distributions** *(sdists)* The `sdist specification `__ will be updated to reflect that for - ``Metadata-Version`` is ``2.3`` or greater, the sdist MUST contain any + ``Metadata-Version`` is ``2.4`` or greater, the sdist MUST contain any license files specified by ``License-File`` in the ``PKG-INFO`` at their respective paths relative to the top-level directory of the sdist (containing the ``pyproject.toml`` and the ``PKG-INFO`` core metadata). **Built distributions** *(wheels)* The `wheel specification `__ will be updated to reflect that if - the ``Metadata-Version`` is ``2.3`` or greater and one or more + the ``Metadata-Version`` is ``2.4`` or greater and one or more ``License-File`` fields is specified, the ``.dist-info`` directory MUST - contain a ``license_files`` subdirectory which MUST contain the files listed + contain a ``licenses`` subdirectory, which MUST contain the files listed in the ``License-File`` fields in the ``METADATA`` file at their respective - paths relative to the ``license_files`` directory. + paths relative to the ``licenses`` directory. **Installed projects** The `Recording Installed Projects specification `__ will be - updated to reflect that if the ``Metadata-Version`` is ``2.3`` or greater + updated to reflect that if the ``Metadata-Version`` is ``2.4`` or greater and one or more ``License-File`` fields is specified, the ``.dist-info`` - directory MUST contain a ``license_files`` subdirectory which MUST contain + directory MUST contain a ``licenses`` subdirectory which MUST contain the files listed in the ``License-File`` fields in the ``METADATA`` file - at their respective paths relative to the ``license_files`` directory, + at their respective paths relative to the ``licenses`` directory, and that any files in this directory MUST be copied from wheels by install tools. @@ -757,35 +778,13 @@ each format, per the :ref:`639-spec-field-license-file` section. Converting legacy metadata -------------------------- -If the contents of the ``license.text`` :pep:`621` source metadata key -(or equivalent for tool-specific config formats) is a valid license expression -containing solely known, non-deprecated license identifiers, and, if -:pep:`621` metadata are defined, the ``license-expression`` key is listed as -``dynamic``, build tools MAY use it to fill the ``License-Expression`` field. - -Similarly, if the ``classifiers`` :pep:`621` source metadata key (or equivalent -for tool-specific config formats) contains exactly one license classifier -that unambiguously maps to exactly one valid, non-deprecated SPDX license -identifier, tools MAY fill the ``License-Expression`` field with the latter. - -If both a ``license.text`` or equivalent value and a single license classifier -are present, the contents of the former, including capitalization -(but excluding leading and trailing whitespace), MUST exactly match the SPDX -license identifier mapped to the license classifier to be considered -unambiguous for the purposes of automatically filling the -``License-Expression`` field. - -If tools have filled the ``License-Expression`` field as described here, -they MUST output a prominent, user-visible warning informing package authors -of that fact, including the ``License-Expression`` string they have output, -and recommending that the project source metadata be updated accordingly -with the indicated license expression. - -In any other case, tools MUST NOT use the contents of the ``license.text`` -key (or equivalent) or license classifiers to fill the -``License-Expression`` field without informing the user and requiring -unambiguous, affirmative user action to select and confirm the desired -``License-Expression`` value before proceeding. +Tools MUST NOT use the contents of the ``license.text`` ``[project]`` key +(or equivalent tool-specific format), +license classifiers or the value of the core metadata ``License`` field +to fill the top-level string value of the ``license`` key `` +or the core metadata ``License-Expression`` field +without informing the user and requiring unambiguous, affirmative user action +to select and confirm the desired license expression value before proceeding. .. _639-spec-mapping-classifiers-identifiers: @@ -794,19 +793,19 @@ Mapping license classifiers to SPDX identifiers ''''''''''''''''''''''''''''''''''''''''''''''' Most single license classifiers (namely, all those not mentioned below) -map to a single valid SPDX license identifier, allowing tools to insert them -into the ``License-Expression`` field following the -:ref:`specification above <639-spec-converting-metadata>`. +map to a single valid SPDX license identifier, +allowing tools to infer the SPDX license identifier they correspond to, +both for use when analyzing and auditing packages, +and providing a semi-automated mechanism of filling the ``license`` key +or the ``License-Expression`` field +following the :ref:`specification above <639-spec-converting-metadata>`. -Many legacy license classifiers intend to specify a particular license, +Some legacy license classifiers intend to specify a particular license, but do not specify the particular version or variant, leading to a -`critical ambiguity `__ as to their terms, compatibility -and acceptability. Tools MUST NOT attempt to automatically infer a -``License-Expression`` when one of these classifiers is used, and SHOULD -instead prompt the user to affirmatively select and confirm their intended -license choice. - -These classifiers are the following: +`critical ambiguity `__ +as to their terms, compatibility and acceptability. +Tools MUST NOT attempt to automatically infer a ``License-Expression`` +when one of these classifiers is used without affirmative user action: - ``License :: OSI Approved :: Academic Free License (AFL)`` - ``License :: OSI Approved :: Apache Software License`` @@ -829,12 +828,14 @@ MAY use as a reference for the identifier selection options to offer users when prompting the user to explicitly select the license identifier they intended for their project. -**Note**: Several additional classifiers, namely the "or later" variants of -the AGPLv3, GPLv2, GPLv3 and LGPLv3, are also listed in the aforementioned -mapping, but as they were merely proposed for textual harmonization and -still unambiguously map to their respective licenses, -they were not included here; LGPLv2 is, however, as it could ambiguously -refer to either the distinct v2.0 or v2.1 variants of that license. +.. note:: + + Several additional classifiers, namely the "or later" variants of + the AGPLv3, GPLv2, GPLv3 and LGPLv3, are also listed in the aforementioned + mapping, but unambiguously map to their respective licenses, + and so are not listed here. + However, LGPLv2 is included above, as it could ambiguously + refer to either the distinct v2.0 or v2.1 variants of that license. In addition, for the various special cases, the following mappings are considered canonical and normative for the purposes of this specification: @@ -849,38 +850,39 @@ considered canonical and normative for the purposes of this specification: since the meaning associated with the term "public domain" is thoroughly dependent on the specific legal jurisdiction involved, some of which lack the concept entirely. - Alternatively, tools MAY choose to treat these classifiers as ambiguous and - require user confirmation to fill ``License-Expression`` in these cases. + Alternatively, tools MAY choose to treat these classifiers as ambiguous. -- The generic and sometimes ambiguous classifiers - ``License :: Free For Educational Use``, - ``License :: Free For Home Use``, - ``License :: Free for non-commercial use``, - ``License :: Freely Distributable``, - ``License :: Free To Use But Restricted``, - ``License :: Freeware``, and - ``License :: Other/Proprietary License`` MAY be mapped to the generic +- The generic and sometimes ambiguous classifiers: + + - ``License :: Free For Educational Use`` + - ``License :: Free For Home Use`` + - ``License :: Free for non-commercial use`` + - ``License :: Freely Distributable`` + - ``License :: Free To Use But Restricted`` + - ``License :: Freeware`` + - ``License :: Other/Proprietary License`` + + MAY be mapped to the generic ``License-Expression: LicenseRef-Proprietary``, but tools MUST issue a prominent, informative warning if they do so. - Alternatively, tools MAY choose to treat these classifiers as ambiguous and - require user confirmation to fill ``License-Expression`` in these cases. + Alternatively, tools MAY choose to treat these classifiers as ambiguous. - The generic and ambiguous classifiers ``License :: OSI Approved`` and ``License :: DFSG approved`` do not map to any license expression, - and thus tools MUST treat them as ambiguous and require user intervention - to fill ``License-Expression``. + and thus tools SHOULD treat them as ambiguous, or if not MUST ignore them. - The classifiers ``License :: GUST Font License 1.0`` and ``License :: GUST Font License 2006-09-30`` have no mapping to SPDX license - identifiers and no PyPI package uses them, as of the writing of this PEP. - Therefore, tools MUST treat them as ambiguous when attempting to fill - ``License-Expression``. + identifiers, and no PyPI package uses them as of 2022-07-09. When multiple license classifiers are used, their relationship is ambiguous, and it is typically not possible to determine if all the licenses apply or if -there is a choice that is possible among the licenses. In this case, tools -MUST NOT automatically infer a license expression, and SHOULD suggest that the -package author construct one which expresses their intent. +there is a choice that is possible among the licenses, +In this case, tools MUST NOT automatically infer a license expression, +unless one license classifier is a parent of the other, +i.e. the child contains all ``::``-delineated components of the parent, +in which case tools MAY ignore the parent classifier +but SHOULD issue an informative warning when doing so. .. _639-backwards-compatibility: @@ -888,15 +890,19 @@ package author construct one which expresses their intent. Backwards Compatibility ======================= -Adding a new, dedicated ``License-Expression`` core metadata field and -``license-expression`` :pep:`621` source metadata key unambiguously signals -support for the specification in this PEP. This avoids the risk of new tooling +Adding a new, dedicated ``License-Expression`` core metadata field +and a top-level string value for the ``license`` key reserved for this purpose +in the ``pyproject.toml`` ``[project]`` table +unambiguously signals support for the specification in this PEP. +This avoids the risk of new tooling misinterpreting a license expression as a free-form license description or vice versa, and raises an error if and only if the user affirmatively upgrades to the latest metadata version and adds the new field/key. -The legacy ``License`` core metadata field and ``license`` :pep:`621` source -metadata key will be deprecated along with the license classifiers, +The legacy ``License`` core metadata field +and the ``license`` key table subkeys (``text`` and ``file``) +in the ``pyproject.toml`` ``[project]`` table +will be deprecated along with the license classifiers, retaining backwards compatibility while gently preparing users for their future removal. Such a removal would follow a suitable transition period, and be left to a future PEP and a new version of the core metadata specification. @@ -906,13 +912,13 @@ inclusion of the listed files in the distribution merely codifies and refines the existing practices in popular packaging tools, including the Wheel and Setuptools projects, and is designed to be largely backwards-compatible with their existing use of that field. Likewise, the new ``license-files`` -:pep:`621` source metadata key standardizes statically specifying the files -to include, as well as the default behavior, and allows other tools to -make use of them, while only having an effect once users and tools expressly -adopt it. +key in the ``[project]`` table of ``pyproject.toml`` +standardizes statically specifying the files to include, +as well as the default behavior, and allows other tools to make use of them, +while only having an effect once users and tools expressly adopt it. Due to requiring license files not be flattened into ``.dist-info`` and -specifying that they should be placed in a dedicated ``license_files`` subdir, +specifying that they should be placed in a dedicated ``licenses`` subdir, wheels produced following this change will have differently-located licenses relative to those produced via the previous unspecified, installer-specific behavior, but as until this PEP there was no way of @@ -982,7 +988,7 @@ For authors still using the now-deprecated, less precise and more redundant ``License`` field or license classifiers, packaging tools will warn them and inform them of the modern replacement, ``License-Expression``. Finally, for users who may have forgotten or not be aware they need to do so, -publishing tools will gently guide them toward including ``license-expression`` +publishing tools will gently guide them toward including ``license`` and ``license-files`` in their project source metadata. Tools may also help with the conversion and suggest a license expression in @@ -992,12 +998,19 @@ many, if not most common cases: tool authors with guidelines on how to suggest a license expression produced from legacy classifiers. -- Tools may also be able to infer and suggest how to update an existing - ``License`` value and convert that to a ``License-Expression``. - For instance, a tool may suggest converting from a ``License`` field with - ``Apache2`` (which is not a valid license expression as defined in this PEP) - to a ``License-Expression`` field with ``Apache-2.0`` (which is a valid - license expression using an SPDX license identifier). +- Tools may also be able to infer and suggest how to update + an existing ``License`` value in project source metadata + and convert that to a license expression, + as also :ref:`specified in this PEP <639-spec-converting-metadata>`. + For instance, a tool may suggest converting a value of ``MIT`` + in the ``license.text`` key in ``[project]`` + (or the equivalent in tool-specific formats) + to a top-level string value of the ``license`` key (or equivalent). + Likewise, a tool could suggest converting from a ``License`` of ``Apache2`` + (which is not a valid license expression + as :ref:`defined in this PEP <639-spec-field-license-expression>`) + to a ``License-Expression`` of ``Apache-2.0`` + (the equivalent valid license expression using an SPDX license identifier). .. _639-reference-implementation: @@ -1151,7 +1164,7 @@ dig through the list to figure out which one(s) apply (and be confused by many ambiguous options), or figure out on their own what should go in the ``license`` key (anything from nothing, to the license text, to a free-form description, to the same SPDX identifier they would be -entering in the ``license-expression`` key anyway, assuming they can +entering in the ``license`` key anyway, assuming they can easily find documentation at all about it). In fact, this can be made even easier thanks to the new field. For example, GitHub's popular `ChooseALicense.com `__ links to how to add SPDX license @@ -1201,7 +1214,7 @@ field was separate from the existing ``License``, which would make validation much more challenging and backwards-incompatible, breaking existing packages. With that change, there was a clear consensus that the new field should be validated from the start, guaranteeing that all -distributions uploaded to PyPI that declare core metadata version 2.3 +distributions uploaded to PyPI that declare core metadata version 2.4 or higher and have the ``License-Expression`` field will have a valid expression, such that PyPI and consumers of its packages and metadata can rely upon to follow the specification here. @@ -1221,14 +1234,14 @@ Source metadata ``license`` key ------------------------------- Alternate possibilities related to the ``license`` key in the -``pyproject.toml`` project source metadata specified in :pep:`621`. +``pyproject.toml`` project source metadata. Add ``expression`` and ``files`` subkeys to table ''''''''''''''''''''''''''''''''''''''''''''''''' A previous working draft of this PEP added ``expression`` and ``files`` subkeys -to the existing ``license`` table in the :pep:`621` source metadata, to parallel +to the existing ``license`` table in the project source metadata, to parallel the existing ``file`` and ``text`` subkeys. While this seemed perhaps the most obvious approach at first glance, it had several serious drawbacks relative to that ultimately taken here. @@ -1238,138 +1251,126 @@ specified under the same top-level key that require very different handling, and furthermore, unlike the previous arrangement, the subkeys were not mutually exclusive and can both be specified at once, and with some subkeys potentially being dynamic and others static, and mapping to different core metadata fields. -This also breaks from the consensus for the core metadata fields, namely to -separate the license expression into its own explicit field. Furthermore, this leads to a conflict with marking the key as ``dynamic`` -(assuming that is intended to specify :pep:`621` keys, as that PEP seems to rather -imprecisely imply, rather than core metadata fields), as either both would have -to be treated as ``dynamic``. A user may want to specify the ``expression`` -key as ``dynamic``, if they intend their tooling to generate it automatically; -conversely, they may rely on their build tool to dynamically detect license -files via means outside of that strictly specified here. And indeed, current -users may mark the present ``license`` key as ``dynamic`` to automatically -fill it in the metadata. Grouping all these uses under the same key forces an -"all or nothing" approach, and creates ambiguity as to user intent. +(assuming that is intended to specify the ``[project]`` table keys, +as that PEP seems to imprecisely imply, +rather than core metadata fields), as either or both would have +to be treated as ``dynamic``. +Grouping both license expressions and license files under the same key +forces an "all or nothing" approach, and creates ambiguity as to user intent. There are further downsides to this as well. Both users and tools would need to keep track of which fields are mutually exclusive with which of the others, greatly increasing cognitive and code complexity, and in turn the probability of errors. Conceptually, juxtaposing so many different fields under the same key is rather jarring, and leads to a much more complex mapping between -:pep:`621` keys and core metadata fields, not in keeping with :pep:`621`. -This causes the :pep:`621` naming and structure to diverge further from -both the core metadata and native formats of the various popular packaging +``[project]`` keys and core metadata fields, not in keeping with :pep:`621`. +This causes the ``[project]`` table naming and structure to diverge further +from both the core metadata and native formats of the various popular packaging tools that use it. Finally, this results in the spec being significantly more complex and convoluted to understand and implement than the alternatives. -The approach this PEP now takes, adding distinct ``license-expression`` and -``license-files`` keys and simply deprecating the whole ``license`` key, avoids -all the issues identified above, and results in a much clearer and cleaner -design overall. It allows ``license`` and ``license-files`` to be tagged +The approach this PEP now takes, using the reserved top-level string value +of the ``license`` key, adding a new ``license-files`` key +and deprecating the ``license`` table subkeys (``text`` and ``file``), +avoids most of the issues identified above, +and results in a much clearer and cleaner design overall. +It allows ``license`` and ``license-files`` to be tagged ``dynamic`` independently, separates two independent types of metadata (syntactically and semantically), restores a closer to 1:1 mapping of -:pep:`621` keys to core metadata fields, and reduces nesting by a level for both. -Other than adding two extra keys to the file, there was no significant +``[project]`` table keys to core metadata fields, +and reduces nesting by a level for both. +Other than adding one extra key to the file, there was no significant apparent downside to this latter approach, so it was adopted for this PEP. -Define license expression as string value -''''''''''''''''''''''''''''''''''''''''' +Add an ``expression`` subkey instead of a string value +'''''''''''''''''''''''''''''''''''''''''''''''''''''' -A compromise approach between adding two new top-level keys for license -expressions and files would be adding a separate ``license-files`` key, -but re-using the ``license`` key for the license expression, either by -defining it as the (previously reserved) string value for the ``license`` -key, retaining the ``expression`` subkey in the ``license`` table, or -allowing both. Indeed, this would seem to have been envisioned by :pep:`621` -itself with this PEP in mind, in particular the first approach: +Adding just an ``expression`` subkey to the ``license`` table, +instead of using the reserved top-level string value, +would be more explicit for readers and writers, +in line with this PEP's goals. +However, it still has the downsides listed above +that are not specific to the inclusion of the ``files`` key. + +Relative to a flat string value, +it adds verbosity, complexity and an extra level of nesting, +and requires users and tools to remember and handle +the mutual exclusivity of the subkeys +and remember which are deprecated and which are not, +instead of cleanly deprecating the table subkeys as a whole. +Furthermore, it is less clearly the "default" choice for modern use, +given users tend to gravitate toward the simplest and most obvious option. +Finally, it seems reasonable to follow the suggested guidance in :pep:`621`, +given the top-level string value was specifically reserved for this purpose. + + +Define a new top-level ``license-expression`` key +''''''''''''''''''''''''''''''''''''''''''''''''' + +An earlier version of this PEP defined a new, top-level ``license-expression`` +under the ``[project]`` table, +rather than using the reserved string value of the ``license`` key. +This was seen as clearer and more explicit for readers and writers, +in line with the goals of this PEP. + +Additionally, while differences from existing tool formats (and core metadata +field names) have precedent in :pep:`621`, +using a key with an identical name as in most/all current tools +to mean something different (and map to a different core metadata field), +with distinct and incompatible syntax and semantics, does not, +and could cause confusion and ambiguity for readers and authors. + +Also, per the `project source metadata spec `__, +this would allow separately marking the ``[project]`` keys +corresponding to the ``License`` and ``License-Expression`` metadata fields +as ``dynamic``, +avoiding a potential concern with back-filling the ``License`` field +from the ``License-Expression`` field as this PEP currently allows +without it as ``license`` as dynamic +(which would not be possible, since they both map to the same top-level key). + +However, community consensus favored using +the top-level string value of the existing ``license`` key, +as :pep:`reserved for this purpose by PEP 621 <621#license>`: A practical string value for the license key has been purposefully left out to allow for a future PEP to specify support for SPDX expressions (the same logic applies to any sort of "type" field specifying what license the file or text represents). -However, while a working draft temporarily explored this solution, it was -ultimately rejected, as it shared most of the downsides identified with -adding new subkeys under the existing ``license`` table, as well as several -of its own, with again minimal advantage over separating both. +This is shorter and simpler for users to remember and type, +avoids adding a new top-level key while taking advantage of an existing one, +guides users toward using a license expression as the default, +and follows what was envisioned in the original :pep:`621`. -Most importantly, it still means that per :pep:`621`, it is not possible to -separately mark the ``[project]`` keys corresponding to the ``License`` and -``License-Expression`` metadata fields as dynamic. This, in turn, still -renders specifying metadata following that standard incompatible with -conversion of legacy metadata, as specified in this PEP's -:ref:`639-spec-converting-metadata`, as :pep:`621` strictly prohibits the -``license`` key from being both present (to define the existing value of -the ``License`` field, or the path to a license file, and thus able to be -converted), and specified as ``dynamic`` (which would allow tools to -use the generated value for the ``License-Expression`` field. +Additionally, this allows cleanly deprecating the table values +without deprecating the key itself, +and makes them inherently mutually exclusive without users having to remember +and tools having to enforce it. -For the same reasons, this would make it impossible to back-fill the -``License`` field from the ``License-Expression`` field as this PEP -currently allows (without making an exception from strict -``dynamic`` behavior in this case), as again, marking ``license`` as dynamic -would mean it cannot be specified in the ``project`` table at all. +Finally, consistency with other tool formats and the underlying core metadata +was not considered a sufficient priority +to override the advantages of using the existing key, +and the ``dynamic`` concerns were mostly mitigated by +not specifying legacy license to license expression conversion at build time, +explicitly specifying backfilling the ``License`` field when not ``dynamic``, +and the fact that both fields are mutually exclusive, +so there is little practical need to distinguish which is dynamic. -Furthermore, this would mean existing project source metadata specifying -``license`` as ``dynamic`` would be ambiguous, as it would be impossible for -tools to statically determine if they are intended to conform to previous -metadata versions specifying ``License``, or this version specifying -``License-Expression``. Tools would have no way of determining which field, -if either, might be filled in the resulting distribution's core metadata. -By contrast, the present approach makes clear what the author intended, -allows tools to unambiguously determine which field(s) may be dynamically -inserted, and ensures backward compatibility such that current project -source metadata do not unknowingly specify both the old and the new field -as dynamic, and instead must do so explicitly per :pep:`621`'s intent. - -Additionally, while differences from existing tool formats (and core metadata -field names) has precedent in :pep:`621` (though is best avoided if practical), -using a key with an identical name as in all current tools (and of an existing -core metadata field) to mean something different (and map to a different -core metadata field), with distinct and incompatible syntax and semantics, -does not, and is likely to create substantial and confusion and ambiguity -for readers and authors, contrary to the fundamental goals of this PEP. - -Finally, this means that the top-level ``license`` key still maps to multiple -core metadata fields with different purposes and interpretation (``License`` -and ``License-Expression``), this would deny a clear separation from the -old behavior by not cleanly deprecating the ``license`` key, and -increases the complexity of the specification and implementation. - -In addition to the aforementioned issues, this also requires deciding between -the three individual approaches (``expression`` subkey, top-level string or -allowing both), all of which have further significant downsides and none of -which are clearly superior or more obvious, leading to needless bikeshedding. - -If the license expression was made the string value of the ``license`` key, -as reserved by :pep:`621`, it would be slightly shorter for users to type and -more obviously the preferred approach. However, it is far *less* obvious that -it is a license expression at all, to authors and those viewing the files, -and this lack of clarity, explicitness, ambiguity and potential for user -confusion is exactly what this PEP seeks to avoid, all to save a few characters -over other approaches. - -If an ``expression`` subkey was added to the ``license`` table, it would retain -the clarity of a new top-level key, but add additional complexity for no -real benefit, with an extra level of nesting, and users and tools needing to -deal with the mutual exclusivity of the subkeys, as before. And allowing both -(as a table subkey *and* the string value) would inherit both's downsides, -while adding even more spec and tool complexity and making there more than -"one obvious way to do it", further potentially confusing users. - -Therefore, a separate top-level ``license-expression`` key was adopted to avoid -all these issues, with relatively minimal downside aside from adding a single -additional key and (versus some approaches) a few extra characters to type. +Therefore, a top-level string value for ``license`` was adopted for this PEP, +as an earlier working draft had temporarily specified. -Add a ``type`` key to treat as expression -''''''''''''''''''''''''''''''''''''''''' +Add a ``type`` key to treat ``text`` as expression +'''''''''''''''''''''''''''''''''''''''''''''''''' -Instead of creating a new top-level ``license-expression`` key in the -:pep:`621` source metadata, one could add a ``type`` subkey to the existing -``license`` table to control whether ``text`` (or a string value) +Instead of using the reserved top-level string value +of the ``license`` key in the ``[project]`` table, +one could add a ``type`` subkey to the ``license`` table +to control whether ``text`` (or a string value) is interpreted as free-text or a license expression. This could make backward compatibility a little more seamless, as older tools could ignore it and always treat ``text`` as ``license``, while newer tools would @@ -1380,9 +1381,9 @@ alternative way that SPDX license expressions could be implemented. However, all the same downsides as in the previous item apply here, including greater complexity, a more complex mapping between the project source metadata and core metadata and inconsistency between the presentation -in tool config, :pep:`621` and core metadata, a much less clean deprecation, -further bikeshedding over what to name it, and inability to mark one but -not the other as dynamic, among others. +in tool config, project source metadata and core metadata, +a much less clean deprecation, further bikeshedding over what to name it, +and inability to mark one but not the other as dynamic, among others. In addition, while theoretically potentially a little easier in the short term, in the long term it would mean users would always have to remember @@ -1394,7 +1395,8 @@ with all the false positive and false negative issues as above. Therefore, for these as well as the same reasons this approach was rejected for the core metadata in favor of a distinct ``License-Expression`` field, -we similarly reject this here. +we similarly reject this here in favor of +the reserved string value of the ``license`` key. Must be marked dynamic to back-fill @@ -1402,14 +1404,15 @@ Must be marked dynamic to back-fill The ``license`` key in the ``pyproject.toml`` could be required to be explicitly set to dynamic in order for the ``License`` core metadata field -to be automatically back-filled from the value of the ``license-expression`` -key. This would be more explicit that the filling will be done, as strictly -speaking the ``license`` key is not (and cannot be) specified in +to be automatically back-filled from +the top-level string value of the ``license`` key. +This would be more explicit that the filling will be done, +as strictly speaking the ``license`` key is not (and cannot be) specified in ``pyproject.toml``, and satisfies a stricter interpretation of the letter -of the current :pep:`621` specification that this PEP revises. +of the previous :pep:`621` specification that this PEP revises. -However, this isn't seen to be necessary, because it is simply using the -static, verbatim literal value of the ``license-expression`` key, as specified +However, this doesn't seem to be necessary, because it is simply using the +static, verbatim literal value of the ``license`` key, as specified strictly in this PEP. Therefore, any conforming tool can trivially, deterministically and unambiguously derive this using only the static data in the ``pyproject.toml`` file itself. @@ -1431,7 +1434,7 @@ Source metadata ``license-files`` key ------------------------------------- Alternatives considered for the ``license-files`` key in the -:pep:`621` project source metadata, primarily related to the +``pyproject.toml`` ``[project]`` table, primarily related to the path/glob type handling. @@ -1439,7 +1442,7 @@ Add a ``type`` subkey to ``license-files`` '''''''''''''''''''''''''''''''''''''''''' Instead of defining mutually exclusive ``paths`` and ``globs`` subkeys -of the ``license-files`` :pep:`621` project metadata key, we could +of the ``license-files`` ``[project]`` table key, we could achieve the same effect with a ``files`` subkey for the list and a ``type`` subkey for how to interpret it. However, the latter offers no real advantage over the former, in exchange for requiring more keystrokes, @@ -1616,7 +1619,7 @@ Must be marked dynamic to use defaults '''''''''''''''''''''''''''''''''''''' It may seem outwardly sensible, at least with a particularly restrictive -interpretation of :pep:`621` 's description of the ``dynamic`` list, to +interpretation of :pep:`621`'s description of the ``dynamic`` list, to consider requiring the ``license-files`` key to be explicitly marked as ``dynamic`` in order for the default glob patterns to be used, or alternatively for license files to be matched and included at all. @@ -1641,8 +1644,9 @@ Finally, aside from adding an additional line of default-required boilerplate to the file, not defining the default as dynamic allows authors to clearly and unambiguously indicate when their build/packaging tools are going to be handling the inclusion of license files themselves rather than strictly -conforming to the :pep:`621` portions of this PEP; to do otherwise would defeat -the primary purpose of the ``dynamic`` list as a marker and escape hatch. +conforming to the project source metadata portions of this PEP; +to do otherwise would defeat the primary purpose of the ``dynamic`` list +as a marker and escape hatch. License file paths @@ -1669,10 +1673,10 @@ their specified license files have not been included. Furthermore, this leads to inconsistent relative file paths for non-root license files between the source, sdist and wheel, and prevents the paths -given in the :pep:`621` "static" metadata from being truly static, as they need -to be flattened, and may potentially overwrite one another. Finally, -the source directory structure often implies valuable information about -what the licenses apply to, and where to find them in the source, +given in the "static" ``[project]`` table metadata from being truly static, +as they need to be flattened, and may potentially overwrite one another. +Finally, the source directory structure often implies valuable information +about what the licenses apply to, and where to find them in the source, which is lost when flattening them and far from trivial to reconstruct. To resolve this, the PEP now proposes, as did contributors on both of the @@ -1683,7 +1687,7 @@ directory. There is still a risk of collision with edge-case custom filenames (e.g. ``RECORD``, ``METADATA``), but that is also the case with the previous approach, and in fact with fewer files flattened into the root, this would actually reduce the risk. Furthermore, -the following proposal rooting the license files under a ``license_files`` +the following proposal rooting the license files under a ``licenses`` subdirectory eliminates both collisions and the clutter problem entirely. @@ -1730,7 +1734,7 @@ without having to reference each of their paths from the core metadata. Therefore, now is a prudent time to specify an alternate approach. The simplest and most obvious solution, as suggested by several on the Wheel and Setuptools implementation issues, is to simply root the license files -relative to a ``license_files`` subdirectory of ``.dist-info``. This is simple +relative to a ``licenses`` subdirectory of ``.dist-info``. This is simple to implement and solves all the problems noted here, without clear significant drawbacks relative to other more complex options. @@ -1754,7 +1758,7 @@ Therefore, the latter has been incorporated into current drafts of this PEP. Add new ``licenses`` category to wheel '''''''''''''''''''''''''''''''''''''' -Instead of defining a root license directory (``license_files``) inside +Instead of defining a root license directory (``licenses``) inside the core metadata directory (``.dist-info``) for wheels, we could instead define a new category (and, presumably, a corresponding install scheme), similar to the others currently included under ``.data`` in the wheel archive, @@ -1790,16 +1794,18 @@ and decided that would avoid name clashes. Therefore, to keep this PEP in scope, the current approach was retained. -Name the subdirectory ``licenses`` -'''''''''''''''''''''''''''''''''' +Name the subdirectory ``license_files`` +''''''''''''''''''''''''''''''''''''''' Both ``licenses`` and ``license_files`` have been suggested as potential names for the root license directory inside ``.dist-info`` of wheels and -installed projects. The former is slightly shorter, but the latter is -more clear and unambiguous regarding its contents, and is consistent with -the name of the core metadata field (``License-File``) and the :pep:`621` -project source metadata key (``license-files``). Therefore, the latter -was chosen instead. +installed projects. An initial draft of the PEP specified the former +due to being slightly clearer and consistent with the +name of the core metadata field (``License-File``) +and the ``[project]`` table key (``license-files``). +However, the current version of the PEP adopts the ``license`` name, +due to a general preference by the community for its shorter length, +greater simplicity and the lack of a separator character (``_``, ``-``, etc.). Other ideas @@ -1993,8 +1999,8 @@ determined to be unnecessary or too problematic in practice. .. _639-examples: -Appendix: License Expression Examples -===================================== +Appendix: Examples +================== .. _639-example-basic: @@ -2023,12 +2029,12 @@ The simplest migration to this PEP would consist of using this instead: [metadata] license_expression = MIT -Or, in a :pep:`621` ``pyproject.toml``: +Or, in the ``[project]`` table of ``pyproject.toml``: .. code-block:: toml [project] - license-expression = "MIT" + license = "MIT" The output core metadata for the distribution packages would then be: @@ -2038,7 +2044,7 @@ The output core metadata for the distribution packages would then be: License-File: LICENSE The ``LICENSE`` file would be stored at ``/setuptools-${VERSION}/LICENSE`` -in the sdist and ``/setuptools-${VERSION}.dist-info/license_files/LICENSE`` +in the sdist and ``/setuptools-${VERSION}.dist-info/licenses/LICENSE`` in the wheel, and unpacked from there into the site directory (e.g. ``site-packages``) on installation; ``/`` is the root of the respective archive and ``${VERSION}`` the version of the Setuptools release in the core metadata. @@ -2108,13 +2114,13 @@ Putting it all together, our ``setup.cfg`` would be: setuptools/_vendor/packaging/LICENSE.APACHE setuptools/_vendor/packaging/LICENSE.BSD -In a :pep:`621` ``pyproject.toml``, with license files specified explicitly -via the ``paths`` subkey, this would look like: +In the ``[project]`` table of ``pyproject.toml``, with license files +specified explicitly via the ``paths`` subkey, this would look like: .. code-block:: toml [project] - license-expression = "MIT AND (Apache-2.0 OR BSD-2-Clause)" + license = "MIT AND (Apache-2.0 OR BSD-2-Clause)" license-files.paths = [ "LICENSE", "setuptools/_vendor/LICENSE", @@ -2127,7 +2133,7 @@ Or alternatively, matched via glob patterns, this could be: .. code-block:: toml [project] - license-expression = "MIT AND (Apache-2.0 OR BSD-2-Clause)" + license = "MIT AND (Apache-2.0 OR BSD-2-Clause)" license-files.globs = [ "LICENSE*", "setuptools/_vendor/LICENSE*", @@ -2160,51 +2166,20 @@ In the built wheel, with ``/`` being the root of the archive and .. code-block:: shell - /setuptools-${VERSION}.dist-info/license_files/LICENSE - /setuptools-${VERSION}.dist-info/license_files/setuptools/_vendor/packaging/LICENSE - /setuptools-${VERSION}.dist-info/license_files/setuptools/_vendor/packaging/LICENSE.APACHE - /setuptools-${VERSION}.dist-info/license_files/setuptools/_vendor/packaging/LICENSE.BSD + /setuptools-${VERSION}.dist-info/licenses/LICENSE + /setuptools-${VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE + /setuptools-${VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.APACHE + /setuptools-${VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.BSD Finally, in the installed project, with ``site-packages`` being the site dir and ``{version}`` as the previous, the license files would be installed to: .. code-block:: shell - site-packages/setuptools-${VERSION}.dist-info/license_files/LICENSE - site-packages/setuptools-${VERSION}.dist-info/license_files/setuptools/_vendor/packaging/LICENSE - site-packages/setuptools-${VERSION}.dist-info/license_files/setuptools/_vendor/packaging/LICENSE.APACHE - site-packages/setuptools-${VERSION}.dist-info/license_files/setuptools/_vendor/packaging/LICENSE.BSD - - -.. _639-example-conversion: - -Conversion example ------------------- - -Suppose we were to return to our simple Setuptools case. -Per the specification, given it only has the following license classifier: - -.. code-block:: email - - Classifier: License :: OSI Approved :: MIT License - -And no value for the ``License`` field, or equivalently, if it had a -value of: - -.. code-block:: email - - License: MIT - -Then the suggested value for the ``License-Expression`` field would be: - -.. code-block:: email - - License-Expression: MIT - -For the more complex case, assuming it was currently expressed as multiple -license classifiers, no automatic conversion could be performed due to the -inherent ambiguity, and the user would be prompted on how to handle the -situation themselves. + site-packages/setuptools-${VERSION}.dist-info/licenses/LICENSE + site-packages/setuptools-${VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE + site-packages/setuptools-${VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.APACHE + site-packages/setuptools-${VERSION}.dist-info/licenses/setuptools/_vendor/packaging/LICENSE.BSD .. _639-example-expression: @@ -2263,7 +2238,7 @@ widely used and allows anyone to do whatever they want with your work To apply it, just paste `the text `__ into a file named ``LICENSE.txt`` at the root of your repo, and add the year and your name to -the copyright line. Then, just add ``license-expression = "MIT"`` under +the copyright line. Then, just add ``license = "MIT"`` under ``[project]`` in your ``pyproject.toml`` if your packaging tool supports it, or in its config file/section (e.g. Setuptools ``license_expression = MIT`` under ``[metadata]`` in ``setup.cfg``). You're done! @@ -2275,7 +2250,7 @@ I want to distribute my project under a specific license To use a particular license, simply paste its text into a ``LICENSE.txt`` file at the root of your repo, if you don't have it in a file starting with ``LICENSE`` or ``COPYING`` already, and add -``license-expression = "LICENSE-ID"`` under ``[project]`` in your +``license = "LICENSE-ID"`` under ``[project]`` in your ``pyproject.toml`` if your packaging tool supports it, or else in its config file (e.g. for Setuptools, ``license_expression = LICENSE-ID`` under ``[metadata]`` in ``setup.cfg``). You can find the ``LICENSE-ID`` @@ -2294,9 +2269,10 @@ should only need to make a couple of tweaks to take advantage of the new functionality. In your project config file, enter your license expression under -``license-expression`` (:pep:`621` ``pyproject.toml``), ``license_expression`` -(Setuptools ``setup.cfg`` / ``setup.py``), or the equivalent for your -packaging tool, and make sure to remove any legacy ``license`` value or +``license`` (``[project]`` table in ``pyproject.toml``), +``license_expression`` (Setuptools ``setup.cfg`` / ``setup.py``), +or the equivalent for your packaging tool, +and make sure to remove any legacy ``license`` table subkeys or ``License ::`` classifiers. Your existing ``license`` value may already be valid as one (e.g. ``MIT``, ``Apache-2.0 OR BSD-2-Clause``, etc); otherwise, check the `SPDX license list `__ for the identifier @@ -2334,10 +2310,11 @@ parenthesis (``()``) for grouping to form expressions that cover even the most complex situations. In your project config file, enter your license expression under -``license-expression`` (:pep:`621` ``pyproject.toml``), ``license_expression`` -(Setuptools ``setup.cfg`` / ``setup.py``), or the equivalent for your -packaging tool, and make sure to remove any legacy ``license`` value or -``License ::`` classifiers. +``license`` (``[project]`` table of ``pyproject.toml``), +``license_expression`` (Setuptools ``setup.cfg`` / ``setup.py``), +or the equivalent for your packaging tool, +and make sure to remove any legacy ``license`` table subkeys +or ``License ::`` classifiers. Also, make sure you add the full license text of all the licenses as files somewhere in your project repository. If all of them are in the root directory @@ -2501,7 +2478,7 @@ Other Python packaging tools - `PBR `__ uses similar data as Setuptools, but always stored in ``setup.cfg``. -- `Poetry `__ specifies the use of the ``license`` field in +- `Poetry `__ specifies the use of the ``license`` key in ``pyproject.toml`` with SPDX license identifiers. @@ -2706,6 +2683,7 @@ References .. _composer: https://getcomposer.org/doc/04-schema.md#license .. _conda: https://docs.conda.io/projects/conda-build/en/stable/resources/define-metadata.html#about-section .. _coremetadataspec: https://packaging.python.org/specifications/core-metadata +.. _coremetadataclassifiers: https://packaging.python.org/en/latest/specifications/core-metadata/#classifier-multiple-use .. _cran: https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Licensing .. _cratesio: https://doc.rust-lang.org/cargo/reference/registries.html#publish .. _dep5: https://dep-team.pages.debian.net/deps/dep5/ @@ -2728,6 +2706,8 @@ References .. _gnu: https://www.gnu.org/licenses/identify-licenses-clearly.html .. _guix: https://git.savannah.gnu.org/cgit/guix.git/tree/guix/licenses.scm?h=v1.3.0 .. _guixlicense: https://guix.gnu.org/manual/en/html_node/package-Reference.html#index-license_002c-of-packages +.. _hatch: https://hatch.pypa.io/latest/ +.. _hatchimplementation: https://discuss.python.org/t/12622/22 .. _installedspec: https://packaging.python.org/specifications/recording-installed-packages/ .. _interopissue: https://github.com/pypa/interoperability-peps/issues/46 .. _licenseexplib: https://github.com/nexB/license-expression/ @@ -2751,6 +2731,7 @@ References .. _packagingtuttxt: https://packaging.python.org/tutorials/packaging-projects/#creating-a-license .. _pbr: https://docs.openstack.org/pbr/latest/user/features.html .. _pep621spec: https://packaging.python.org/specifications/declaring-project-metadata/ +.. _pep621specdynamic: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#dynamic .. _pepissue: https://github.com/pombredanne/spdx-pypi-pep/issues/1 .. _perl: https://metacpan.org/pod/CPAN::Meta::Spec#license .. _pipsetup: https://github.com/pypa/pip/blob/21.3.1/setup.cfg#L114