python-peps/pep-0459.txt

703 lines
24 KiB
Plaintext

PEP: 459
Title: Standard Metadata Extensions for Python Software Packages
Version: $Revision$
Last-Modified: $Date$
Author: Nick Coghlan <ncoghlan@gmail.com>
BDFL-Delegate: Nick Coghlan <ncoghlan@gmail.com>
Discussions-To: Distutils SIG <distutils-sig@python.org>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Requires: 426
Created: 11 Nov 2013
Post-History: 21 Dec 2013
Abstract
========
This PEP describes several standard extensions to the Python metadata.
Like all metadata extensions, each standard extension format is
independently versioned. Changing any of the formats requires an update
to this PEP, but does not require an update to the core packaging metadata.
.. note::
These extensions may eventually be separated out into their own PEPs,
but we're already suffering from PEP overload in the packaging
metadata space.
This PEP was initially created by slicing out large sections of earlier
drafts of PEP 426 and making them extensions, so some of the specifics
may still be rough in the new context.
Standard Extension Namespace
============================
The ``python`` project on the Python Package Index refers to the CPython
reference interpreter. This namespace is used as the namespace for the
standard metadata extensions.
The currently defined standard extensions are:
* ``python.details``
* ``python.project``
* ``python.integrator``
* ``python.commands``
* ``python.exports``
* ``python.metadata_hooks``
All standard extensions are currently at version ``1.0``, and thus the
``extension_metadata`` field may be omitted without losing access to any
functionality.
The ``details`` extension
=========================
The ``details`` extension allows for more information to be provided
regarding the software distribution.
The ``details`` extension contains three subfields:
* ``license``: the copyright license for the distribution
* ``keywords``: package index keywords for the distribution
* ``classifiers``: package index Trove classifiers for the distribution
* ``document_names``: the names of additional metadata files
All of these fields are optional. Automated tools MUST operate correctly if
a distribution does not provide them, including failing cleanly when an
operation depending on one of these fields is requested.
License
-------
A short string summarising the license used for this distribution.
Note that distributions that provide this field should still specify any
applicable license Trove classifiers in the `Classifiers`_ field. Even
when an appropriate Trove classifier is available, the license summary can
be a good way to specify a particular version of that license, or to
indicate any variations or exception to the license.
This field SHOULD contain fewer than 512 characters and MUST contain fewer
than 2048.
This field SHOULD NOT contain any line breaks.
The full license text SHOULD be included as a separate file in the source
archive for the distribution. See `Document names`_ for details.
Example::
"license": "GPL version 3, excluding DRM provisions"
Keywords
--------
A list of additional keywords to be used to assist searching for the
distribution in a larger catalog.
Example::
"keywords": ["comfy", "chair", "cushions", "too silly", "monty python"]
Classifiers
-----------
A list of strings, with each giving a single classification value
for the distribution. Classifiers are described in PEP 301 [2].
Example::
"classifiers": [
"Development Status :: 4 - Beta",
"Environment :: Console (Text Based)",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)"
]
Document names
--------------
Filenames for supporting documents included in the distribution's
``dist-info`` metadata directory.
The following supporting documents can be named:
* ``description``: a file containing a long description of the distribution
* ``license``: a file with the full text of the distribution's license
* ``changelog``: a file describing changes made to the distribution
Supporting documents MUST be included directly in the ``dist-info``
directory. Directory separators are NOT permitted in document names.
The markup format (if any) for the file is indicated by the file extension.
This allows index servers and other automated tools to render included
text documents correctly and provide feedback on rendering errors, rather
than having to guess the intended format.
If the filename has no extension, or the extension is not recognised, the
default rendering format MUST be plain text.
The following markup renderers SHOULD be used for the specified file
extensions:
* Plain text: ``.txt``, no extension, unknown extension
* reStructured Text: ``.rst``
* Markdown: ``.md``
* AsciiDoc: ``.adoc``, ``.asc``, ``.asciidoc``
* HTML: ``.html``, ``.htm``
Automated tools MAY render one or more of the specified formats as plain
text and MAY render other markup formats beyond those listed.
Automated tools SHOULD NOT make any assumptions regarding the maximum length
of supporting document content, except as necessary to protect the
integrity of a service.
Example::
"document_names": {
"description": "README.rst",
"license": "LICENSE.rst",
"changelog": "NEWS"
}
The ``project`` extension
=========================
The ``project`` extension allows for more information to be provided
regarding the creation and maintenance of the distribution.
The ``project`` extension contains three subfields:
* ``contacts``: key contact points for the distribution
* ``contributors``: other contributors to the distribution
* ``project_urls``: relevant URLs for the distribution
Contact information
-------------------
Details on individuals and organisations are recorded as mappings with
the following subfields:
* ``name``: the name of an individual or group
* ``email``: an email address (this may be a mailing list)
* ``url``: a URL (such as a profile page on a source code hosting service)
* ``role``: one of ``"author"``, ``"maintainer"`` or ``"contributor"``
The ``name`` subfield is required, the other subfields are optional.
If no specific role is stated, the default is ``contributor``.
Email addresses must be in the form ``local-part@domain`` where the
local-part may be up to 64 characters long and the entire email address
contains no more than 254 characters. The formal specification of the
format is in RFC 5322 (sections 3.2.3 and 3.4.1) and RFC 5321, with a more
readable form given in the informational RFC 3696 and the associated errata.
The defined contributor roles are as follows:
* ``author``: the original creator of a distribution
* ``maintainer``: the current lead contributor for a distribution, when
they are not the original creator
* ``contributor``: any other individuals or organizations involved in the
creation of the distribution
Contact and contributor metadata is optional. Automated tools MUST operate
correctly if a distribution does not provide it, including failing cleanly
when an operation depending on one of these fields is requested.
Contacts
--------
A list of contributor entries giving the recommended contact points for
getting more information about the project.
The example below would be suitable for a project that was in the process
of handing over from the original author to a new lead maintainer, while
operating as part of a larger development group.
Example::
"contacts": [
{
"name": "Python Packaging Authority/Distutils-SIG",
"email": "distutils-sig@python.org",
"url": "https://bitbucket.org/pypa/"
},
{
"name": "Samantha C.",
"role": "maintainer",
"email": "dontblameme@example.org"
},
{
"name": "Charlotte C.",
"role": "author",
"email": "iambecomingasketchcomedian@example.com"
}
]
Contributors
------------
A list of contributor entries for other contributors not already listed as
current project points of contact. The subfields within the list elements
are the same as those for the main contact field.
Example::
"contributors": [
{"name": "John C."},
{"name": "Erik I."},
{"name": "Terry G."},
{"name": "Mike P."},
{"name": "Graeme C."},
{"name": "Terry J."}
]
Project URLs
------------
A mapping of arbitrary text labels to additional URLs relevant to the
project.
While projects are free to choose their own labels and specific URLs,
it is RECOMMENDED that home page, source control, issue tracker and
documentation links be provided using the labels in the example below.
URL labels MUST be treated as case insensitive by automated tools, but they
are not required to be valid Python identifiers. Any legal JSON string is
permitted as a URL label.
Example::
"project_urls": {
"Documentation": "https://distlib.readthedocs.org",
"Home": "https://bitbucket.org/pypa/distlib",
"Repository": "https://bitbucket.org/pypa/distlib/src",
"Tracker": "https://bitbucket.org/pypa/distlib/issues"
}
The ``integrator`` extension
============================
Structurally, this extension is identical to the ``project`` extension.
However, where the ``project`` metadata refers to the upstream creators
of the software, the ``integrator`` metadata refers to the downstream
redistributor of a modified version.
If the software is being redistributed unmodified, then typically this
extension will not be used. However, if the software has been patched (for
example, backporting compatible fixes from a later version, or addressing
a platform compatibility issue), then this extension SHOULD be used, and
an integrator suffix added to the package version number.
If there are multiple redistributors in the chain, each one just overwrites
this extension with their particular metadata.
The ``exports`` extension
=========================
Most Python distributions expose packages and modules for import through
the Python module namespace. Distributions may also expose other
interfaces when installed.
The ``exports`` extension contains three subfields:
* ``modules``: modules exported by the distribution
* ``namespaces``: namespace packages that the distribution contributes to
* ``exports``: other Python interfaces exported by the distribution
Export specifiers
-----------------
An export specifier is a string consisting of a fully qualified name, as
well as an optional extra name enclosed in square brackets. This gives the
following four possible forms for an export specifier::
module
module:name
module[requires_extra]
module:name[requires_extra]
.. note::
The jsonschema file currently restricts qualified names using the
Python 2 ASCII identifier rules. This may need to be reconsidered
given the more relaxed identifier rules in Python 3.
The meaning of the subfields is as follows:
* ``module``: the module providing the export
* ``name``: if applicable, the qualified name of the export within the module
* ``requires_extra``: indicates the export will only work correctly if the
additional dependencies named in the given extra are available in the
installed environment
.. note::
I tried this as a mapping with subfields, and it made the examples below
unreadable. While this PEP is mostly for tool use, readability still
matters to some degree for debugging purposes, and because I expect
snippets of the format to be reused elsewhere.
Modules
-------
A list of qualified names of modules and packages that the distribution
provides for import.
.. note::
The jsonschema file currently restricts qualified names using the
Python 2 ASCII identifier rules. This may need to be reconsidered
given the more relaxed identifier rules in Python 3.
For names that contain dots, the portion of the name before the final dot
MUST appear either in the installed module list or in the namespace package
list.
To help avoid name conflicts, it is RECOMMENDED that distributions provide
a single top level module or package that matches the distribution name
(or a lower case equivalent). This requires that the distribution name also
meet the requirements of a Python identifier, which are stricter than
those for distribution names). This practice will also make it easier to
find authoritative sources for modules.
Index servers SHOULD allow multiple distributions to publish the same
modules, but MAY notify distribution authors of potential conflicts.
Installation tools SHOULD report an error when asked to install a
distribution that provides a module that is also provided by a different,
previously installed, distribution.
Note that attempting to import some declared modules may result in an
exception if the appropriate extras are not installed.
Example::
"modules": ["chair", "chair.cushions", "python_sketches.nobody_expects"]
.. note::
Making this a list of export specifiers instead would allow a distribution
to declare when a particular module requires a particular extra in order
to run correctly. On the other hand, there's an argument to be made that
that is the point where it starts to become worthwhile to split out a
separate distribution rather than using extras.
Namespaces
----------
A list of qualified names of namespace packages that the distribution
contributes modules to.
.. note::
The jsonschema file currently restricts qualified names using the
Python 2 ASCII identifier rules. This may need to be reconsidered
given the more relaxed identifier rules in Python 3.
On versions of Python prior to Python 3.3 (which provides native namespace
package support), installation tools SHOULD emit a suitable ``__init__.py``
file to properly initialise the namespace rather than using a distribution
provided file.
Installation tools SHOULD emit a warning and MAY emit an error if a
distribution declares a namespace package that conflicts with the name of
an already installed module or vice-versa.
Example::
"namespaces": ["python_sketches"]
Exports
-------
The ``exports`` field is a mapping containing prefixed names as keys. Each
key identifies an export group containing one or more exports published by
the distribution.
Export group names are defined by distributions that will then make use of
the published export information in some way. The primary use case is for
distributions that support a plugin model: defining an export group allows
other distributions to indicate which plugins they provide, how they
can be imported and accessed, and which additional dependencies (if any)
are needed for the plugin to work correctly.
To reduce the chance of name conflicts, export group names SHOULD use a
prefix that corresponds to a module name in the distribution that defines
the meaning of the export group. This practice will also make it easier to
find authoritative documentation for export groups.
Each individual export group is then a mapping of arbitrary non-empty string
keys to export specifiers. The meaning of export names within an export
group is up to the distribution that defines the export group. Creating an
appropriate definition for the export name format can allow the importing
distribution to determine whether or not an export is relevant without
needing to import every exporting module.
Example::
"exports": {
"nose.plugins.0.10": {
"chairtest": "chair:NosePlugin"
}
}
The ``commands`` extension
==========================
The ``commands`` extension contains three subfields:
* ``wrap_console``: console wrapper scripts to be generated by the installer
* ``wrap_gui``: GUI wrapper scripts to be generated by the installer
* ``prebuilt``: scripts created by the distribution's build process and
installed directly to the configured scripts directory
``wrap_console`` and ``wrap_gui`` are both mappings of script names to
export specifiers. The script names must follow the same naming rules as
distribution names.
The export specifiers for wrapper scripts must refer to either a package
with a __main__ submodule (if no ``name`` subfield is given in the export
specifier) or else to a callable inside the named module.
Installation tools should generate appropriate wrappers as part of the
installation process.
.. note::
Still needs more detail on what "appropriate wrappers" means. For now,
refer to what setuptools and zc.buildout generate as wrapper scripts.
``prebuilt`` is a list of script paths, relative to the scripts directory in
a wheel file or following installation. They are provided for informational
purpose only - installing them is handled through the normal processes for
files created when building a distribution.
Index servers SHOULD allow multiple distributions to publish the same
commands, but MAY notify distribution authors of potential conflicts.
Installation tools SHOULD report an error when asked to install a
distribution that provides a command that is also provided by a different,
previously installed, distribution.
Example::
"commands": {
"wrap_console": [{"chair": "chair:run_cli"}],
"wrap_gui": [{"chair-gui": "chair:run_gui"}],
"prebuilt": ["reduniforms"]
}
The ``metadata_hooks`` extension
================================
The ``metadata_hooks`` extension is used to define operations to be
invoked on the distribution in the following situations:
* a relevant distribution has been installed or changed on the system
* a relevant distribution has been completely uninstalled from the system
The following subfields determine when hooks are triggered:
* ``export_groups``: trigger based on named export groups
* ``extensions``: trigger based on named extensions
Note that distributions *do* trigger their own install hooks, but do
*not* trigger their own uninstall hooks.
Hook signatures
---------------
The currently defined metadata hooks are:
* ``postinstall``: run after a relevant distribution has been installed,
upgraded or downgraded on the current system. May also be run as part
of a system state resync operation. If the hook is not defined, it
indicates no distribution specific actions are needed following
installation.
* ``postuninstall``: run after a relevant distribution has been completely
removed from the current system. If the hook is not defined, it indicates
no distribution specific actions are needed following uninstallation.
The required signatures of these hooks are as follows::
def postinstall(current_meta, previous_meta=None):
"""Run following installation or upgrade of a relevant distribution
*current_meta* is the distribution metadata for the version now
installed on the current system
*previous_meta* is either omitted or ``None`` (indicating a fresh
install) or else the distribution metadata for the version that
was previously installed (indicating an upgrade, downgrade or
resynchronisation of the system state).
"""
def postuninstall(previous_meta):
"""Run after complete uninstallation of a relevant distribution
*previous_meta* is the distribution metadata for the version that
was previously installed on the current system
"""
Export group hooks
------------------
Export group hooks are named after the export group of interest::
"export_groups": {
"ComfyChair.plugins": {
"postinstall": "ComfyChair.plugins:install_hook",
"postuininstall": "ComfyChair.plugins:uninstall_hook"
}
}
The nominated hooks will then be invoked appropriately for any distribution
that publishes that export group as part of their ``python.exports``
extension metadata.
A trailing ".*" may be used to request prefix matching rather than
requiring an exact match on the export group name.
Extension hooks
---------------
Extension hooks are named after the metadata extension of interest::
"extensions": {
"python.exports": {
"postinstall": "pip.export_group_hooks:run_install_hooks",
"postuininstall": "pip.export_group_hooks:run_uninstall_hooks"
}
"python.commands": {
"postinstall": "pip.command_hook:install_wrapper_scripts",
}
}
(Note: this is just an example, but the intent is that pip *could* implement
that functionality that way if it wanted to).
A trailing ".*" may be used to request prefix matching rather than
requiring an exact match on the extension name.
Guidelines for metadata hook invocation
---------------------------------------
.. note::
Metadata hooks are likely to run with elevated privileges, this needs
to be considered carefully (e.g. by *requiring* that metadata hook
installation be opt in when using the standard tools and running with
elevated privileges).
The given parameter names are considered part of the hook signature.
Installation tools MUST call metadata hooks solely with keyword arguments.
When metadata hooks are defined, it is assumed that they MUST be executed
to obtain a properly working installation of the distribution, and to
properly remove the distribution from a system.
Installation tools MUST ensure the new or updated distribution is fully
installed, and available through the import system and installation database
when invoking install hooks.
Installation tools MUST ensure the removed distribution is fully uninstalled,
and no longer available through the import system and installation database
when invoking uninstall hooks.
Installation tools MUST call metadata hooks with full metadata (including
all extensions), rather than only the core metadata.
Installation tools SHOULD invoke metadata hooks automatically after
installing a distribution from a binary archive.
When installing from an sdist, source archive or VCS checkout, installation
tools SHOULD create a binary archive using ``setup.py bdist_wheel`` and
then install the binary archive normally (including invocation of any
metadata hooks). Installation tools SHOULD NOT invoke ``setup.py install``
directly.
Installation tools SHOULD treat an exception thrown by a metadata install
hook as a failure of the installation and revert any other changes made
to the system. The installed distribution responsible for the hook that
failed should be clearly indicated to the user.
Installation tools SHOULD provide a warning to the user for any exception
thrown by a metadata uninstall hook, again clearly indicating to the user
the installed distribution that triggered the warning.
Installation tools MUST NOT silently ignore metadata hooks, as failing
to call these hooks may result in a misconfigured installation that fails
unexpectedly at runtime. Installation tools MAY refuse to install
distributions that define metadata hooks, or require that users
explicitly opt in to permitting the installation of packages that
define such hooks.
Guidelines for metadata hook implementations
--------------------------------------------
The given parameter names are considered part of the hook signature.
Metadata hook implementations MUST use the given parameter names.
Metadata hooks SHOULD NOT be used to provide functionality that is
expected to be provided by installation tools (such as rewriting of
shebang lines and generation of executable wrappers for Windows).
Metadata hook implementations MUST NOT make any assumptions regarding the
current working directory when they are invoked, and MUST NOT make
persistent alterations to the working directory or any other process global
state (other than potentially importing additional modules, or other
expected side effects of running the distribution).
Metadata install hooks have access to the full metadata for the release being
installed, that of the previous/next release (as appropriate), as well as
to all the normal runtime information (such as available imports). Hook
implementations can use this information to perform additional platform
specific installation steps. To check for the presence or absence of
"extras", hook implementations should use the same runtime checks that
would be used during normal operation (such as checking for the availability
of the relevant dependencies).
Copyright
=========
This document has been placed in the public domain.
..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End: