Commit ffa10162 authored by Éric Araujo's avatar Éric Araujo

Remove packaging from the standard library.

Distutils2 will live on on PyPI and be included in the stdlib when it
is ready.  See discussion starting at
http://mail.python.org/pipermail/python-dev/2012-June/120430.html
parent 5f121e50
......@@ -11,7 +11,7 @@
library/index.rst
extending/index.rst
c-api/index.rst
packaging/index.rst
distutils/index.rst
install/index.rst
howto/index.rst
faq/index.rst
......
......@@ -14,12 +14,9 @@ the module developer's point of view, describing how to use the Distutils to
make Python modules and extensions easily available to a wider audience with
very little overhead for build/release/install mechanics.
.. deprecated:: 3.3
:mod:`packaging` replaces Distutils. See :ref:`packaging-index` and
:ref:`packaging-install-index`.
.. toctree::
:maxdepth: 2
:numbered:
introduction.rst
setupscript.rst
......@@ -32,10 +29,3 @@ 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
.. _packaging-install-index:
******************************
Installing Python Projects
******************************
:Author: The Fellowship of the Packaging
:Release: |version|
:Date: |today|
.. TODO: Fill in XXX comments
.. The audience for this document includes people who don't know anything
about Python and aren't about to learn the language just in order to
install and maintain it for their users, i.e. system administrators.
Thus, I have to be sure to explain the basics at some point:
sys.path and PYTHONPATH at least. Should probably give pointers to
other docs on "import site", PYTHONSTARTUP, PYTHONHOME, etc.
Finally, it might be useful to include all the material from my "Care
and Feeding of a Python Installation" talk in here somewhere. Yow!
.. topic:: Abstract
This document describes Packaging from the end-user's point of view: it
explains how to extend the functionality of a standard Python installation by
building and installing third-party Python modules and applications.
This guide is split into a simple overview followed by a longer presentation of
the :program:`pysetup` script, the Python package management tool used to
build, distribute, search for, install, remove and list Python distributions.
.. TODO integrate install and pysetup instead of duplicating
.. toctree::
:maxdepth: 2
:numbered:
install
pysetup
pysetup-config
pysetup-servers
.. 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.
: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.
.. _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 list virtualenv
'virtualenv' 1.6 at '/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info'
$ pysetup list
'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'
...
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
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 in the indexes
list: List installed projects
graph: Display a graph
create: Create a project
generate-setup: Generate a backward-compatible setup.py
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
......@@ -12,10 +12,6 @@ additional modules into a Python installation. The new modules may be either
100%-pure Python, or may be extension modules written in C, or may be
collections of Python packages which include modules coded in both Python and C.
.. deprecated:: 3.3
:mod:`packaging` replaces Distutils. See :ref:`packaging-index` and
:ref:`packaging-install-index`.
User documentation and API reference are provided in another document:
......@@ -27,11 +23,3 @@ User documentation and API reference are provided in another document:
easily installed into an existing Python installation. If also contains
instructions for end-users wanting to install a distutils-based package,
:ref:`install-index`.
.. trick to silence a Sphinx warning
.. 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 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 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.base` --- Base class for index crawlers
============================================================
.. module:: packaging.pypi.base
:synopsis: Base class used to implement crawlers.
.. class:: BaseClient(prefer_final, prefer_source)
Base class containing common methods for the index crawlers or clients. One
method is currently defined:
.. method:: download_distribution(requirements, temp_path=None, \
prefer_source=None, prefer_final=None)
Download a distribution from the last release according to the
requirements. If *temp_path* is provided, download to this path,
otherwise, create a temporary directory for the download. If a release is
found, the full path to the downloaded file is returned.
: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.
The class provided by :mod:`packaging.pypi.simple` can access project indexes
and provide useful information about distributions. PyPI, other indexes and
local indexes are supported.
You should use this module to search distributions by name and versions, process
index external pages and download distributions. It is not suited for things
that will end up in too long index processing (like "finding all distributions
with a specific version, no matter the name"); use :mod:`packaging.pypi.xmlrpc`
for that.
API
---
.. class:: Crawler(index_url=DEFAULT_SIMPLE_INDEX_URL, \
prefer_final=False, prefer_source=True, \
hosts=('*',), follow_externals=False, \
mirrors_url=None, mirrors=None, timeout=15, \
mirrors_max_tries=0)
*index_url* is the address of the index to use for requests.
The first two parameters control the query results. *prefer_final*
indicates whether a final version (not alpha, beta or candidate) is to be
preferred over a newer but non-final version (for example, whether to pick
up 1.0 over 2.0a3). It is used only for queries that don't give a version
argument. Likewise, *prefer_source* tells whether to prefer a source
distribution over a binary one, if no distribution argument was prodived.
Other parameters are related to external links (that is links that go
outside the simple index): *hosts* is a list of hosts allowed to be
processed if *follow_externals* is true (default behavior is to follow all
hosts), *follow_externals* enables or disables following external links
(default is false, meaning disabled).
The remaining parameters are related to the mirroring infrastructure
defined in :PEP:`381`. *mirrors_url* gives a URL to look on for DNS
records giving mirror adresses; *mirrors* is a list of mirror URLs (see
the PEP). If both *mirrors* and *mirrors_url* are given, *mirrors_url*
will only be used if *mirrors* is set to ``None``. *timeout* is the time
(in seconds) to wait before considering a URL has timed out;
*mirrors_max_tries"* is the number of times to try requesting informations
on mirrors before switching.
The following methods are defined:
.. method:: get_distributions(project_name, version)
Return the distributions found in the index for the given release.
.. method:: get_metadata(project_name, version)
Return the metadata found on the index for this project name and
version. Currently downloads and unpacks a distribution to read the
PKG-INFO file.
.. method:: get_release(requirements, prefer_final=None)
Return one release that fulfills the given requirements.
.. method:: get_releases(requirements, prefer_final=None, force_update=False)
Search for releases and return a
:class:`~packaging.pypi.dist.ReleasesList` object containing the
results.
.. method:: search_projects(name=None)
Search the index for projects containing the given name and return a
list of matching names.
See also the base class :class:`packaging.pypi.base.BaseClient` for inherited
methods.
.. data:: DEFAULT_SIMPLE_INDEX_URL
The address used by default by the crawler class. It is currently
``'http://a.pypi.python.org/simple/'``, the main PyPI installation.
Usage Examples
---------------
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 preferred 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
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
packaging.dist
packaging.command
packaging.compiler
packaging.fancy_getopt
Other utilities
----------------
.. toctree::
:maxdepth: 2
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:: execute(func, args, msg=None, dry_run=False)
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.
.. function:: byte_compile(py_files, optimize=0, force=0, prefix=None, \
base_dir=None, dry_run=0, direct=None)
Byte-compile a collection of Python source files to either :file:`.pyc` or
:file:`.pyo` files in a :file:`__pycache__` subdirectory (see :pep:`3147`),
or to the same directory when using the distutils2 backport on Python
versions older than 3.2.
*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``)
This function is independent from the running Python's :option:`-O` or
:option:`-B` options; it is fully controlled by the parameters passed in.
If *force* is true, all files are recompiled regardless of timestamps.
The source filename encoded in each :term:`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``.
: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,5 +25,4 @@ overview:
inspect.rst
site.rst
fpectl.rst
packaging.rst
distutils.rst
......@@ -134,9 +134,9 @@ empty, and the path manipulations are skipped; however the import of
:func:`getuserbase` hasn't been called yet. Default value is
:file:`~/.local` for UNIX and Mac OS X non-framework builds,
:file:`~/Library/Python/{X.Y}` for Mac framework builds, and
:file:`{%APPDATA%}\\Python` for Windows. This value is used by Packaging to
:file:`{%APPDATA%}\\Python` for Windows. This value is used by Distutils to
compute the installation directories for scripts, data files, Python modules,
etc. for the :ref:`user installation scheme <packaging-alt-install-user>`.
etc. for the :ref:`user installation scheme <inst-alt-install-user>`.
See also :envvar:`PYTHONUSERBASE`.
......
......@@ -35,8 +35,7 @@ directories that don't exist already) and places a ``pyvenv.cfg`` file
in it with a ``home`` key pointing to the Python installation the
command was run from. It also creates a ``bin`` (or ``Scripts`` on
Windows) subdirectory containing a copy of the ``python`` binary (or
binaries, in the case of Windows) and the ``pysetup3`` script (to
facilitate easy installation of packages from PyPI into the new virtualenv).
binaries, in the case of Windows).
It also creates an (initially empty) ``lib/pythonX.Y/site-packages``
subdirectory (on Windows, this is ``Lib\site-packages``).
......
This diff is collapsed.
.. TODO integrate this in commandref and configfile
.. _packaging-command-hooks:
=============
Command hooks
=============
Packaging provides a way of extending its commands by the use of pre- and
post-command hooks. Hooks are Python functions (or any callable object) that
take a command object as argument. They're specified in :ref:`config files
<packaging-config-filenames>` using their fully qualified names. After a
command is finalized (its options are processed), the pre-command hooks are
executed, then the command itself is run, and finally the post-command hooks are
executed.
See also global setup hooks in :ref:`setupcfg-spec`.
.. _packaging-finding-hooks:
Finding hooks
=============
As a hook is configured with a Python dotted name, it must either be defined in
a module installed on the system, or in a module present in the project
directory, where the :file:`setup.cfg` file lives::
# file: _setuphooks.py
def hook(install_cmd):
metadata = install_cmd.dist.metadata
print('Hooked while installing %r %s!' % (metadata['Name'],
metadata['Version']))
Then you need to configure it in :file:`setup.cfg`::
[install_dist]
pre-hook.a = _setuphooks.hook
Packaging will add the project directory to :data:`sys.path` and find the
``_setuphooks`` module.
Hooks defined in different config files (system-wide, user-wide and
project-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 ``a``.
This diff is collapsed.
.. _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: The Fellowship of the Packaging
: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.
.. _packaging-package-upload:
***************************************
Uploading Packages to the Package Index
***************************************
The Python Package Index (PyPI) not only stores the package info, but also the
package data if the author of the package wishes to. The packaging command
:command:`upload` pushes the distribution files to PyPI.
The command is invoked immediately after building one or more distribution
files. For example, the command ::
python setup.py sdist bdist_wininst upload
will cause the source distribution and the Windows installer to be uploaded to
PyPI. Note that these will be uploaded even if they are built using an earlier
invocation of :file:`setup.py`, but that only distributions named on the command
line for the invocation including the :command:`upload` command are uploaded.
The :command:`upload` command uses the username, password, and repository URL
from the :file:`$HOME/.pypirc` file (see section :ref:`packaging-pypirc` for more on this
file). If a :command:`register` command was previously called in the same
command, and if the password was entered in the prompt, :command:`upload` will
reuse the entered password. This is useful if you do not want to store a clear
text password in the :file:`$HOME/.pypirc` file.
You can specify another PyPI server with the :option:`--repository=*url*`
option::
python setup.py sdist bdist_wininst upload -r http://example.com/pypi
See section :ref:`packaging-pypirc` for more on defining several servers.
You can use the :option:`--sign` option to tell :command:`upload` to sign each
uploaded file using GPG (GNU Privacy Guard). The :program:`gpg` program must
be available for execution on the system :envvar:`PATH`. You can also specify
which key to use for signing using the :option:`--identity=*name*` option.
Other :command:`upload` options include :option:`--repository=<url>` or
:option:`--repository=<section>` where *url* is the url of the server and
*section* the name of the section in :file:`$HOME/.pypirc`, and
:option:`--show-response` (which displays the full response text from the PyPI
server for help in debugging upload problems).
PyPI package display
====================
The ``description`` field plays a special role at PyPI. It is used by
the server to display a home page for the registered package.
If you use the `reStructuredText <http://docutils.sourceforge.net/rst.html>`_
syntax for this field, PyPI will parse it and display an HTML output for
the package home page.
The ``description`` field can be filled from a text file located in the
project::
from packaging.core import setup
fp = open('README.txt')
try:
description = fp.read()
finally:
fp.close()
setup(name='Packaging',
description=description)
In that case, :file:`README.txt` is a regular reStructuredText text file located
in the root of the package besides :file:`setup.py`.
To prevent registering broken reStructuredText content, you can use the
:program:`rst2html` program that is provided by the :mod:`docutils` package
and check the ``description`` from the command line::
$ python setup.py --description | rst2html.py > output.html
:mod:`docutils` will display a warning if there's something wrong with your
syntax.
......@@ -20,10 +20,10 @@
<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 Projects</a><br/>
<span class="linkdescr">finding and installing modules and applications</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("packaging/index") }}">Distributing Python Projects</a><br/>
<span class="linkdescr">packaging and distributing modules and applications</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("install/index") }}">Installing Python Modules</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/>
<span class="linkdescr">sharing modules with others</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("faq/index") }}">FAQs</a><br/>
<span class="linkdescr">frequently asked questions (with answers!)</span></p>
</td></tr>
......
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.
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.
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.
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.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
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.
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.
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.
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.
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.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff was suppressed by a .gitattributes entry.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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