changes according to community feedback + uninstall script
This commit is contained in:
parent
6d8ec98027
commit
1eb61be116
189
pep-0376.txt
189
pep-0376.txt
|
@ -18,37 +18,41 @@ This PEP proposes various enhancements for Distutils:
|
|||
|
||||
- A new format for the .egg-info structure.
|
||||
- Some APIs to read the meta-data of a project
|
||||
- An install script to install a package in Python.
|
||||
- An uninstall script to uninstall a package in Python.
|
||||
|
||||
Definitions
|
||||
===========
|
||||
|
||||
A **project** is a Python application composed of one or many Python packages.
|
||||
It is distributed using a `setup.py` script with Distutils and/or Setuptools.
|
||||
|
||||
Once installed, one or several **packages** are added in Python's site-packages.
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
There are three problems right now in the way packages
|
||||
are installed in Python:
|
||||
|
||||
- There are too many ways to install a package in Python.
|
||||
|
||||
- There is no way to uninstall a package.
|
||||
There are three problems right now in the way projects are installed in
|
||||
Python:
|
||||
|
||||
- There are too many ways to install a project in Python.
|
||||
- There is no API to get the metadata of installed packages.
|
||||
|
||||
How packages are installed
|
||||
How projects are installed
|
||||
--------------------------
|
||||
|
||||
Right now, when a package is installed in Python, using the
|
||||
Distutils `install` command, the `install_egg_info` subcommand is
|
||||
called in order to create an `.egg-info` file in the site-packages directory,
|
||||
right beside the package itself.
|
||||
Right now, when a project is installed in Python, every package its contains
|
||||
is installed in the `site-packages` directory with the Distutils `install`
|
||||
command.
|
||||
|
||||
For example, if the `zlib` package is installed, two elements
|
||||
will be installed in `site-packages`::
|
||||
The `install_egg_info` subcommand is called during this process, in order to
|
||||
create an `.egg-info` file in the `site-packages` directory.
|
||||
|
||||
For example, if the `zlib` project is installed (which contains one package),
|
||||
two elements will be installed in `site-packages`::
|
||||
|
||||
- zlib
|
||||
- zlib-2.5.2.egg-info
|
||||
- zlib-2.5.2-py2.4.egg-info
|
||||
|
||||
Where `zlib` is the package itself, and `zlib-2.5.2.egg-info` is
|
||||
Where `zlib` is the package, and `zlib-2.5.2-py2.4.egg-info` is
|
||||
a file containing the package metadata as described in PEP 314.
|
||||
|
||||
This file corresponds to the file called `PKG-INFO`, built by
|
||||
|
@ -59,42 +63,31 @@ to install their packages, and these third-party tools do not install
|
|||
packages in the same way that Distutils does:
|
||||
|
||||
- `easy_install` creates an `EGG-INFO` directory inside an `.egg` directory,
|
||||
and adds a `PKG-INFO` file inside this directory, amongst other files.
|
||||
and adds a `PKG-INFO` file inside this directory. The `.egg` directory
|
||||
contains in that case the packages of the project.
|
||||
|
||||
- `pip` creates an `.egg-info` directory inside the site-packages directory
|
||||
besides the package, and adds a `PKG-INFO` file inside it.
|
||||
and adds a `PKG-INFO` file inside it. Packages are installed in
|
||||
site-packages directory in a regular way.
|
||||
|
||||
They both add other files in the `EGG-INFO` or `.egg-info` directory, and
|
||||
create or modify `.pth` files. `pip` also creates one `.pth` file
|
||||
per installed package, which may lead to slow initialisation of Python.
|
||||
create or modify `.pth` files.
|
||||
|
||||
The uninstall command
|
||||
Uninstall information
|
||||
---------------------
|
||||
|
||||
Python doesn't provide any `uninstall` command. If you want to uninstall
|
||||
a package, you have to be a power user and remove the package directory
|
||||
from the right site-packages directory, then look over the right pth
|
||||
files. And this method differs, depending on the tools you are using.
|
||||
Distutils doesn't provide any `uninstall` command. If you want to uninstall
|
||||
a project, you have to be a power user and remove the various package
|
||||
directories from the right `site-packages` directory, then look over the right
|
||||
`pth` files. And this method differs, depending on the tools you are using.
|
||||
|
||||
The worst issue is that you depend on the way the packager created his package.
|
||||
When you call `python setup.py install`, it will not be installed the same way
|
||||
depending on the tool used by the packager (distutils or setuptools).
|
||||
depending on the tool used by the packager (mainly Distutils or Setuptools).
|
||||
|
||||
But there's common behavior: files are copied in your installation.
|
||||
And there's a way to keep track of theses file, so to remove them.
|
||||
|
||||
Installing a package
|
||||
--------------------
|
||||
|
||||
There are too many different ways to install a package in Python:
|
||||
|
||||
- by hand, by getting a distribution and running the install command
|
||||
- using `easy_install`, the script provided by setuptools
|
||||
- using `pip`
|
||||
|
||||
The problem is: they do not install the package the same way,
|
||||
and Python should provide one and only one way to do it.
|
||||
|
||||
What this PEP proposes
|
||||
----------------------
|
||||
|
||||
|
@ -102,9 +95,8 @@ To address those issues, this PEP proposes a few changes:
|
|||
|
||||
- a new `.egg-info` structure using a directory;
|
||||
- a list of elements this directory holds;
|
||||
- some new functions in `pkgutil`
|
||||
- addition of an install and an uninstall script
|
||||
|
||||
- new functions in `pkgutil` to be able to query the information
|
||||
of installed projects.
|
||||
|
||||
.egg-info becomes a directory
|
||||
=============================
|
||||
|
@ -124,48 +116,57 @@ For example, if the `zlib` package is installed, two elements
|
|||
will be installed in `site-packages`::
|
||||
|
||||
- zlib
|
||||
- zlib-2.5.2-py2.6.egg-info/
|
||||
- zlib-2.5.2.egg-info/
|
||||
PKG-INFO
|
||||
|
||||
To be able to implement this change, the impacted code in Distutils
|
||||
is the `install_egg_info` command.
|
||||
The Python version will also be removed from the .egg-info directory
|
||||
name. To be able to implement this change, the impacted code in Distutils
|
||||
is the `install_egg_info` command, and the various third-party projects.
|
||||
|
||||
Adding a RECORD in the .egg-info directory
|
||||
==========================================
|
||||
|
||||
Adding MANIFEST and RECORD in the .egg-info directory
|
||||
=====================================================
|
||||
|
||||
Some files can be added inside the `.egg-info` directory at installation
|
||||
time. They will all be UPPERCASE files.
|
||||
|
||||
- the `MANIFEST` file built by the `sdist` command. Notice that
|
||||
some fixes were made lately on the default file names added in `MANIFEST`
|
||||
when `MANIFEST.in` is not provided (see #2279 for instance).
|
||||
A `RECORD` file will be added inside the `.egg-info` directory at installation
|
||||
time.
|
||||
|
||||
- the `RECORD` file will hold the list of installed files. These
|
||||
correspond to the files listed by the `record` option of the `install`
|
||||
command, and will always be generated. This will allow uninstall, as
|
||||
explained later in this PEP.
|
||||
|
||||
The two files will need to use '/'-separated relative paths.
|
||||
The `install` command will record by default installed files in the
|
||||
RECORD file.
|
||||
RECORD file, using these rules:
|
||||
|
||||
The `sdist` module will introduce an `EGG_INFO_FILES` constant to list
|
||||
all files located in the `.egg-info` directory::
|
||||
- if the installed file is located in a directory in `site-packages`,
|
||||
it will be a '/'-separated relative path, no matter what is the target
|
||||
system. This makes this information cross-compatible and allows simple
|
||||
installation to be relocatable.
|
||||
|
||||
- if the installed file is located elswhere in the system, a
|
||||
'/'-separated absolute path is used.
|
||||
|
||||
This will require changing the way the `install` command writes the record
|
||||
file, so the old `record` behavior will be deprecated.
|
||||
XXX see how to handle old record (new option, or wait for 2 version?)
|
||||
|
||||
Listing the .egg-info elements in Distutils
|
||||
===========================================
|
||||
|
||||
In Distutils, the `dist` module will introduce an `EGG_INFO_FILES` constant
|
||||
to list all files located in the `.egg-info` directory::
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
EggInfos = namedtuple('EggInfo', 'manifest record pkg_info')
|
||||
|
||||
# files added in egg-info
|
||||
EGG_INFO_FILES = EggInfos('MANIFEST', 'RECORD', 'PKG-INFO')
|
||||
EGG_INFO_FILES = EggInfos('RECORD', 'PKG-INFO')
|
||||
|
||||
Back to our `zlib` example, we will have::
|
||||
|
||||
- zlib
|
||||
- zlib-2.5.2.egg-info/
|
||||
PKG-INFO
|
||||
MANIFEST
|
||||
RECORD
|
||||
|
||||
XXX See if we want to add Python version in the PKG-INFO
|
||||
|
@ -176,7 +177,6 @@ New functions in pkgutil
|
|||
To use the `.egg-info` directory content, we need to add in the standard
|
||||
library a set of APIs. The best place to put these APIs seems to be `pkgutil`.
|
||||
|
||||
|
||||
The new functions added in the package are :
|
||||
|
||||
- get_egg_info(project_name) -> path or None
|
||||
|
@ -216,57 +216,38 @@ Let's use it with our `zlib` example::
|
|||
files
|
||||
|
||||
|
||||
Adding an install and an uninstall script
|
||||
=========================================
|
||||
Adding an Uninstall API
|
||||
=======================
|
||||
|
||||
XXX decide wheter we include these scripts.
|
||||
Distutils provides a very basic way to install a project, which is running
|
||||
the `install` command over the `setup.py` script of the distribution.
|
||||
|
||||
`easy_install` and `pip` does basically the same work, besides other features
|
||||
that are not discussed here.
|
||||
Distutils will provide a very basic `uninstall` command that will remove
|
||||
all files listed in the `RECORD` file of a project, as long as they are not
|
||||
mentioned in another `RECORD` file.
|
||||
|
||||
- they look for the package at PyPI
|
||||
- they download it and build it
|
||||
- they install it inside the site-packages directory
|
||||
- they add an entry in a .pth file
|
||||
This command will be added in the `util` module and will take the name
|
||||
of the project to uninstall::
|
||||
|
||||
Distutils will provide two simple reference scripts, that are just able
|
||||
to do the features mentioned. Third party packages will be able to fetch
|
||||
dependencies.
|
||||
>>> from distutils.util import uninstall
|
||||
>>> uninstall('zlib')
|
||||
|
||||
Install script
|
||||
--------------
|
||||
To make it a reference API for third-party projects that wish to provide
|
||||
an `uninstall feature`. The `uninstall` API can also be invoked with a
|
||||
second callable argument, that will be invoked for each file to be removed.
|
||||
If it returns `True`, the file will be removed.
|
||||
|
||||
A new script called `install.py` is added in a new directory called `scripts`
|
||||
in Distutils, and lets people run an installation using::
|
||||
Examples::
|
||||
|
||||
$ python -m distutils.scripts.install zlib
|
||||
>>> def _remove_and_log(path):
|
||||
... logging.info('Removing %s' % path)
|
||||
... return True
|
||||
>>> uninstall('zlib', _remove_and_log)
|
||||
>>> def _dry_run(path):
|
||||
... logging.info('Removing %s (dry run)' % path)
|
||||
... return False
|
||||
>>> uninstall('zlib', _dry_run)
|
||||
|
||||
Where `zlib` can be:
|
||||
- the name of the package
|
||||
- an url of an archive
|
||||
- a path
|
||||
|
||||
The install script process is done in 3 steps:
|
||||
|
||||
1. it looks for the package at PyPI if it's a package name
|
||||
XXX explain here how (easy_install code)
|
||||
2. it downloads it in a temporary directory (or copy it if it's a path)
|
||||
3. it runs the install command, with the --record option
|
||||
XXX explains here how (see pip code)
|
||||
|
||||
The install script takes several options :
|
||||
|
||||
Uninstall script
|
||||
----------------
|
||||
|
||||
An uninstall command is added as well that removes the files recorded
|
||||
in the RECORD file. This removal will warn on files that no longer exist
|
||||
and will not take care of side effects, like the removal of a file
|
||||
used by another element of the system.
|
||||
|
||||
$ python -m distutils.scripts.uninstall zlib
|
||||
|
||||
XXX work to be done here : detail specification of the uninstall process
|
||||
|
||||
Aknowledgments
|
||||
==============
|
||||
|
|
Loading…
Reference in New Issue