PEP: 390 Title: Static metadata for Distutils Version: $Revision$
Last-Modified: $Date$ Author: Tarek Ziadé <tarek@ziade.org>
BDFL-Delegate: Alyssa Coghlan Discussions-To: distutils-sig@python.org
Status: Rejected Type: Standards Track Topic: Packaging Content-Type:
text/x-rst Created: 10-Oct-2009 Python-Version: 2.7, 3.2 Post-History:
Resolution:
https://mail.python.org/pipermail/distutils-sig/2013-April/020597.html

Abstract

This PEP describes a new section and a new format for the setup.cfg
file, that allows describing the Metadata of a package without using
setup.py.

Rejection Notice

As distutils2 is no longer going to be incorporated into the standard
library, this PEP was rejected by Alyssa Coghlan in late April, 2013.

A replacement PEP based on PEP 426 (metadata 2.0) will be created that
defines the minimum amount of information needed to generate an sdist
archive given a source tarball or VCS checkout.

Rationale

Today, if you want to list all the Metadata of a distribution (see PEP
314) that is not installed, you need to use the setup.py command line
interface.

So, basically, you download it, and run:

    $ python setup.py --name
    Distribute

    $ python setup.py --version
    0.6.4

Where name and version are metadata fields. This is working fine but as
soon as the developers add more code in setup.py, this feature might
break or in worst cases might do unwanted things on the target system.

Moreover, when an OS packager wants to get the metadata of a
distribution he is re-packaging, he might encounter some problems to
understand the setup.py file he's working with.

So the rationale of this PEP is to provide a way to declare the metadata
in a static configuration file alongside setup.py that doesn't require
any third party code to run.

Adding a metadata section in setup.cfg

The first thing we want to introduce is a [metadata] section, in the
setup.cfg file, that may contain any field from the Metadata:

    [metadata]
    name = Distribute
    version = 0.6.4

The setup.cfg file is used to avoid adding yet another configuration
file to work with in Distutils.

This file is already read by Distutils when a command is executed, and
if the metadata section is found, it will be used to fill the metadata
fields. If an option that corresponds to a Metadata field is given to
setup(), it will override the value that was possibly present in
setup.cfg.

Notice that setup.py is still used and can be required to define some
options that are not part of the Metadata fields. For instance, the
sdist command can use options like packages or scripts.

Multi-lines values

Some Metadata fields can have multiple values. To keep setup.cfg
compatible with ConfigParser and the 822 LONG HEADER FIELDS (see section
3.1.1), these are expressed with ,-separated values:

    requires = pywin32, bar > 1.0, foo

When this variable is read, the values are parsed and transformed into a
list: ['pywin32', 'bar > 1.0', 'foo'].

Context-dependant sections

The metadata section will also be able to use context-dependant
sections.

A context-dependant section is a section with a condition about the
execution environment. Here's some examples:

    [metadata]
    name = Distribute
    version = 0.6.4

    [metadata:sys_platform == 'win32']
    requires = pywin32, bar > 1.0
    obsoletes = pywin31

    [metadata:os_machine == 'i386']
    requires = foo

    [metadata:python_version == '2.4' or python_version == '2.5']
    requires = bar

    [metadata:'linux' in sys_platform]
    requires = baz

Every [metadata:condition] section will be used only if the condition is
met when the file is read. The background motivation for these
context-dependant sections is to be able to define requirements that
varies depending on the platform the distribution might be installed on.
(see PEP 314).

The micro-language behind this is the simplest possible: it compares
only strings, with the == and in operators (and their opposites), and
with the ability to combine expressions. It makes it also easy to
understand to non-pythoneers.

The pseudo-grammar is :

    EXPR [in|==|!=|not in] EXPR [or|and] ...

where EXPR belongs to any of those:

-   python_version = '%s.%s' % (sys.version_info[0],
    sys.version_info[1])
-   os_name = os.name
-   sys_platform = sys.platform
-   platform_version = platform.version()
-   platform_machine = platform.machine()
-   a free string, like 2.4, or win32

Notice that in is restricted to strings, meaning that it is not possible
to use other sequences like tuples or lists on the right side.

Distutils will provide a function that is able to generate the metadata
of a distribution, given a setup.cfg file, for the execution
environment:

    >>> from distutils.util import local_metadata
    >>> local_metadata('setup.cfg')
    <DistributionMetadata instance>

This means that a vanilla Python will be able to read the metadata of a
package without running any third party code.

Notice that this feature is not restricted to the metadata namespace.
Consequently, any other section can be extended with such
context-dependant sections.

Impact on PKG-INFO generation and PEP 314

When PKG-INFO is generated by Distutils, every field that relies on a
condition will have that condition written at the end of the line, after
a ; separator:

    Metadata-Version: 1.2
    Name: distribute
    Version: 0.6.4
    ...
    Requires: pywin32, bar > 1.0; sys_platform == 'win32'
    Requires: foo; os_machine == 'i386'
    Requires: bar; python_version == '2.4' or python_version == '2.5'
    Requires: baz; 'linux' in sys_platform
    Obsoletes = pywin31; sys_platform == 'win32'
    ...
    Classifier: Development Status :: 5 - Production/Stable
    Classifier: Intended Audience :: Developers
    Classifier: License :: OSI Approved :: Python Software Foundation License

Notice that this file can be opened with the DistributionMetadata class.
This class will be able to use the micro-language using the execution
environment.

Let's run in on a Python 2.5 i386 Linux:

    >>> from distutils.dist import DistributionMetadata
    >>> metadata = DistributionMetadata('PKG_INFO')
    >>> metadata.get_requires()
    ['foo', 'bar', 'baz']

The execution environment can be overridden in case we want to get the
metadata for another environment:

    >>> env = {'python_version': '2.4',
    ...        'os_name': 'nt',
    ...        'sys_platform': 'win32',
    ...        'platform_version': 'MVCC++ 6.0'
    ...        'platform_machine': 'i386'}
    ...
    >>> metadata = DistributionMetadata('PKG_INFO', environment=env)
    >>> metadata.get_requires()
    ['bar > 1.0', 'foo', 'bar']

PEP 314 is changed accordingly, meaning that each field will be able to
have that extra condition marker.

Compatibility

This change is based on a new metadata 1.2 format meaning that Distutils
will be able to distinguish old PKG-INFO files from new ones.

The setup.cfg file change will stay ConfigParser-compatible and will not
break existing setup.cfg files.

Limitations

We are not providing < and > operators at this time, and python_version
is a regular string. This implies using or operators when a section
needs to be restricted to a couple of Python versions. Although, if PEP
386 is accepted, python_version could be changed internally into
something comparable with strings, and < and > operators introduced.

Last, if a distribution is unable to set all metadata fields in
setup.cfg, that's fine, the fields will be set to UNKNOWN when
local_metadata is called. Getting UNKNOWN values will mean that it might
be necessary to run the setup.py command line interface to get the whole
set of metadata.

Acknowledgments

The Distutils-SIG.

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 coding: utf-8 End: