Kaydet (Commit) 3a9f58f6 authored tarafından Éric Araujo's avatar Éric Araujo

Add documentation for the packaging module.

This updates the user guide to refer to Packaging instead of Distutils.
Some files still require an update.
üst a003af1c
......@@ -11,7 +11,7 @@
library/index.rst
extending/index.rst
c-api/index.rst
distutils/index.rst
packaging/index.rst
install/index.rst
documenting/index.rst
howto/index.rst
......
......@@ -29,3 +29,16 @@ very little overhead for build/release/install mechanics.
extending.rst
commandref.rst
apiref.rst
Another document describes how to install modules and extensions packaged
following the above guidelines:
.. toctree::
install.rst
.. seealso::
:ref:`packaging-index` and :ref:`packaging-install-index`
Documentation of Packaging, the new version of Distutils.
This diff is collapsed.
.. _packaging-pysetup-config:
=====================
Pysetup Configuration
=====================
Pysetup supports two configuration files: :file:`.pypirc` and :file:`packaging.cfg`.
.. FIXME integrate with configfile instead of duplicating
Configuring indexes
-------------------
You can configure additional indexes in :file:`.pypirc` to be used for index-related
operations. By default, all configured index-servers and package-servers will be used
in an additive fashion. To limit operations to specific indexes, use the :option:`--index`
and :option:`--package-server options`::
$ pysetup install --index pypi --package-server django some.project
Adding indexes to :file:`.pypirc`::
[packaging]
index-servers =
pypi
other
package-servers =
django
[pypi]
repository: <repository-url>
username: <username>
password: <password>
[other]
repository: <repository-url>
username: <username>
password: <password>
[django]
repository: <repository-url>
username: <username>
password: <password>
.. _packaging-pysetup-servers:
===============
Package Servers
===============
Pysetup supports installing Python packages from *Package Servers* in addition
to PyPI indexes and mirrors.
Package Servers are simple directory listings of Python distributions. Directories
can be served via HTTP or a local file system. This is useful when you want to
dump source distributions in a directory and not worry about the full index structure.
Serving distributions from Apache
---------------------------------
::
$ mkdir -p /var/www/html/python/distributions
$ cp *.tar.gz /var/www/html/python/distributions/
<VirtualHost python.example.org:80>
ServerAdmin webmaster@domain.com
DocumentRoot "/var/www/html/python"
ServerName python.example.org
ErrorLog logs/python.example.org-error.log
CustomLog logs/python.example.org-access.log common
Options Indexes FollowSymLinks MultiViews
DirectoryIndex index.html index.htm
<Directory "/var/www/html/python/distributions">
Options Indexes FollowSymLinks MultiViews
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Add the Apache based distribution server to :file:`.pypirc`::
[packaging]
package-servers =
apache
[apache]
repository: http://python.example.org/distributions/
Serving distributions from a file system
----------------------------------------
::
$ mkdir -p /data/python/distributions
$ cp *.tar.gz /data/python/distributions/
Add the directory to :file:`.pypirc`::
[packaging]
package-servers =
local
[local]
repository: file:///data/python/distributions/
.. _packaging-pysetup:
================
Pysetup Tutorial
================
Getting started
---------------
Pysetup is a simple script that supports the following features:
- install, remove, list, and verify Python packages;
- search for available packages on PyPI or any *Simple Index*;
- verify installed packages (md5sum, installed files, version).
Finding out what's installed
----------------------------
Pysetup makes it easy to find out what Python packages are installed::
$ pysetup search virtualenv
virtualenv 1.6 at /opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info
$ pysetup search --all
pyverify 0.8.1 at /opt/python3.3/lib/python3.3/site-packages/pyverify-0.8.1.dist-info
virtualenv 1.6 at /opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info
wsgiref 0.1.2 at /opt/python3.3/lib/python3.3/wsgiref.egg-info
...
Installing a distribution
-------------------------
Pysetup can install a Python project from the following sources:
- PyPI and Simple Indexes;
- source directories containing a valid :file:`setup.py` or :file:`setup.cfg`;
- distribution source archives (:file:`project-1.0.tar.gz`, :file:`project-1.0.zip`);
- HTTP (http://host/packages/project-1.0.tar.gz).
Installing from PyPI and Simple Indexes::
$ pysetup install project
$ pysetup install project==1.0
Installing from a distribution source archive::
$ pysetup install project-1.0.tar.gz
Installing from a source directory containing a valid :file:`setup.py` or
:file:`setup.cfg`::
$ cd path/to/source/directory
$ pysetup install
$ pysetup install path/to/source/directory
Installing from HTTP::
$ pysetup install http://host/packages/project-1.0.tar.gz
Retrieving metadata
-------------------
You can gather metadata from two sources, a project's source directory or an
installed distribution. The `pysetup metadata` command can retrieve one or
more metadata fields using the `-f` option and a metadata field as the
argument. ::
$ pysetup metadata virtualenv -f version -f name
Version:
1.6
Name:
virtualenv
$ pysetup metadata virtualenv --all
Metadata-Version:
1.0
Name:
virtualenv
Version:
1.6
Platform:
UNKNOWN
Summary:
Virtual Python Environment builder
...
.. seealso::
There are three metadata versions, 1.0, 1.1, and 1.2. The following PEPs
describe specifics of the field names, and their semantics and usage. 1.0
:PEP:`241`, 1.1 :PEP:`314`, and 1.2 :PEP:`345`
Removing a distribution
-----------------------
You can remove one or more installed distributions using the `pysetup remove`
command::
$ pysetup remove virtualenv
removing 'virtualenv':
/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info/dependency_links.txt
/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info/entry_points.txt
/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info/not-zip-safe
/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info/PKG-INFO
/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info/SOURCES.txt
/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info/top_level.txt
Proceed (y/n)? y
success: removed 6 files and 1 dirs
The optional '-y' argument auto confirms, skipping the conformation prompt::
$ pysetup remove virtualenv -y
Getting help
------------
All pysetup actions take the `-h` and `--help` options which prints the commands
help string to stdout. ::
$ pysetup remove -h
Usage: pysetup remove dist [-y]
or: pysetup remove --help
Uninstall a Python package.
positional arguments:
dist installed distribution name
optional arguments:
-y auto confirm package removal
Getting a list of all pysetup actions and global options::
$ pysetup --help
Usage: pysetup [options] action [action_options]
Actions:
run: Run one or several commands
metadata: Display the metadata of a project
install: Install a project
remove: Remove a project
search: Search for a project
graph: Display a graph
create: Create a Project
To get more help on an action, use:
pysetup action --help
Global options:
--verbose (-v) run verbosely (default)
--quiet (-q) run quietly (turns verbosity off)
--dry-run (-n) don't actually do anything
--help (-h) show detailed help message
--no-user-cfg ignore pydistutils.cfg in your home directory
--version Display the version
This diff was suppressed by a .gitattributes entry.
......@@ -27,3 +27,8 @@ This package is discussed in two separate chapters:
modules into an existing Python installation. You do not need to be a
Python programmer to read this manual.
.. toctree::
:hidden:
../distutils/index
.. temporary file for modules that don't need a dedicated file yet
:mod:`packaging.errors` --- Packaging exceptions
================================================
.. module:: packaging.errors
:synopsis: Packaging exceptions.
Provides exceptions used by the Packaging modules. Note that Packaging modules
may raise standard exceptions; in particular, SystemExit is usually raised for
errors that are obviously the end-user's fault (e.g. bad command-line arguments).
This module is safe to use in ``from ... import *`` mode; it only exports
symbols whose names start with ``Packaging`` and end with ``Error``.
:mod:`packaging.manifest` --- The Manifest class
================================================
.. module:: packaging.manifest
:synopsis: The Manifest class, used for poking about the file system and
building lists of files.
This module provides the :class:`Manifest` class, used for poking about the
filesystem and building lists of files.
:mod:`packaging.command` --- Standard Packaging commands
========================================================
.. module:: packaging.command
:synopsis: Standard packaging commands.
This subpackage contains one module for each standard Packaging command, such as
:command:`build` or :command:`upload`. Each command is implemented as a
separate module, with the command name as the name of the module and of the
class defined therein.
:mod:`packaging.command.cmd` --- Abstract base class for Packaging commands
===========================================================================
.. module:: packaging.command.cmd
:synopsis: Abstract base class for commands.
This module supplies the abstract base class :class:`Command`. This class is
subclassed by the modules in the packaging.command subpackage.
.. class:: Command(dist)
Abstract base class for defining command classes, the "worker bees" of the
Packaging. A useful analogy for command classes is to think of them as
subroutines with local variables called *options*. The options are declared
in :meth:`initialize_options` and defined (given their final values) in
:meth:`finalize_options`, both of which must be defined by every command
class. The distinction between the two is necessary because option values
might come from the outside world (command line, config file, ...), and any
options dependent on other options must be computed after these outside
influences have been processed --- hence :meth:`finalize_options`. The body
of the subroutine, where it does all its work based on the values of its
options, is the :meth:`run` method, which must also be implemented by every
command class.
The class constructor takes a single argument *dist*, a
:class:`~packaging.dist.Distribution` instance.
Creating a new Packaging command
--------------------------------
This section outlines the steps to create a new Packaging command.
.. XXX the following paragraph is focused on the stdlib; expand it to document
how to write and register a command in third-party projects
A new command lives in a module in the :mod:`packaging.command` package. There
is a sample template in that directory called :file:`command_template`. Copy
this file to a new module with the same name as the new command you're
implementing. This module should implement a class with the same name as the
module (and the command). So, for instance, to create the command
``peel_banana`` (so that users can run ``setup.py peel_banana``), you'd copy
:file:`command_template` to :file:`packaging/command/peel_banana.py`, then edit
it so that it's implementing the class :class:`peel_banana`, a subclass of
:class:`Command`. It must define the following methods:
.. method:: Command.initialize_options()
Set default values for all the options that this command supports. Note that
these defaults may be overridden by other commands, by the setup script, by
config files, or by the command line. Thus, this is not the place to code
dependencies between options; generally, :meth:`initialize_options`
implementations are just a bunch of ``self.foo = None`` assignments.
.. method:: Command.finalize_options()
Set final values for all the options that this command supports. This is
always called as late as possible, i.e. after any option assignments from the
command line or from other commands have been done. Thus, this is the place
to to code option dependencies: if *foo* depends on *bar*, then it is safe to
set *foo* from *bar* as long as *foo* still has the same value it was
assigned in :meth:`initialize_options`.
.. method:: Command.run()
A command's raison d'etre: carry out the action it exists to perform,
controlled by the options initialized in :meth:`initialize_options`,
customized by other commands, the setup script, the command line, and config
files, and finalized in :meth:`finalize_options`. All terminal output and
filesystem interaction should be done by :meth:`run`.
Command classes may define this attribute:
.. attribute:: Command.sub_commands
*sub_commands* formalizes the notion of a "family" of commands,
e.g. ``install_dist`` as the parent with sub-commands ``install_lib``,
``install_headers``, etc. The parent of a family of commands defines
*sub_commands* as a class attribute; it's a list of 2-tuples ``(command_name,
predicate)``, with *command_name* a string and *predicate* a function, a
string or ``None``. *predicate* is a method of the parent command that
determines whether the corresponding command is applicable in the current
situation. (E.g. ``install_headers`` is only applicable if we have any C
header files to install.) If *predicate* is ``None``, that command is always
applicable.
*sub_commands* is usually defined at the *end* of a class, because
predicates can be methods of the class, so they must already have been
defined. The canonical example is the :command:`install_dist` command.
.. XXX document how to add a custom command to another one's subcommands
This diff is collapsed.
This diff is collapsed.
:mod:`packaging.depgraph` --- Dependency graph builder
======================================================
.. module:: packaging.depgraph
:synopsis: Graph builder for dependencies between releases.
This module provides the means to analyse the dependencies between various
distributions and to create a graph representing these dependency relationships.
In this document, "distribution" refers to an instance of
:class:`packaging.database.Distribution` or
:class:`packaging.database.EggInfoDistribution`.
.. XXX terminology problem with dist vs. release: dists are installed, but deps
use releases
.. XXX explain how to use it with dists not installed: Distribution can only be
instantiated with a path, but this module is useful for remote dist too
.. XXX functions should accept and return iterators, not lists
The :class:`DependencyGraph` class
----------------------------------
.. class:: DependencyGraph
Represent a dependency graph between releases. The nodes are distribution
instances; the edge model dependencies. An edge from ``a`` to ``b`` means
that ``a`` depends on ``b``.
.. method:: add_distribution(distribution)
Add *distribution* to the graph.
.. method:: add_edge(x, y, label=None)
Add an edge from distribution *x* to distribution *y* with the given
*label* (string).
.. method:: add_missing(distribution, requirement)
Add a missing *requirement* (string) for the given *distribution*.
.. method:: repr_node(dist, level=1)
Print a subgraph starting from *dist*. *level* gives the depth of the
subgraph.
Direct access to the graph nodes and edges is provided through these
attributes:
.. attribute:: adjacency_list
Dictionary mapping distributions to a list of ``(other, label)`` tuples
where ``other`` is a distribution and the edge is labeled with ``label``
(i.e. the version specifier, if such was provided).
.. attribute:: reverse_list
Dictionary mapping distributions to a list of predecessors. This allows
efficient traversal.
.. attribute:: missing
Dictionary mapping distributions to a list of requirements that were not
provided by any distribution.
Auxiliary functions
-------------------
.. function:: dependent_dists(dists, dist)
Recursively generate a list of distributions from *dists* that are dependent
on *dist*.
.. XXX what does member mean here: "dist is a member of *dists* for which we
are interested"
.. function:: generate_graph(dists)
Generate a :class:`DependencyGraph` from the given list of distributions.
.. XXX make this alternate constructor a DepGraph classmethod or rename;
'generate' can suggest it creates a file or an image, use 'make'
.. function:: graph_to_dot(graph, f, skip_disconnected=True)
Write a DOT output for the graph to the file-like object *f*.
If *skip_disconnected* is true, all distributions that are not dependent on
any other distribution are skipped.
.. XXX why is this not a DepGraph method?
Example Usage
-------------
Depict all dependenciess in the system
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
First, we shall generate a graph of all the distributions on the system
and then create an image out of it using the tools provided by
`Graphviz <http://www.graphviz.org/>`_::
from packaging.database import get_distributions
from packaging.depgraph import generate_graph
dists = list(get_distributions())
graph = generate_graph(dists)
It would be interesting to print out the missing requirements. This can be done
as follows::
for dist, reqs in graph.missing.items():
if reqs:
reqs = ' ,'.join(repr(req) for req in reqs)
print('Missing dependencies for %r: %s' % (dist.name, reqs))
Example output is:
.. code-block:: none
Missing dependencies for 'TurboCheetah': 'Cheetah'
Missing dependencies for 'TurboGears': 'ConfigObj', 'DecoratorTools', 'RuleDispatch'
Missing dependencies for 'jockey': 'PyKDE4.kdecore', 'PyKDE4.kdeui', 'PyQt4.QtCore', 'PyQt4.QtGui'
Missing dependencies for 'TurboKid': 'kid'
Missing dependencies for 'TurboJson: 'DecoratorTools', 'RuleDispatch'
Now, we proceed with generating a graphical representation of the graph. First
we write it to a file, and then we generate a PNG image using the
:program:`dot` command-line tool::
from packaging.depgraph import graph_to_dot
with open('output.dot', 'w') as f:
# only show the interesting distributions, skipping the disconnected ones
graph_to_dot(graph, f, skip_disconnected=True)
We can create the final picture using:
.. code-block:: sh
$ dot -Tpng output.dot > output.png
An example result is:
.. figure:: depgraph-output.png
:alt: Example PNG output from packaging.depgraph and dot
If you want to include egg distributions as well, then the code requires only
one change, namely the line::
dists = list(packaging.database.get_distributions())
has to be replaced with::
dists = list(packaging.database.get_distributions(use_egg_info=True))
On many platforms, a richer graph is obtained because at the moment most
distributions are provided in the egg rather than the new standard
``.dist-info`` format.
.. XXX missing image
An example of a more involved graph for illustrative reasons can be seen
here:
.. image:: depgraph_big.png
List all dependent distributions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We will list all distributions that are dependent on some given distibution.
This time, egg distributions will be considered as well::
import sys
from packaging.database import get_distribution, get_distributions
from packaging.depgraph import dependent_dists
dists = list(get_distributions(use_egg_info=True))
dist = get_distribution('bacon', use_egg_info=True)
if dist is None:
sys.exit('No such distribution in the system')
deps = dependent_dists(dists, dist)
deps = ', '.join(repr(x.name) for x in deps)
print('Distributions depending on %r: %s' % (dist.name, deps))
And this is example output:
.. with the dependency relationships as in the previous section
(depgraph_big)
.. code-block:: none
Distributions depending on 'bacon': 'towel-stuff', 'choxie', 'grammar'
This diff is collapsed.
:mod:`packaging.fancy_getopt` --- Wrapper around the getopt module
==================================================================
.. module:: packaging.fancy_getopt
:synopsis: Additional getopt functionality.
.. warning::
This module is deprecated and will be replaced with :mod:`optparse`.
This module provides a wrapper around the standard :mod:`getopt` module that
provides the following additional features:
* short and long options are tied together
* options have help strings, so :func:`fancy_getopt` could potentially create a
complete usage summary
* options set attributes of a passed-in object
* boolean options can have "negative aliases" --- e.g. if :option:`--quiet` is
the "negative alias" of :option:`--verbose`, then :option:`--quiet` on the
command line sets *verbose* to false.
.. function:: fancy_getopt(options, negative_opt, object, args)
Wrapper function. *options* is a list of ``(long_option, short_option,
help_string)`` 3-tuples as described in the constructor for
:class:`FancyGetopt`. *negative_opt* should be a dictionary mapping option names
to option names, both the key and value should be in the *options* list.
*object* is an object which will be used to store values (see the :meth:`getopt`
method of the :class:`FancyGetopt` class). *args* is the argument list. Will use
``sys.argv[1:]`` if you pass ``None`` as *args*.
.. class:: FancyGetopt([option_table=None])
The option_table is a list of 3-tuples: ``(long_option, short_option,
help_string)``
If an option takes an argument, its *long_option* should have ``'='`` appended;
*short_option* should just be a single character, no ``':'`` in any case.
*short_option* should be ``None`` if a *long_option* doesn't have a
corresponding *short_option*. All option tuples must have long options.
The :class:`FancyGetopt` class provides the following methods:
.. method:: FancyGetopt.getopt([args=None, object=None])
Parse command-line options in args. Store as attributes on *object*.
If *args* is ``None`` or not supplied, uses ``sys.argv[1:]``. If *object* is
``None`` or not supplied, creates a new :class:`OptionDummy` instance, stores
option values there, and returns a tuple ``(args, object)``. If *object* is
supplied, it is modified in place and :func:`getopt` just returns *args*; in
both cases, the returned *args* is a modified copy of the passed-in *args* list,
which is left untouched.
.. TODO and args returned are?
.. method:: FancyGetopt.get_option_order()
Returns the list of ``(option, value)`` tuples processed by the previous run of
:meth:`getopt` Raises :exc:`RuntimeError` if :meth:`getopt` hasn't been called
yet.
.. method:: FancyGetopt.generate_help([header=None])
Generate help text (a list of strings, one per suggested line of output) from
the option table for this :class:`FancyGetopt` object.
If supplied, prints the supplied *header* at the top of the help.
:mod:`packaging.install` --- Installation tools
===============================================
.. module:: packaging.install
:synopsis: Download and installation building blocks
Packaging provides a set of tools to deal with downloads and installation of
distributions. Their role is to download the distribution from indexes, resolve
the dependencies, and provide a safe way to install distributions. An operation
that fails will cleanly roll back, not leave half-installed distributions on the
system. Here's the basic process followed:
#. Move all distributions that will be removed to a temporary location.
#. Install all the distributions that will be installed in a temporary location.
#. If the installation fails, move the saved distributions back to their
location and delete the installed distributions.
#. Otherwise, move the installed distributions to the right location and delete
the temporary locations.
This is a higher-level module built on :mod:`packaging.database` and
:mod:`packaging.pypi`.
Public functions
----------------
.. function:: get_infos(requirements, index=None, installed=None, \
prefer_final=True)
Return information about what's going to be installed and upgraded.
*requirements* is a string string containing the requirements for this
project, for example ``'FooBar 1.1'`` or ``'BarBaz (<1.2)'``.
.. XXX are requirements comma-separated?
If you want to use another index than the main PyPI, give its URI as *index*
argument.
*installed* is a list of already installed distributions used to find
satisfied dependencies, obsoleted distributions and eventual conflicts.
By default, alpha, beta and candidate versions are not picked up. Set
*prefer_final* to false to accept them too.
The results are returned in a dictionary containing all the information
needed to perform installation of the requirements with the
:func:`install_from_infos` function:
>>> get_install_info("FooBar (<=1.2)")
{'install': [<FooBar 1.1>], 'remove': [], 'conflict': []}
.. TODO should return tuple or named tuple, not dict
.. TODO use "predicate" or "requirement" consistently in version and here
.. FIXME "info" cannot be plural in English, s/infos/info/
.. function:: install(project)
.. function:: install_dists(dists, path, paths=None)
Safely install all distributions provided in *dists* into *path*. *paths* is
a list of paths where already-installed distributions will be looked for to
find satisfied dependencies and conflicts (default: :data:`sys.path`).
Returns a list of installed dists.
.. FIXME dists are instances of what?
.. function:: install_from_infos(install_path=None, install=[], remove=[], \
conflicts=[], paths=None)
Safely install and remove given distributions. This function is designed to
work with the return value of :func:`get_infos`: *install*, *remove* and
*conflicts* should be list of distributions returned by :func:`get_infos`.
If *install* is not empty, *install_path* must be given to specify the path
where the distributions should be installed. *paths* is a list of paths
where already-installed distributions will be looked for (default:
:data:`sys.path`).
This function is a very basic installer; if *conflicts* is not empty, the
system will be in a conflicting state after the function completes. It is a
building block for more sophisticated installers with conflict resolution
systems.
.. TODO document typical value for install_path
.. TODO document integration with default schemes, esp. user site-packages
.. function:: install_local_project(path)
Install a distribution from a source directory, which must contain either a
Packaging-compliant :file:`setup.cfg` file or a legacy Distutils
:file:`setup.py` script (in which case Distutils will be used under the hood
to perform the installation).
.. function:: remove(project_name, paths=None, auto_confirm=True)
Remove one distribution from the system.
.. FIXME this is the only function using "project" instead of dist/release
..
Example usage
--------------
Get the scheme of what's gonna be installed if we install "foobar":
:mod:`packaging.metadata` --- Metadata handling
===============================================
.. module:: packaging.metadata
:synopsis: Class holding the metadata of a release.
.. TODO use sphinx-autogen to generate basic doc from the docstrings
.. class:: Metadata
This class can read and write metadata files complying with any of the
defined versions: 1.0 (:PEP:`241`), 1.1 (:PEP:`314`) and 1.2 (:PEP:`345`). It
implements methods to parse Metadata files and write them, and a mapping
interface to its contents.
The :PEP:`345` implementation supports the micro-language for the environment
markers, and displays warnings when versions that are supposed to be
:PEP:`386`-compliant are violating the specification.
Reading metadata
----------------
The :class:`Metadata` class can be instantiated
with the path of the metadata file, and provides a dict-like interface to the
values::
>>> from packaging.metadata import Metadata
>>> metadata = Metadata('PKG-INFO')
>>> metadata.keys()[:5]
('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform')
>>> metadata['Name']
'CLVault'
>>> metadata['Version']
'0.5'
>>> metadata['Requires-Dist']
["pywin32; sys.platform == 'win32'", "Sphinx"]
The fields that support environment markers can be automatically ignored if
the object is instantiated using the ``platform_dependent`` option.
:class:`Metadata` will interpret in this case
the markers and will automatically remove the fields that are not compliant
with the running environment. Here's an example under Mac OS X. The win32
dependency we saw earlier is ignored::
>>> from packaging.metadata import Metadata
>>> metadata = Metadata('PKG-INFO', platform_dependent=True)
>>> metadata['Requires-Dist']
['Sphinx']
If you want to provide your own execution context, let's say to test the
metadata under a particular environment that is not the current environment,
you can provide your own values in the ``execution_context`` option, which
is the dict that may contain one or more keys of the context the micro-language
expects.
Here's an example, simulating a win32 environment::
>>> from packaging.metadata import Metadata
>>> context = {'sys.platform': 'win32'}
>>> metadata = Metadata('PKG-INFO', platform_dependent=True,
... execution_context=context)
...
>>> metadata['Requires-Dist'] = ["pywin32; sys.platform == 'win32'",
... "Sphinx"]
...
>>> metadata['Requires-Dist']
['pywin32', 'Sphinx']
Writing metadata
----------------
Writing metadata can be done using the ``write`` method::
>>> metadata.write('/to/my/PKG-INFO')
The class will pick the best version for the metadata, depending on the values
provided. If all the values provided exist in all versions, the class will
use :attr:`PKG_INFO_PREFERRED_VERSION`. It is set by default to 1.0, the most
widespread version.
Conflict checking and best version
----------------------------------
Some fields in :PEP:`345` have to comply with the version number specification
defined in :PEP:`386`. When they don't comply, a warning is emitted::
>>> from packaging.metadata import Metadata
>>> metadata = Metadata()
>>> metadata['Requires-Dist'] = ['Funky (Groovie)']
"Funky (Groovie)" is not a valid predicate
>>> metadata['Requires-Dist'] = ['Funky (1.2)']
See also :mod:`packaging.version`.
.. TODO talk about check()
:mod:`packaging.markers` --- Environment markers
================================================
.. module:: packaging.markers
:synopsis: Micro-language for environment markers
This is an implementation of environment markers `as defined in PEP 345
<http://www.python.org/dev/peps/pep-0345/#environment-markers>`_. It is used
for some metadata fields.
.. function:: interpret(marker, execution_context=None)
Interpret a marker and return a boolean result depending on the environment.
Example:
>>> interpret("python_version > '1.0'")
True
:mod:`packaging.pypi.dist` --- Classes representing query results
=================================================================
.. module:: packaging.pypi.dist
:synopsis: Classes representing the results of queries to indexes.
Information coming from the indexes is held in instances of the classes defined
in this module.
Keep in mind that each project (eg. FooBar) can have several releases
(eg. 1.1, 1.2, 1.3), and each of these releases can be provided in multiple
distributions (eg. a source distribution, a binary one, etc).
ReleaseInfo
-----------
Each release has a project name, version, metadata, and related distributions.
This information is stored in :class:`ReleaseInfo`
objects.
.. class:: ReleaseInfo
DistInfo
---------
:class:`DistInfo` is a simple class that contains
information related to distributions; mainly the URLs where distributions
can be found.
.. class:: DistInfo
ReleasesList
------------
The :mod:`~packaging.pypi.dist` module provides a class which works
with lists of :class:`ReleaseInfo` classes;
used to filter and order results.
.. class:: ReleasesList
Example usage
-------------
Build a list of releases and order them
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Assuming we have a list of releases::
>>> from packaging.pypi.dist import ReleasesList, ReleaseInfo
>>> fb10 = ReleaseInfo("FooBar", "1.0")
>>> fb11 = ReleaseInfo("FooBar", "1.1")
>>> fb11a = ReleaseInfo("FooBar", "1.1a1")
>>> ReleasesList("FooBar", [fb11, fb11a, fb10])
>>> releases.sort_releases()
>>> releases.get_versions()
['1.1', '1.1a1', '1.0']
>>> releases.add_release("1.2a1")
>>> releases.get_versions()
['1.1', '1.1a1', '1.0', '1.2a1']
>>> releases.sort_releases()
['1.2a1', '1.1', '1.1a1', '1.0']
>>> releases.sort_releases(prefer_final=True)
>>> releases.get_versions()
['1.1', '1.0', '1.2a1', '1.1a1']
Add distribution related information to releases
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It's easy to add distribution information to releases::
>>> from packaging.pypi.dist import ReleasesList, ReleaseInfo
>>> r = ReleaseInfo("FooBar", "1.0")
>>> r.add_distribution("sdist", url="http://example.org/foobar-1.0.tar.gz")
>>> r.dists
{'sdist': FooBar 1.0 sdist}
>>> r['sdist'].url
{'url': 'http://example.org/foobar-1.0.tar.gz', 'hashname': None, 'hashval':
None, 'is_external': True}
Getting attributes from the dist objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To abstract querying information returned from the indexes, attributes and
release information can be retrieved directly from dist objects.
For instance, if you have a release instance that does not contain the metadata
attribute, it can be fetched by using the "fetch_metadata" method::
>>> r = Release("FooBar", "1.1")
>>> print r.metadata
None # metadata field is actually set to "None"
>>> r.fetch_metadata()
<Metadata for FooBar 1.1>
.. XXX add proper roles to these constructs
It's possible to retrieve a project's releases (`fetch_releases`),
metadata (`fetch_metadata`) and distributions (`fetch_distributions`) using
a similar work flow.
.. XXX what is possible?
Internally, this is possible because while retrieving information about
projects, releases or distributions, a reference to the client used is
stored which can be accessed using the objects `_index` attribute.
:mod:`packaging.pypi` --- Interface to projects indexes
=======================================================
.. module:: packaging.pypi
:synopsis: Low-level and high-level APIs to query projects indexes.
Packaging queries PyPI to get information about projects or download them. The
low-level facilities used internally are also part of the public API designed to
be used by other tools.
The :mod:`packaging.pypi` package provides those facilities, which can be
used to access information about Python projects registered at indexes, the
main one being PyPI, located ad http://pypi.python.org/.
There is two ways to retrieve data from these indexes: a screen-scraping
interface called the "simple API", and XML-RPC. The first one uses HTML pages
located under http://pypi.python.org/simple/, the second one makes XML-RPC
requests to http://pypi.python.org/pypi/. All functions and classes also work
with other indexes such as mirrors, which typically implement only the simple
interface.
Packaging provides a class that wraps both APIs to provide full query and
download functionality: :class:`packaging.pypi.client.ClientWrapper`. If you
want more control, you can use the underlying classes
:class:`packaging.pypi.simple.Crawler` and :class:`packaging.pypi.xmlrpc.Client`
to connect to one specific interface.
:mod:`packaging.pypi.client` --- High-level query API
=====================================================
.. module:: packaging.pypi.client
:synopsis: Wrapper around :mod;`packaging.pypi.xmlrpc` and
:mod:`packaging.pypi.simple` to query indexes.
This module provides a high-level API to query indexes and search
for releases and distributions. The aim of this module is to choose the best
way to query the API automatically, either using XML-RPC or the simple index,
with a preference toward the latter.
.. class:: ClientWrapper
Instances of this class will use the simple interface or XML-RPC requests to
query indexes and return :class:`packaging.pypi.dist.ReleaseInfo` and
:class:`packaging.pypi.dist.ReleasesList` objects.
.. method:: find_projects
.. method:: get_release
.. method:: get_releases
:mod:`packaging.pypi.simple` --- Crawler using the PyPI "simple" interface
==========================================================================
.. module:: packaging.pypi.simple
:synopsis: Crawler using the screen-scraping "simple" interface to fetch info
and distributions.
`packaging.pypi.simple` can process Python Package Indexes and provides
useful information about distributions. It also can crawl local indexes, for
instance.
You should use `packaging.pypi.simple` for:
* Search distributions by name and versions.
* Process index external pages.
* Download distributions by name and versions.
And should not be used for:
* Things that will end up in too long index processing (like "finding all
distributions with a specific version, no matters the name")
API
---
.. class:: Crawler
Usage Exemples
---------------
To help you understand how using the `Crawler` class, here are some basic
usages.
Request the simple index to get a specific distribution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Supposing you want to scan an index to get a list of distributions for
the "foobar" project. You can use the "get_releases" method for that.
The get_releases method will browse the project page, and return
:class:`ReleaseInfo` objects for each found link that rely on downloads. ::
>>> from packaging.pypi.simple import Crawler
>>> crawler = Crawler()
>>> crawler.get_releases("FooBar")
[<ReleaseInfo "Foobar 1.1">, <ReleaseInfo "Foobar 1.2">]
Note that you also can request the client about specific versions, using version
specifiers (described in `PEP 345
<http://www.python.org/dev/peps/pep-0345/#version-specifiers>`_)::
>>> client.get_releases("FooBar < 1.2")
[<ReleaseInfo "FooBar 1.1">, ]
`get_releases` returns a list of :class:`ReleaseInfo`, but you also can get the
best distribution that fullfil your requirements, using "get_release"::
>>> client.get_release("FooBar < 1.2")
<ReleaseInfo "FooBar 1.1">
Download distributions
^^^^^^^^^^^^^^^^^^^^^^
As it can get the urls of distributions provided by PyPI, the `Crawler`
client also can download the distributions and put it for you in a temporary
destination::
>>> client.download("foobar")
/tmp/temp_dir/foobar-1.2.tar.gz
You also can specify the directory you want to download to::
>>> client.download("foobar", "/path/to/my/dir")
/path/to/my/dir/foobar-1.2.tar.gz
While downloading, the md5 of the archive will be checked, if not matches, it
will try another time, then if fails again, raise `MD5HashDoesNotMatchError`.
Internally, that's not the Crawler which download the distributions, but the
`DistributionInfo` class. Please refer to this documentation for more details.
Following PyPI external links
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The default behavior for packaging is to *not* follow the links provided
by HTML pages in the "simple index", to find distributions related
downloads.
It's possible to tell the PyPIClient to follow external links by setting the
`follow_externals` attribute, on instantiation or after::
>>> client = Crawler(follow_externals=True)
or ::
>>> client = Crawler()
>>> client.follow_externals = True
Working with external indexes, and mirrors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The default `Crawler` behavior is to rely on the Python Package index stored
on PyPI (http://pypi.python.org/simple).
As you can need to work with a local index, or private indexes, you can specify
it using the index_url parameter::
>>> client = Crawler(index_url="file://filesystem/path/")
or ::
>>> client = Crawler(index_url="http://some.specific.url/")
You also can specify mirrors to fallback on in case the first index_url you
provided doesnt respond, or not correctly. The default behavior for
`Crawler` is to use the list provided by Python.org DNS records, as
described in the :PEP:`381` about mirroring infrastructure.
If you don't want to rely on these, you could specify the list of mirrors you
want to try by specifying the `mirrors` attribute. It's a simple iterable::
>>> mirrors = ["http://first.mirror","http://second.mirror"]
>>> client = Crawler(mirrors=mirrors)
Searching in the simple index
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It's possible to search for projects with specific names in the package index.
Assuming you want to find all projects containing the "distutils" keyword::
>>> c.search_projects("distutils")
[<Project "collective.recipe.distutils">, <Project "Distutils">, <Project
"Packaging">, <Project "distutilscross">, <Project "lpdistutils">, <Project
"taras.recipe.distutils">, <Project "zerokspot.recipe.distutils">]
You can also search the projects starting with a specific text, or ending with
that text, using a wildcard::
>>> c.search_projects("distutils*")
[<Project "Distutils">, <Project "Packaging">, <Project "distutilscross">]
>>> c.search_projects("*distutils")
[<Project "collective.recipe.distutils">, <Project "Distutils">, <Project
"lpdistutils">, <Project "taras.recipe.distutils">, <Project
"zerokspot.recipe.distutils">]
:mod:`packaging.pypi.xmlrpc` --- Crawler using the PyPI XML-RPC interface
=========================================================================
.. module:: packaging.pypi.xmlrpc
:synopsis: Client using XML-RPC requests to fetch info and distributions.
Indexes can be queried using XML-RPC calls, and Packaging provides a simple
way to interface with XML-RPC.
You should **use** XML-RPC when:
* Searching the index for projects **on other fields than project
names**. For instance, you can search for projects based on the
author_email field.
* Searching all the versions that have existed for a project.
* you want to retrieve METADATAs information from releases or
distributions.
You should **avoid using** XML-RPC method calls when:
* Retrieving the last version of a project
* Getting the projects with a specific name and version.
* The simple index can match your needs
When dealing with indexes, keep in mind that the index queries will always
return you :class:`packaging.pypi.dist.ReleaseInfo` and
:class:`packaging.pypi.dist.ReleasesList` objects.
Some methods here share common APIs with the one you can find on
:class:`packaging.pypi.simple`, internally, :class:`packaging.pypi.client`
is inherited by :class:`Client`
API
---
.. class:: Client
Usage examples
--------------
Use case described here are use case that are not common to the other clients.
If you want to see all the methods, please refer to API or to usage examples
described in :class:`packaging.pypi.client.Client`
Finding releases
^^^^^^^^^^^^^^^^
It's a common use case to search for "things" within the index. We can
basically search for projects by their name, which is the most used way for
users (eg. "give me the last version of the FooBar project").
This can be accomplished using the following syntax::
>>> client = xmlrpc.Client()
>>> client.get_release("Foobar (<= 1.3))
<FooBar 1.2.1>
>>> client.get_releases("FooBar (<= 1.3)")
[FooBar 1.1, FooBar 1.1.1, FooBar 1.2, FooBar 1.2.1]
And we also can find for specific fields::
>>> client.search_projects(field=value)
You could specify the operator to use, default is "or"::
>>> client.search_projects(field=value, operator="and")
The specific fields you can search are:
* name
* version
* author
* author_email
* maintainer
* maintainer_email
* home_page
* license
* summary
* description
* keywords
* platform
* download_url
Getting metadata information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
XML-RPC is a prefered way to retrieve metadata information from indexes.
It's really simple to do so::
>>> client = xmlrpc.Client()
>>> client.get_metadata("FooBar", "1.1")
<ReleaseInfo FooBar 1.1>
Assuming we already have a :class:`packaging.pypi.ReleaseInfo` object defined,
it's possible to pass it to the xmlrpc client to retrieve and complete its
metadata::
>>> foobar11 = ReleaseInfo("FooBar", "1.1")
>>> client = xmlrpc.Client()
>>> returned_release = client.get_metadata(release=foobar11)
>>> returned_release
<ReleaseInfo FooBar 1.1>
Get all the releases of a project
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To retrieve all the releases for a project, you can build them using
`get_releases`::
>>> client = xmlrpc.Client()
>>> client.get_releases("FooBar")
[<ReleaseInfo FooBar 0.9>, <ReleaseInfo FooBar 1.0>, <ReleaseInfo 1.1>]
Get information about distributions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Indexes have information about projects, releases **and** distributions.
If you're not familiar with those, please refer to the documentation of
:mod:`packaging.pypi.dist`.
It's possible to retrieve information about distributions, e.g "what are the
existing distributions for this release ? How to retrieve them ?"::
>>> client = xmlrpc.Client()
>>> release = client.get_distributions("FooBar", "1.1")
>>> release.dists
{'sdist': <FooBar 1.1 sdist>, 'bdist': <FooBar 1.1 bdist>}
As you see, this does not return a list of distributions, but a release,
because a release can be used like a list of distributions.
:mod:`packaging` --- Packaging support
======================================
.. module:: packaging
:synopsis: Packaging system and building blocks for other packaging systems.
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>, distutils and packaging
contributors
The :mod:`packaging` package provides support for building, packaging,
distributing and installing additional projects into a Python installation.
Projects may include Python modules, extension modules, packages and scripts.
:mod:`packaging` also provides building blocks for other packaging systems
that are not tied to the command system.
This manual is the reference documentation for those standalone building
blocks and for extending Packaging. If you're looking for the user-centric
guides to install a project or package your own code, head to `See also`__.
Building blocks
---------------
.. toctree::
:maxdepth: 2
:numbered:
packaging-misc
packaging.version
packaging.metadata
packaging.database
packaging.depgraph
packaging.pypi
packaging.pypi.dist
packaging.pypi.simple
packaging.pypi.xmlrpc
packaging.install
The command machinery
---------------------
.. toctree::
:maxdepth: 2
:numbered:
packaging.dist
packaging.command
packaging.compiler
packaging.fancy_getopt
Other utilities
----------------
.. toctree::
:maxdepth: 2
:numbered:
packaging.util
packaging.tests.pypi_server
.. XXX missing: compat config create (dir_util) run pypi.{base,mirrors}
.. __:
.. seealso::
:ref:`packaging-index`
The manual for developers of Python projects who want to package and
distribute them. This describes how to use :mod:`packaging` to make
projects easily found and added to an existing Python installation.
:ref:`packaging-install-index`
A user-centered manual which includes information on adding projects
into an existing Python installation. You do not need to be a Python
programmer to read this manual.
:mod:`packaging.tests.pypi_server` --- PyPI mock server
=======================================================
.. module:: packaging.tests.pypi_server
:synopsis: Mock server used to test PyPI-related modules and commands.
When you are testing code that works with Packaging, you might find these tools
useful.
The mock server
---------------
.. class:: PyPIServer
PyPIServer is a class that implements an HTTP server running in a separate
thread. All it does is record the requests for further inspection. The recorded
data is available under ``requests`` attribute. The default
HTTP response can be overridden with the ``default_response_status``,
``default_response_headers`` and ``default_response_data`` attributes.
By default, when accessing the server with urls beginning with `/simple/`,
the server also record your requests, but will look for files under
the `/tests/pypiserver/simple/` path.
You can tell the sever to serve static files for other paths. This could be
accomplished by using the `static_uri_paths` parameter, as below::
server = PyPIServer(static_uri_paths=["first_path", "second_path"])
You need to create the content that will be served under the
`/tests/pypiserver/default` path. If you want to serve content from another
place, you also can specify another filesystem path (which needs to be under
`tests/pypiserver/`. This will replace the default behavior of the server, and
it will not serve content from the `default` dir ::
server = PyPIServer(static_filesystem_paths=["path/to/your/dir"])
If you just need to add some paths to the existing ones, you can do as shown,
keeping in mind that the server will always try to load paths in reverse order
(e.g here, try "another/super/path" then the default one) ::
server = PyPIServer(test_static_path="another/super/path")
server = PyPIServer("another/super/path")
# or
server.static_filesystem_paths.append("another/super/path")
As a result of what, in your tests, while you need to use the PyPIServer, in
order to isolates the test cases, the best practice is to place the common files
in the `default` folder, and to create a directory for each specific test case::
server = PyPIServer(static_filesystem_paths = ["default", "test_pypi_server"],
static_uri_paths=["simple", "external"])
Base class and decorator for tests
----------------------------------
.. class:: PyPIServerTestCase
``PyPIServerTestCase`` is a test case class with setUp and tearDown methods that
take care of a single PyPIServer instance attached as a ``pypi`` attribute on
the test class. Use it as one of the base classes in your test case::
class UploadTestCase(PyPIServerTestCase):
def test_something(self):
cmd = self.prepare_command()
cmd.ensure_finalized()
cmd.repository = self.pypi.full_address
cmd.run()
environ, request_data = self.pypi.requests[-1]
self.assertEqual(request_data, EXPECTED_REQUEST_DATA)
.. decorator:: use_pypi_server
You also can use a decorator for your tests, if you do not need the same server
instance along all you test case. So, you can specify, for each test method,
some initialisation parameters for the server.
For this, you need to add a `server` parameter to your method, like this::
class SampleTestCase(TestCase):
@use_pypi_server()
def test_something(self, server):
...
The decorator will instantiate the server for you, and run and stop it just
before and after your method call. You also can pass the server initializer,
just like this::
class SampleTestCase(TestCase):
@use_pypi_server("test_case_name")
def test_something(self, server):
...
:mod:`packaging.util` --- Miscellaneous utility functions
=========================================================
.. module:: packaging.util
:synopsis: Miscellaneous utility functions.
This module contains various helpers for the other modules.
.. XXX a number of functions are missing, but the module may be split first
(it's ginormous right now, some things could go to compat for example)
.. function:: get_platform()
Return a string that identifies the current platform. This is used mainly to
distinguish platform-specific build directories and platform-specific built
distributions. Typically includes the OS name and version and the
architecture (as supplied by 'os.uname()'), although the exact information
included depends on the OS; e.g. for IRIX the architecture isn't particularly
important (IRIX only runs on SGI hardware), but for Linux the kernel version
isn't particularly important.
Examples of returned values:
* ``linux-i586``
* ``linux-alpha``
* ``solaris-2.6-sun4u``
* ``irix-5.3``
* ``irix64-6.2``
For non-POSIX platforms, currently just returns ``sys.platform``.
For Mac OS X systems the OS version reflects the minimal version on which
binaries will run (that is, the value of ``MACOSX_DEPLOYMENT_TARGET``
during the build of Python), not the OS version of the current system.
For universal binary builds on Mac OS X the architecture value reflects
the univeral binary status instead of the architecture of the current
processor. For 32-bit universal binaries the architecture is ``fat``,
for 64-bit universal binaries the architecture is ``fat64``, and
for 4-way universal binaries the architecture is ``universal``. Starting
from Python 2.7 and Python 3.2 the architecture ``fat3`` is used for
a 3-way universal build (ppc, i386, x86_64) and ``intel`` is used for
a univeral build with the i386 and x86_64 architectures
Examples of returned values on Mac OS X:
* ``macosx-10.3-ppc``
* ``macosx-10.3-fat``
* ``macosx-10.5-universal``
* ``macosx-10.6-intel``
.. XXX reinvention of platform module?
.. function:: convert_path(pathname)
Return 'pathname' as a name that will work on the native filesystem, i.e.
split it on '/' and put it back together again using the current directory
separator. Needed because filenames in the setup script are always supplied
in Unix style, and have to be converted to the local convention before we
can actually use them in the filesystem. Raises :exc:`ValueError` on
non-Unix-ish systems if *pathname* either starts or ends with a slash.
.. function:: change_root(new_root, pathname)
Return *pathname* with *new_root* prepended. If *pathname* is relative, this
is equivalent to ``os.path.join(new_root,pathname)`` Otherwise, it requires
making *pathname* relative and then joining the two, which is tricky on
DOS/Windows.
.. function:: check_environ()
Ensure that 'os.environ' has all the environment variables we guarantee that
users can use in config files, command-line options, etc. Currently this
includes:
* :envvar:`HOME` - user's home directory (Unix only)
* :envvar:`PLAT` - description of the current platform, including hardware
and OS (see :func:`get_platform`)
.. function:: find_executable(executable, path=None)
Search the path for a given executable name.
.. function:: subst_vars(s, local_vars)
Perform shell/Perl-style variable substitution on *s*. Every occurrence of
``$`` followed by a name is considered a variable, and variable is
substituted by the value found in the *local_vars* dictionary, or in
``os.environ`` if it's not in *local_vars*. *os.environ* is first
checked/augmented to guarantee that it contains certain values: see
:func:`check_environ`. Raise :exc:`ValueError` for any variables not found
in either *local_vars* or ``os.environ``.
Note that this is not a fully-fledged string interpolation function. A valid
``$variable`` can consist only of upper and lower case letters, numbers and
an underscore. No { } or ( ) style quoting is available.
.. function:: split_quoted(s)
Split a string up according to Unix shell-like rules for quotes and
backslashes. In short: words are delimited by spaces, as long as those spaces
are not escaped by a backslash, or inside a quoted string. Single and double
quotes are equivalent, and the quote characters can be backslash-escaped.
The backslash is stripped from any two-character escape sequence, leaving
only the escaped character. The quote characters are stripped from any
quoted string. Returns a list of words.
.. TODO Should probably be moved into the standard library.
.. function:: execute(func, args[, msg=None, verbose=0, dry_run=0])
Perform some action that affects the outside world (for instance, writing to
the filesystem). Such actions are special because they are disabled by the
*dry_run* flag. This method takes care of all that bureaucracy for you;
all you have to do is supply the function to call and an argument tuple for
it (to embody the "external action" being performed), and an optional message
to print.
.. function:: newer(source, target)
Return true if *source* exists and is more recently modified than *target*,
or if *source* exists and *target* doesn't. Return false if both exist and
*target* is the same age or newer than *source*. Raise
:exc:`PackagingFileError` if *source* does not exist.
.. function:: strtobool(val)
Convert a string representation of truth to true (1) or false (0).
True values are ``y``, ``yes``, ``t``, ``true``, ``on`` and ``1``; false
values are ``n``, ``no``, ``f``, ``false``, ``off`` and ``0``. Raises
:exc:`ValueError` if *val* is anything else.
.. TODO Add :term: markup to bytecode when merging into the stdlib
.. function:: byte_compile(py_files[, optimize=0, force=0, prefix=None, base_dir=None, verbose=1, dry_run=0, direct=None])
Byte-compile a collection of Python source files to either :file:`.pyc` or
:file:`.pyo` files in the same directory. *py_files* is a list of files to
compile; any files that don't end in :file:`.py` are silently skipped.
*optimize* must be one of the following:
* ``0`` - don't optimize (generate :file:`.pyc`)
* ``1`` - normal optimization (like ``python -O``)
* ``2`` - extra optimization (like ``python -OO``)
If *force* is true, all files are recompiled regardless of timestamps.
The source filename encoded in each bytecode file defaults to the filenames
listed in *py_files*; you can modify these with *prefix* and *basedir*.
*prefix* is a string that will be stripped off of each source filename, and
*base_dir* is a directory name that will be prepended (after *prefix* is
stripped). You can supply either or both (or neither) of *prefix* and
*base_dir*, as you wish.
If *dry_run* is true, doesn't actually do anything that would affect the
filesystem.
Byte-compilation is either done directly in this interpreter process with the
standard :mod:`py_compile` module, or indirectly by writing a temporary
script and executing it. Normally, you should let :func:`byte_compile`
figure out to use direct compilation or not (see the source for details).
The *direct* flag is used by the script generated in indirect mode; unless
you know what you're doing, leave it set to ``None``.
.. function:: rfc822_escape(header)
Return a version of *header* escaped for inclusion in an :rfc:`822` header, by
ensuring there are 8 spaces space after each newline. Note that it does no
other modification of the string.
.. TODO this _can_ be replaced
:mod:`packaging.version` --- Version number classes
===================================================
.. module:: packaging.version
:synopsis: Classes that represent project version numbers.
This module contains classes and functions useful to deal with version numbers.
It's an implementation of version specifiers `as defined in PEP 345
<http://www.python.org/dev/peps/pep-0345/#version-specifiers>`_.
Version numbers
---------------
.. class:: NormalizedVersion(self, s, error_on_huge_major_num=True)
A specific version of a distribution, as described in PEP 345. *s* is a
string object containing the version number (for example ``'1.2b1'``),
*error_on_huge_major_num* a boolean specifying whether to consider an
apparent use of a year or full date as the major version number an error.
The rationale for the second argument is that there were projects using years
or full dates as version numbers, which could cause problems with some
packaging systems sorting.
Instances of this class can be compared and sorted::
>>> NormalizedVersion('1.2b1') < NormalizedVersion('1.2')
True
:class:`NormalizedVersion` is used internally by :class:`VersionPredicate` to
do its work.
.. class:: IrrationalVersionError
Exception raised when an invalid string is given to
:class:`NormalizedVersion`.
>>> NormalizedVersion("irrational_version_number")
...
IrrationalVersionError: irrational_version_number
.. function:: suggest_normalized_version(s)
Before standardization in PEP 386, various schemes were in use. Packaging
provides a function to try to convert any string to a valid, normalized
version::
>>> suggest_normalized_version('2.1-rc1')
2.1c1
If :func:`suggest_normalized_version` can't make sense of the given string,
it will return ``None``::
>>> print(suggest_normalized_version('not a version'))
None
Version predicates
------------------
.. class:: VersionPredicate(predicate)
This class deals with the parsing of field values like
``ProjectName (>=version)``.
.. method:: match(version)
Test if a version number matches the predicate:
>>> version = VersionPredicate("ProjectName (<1.2, >1.0)")
>>> version.match("1.2.1")
False
>>> version.match("1.1.1")
True
Validation helpers
------------------
If you want to use :term:`LBYL`-style checks instead of instantiating the
classes and catching :class:`IrrationalVersionError` and :class:`ValueError`,
you can use these functions:
.. function:: is_valid_version(predicate)
Check whether the given string is a valid version number. Example of valid
strings: ``'1.2'``, ``'4.2.0.dev4'``, ``'2.5.4.post2'``.
.. function:: is_valid_versions(predicate)
Check whether the given string is a valid value for specifying multiple
versions, such as in the Requires-Python field. Example: ``'2.7, >=3.2'``.
.. function:: is_valid_predicate(predicate)
Check whether the given string is a valid version predicate. Examples:
``'some.project == 4.5, <= 4.7'``, ``'speciallib (> 1.0, != 1.4.2, < 2.0)'``.
......@@ -25,4 +25,5 @@ overview:
inspect.rst
site.rst
fpectl.rst
packaging.rst
distutils.rst
This diff is collapsed.
=============
Command hooks
=============
Packaging provides a way of extending its commands by the use of pre- and
post- command hooks. The hooks are simple Python functions (or any callable
objects) and are specified in the config file using their full qualified names.
The pre-hooks are run after the command is finalized (its options are
processed), but before it is run. The post-hooks are run after the command
itself. Both types of hooks receive an instance of the command object.
Sample usage of hooks
=====================
Firstly, you need to make sure your hook is present in the path. This is usually
done by dropping them to the same folder where `setup.py` file lives ::
# file: myhooks.py
def my_install_hook(install_cmd):
print "Oh la la! Someone is installing my project!"
Then, you need to point to it in your `setup.cfg` file, under the appropriate
command section ::
[install_dist]
pre-hook.project = myhooks.my_install_hook
The hooks defined in different config files (system-wide, user-wide and
package-wide) do not override each other as long as they are specified with
different aliases (additional names after the dot). The alias in the example
above is ``project``.
.. _packaging-command-reference:
*****************
Command Reference
*****************
This reference briefly documents all standard Packaging commands and some of
their options.
.. FIXME does not work: Use pysetup run --help-commands to list all
standard and extra commands availavble on your system, with their
description. Use pysetup run <command> --help to get help about the options
of one command.
Preparing distributions
=======================
:command:`check`
----------------
Perform some tests on the metadata of a distribution.
For example, it verifies that all required metadata fields are provided in the
:file:`setup.cfg` file.
.. TODO document reST checks
:command:`test`
---------------
Run a test suite.
When doing test-driven development, or running automated builds that need
testing before they are installed for downloading or use, it's often useful to
be able to run a project's unit tests without actually installing the project
anywhere. The :command:`test` command runs project's unit tests without
actually installing it, by temporarily putting the project's source on
:data:`sys.path`, after first running :command:`build_ext -i` to ensure that any
C extensions are built.
You can use this command in one of two ways: either by specifying a
unittest-compatible test suite for your project (or any callable that returns
it) or by passing a test runner function that will run your tests and display
results in the console. Both options take a Python dotted name in the form
``package.module.callable`` to specify the object to use.
If none of these options are specified, Packaging will try to perform test
discovery using either unittest (for Python 3.2 and higher) or unittest2 (for
older versions, if installed).
.. this is a pseudo-command name used to disambiguate the options in indexes and
links
.. program:: packaging test
.. cmdoption:: --suite=NAME, -s NAME
Specify the test suite (or module, class, or method) to be run. The default
for this option can be set by in the project's :file:`setup.cfg` file::
.. code-block:: cfg
[test]
suite = mypackage.tests.get_all_tests
.. cmdoption:: --runner=NAME, -r NAME
Specify the test runner to be called.
:command:`config`
-----------------
Perform distribution configuration.
The build step
==============
This step is mainly useful to compile C/C++ libraries or extension modules. The
build commands can be run manually to check for syntax errors or packaging
issues (for example if the addition of a new source file was forgotten in the
:file:`setup.cfg` file), and is also run automatically by commands which need
it. Packaging checks the mtime of source and built files to avoid re-building
if it's not necessary.
:command:`build`
----------------
Build all files of a distribution, delegating to the other :command:`build_*`
commands to do the work.
:command:`build_clib`
---------------------
Build C libraries.
:command:`build_ext`
--------------------
Build C/C++ extension modules.
:command:`build_py`
-------------------
Build the Python modules (just copy them to the build directory) and
byte-compile them to .pyc files.
:command:`build_scripts`
------------------------
Build the scripts (just copy them to the build directory and adjust their
shebang if they're Python scripts).
:command:`clean`
----------------
Clean the build tree of the release.
.. program:: packaging clean
.. cmdoption:: --all, -a
Remove build directories for modules, scripts, etc., not only temporary build
by-products.
Creating source and built distributions
=======================================
:command:`sdist`
----------------
Build a source distribution for a release.
It is recommended that you always build and upload a source distribution. Users
of OSes with easy access to compilers and users of advanced packaging tools will
prefer to compile from source rather than using pre-built distributions. For
Windows users, providing a binary installer is also recommended practice.
:command:`bdist`
----------------
Build a binary distribution for a release.
This command will call other :command:`bdist_*` commands to create one or more
distributions depending on the options given. The default is to create a
.tar.gz archive on Unix and a zip archive on Windows or OS/2.
.. program:: packaging bdist
.. cmdoption:: --formats
Binary formats to build (comma-separated list).
.. cmdoption:: --show-formats
Dump list of available formats.
:command:`bdist_dumb`
---------------------
Build a "dumb" installer, a simple archive of files that could be unpacked under
``$prefix`` or ``$exec_prefix``.
:command:`bdist_wininst`
------------------------
Build a Windows installer.
:command:`bdist_msi`
--------------------
Build a `Microsoft Installer`_ (.msi) file.
.. _Microsoft Installer: http://msdn.microsoft.com/en-us/library/cc185688(VS.85).aspx
In most cases, the :command:`bdist_msi` installer is a better choice than the
:command:`bdist_wininst` installer, because it provides better support for Win64
platforms, allows administrators to perform non-interactive installations, and
allows installation through group policies.
Publishing distributions
========================
:command:`register`
-------------------
This command registers the current release with the Python Package Index. This
is described in more detail in :PEP:`301`.
.. TODO explain user and project registration with the web UI
:command:`upload`
-----------------
Upload source and/or binary distributions to PyPI.
The distributions have to be built on the same command line as the
:command:`upload` command; see :ref:`packaging-package-upload` for more info.
.. program:: packaging upload
.. cmdoption:: --sign, -s
Sign each uploaded file using GPG (GNU Privacy Guard). The ``gpg`` program
must be available for execution on the system ``PATH``.
.. cmdoption:: --identity=NAME, -i NAME
Specify the identity or key name for GPG to use when signing. The value of
this option will be passed through the ``--local-user`` option of the
``gpg`` program.
.. cmdoption:: --show-response
Display the full response text from server; this is useful for debugging
PyPI problems.
.. cmdoption:: --repository=URL, -r URL
The URL of the repository to upload to. Defaults to
http://pypi.python.org/pypi (i.e., the main PyPI installation).
.. cmdoption:: --upload-docs
Also run :command:`upload_docs`. Mainly useful as a default value in
:file:`setup.cfg` (on the command line, it's shorter to just type both
commands).
:command:`upload_docs`
----------------------
Upload HTML documentation to PyPI.
PyPI now supports publishing project documentation at a URI of the form
``http://packages.python.org/<project>``. :command:`upload_docs` will create
the necessary zip file out of a documentation directory and will post to the
repository.
Note that to upload the documentation of a project, the corresponding version
must already be registered with PyPI, using the :command:`register` command ---
just like with :command:`upload`.
Assuming there is an ``Example`` project with documentation in the subdirectory
:file:`docs`, for example::
Example/
example.py
setup.cfg
docs/
build/
html/
index.html
tips_tricks.html
conf.py
index.txt
tips_tricks.txt
You can simply specify the directory with the HTML files in your
:file:`setup.cfg` file:
.. code-block:: cfg
[upload_docs]
upload-dir = docs/build/html
.. program:: packaging upload_docs
.. cmdoption:: --upload-dir
The directory to be uploaded to the repository. By default documentation
is searched for in ``docs`` (or ``doc``) directory in project root.
.. cmdoption:: --show-response
Display the full response text from server; this is useful for debugging
PyPI problems.
.. cmdoption:: --repository=URL, -r URL
The URL of the repository to upload to. Defaults to
http://pypi.python.org/pypi (i.e., the main PyPI installation).
The install step
================
These commands are used by end-users of a project using :program:`pysetup` or
another compatible installer. Each command will run the corresponding
:command:`build_*` command and then move the built files to their destination on
the target system.
:command:`install_dist`
-----------------------
Install a distribution, delegating to the other :command:`install_*` commands to
do the work.
.. program:: packaging install_dist
.. cmdoption:: --user
Install in user site-packages directory (see :PEP:`370`).
:command:`install_data`
-----------------------
Install data files.
:command:`install_distinfo`
---------------------------
Install files recording details of the installation as specified in :PEP:`376`.
:command:`install_headers`
--------------------------
Install C/C++ header files.
:command:`install_lib`
----------------------
Install C library files.
:command:`install_scripts`
--------------------------
Install scripts.
.. _packaging-setup-config:
************************************
Writing the Setup Configuration File
************************************
Often, it's not possible to write down everything needed to build a distribution
*a priori*: you may need to get some information from the user, or from the
user's system, in order to proceed. As long as that information is fairly
simple---a list of directories to search for C header files or libraries, for
example---then providing a configuration file, :file:`setup.cfg`, for users to
edit is a cheap and easy way to solicit it. Configuration files also let you
provide default values for any command option, which the installer can then
override either on the command line or by editing the config file.
The setup configuration file is a useful middle-ground between the setup script
---which, ideally, would be opaque to installers [#]_---and the command line to
the setup script, which is outside of your control and entirely up to the
installer. In fact, :file:`setup.cfg` (and any other Distutils configuration
files present on the target system) are processed after the contents of the
setup script, but before the command line. This has several useful
consequences:
.. If you have more advanced needs, such as determining which extensions to
build based on what capabilities are present on the target system, then you
need the Distutils auto-configuration facility. This started to appear in
Distutils 0.9 but, as of this writing, isn't mature or stable enough yet
for real-world use.
* installers can override some of what you put in :file:`setup.py` by editing
:file:`setup.cfg`
* you can provide non-standard defaults for options that are not easily set in
:file:`setup.py`
* installers can override anything in :file:`setup.cfg` using the command-line
options to :file:`setup.py`
The basic syntax of the configuration file is simple::
[command]
option = value
...
where *command* is one of the Distutils commands (e.g. :command:`build_py`,
:command:`install_dist`), and *option* is one of the options that command supports.
Any number of options can be supplied for each command, and any number of
command sections can be included in the file. Blank lines are ignored, as are
comments, which run from a ``'#'`` character until the end of the line. Long
option values can be split across multiple lines simply by indenting the
continuation lines.
You can find out the list of options supported by a particular command with the
universal :option:`--help` option, e.g. ::
> python setup.py --help build_ext
[...]
Options for 'build_ext' command:
--build-lib (-b) directory for compiled extension modules
--build-temp (-t) directory for temporary files (build by-products)
--inplace (-i) ignore build-lib and put compiled extensions into the
source directory alongside your pure Python modules
--include-dirs (-I) list of directories to search for header files
--define (-D) C preprocessor macros to define
--undef (-U) C preprocessor macros to undefine
--swig-opts list of SWIG command-line options
[...]
.. XXX do we want to support ``setup.py --help metadata``?
Note that an option spelled :option:`--foo-bar` on the command line is spelled
:option:`foo_bar` in configuration files.
For example, say you want your extensions to be built "in-place"---that is, you
have an extension :mod:`pkg.ext`, and you want the compiled extension file
(:file:`ext.so` on Unix, say) to be put in the same source directory as your
pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the
:option:`--inplace` option on the command line to ensure this::
python setup.py build_ext --inplace
But this requires that you always specify the :command:`build_ext` command
explicitly, and remember to provide :option:`--inplace`. An easier way is to
"set and forget" this option, by encoding it in :file:`setup.cfg`, the
configuration file for this distribution::
[build_ext]
inplace = 1
This will affect all builds of this module distribution, whether or not you
explicitly specify :command:`build_ext`. If you include :file:`setup.cfg` in
your source distribution, it will also affect end-user builds---which is
probably a bad idea for this option, since always building extensions in-place
would break installation of the module distribution. In certain peculiar cases,
though, modules are built right in their installation directory, so this is
conceivably a useful ability. (Distributing extensions that expect to be built
in their installation directory is almost always a bad idea, though.)
Another example: certain commands take options that vary from project to
project but not depending on the installation system, for example,
:command:`test` needs to know where your test suite is located and what test
runner to use; likewise, :command:`upload_docs` can find HTML documentation in
a :file:`doc` or :file:`docs` directory, but needs an option to find files in
:file:`docs/build/html`. Instead of having to type out these options each
time you want to run the command, you can put them in the project's
:file:`setup.cfg`::
[test]
suite = packaging.tests
[upload_docs]
upload-dir = docs/build/html
.. seealso::
:ref:`packaging-config-syntax` in "Installing Python Projects"
More information on the configuration files is available in the manual for
system administrators.
.. rubric:: Footnotes
.. [#] This ideal probably won't be achieved until auto-configuration is fully
supported by the Distutils.
This diff is collapsed.
.. _extending-packaging:
*******************
Extending Distutils
*******************
Distutils can be extended in various ways. Most extensions take the form of new
commands or replacements for existing commands. New commands may be written to
support new types of platform-specific packaging, for example, while
replacements for existing commands may be made to modify details of how the
command operates on a package.
Most extensions of the packaging are made within :file:`setup.py` scripts that
want to modify existing commands; many simply add a few file extensions that
should be copied into packages in addition to :file:`.py` files as a
convenience.
Most packaging command implementations are subclasses of the
:class:`packaging.cmd.Command` class. New commands may directly inherit from
:class:`Command`, while replacements often derive from :class:`Command`
indirectly, directly subclassing the command they are replacing. Commands are
required to derive from :class:`Command`.
.. .. _extend-existing:
Extending existing commands
===========================
.. .. _new-commands:
Writing new commands
====================
Integrating new commands
========================
There are different ways to integrate new command implementations into
packaging. The most difficult is to lobby for the inclusion of the new features
in packaging itself, and wait for (and require) a version of Python that
provides that support. This is really hard for many reasons.
The most common, and possibly the most reasonable for most needs, is to include
the new implementations with your :file:`setup.py` script, and cause the
:func:`packaging.core.setup` function use them::
from packaging.core import setup
from packaging.command.build_py import build_py as _build_py
class build_py(_build_py):
"""Specialized Python source builder."""
# implement whatever needs to be different...
setup(..., cmdclass={'build_py': build_py})
This approach is most valuable if the new implementations must be used to use a
particular package, as everyone interested in the package will need to have the
new command implementation.
Beginning with Python 2.4, a third option is available, intended to allow new
commands to be added which can support existing :file:`setup.py` scripts without
requiring modifications to the Python installation. This is expected to allow
third-party extensions to provide support for additional packaging systems, but
the commands can be used for anything packaging commands can be used for. A new
configuration option, :option:`command_packages` (command-line option
:option:`--command-packages`), can be used to specify additional packages to be
searched for modules implementing commands. Like all packaging options, this
can be specified on the command line or in a configuration file. This option
can only be set in the ``[global]`` section of a configuration file, or before
any commands on the command line. If set in a configuration file, it can be
overridden from the command line; setting it to an empty string on the command
line causes the default to be used. This should never be set in a configuration
file provided with a package.
This new option can be used to add any number of packages to the list of
packages searched for command implementations; multiple package names should be
separated by commas. When not specified, the search is only performed in the
:mod:`packaging.command` package. When :file:`setup.py` is run with the option
:option:`--command-packages` :option:`distcmds,buildcmds`, however, the packages
:mod:`packaging.command`, :mod:`distcmds`, and :mod:`buildcmds` will be searched
in that order. New commands are expected to be implemented in modules of the
same name as the command by classes sharing the same name. Given the example
command-line option above, the command :command:`bdist_openpkg` could be
implemented by the class :class:`distcmds.bdist_openpkg.bdist_openpkg` or
:class:`buildcmds.bdist_openpkg.bdist_openpkg`.
Adding new distribution types
=============================
Commands that create distributions (files in the :file:`dist/` directory) need
to add ``(command, filename)`` pairs to ``self.distribution.dist_files`` so that
:command:`upload` can upload it to PyPI. The *filename* in the pair contains no
path information, only the name of the file itself. In dry-run mode, pairs
should still be added to represent what would have been created.
.. _packaging-index:
##############################
Distributing Python Projects
##############################
:Authors: Greg Ward, Anthony Baxter and Packaging contributors
:Email: distutils-sig@python.org
:Release: |version|
:Date: |today|
This document describes Packaging for Python authors, describing how to use the
module to make Python applications, packages or modules easily available to a
wider audience with very little overhead for build/release/install mechanics.
.. toctree::
:maxdepth: 2
:numbered:
tutorial
setupcfg
introduction
setupscript
configfile
sourcedist
builtdist
packageindex
uploading
examples
extending
commandhooks
commandref
.. seealso::
:ref:`packaging-install-index`
A user-centered manual which includes information on adding projects
into an existing Python installation. You do not need to be a Python
programmer to read this manual.
:mod:`packaging`
A library reference for developers of packaging tools wanting to use
standalone building blocks like :mod:`~packaging.version` or
:mod:`~packaging.metadata`, or extend Packaging itself.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -20,9 +20,9 @@
<span class="linkdescr">tutorial for C/C++ programmers</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("c-api/index") }}">Python/C API</a><br/>
<span class="linkdescr">reference for C/C++ programmers</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("install/index") }}">Installing Python Modules</a><br/>
<p class="biglink"><a class="biglink" href="{{ pathto("install/index") }}">Installing Python Projects</a><br/>
<span class="linkdescr">information for installers &amp; sys-admins</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("distutils/index") }}">Distributing Python Modules</a><br/>
<p class="biglink"><a class="biglink" href="{{ pathto("packaging/index") }}">Distributing Python Projects</a><br/>
<span class="linkdescr">sharing modules with others</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("documenting/index") }}">Documenting Python</a><br/>
<span class="linkdescr">guide for documentation authors</span></p>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment