From 1eb61be11681a8043aaeffaa7407d61e2a2c4458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarek=20Ziad=C3=A9?= Date: Fri, 24 Apr 2009 16:03:02 +0000 Subject: [PATCH] changes according to community feedback + uninstall script --- pep-0376.txt | 193 +++++++++++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 106 deletions(-) diff --git a/pep-0376.txt b/pep-0376.txt index 724bc0721..b9ba37c7e 100644 --- a/pep-0376.txt +++ b/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. - - 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 ==============