changes according to community feedback + uninstall script

This commit is contained in:
Tarek Ziadé 2009-04-24 16:03:02 +00:00
parent 6d8ec98027
commit 1eb61be116
1 changed files with 87 additions and 106 deletions

View File

@ -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.
- zlib
- zlib-2.5.2.egg-info
For example, if the `zlib` project is installed (which contains one package),
two elements will be installed in `site-packages`::
Where `zlib` is the package itself, and `zlib-2.5.2.egg-info` is
- zlib
- zlib-2.5.2-py2.4.egg-info
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.
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
==============