aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2012-03-29 23:15:27 -0400
committerJason R. Coombs <jaraco@jaraco.com>2012-03-29 23:15:27 -0400
commitd6d8bcaf4e80dae0f8ba9f81ba1db4b05b857909 (patch)
tree2292042ee7e74f0f09171f058e751f0cbe792841
parent0d6b0fdd59f5fb29c06ed335fc7597951c5f277f (diff)
parentdf1e3725c0ef744f89e1769767e04b78ebc9a525 (diff)
downloadexternal_python_setuptools-d6d8bcaf4e80dae0f8ba9f81ba1db4b05b857909.tar.gz
external_python_setuptools-d6d8bcaf4e80dae0f8ba9f81ba1db4b05b857909.tar.bz2
external_python_setuptools-d6d8bcaf4e80dae0f8ba9f81ba1db4b05b857909.zip
Merge with default
--HG-- branch : distribute extra : rebase_source : a19a5411e30665acdd86f2554921e385759b1ef3
-rw-r--r--.hgtags5
-rw-r--r--CHANGES.txt40
-rw-r--r--DEVGUIDE.txt18
-rwxr-xr-xREADME.txt6
-rw-r--r--distribute.egg-info/entry_points.txt3
-rw-r--r--distribute_setup.py17
-rw-r--r--docs/conf.py4
-rw-r--r--docs/easy_install.txt218
-rw-r--r--docs/python3.txt33
-rwxr-xr-xlauncher.c102
-rw-r--r--pkg_resources.py8
-rw-r--r--release.py99
-rwxr-xr-xrelease.sh23
-rwxr-xr-xsetup.py5
-rwxr-xr-xsetuptools/archive_util.py29
-rw-r--r--setuptools/cli-32.exebin0 -> 69632 bytes
-rw-r--r--setuptools/cli-64.exebin0 -> 75264 bytes
-rw-r--r--setuptools/cli.exebin7168 -> 69632 bytes
-rw-r--r--setuptools/command/__init__.py1
-rw-r--r--setuptools/command/build_py.py28
-rwxr-xr-xsetuptools/command/easy_install.py45
-rwxr-xr-xsetuptools/command/install_egg_info.py2
-rwxr-xr-xsetuptools/command/sdist.py18
-rwxr-xr-xsetuptools/command/upload.py1
-rw-r--r--setuptools/extension.py56
-rw-r--r--setuptools/gui-32.exebin0 -> 65536 bytes
-rw-r--r--setuptools/gui-64.exebin0 -> 75264 bytes
-rw-r--r--setuptools/gui.exebin7168 -> 65536 bytes
-rwxr-xr-xsetuptools/package_index.py19
-rw-r--r--setuptools/script template (dev).py6
-rw-r--r--setuptools/script template.py4
-rw-r--r--setuptools/tests/test_easy_install.py21
-rw-r--r--setuptools/tests/test_resources.py41
33 files changed, 518 insertions, 334 deletions
diff --git a/.hgtags b/.hgtags
index 734cd0c0..19680f4f 100644
--- a/.hgtags
+++ b/.hgtags
@@ -29,3 +29,8 @@ dae247400d0ca1fdfaf38db275622c9bec550b08 0.6.13
a7cf5ae137f1646adf86ce5d6b5d8b7bd6eab69f 0.6.20
c4a375336d552129aef174486018ed09c212d684 0.6.20
de44acab3cfce1f5bc811d6c0fa1a88ca0e9533f 0.6.21
+1a1ab844f03e10528ae693ad3cb45064e08f49e5 0.6.23
+1a1ab844f03e10528ae693ad3cb45064e08f49e5 0.6.23
+9406c5dac8429216f1a264e6f692fdc534476acd 0.6.23
+7fd7b6e30a0effa082baed1c4103a0efa56be98c 0.6.24
+6124053afb5c98f11e146ae62049b4c232d50dc5 0.6.25
diff --git a/CHANGES.txt b/CHANGES.txt
index fe529fb3..3895b0a3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,9 +3,47 @@ CHANGES
=======
------
-0.6.22
+0.6.26
------
+* Issue #183: Symlinked files are now extracted from source distributions.
+
+------
+0.6.25
+------
+
+* Issue #258: Workaround a cache issue
+* Issue #260: distribute_setup.py now accepts the --user parameter for
+ Python 2.6 and later.
+* Issue #262: package_index.open_with_auth no longer throws LookupError
+ on Python 3.
+* Issue #269: AttributeError when an exception occurs reading Manifest.in
+ on late releases of Python.
+* Issue #272: Prevent TypeError when namespace package names are unicode
+ and single-install-externally-managed is used. Also fixes PIP issue
+ 449.
+* Issue #273: Legacy script launchers now install with Python2/3 support.
+
+------
+0.6.24
+------
+
+* Issue #249: Added options to exclude 2to3 fixers
+
+------
+0.6.23
+------
+
+* Issue #244: Fixed a test
+* Issue #243: Fixed a test
+* Issue #239: Fixed a test
+* Issue #240: Fixed a test
+* Issue #241: Fixed a test
+* Issue #237: Fixed a test
+* Issue #238: easy_install now uses 64bit executable wrappers on 64bit Python
+* Issue #208: Fixed parsed_versions, it now honors post-releases as noted in the documentation
+* Issue #207: Windows cli and gui wrappers pass CTRL-C to child python process
+* Issue #227: easy_install now passes its arguments to setup.py bdist_egg
* Issue #225: Fixed a NameError on Python 2.5, 2.4
------
diff --git a/DEVGUIDE.txt b/DEVGUIDE.txt
index 54b7f71c..8dcabfd1 100644
--- a/DEVGUIDE.txt
+++ b/DEVGUIDE.txt
@@ -6,22 +6,16 @@ Distribute is using Mercurial.
Grab the code at bitbucket::
- $ hg clone https://tarek@bitbucket.org/tarek/distribute distribute
+ $ hg clone https://bitbucket.org/tarek/distribute
-If you want to work in the 0.6 branch, you have to switch to it::
+If you want to contribute changes, we recommend you fork the repository on
+bitbucket, commit the changes to your repository, and then make a pull request
+on bitbucket. If you make some changes, don't forget to:
- $ hg update 0.6-maintenance
-
- $ hg branch
- 0.6-maintenance
-
-If you make some changes, don't forget to:
-
-- backport it to the 0.7 branch
- add a note in CHANGES.txt
-And remember that 0.6 is only bug fixes, and the APIs should
-be fully backward compatible with Setuptools.
+And remember that 0.6 (the only development line) is only bug fixes, and the
+APIs should be fully backward compatible with Setuptools.
You can run the tests via::
diff --git a/README.txt b/README.txt
index 8faa59b4..bc9b8454 100755
--- a/README.txt
+++ b/README.txt
@@ -99,9 +99,9 @@ Source installation
Download the source tarball, uncompress it, then run the install command::
- $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.22.tar.gz
- $ tar -xzvf distribute-0.6.22.tar.gz
- $ cd distribute-0.6.22
+ $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.26.tar.gz
+ $ tar -xzvf distribute-0.6.26.tar.gz
+ $ cd distribute-0.6.26
$ python setup.py install
---------------------------
diff --git a/distribute.egg-info/entry_points.txt b/distribute.egg-info/entry_points.txt
index 1c9f123d..663882d6 100644
--- a/distribute.egg-info/entry_points.txt
+++ b/distribute.egg-info/entry_points.txt
@@ -32,7 +32,7 @@ depends.txt = setuptools.command.egg_info:warn_depends_obsolete
[console_scripts]
easy_install = setuptools.command.easy_install:main
-easy_install-2.6 = setuptools.command.easy_install:main
+easy_install-2.7 = setuptools.command.easy_install:main
[setuptools.file_finders]
svn_cvs = setuptools.command.sdist:_default_revctrl
@@ -41,6 +41,7 @@ svn_cvs = setuptools.command.sdist:_default_revctrl
dependency_links = setuptools.dist:assert_string_list
entry_points = setuptools.dist:check_entry_points
extras_require = setuptools.dist:check_extras
+use_2to3_exclude_fixers = setuptools.dist:assert_string_list
package_data = setuptools.dist:check_package_data
install_requires = setuptools.dist:check_requirements
use_2to3 = setuptools.dist:assert_bool
diff --git a/distribute_setup.py b/distribute_setup.py
index 2ee0f124..3bc42fa1 100644
--- a/distribute_setup.py
+++ b/distribute_setup.py
@@ -46,7 +46,7 @@ except ImportError:
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
-DEFAULT_VERSION = "0.6.22"
+DEFAULT_VERSION = "0.6.26"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
@@ -63,7 +63,7 @@ Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
-def _install(tarball):
+def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
@@ -81,7 +81,7 @@ def _install(tarball):
# installing
log.warn('Installing Distribute')
- if not _python_cmd('setup.py', 'install'):
+ if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
finally:
@@ -474,11 +474,20 @@ def _extractall(self, path=".", members=None):
else:
self._dbg(1, "tarfile: %s" % e)
+def _build_install_args(argv):
+ install_args = []
+ user_install = '--user' in argv
+ if user_install and sys.version_info < (2,6):
+ log.warn("--user requires Python 2.6 or later")
+ raise SystemExit(1)
+ if user_install:
+ install_args.append('--user')
+ return install_args
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
tarball = download_setuptools()
- _install(tarball)
+ _install(tarball, _build_install_args(argv))
if __name__ == '__main__':
diff --git a/docs/conf.py b/docs/conf.py
index e52891fe..80d8c0e1 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,9 +48,9 @@ copyright = u'2009-2011, The fellowship of the packaging'
# built documents.
#
# The short X.Y version.
-version = '0.6.17'
+version = '0.6.26'
# The full version, including alpha/beta/rc tags.
-release = '0.6.17'
+release = '0.6.26'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/easy_install.txt b/docs/easy_install.txt
index ab008a1d..9b4fcfbb 100644
--- a/docs/easy_install.txt
+++ b/docs/easy_install.txt
@@ -875,9 +875,6 @@ Command-Line Options
judgment and force an installation directory to be treated as if it
supported ``.pth`` files.
- (If you want to *make* a non-``PYTHONPATH`` directory support ``.pth``
- files, please see the `Administrator Installation`_ section below.)
-
``--no-deps, -N`` (New in 0.6a6)
Don't install any dependencies. This is intended as a convenience for
tools that wrap eggs in a platform-specific packaging system. (We don't
@@ -940,194 +937,65 @@ Command-Line Options
Custom Installation Locations
-----------------------------
-EasyInstall manages what packages are active using Python ``.pth`` files, which
-are normally only usable in Python's main ``site-packages`` directory. On some
-platforms (such as Mac OS X), there are additional ``site-packages``
-directories that you can use besides the main one, but usually there is only
-one directory on the system where you can install packages without extra steps.
-
-There are many reasons, however, why you might want to install packages
-somewhere other than the ``site-packages`` directory. For example, you might
-not have write access to that directory. You may be working with unstable
-versions of packages that you don't want to install system-wide. And so on.
-
-The following sections describe various approaches to custom installation; feel
-free to choose which one best suits your system and needs.
-
-`Administrator Installation`_
- This approach is for when you have write access to ``site-packages`` (or
- another directory where ``.pth`` files are processed), but don't want to
- install packages there. This can also be used by a system administrator
- to enable each user having their own private directories that EasyInstall
- will use to install packages.
-
-`Mac OS X "User" Installation`_
- This approach produces a result similar to an administrator installation
- that gives each user their own private package directory, but on Mac OS X
- the hard part has already been done for you. This is probably the best
- approach for Mac OS X users.
-
-`Creating a "Virtual" Python`_
- This approach is for when you don't have "root" or access to write to the
- ``site-packages`` directory, and would like to be able to set up one or
- more "virtual python" executables for your projects. This approach
- gives you the benefits of multiple Python installations, but without having
- to actually install Python more than once and use up lots of disk space.
- (Only the Python executable is copied; the libraries will be symlinked
- from the systemwide Python.)
-
- If you don't already have any ``PYTHONPATH`` customization or
- special distutils configuration, and you can't use either of the preceding
- approaches, this is probably the best one for you.
-
-`"Traditional" PYTHONPATH-based Installation`_
- If you already have a custom ``PYTHONPATH``, and/or a custom distutils
- configuration, and don't want to change any of your existing setup, you may
- be interested in this approach. (If you're using a custom ``.pth`` file to
- point to your custom installation location, however, you should use
- `Administrator Installation`_ to enable ``.pth`` processing in the custom
- location instead, as that is easier and more flexible than this approach.)
-
-
-Administrator Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you have root access to your machine, you can easily configure it to allow
-each user to have their own directory where Python packages can be installed
-and managed by EasyInstall.
-
-First, create an ``altinstall.pth`` file in Python's ``site-packages``
-directory, containing the following line (substituting the correct Python
-version)::
-
- import os, site; site.addsitedir(os.path.expanduser('~/lib/python2.3'))
-
-This will automatically add each user's ``~/lib/python2.X`` directory to
-``sys.path`` (if it exists), *and* it will process any ``.pth`` files in that
-directory -- which is what makes it usable with EasyInstall.
-
-The next step is to create or modify ``distutils.cfg`` in the ``distutils``
-directory of your Python library. The correct directory will be something like
-``/usr/lib/python2.X/distutils`` on most Posix systems and something like
-``C:\\Python2X\Lib\distutils`` on Windows machines. Add the following lines
-to the file, substituting the correct Python version if necessary:
-
-.. code-block:: ini
-
- [install]
- install_lib = ~/lib/python2.3
-
- # This next line is optional but often quite useful; it directs EasyInstall
- # and the distutils to install scripts in the user's "bin" directory. For
- # Mac OS X framework Python builds, you should use /usr/local/bin instead,
- # because neither ~/bin nor the default script installation location are on
- # the system PATH.
- #
- install_scripts = ~/bin
-
-This will configure the distutils and EasyInstall to install packages to the
-user's home directory by default.
-
-Of course, you aren't limited to using a ``~/lib/python2.X`` directory with
-this approach. You can substitute a specific systemwide directory if you like.
-You can also edit ``~/.pydistutils.cfg`` (or ``~/pydistutils.cfg`` on Windows)
-instead of changing the master ``distutils.cfg`` file. The true keys of this
-approach are simply that:
-
-1. any custom installation directory must be added to ``sys.path`` using a
- ``site.addsitedir()`` call from a working ``.pth`` file or
- ``sitecustomize.py``.
+By default, EasyInstall installs python packages into Python's main ``site-packages`` directory,
+and manages them using a custom ``.pth`` file in that same directory.
-2. The active distutils configuration file(s) or ``easy_install`` command line
- should include the custom directory in the ``--site-dirs`` option, so that
- EasyInstall knows that ``.pth`` files will work in that location. (This is
- because Python does not keep track of what directories are or aren't enabled
- for ``.pth`` processing, in any way that EasyInstall can find out.)
+Very often though, a user or developer wants ``easy_install`` to install and manage python packages
+in an alternative location, usually for one of 3 reasons:
-As long as both of these things have been done, your custom installation
-location is good to go.
+1. They don't have access to write to the main Python site-packages directory.
+2. They want a user-specific stash of packages, that is not visible to other users.
-Mac OS X "User" Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3. They want to isolate a set of packages to a specific python application, usually to minimize
+ the possibility of version conflicts.
-If you are on a Mac OS X machine, you should just use the
-``~/Library/Python/2.x/site-packages`` directory as your custom installation
-location, because it is already configured to process ``.pth`` files, and
-EasyInstall already knows this.
-
-Before installing EasyInstall/setuptools, just create a ``~/.pydistutils.cfg``
-file with the following contents (or add this to the existing contents):
-
-.. code-block:: ini
+Historically, there have been many approaches to achieve custom installation.
+The following section lists only the easiest and most relevant approaches [1]_.
- [install]
- install_lib = ~/Library/Python/$py_version_short/site-packages
- install_scripts = ~/bin
+`Use the "--user" option`_
-This will tell the distutils and EasyInstall to always install packages in
-your personal ``site-packages`` directory, and scripts to ``~/bin``. (Note: do
-*not* replace ``$py_version_short`` with an actual Python version in the
-configuration file! The distutils will substitute the correct value at
-runtime, so that the above configuration file should work correctly no matter
-what Python version you use, now or in the future.)
+`Use the "--user" option and customize "PYTHONUSERBASE"`_
-Once you have done this, you can follow the normal `installation instructions`_
-and use ``easy_install`` without any other special options or steps.
+`Use "virtualenv"`_
-(Note, however, that ``~/bin`` is not in the default ``PATH``, so you may have
-to refer to scripts by their full location. You may want to modify your shell
-startup script (likely ``.bashrc`` or ``.profile``) or your
-``~/.MacOSX/environment.plist`` to include ``~/bin`` in your ``PATH``.
+.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by `PEP-370`_ in Python 2.6.
+.. _PEP-370: http://www.python.org/dev/peps/pep-0370/
-Creating a "Virtual" Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating
-system, but don't have root access, you can create your own "virtual"
-Python installation, which uses its own library directories and some symlinks
-to the site-wide Python.
-
-Please refer to the `virtualenv`_ documentation for creating such an
-environment.
+Use the "--user" option
+~~~~~~~~~~~~~~~~~~~~~~~
+With Python 2.6 came the User scheme for installation, which means that all
+python distributions support an alternative install location that is specific to a user [2]_ [3]_.
+The Default location for each OS is explained in the python documentation
+for the ``site.USER_BASE`` variable. This mode of installation can be turned on by
+specifying the ``--user`` option to ``setup.py install`` or ``easy_install``.
+This approach serves the need to have a user-specific stash of packages.
+
+.. [2] Prior to Python2.6, Mac OS X offered a form of the User scheme. That is now subsumed into the User scheme introduced in Python 2.6.
+.. [3] Prior to the User scheme, there was the Home scheme, which is still available, but requires more effort than the User scheme to get packages recognized.
+
+Use the "--user" option and customize "PYTHONUSERBASE"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The User scheme install location can be customized by setting the ``PYTHONUSERBASE`` environment
+variable, which updates the value of ``site.USER_BASE``. To isolate packages to a specific
+application, simply set the OS environment of that application to a specific value of
+``PYTHONUSERBASE``, that contains just those packages.
+
+Use "virtualenv"
+~~~~~~~~~~~~~~~~
+"virtualenv" is a 3rd-party python package that effectively "clones" a python installation, thereby
+creating an isolated location to intall packages. The evolution of "virtualenv" started before the existence
+of the User installation scheme. "virtualenv" provides a version of ``easy_install`` that is
+scoped to the cloned python install and is used in the normal way. "virtualenv" does offer various features
+that the User installation scheme alone does not provide, e.g. the ability to hide the main python site-packages.
+
+Please refer to the `virtualenv`_ documentation for more details.
.. _virtualenv: http://pypi.python.org/pypi/virtualenv
-"Traditional" ``PYTHONPATH``-based Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This installation method is not as robust or as flexible as `creating a
-"virtual" python`_ installation, as it uses various tricks to fool Python into
-processing ``.pth`` files where it normally wouldn't. We suggest you at least
-consider using one of the other approaches, as they will generally result in
-a cleaner, more usable Python configuration. However, if for some reason you
-can't or won't use one of the other approaches, here's how to do it.
-
-Assuming that you want to install packages in a directory called ``~/py-lib``,
-and scripts in ``~/bin``, here's what you need to do:
-
-First, edit ``~/.pydistutils.cfg`` to include these settings, if you don't
-already have them:
-
-.. code-block:: ini
-
- [install]
- install_lib = ~/py-lib
- install_scripts = ~/bin
-
-Be sure to do this *before* you try to run the ``distribute_setup.py``
-installation script. Then, follow the standard `installation instructions`_,
-but make sure that ``~/py-lib`` is listed in your ``PYTHONPATH`` environment
-variable.
-
-Your library installation directory *must* be in listed in ``PYTHONPATH``,
-not only when you install packages with EasyInstall, but also when you use
-any packages that are installed using EasyInstall. You will probably want to
-edit your ``~/.profile`` or other configuration file(s) to ensure that it is
-set, if you haven't already got this set up on your machine.
-
Package Index "API"
-------------------
diff --git a/docs/python3.txt b/docs/python3.txt
index 43845f60..2f6cde4a 100644
--- a/docs/python3.txt
+++ b/docs/python3.txt
@@ -26,18 +26,20 @@ directory, as opposed from the source directory as is normally done.
Distribute will convert all Python files, and also all doctests in Python
files. However, if you have doctests located in separate text files, these
-will not automatically be converted. By adding them to the
-``convert_2to3_doctests`` keyword parameter Distrubute will convert them as
-well.
+will not automatically be converted. By adding them to the
+``convert_2to3_doctests`` keyword parameter Distrubute will convert them as
+well.
By default, the conversion uses all fixers in the ``lib2to3.fixers`` package.
-To use additional fixes, the parameter ``use_2to3_fixers`` can be set
-to a list of names of packages containing fixers.
+To use additional fixers, the parameter ``use_2to3_fixers`` can be set
+to a list of names of packages containing fixers. To exclude fixers, the
+parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be
+skipped.
A typical setup.py can look something like this::
from setuptools import setup
-
+
setup(
name='your.module',
version = '1.0',
@@ -49,7 +51,8 @@ A typical setup.py can look something like this::
test_suite = 'your.module.tests',
use_2to3 = True,
convert_2to3_doctests = ['src/your/module/README.txt'],
- use_2to3_fixers = ['your.fixers']
+ use_2to3_fixers = ['your.fixers'],
+ use_2to3_exclude_fixers = ['lib2to3.fixes.fix_import'],
)
Differential conversion
@@ -58,10 +61,10 @@ Differential conversion
Note that a file will only be copied and converted during the build process
if the source file has been changed. If you add a file to the doctests
that should be converted, it will not be converted the next time you run
-the tests, since it hasn't been modified. You need to remove it from the
+the tests, since it hasn't been modified. You need to remove it from the
build directory. Also if you run the build, install or test commands before
adding the use_2to3 parameter, you will have to remove the build directory
-before you run the test command, as the files otherwise will seem updated,
+before you run the test command, as the files otherwise will seem updated,
and no conversion will happen.
In general, if code doesn't seem to be converted, deleting the build directory
@@ -80,12 +83,6 @@ already converted code, and hence no 2to3 conversion is needed during install.
Advanced features
=================
-If certain fixers are to be suppressed, this again can be overridden with the
-list ``setuptools.command.build_py.build_py.fixer_names``, which at some
-point contains the list of all fixer class names. For an example of how this
-can be done, see the `jaraco.util <https://bitbucket.org/jaraco/jaraco.util>`_
-project.
-
If you don't want to run the 2to3 conversion on the doctests in Python files,
you can turn that off by setting ``setuptools.use_2to3_on_doctests = False``.
@@ -96,18 +93,18 @@ Setuptools do not know about the new keyword parameters to support Python 3.
As a result it will warn about the unknown keyword parameters if you use
setuptools instead of Distribute under Python 2. This is not an error, and
install process will continue as normal, but if you want to get rid of that
-error this is easy. Simply conditionally add the new parameters into an extra
+error this is easy. Simply conditionally add the new parameters into an extra
dict and pass that dict into setup()::
from setuptools import setup
import sys
-
+
extra = {}
if sys.version_info >= (3,):
extra['use_2to3'] = True
extra['convert_2to3_doctests'] = ['src/your/module/README.txt']
extra['use_2to3_fixers'] = ['your.fixers']
-
+
setup(
name='your.module',
version = '1.0',
diff --git a/launcher.c b/launcher.c
index 201219cc..ea4c80b5 100755
--- a/launcher.c
+++ b/launcher.c
@@ -25,9 +25,12 @@
#include <stdlib.h>
#include <stdio.h>
-#include <unistd.h>
+#include <string.h>
+#include <windows.h>
+#include <tchar.h>
#include <fcntl.h>
-#include "windows.h"
+
+int child_pid=0;
int fail(char *format, char *data) {
/* Print error message to stderr and return 2 */
@@ -35,10 +38,6 @@ int fail(char *format, char *data) {
return 2;
}
-
-
-
-
char *quoted(char *data) {
int i, ln = strlen(data), nb;
@@ -90,7 +89,7 @@ char *loadable_exe(char *exename) {
/* Return the absolute filename for spawnv */
result = calloc(MAX_PATH, sizeof(char));
strncpy(result, exename, MAX_PATH);
- /*if (result) GetModuleFileName(hPython, result, MAX_PATH);
+ /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
FreeLibrary(hPython); */
return result;
@@ -160,8 +159,82 @@ char **parse_argv(char *cmdline, int *argc)
} while (1);
}
+void pass_control_to_child(DWORD control_type) {
+ /*
+ * distribute-issue207
+ * passes the control event to child process (Python)
+ */
+ if (!child_pid) {
+ return;
+ }
+ GenerateConsoleCtrlEvent(child_pid,0);
+}
+
+BOOL control_handler(DWORD control_type) {
+ /*
+ * distribute-issue207
+ * control event handler callback function
+ */
+ switch (control_type) {
+ case CTRL_C_EVENT:
+ pass_control_to_child(0);
+ break;
+ }
+ return TRUE;
+}
+
+int create_and_wait_for_subprocess(char* command) {
+ /*
+ * distribute-issue207
+ * launches child process (Python)
+ */
+ DWORD return_value = 0;
+ LPSTR commandline = command;
+ STARTUPINFOA s_info;
+ PROCESS_INFORMATION p_info;
+ ZeroMemory(&p_info, sizeof(p_info));
+ ZeroMemory(&s_info, sizeof(s_info));
+ s_info.cb = sizeof(STARTUPINFO);
+ // set-up control handler callback funciotn
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
+ if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
+ fprintf(stderr, "failed to create process.\n");
+ return 0;
+ }
+ child_pid = p_info.dwProcessId;
+ // wait for Python to exit
+ WaitForSingleObject(p_info.hProcess, INFINITE);
+ if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
+ fprintf(stderr, "failed to get exit code from process.\n");
+ return 0;
+ }
+ return return_value;
+}
+char* join_executable_and_args(char *executable, char **args, int argc)
+{
+ /*
+ * distribute-issue207
+ * CreateProcess needs a long string of the executable and command-line arguments,
+ * so we need to convert it from the args that was built
+ */
+ int len,counter;
+ char* cmdline;
+
+ len=strlen(executable)+2;
+ for (counter=1; counter<argc; counter++) {
+ len+=strlen(args[counter])+1;
+ }
+ cmdline = (char*)calloc(len, sizeof(char));
+ sprintf(cmdline, "%s", executable);
+ len=strlen(executable);
+ for (counter=1; counter<argc; counter++) {
+ sprintf(cmdline+len, " %s", args[counter]);
+ len+=strlen(args[counter])+1;
+ }
+ return cmdline;
+}
int run(int argc, char **argv, int is_gui) {
@@ -173,10 +246,11 @@ int run(int argc, char **argv, int is_gui) {
char **newargs, **newargsp, **parsedargs; /* argument array for exec */
char *ptr, *end; /* working pointers for string manipulation */
+ char *cmdline;
int i, parsedargc; /* loop counter */
/* compute script name from our .exe name*/
- GetModuleFileName(NULL, script, sizeof(script));
+ GetModuleFileNameA(NULL, script, sizeof(script));
end = script + strlen(script);
while( end>script && *end != '.')
*end-- = '\0';
@@ -236,12 +310,18 @@ int run(int argc, char **argv, int is_gui) {
return fail("Could not exec %s", ptr); /* shouldn't get here! */
}
- /* We *do* need to wait for a CLI to finish, so use spawn */
- return spawnv(P_WAIT, ptr, (const char * const *)(newargs));
+ /*
+ * distribute-issue207: using CreateProcessA instead of spawnv
+ */
+ cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
+ return create_and_wait_for_subprocess(cmdline);
}
-
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
return run(__argc, __argv, GUI);
}
+int main(int argc, char** argv) {
+ return run(argc, argv, GUI);
+}
+
diff --git a/pkg_resources.py b/pkg_resources.py
index 52d92669..4cc73bb8 100644
--- a/pkg_resources.py
+++ b/pkg_resources.py
@@ -508,6 +508,10 @@ class WorkingSet(object):
"""
seen = {}
for item in self.entries:
+ if item not in self.entry_keys:
+ # workaround a cache issue
+ continue
+
for key in self.entry_keys[item]:
if key not in seen:
seen[key]=1
@@ -1912,7 +1916,7 @@ replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
def _parse_version_parts(s):
for part in component_re.split(s):
part = replace(part,part)
- if not part or part=='.':
+ if part in ['', '.']:
continue
if part[:1] in '0123456789':
yield part.zfill(8) # pad for numeric comparison
@@ -1955,8 +1959,6 @@ def parse_version(s):
parts = []
for part in _parse_version_parts(s.lower()):
if part.startswith('*'):
- if part<'*final': # remove '-' before a prerelease tag
- while parts and parts[-1]=='*final-': parts.pop()
# remove trailing zeros from each series of numeric parts
while parts and parts[-1]=='00000000':
parts.pop()
diff --git a/release.py b/release.py
new file mode 100644
index 00000000..c6ae00d5
--- /dev/null
+++ b/release.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+"""
+Script to fully automate the release process. Requires Python 2.6+
+with sphinx installed and the 'hg' command on the path.
+"""
+
+from __future__ import print_function
+
+import subprocess
+import shutil
+import os
+import sys
+
+VERSION = '0.6.26'
+
+def get_next_version():
+ digits = map(int, VERSION.split('.'))
+ digits[-1] += 1
+ return '.'.join(map(str, digits))
+
+NEXT_VERSION = get_next_version()
+
+files_with_versions = ('docs/conf.py', 'setup.py', 'release.py',
+ 'README.txt', 'distribute_setup.py')
+
+def bump_versions():
+ list(map(bump_version, files_with_versions))
+
+def bump_version(filename):
+ with open(filename, 'rb') as f:
+ lines = [line.replace(VERSION, NEXT_VERSION) for line in f]
+ with open(filename, 'wb') as f:
+ f.writelines(lines)
+
+def do_release():
+ assert all(map(os.path.exists, files_with_versions)), (
+ "Expected file(s) missing")
+ res = raw_input('Have you read through the SCM changelog and '
+ 'confirmed the changelog is current for releasing {VERSION}? '
+ .format(**globals()))
+ if not res.lower().startswith('y'):
+ print("Please do that")
+ raise SystemExit(1)
+
+ res = raw_input('Have you or has someone verified that the tests '
+ 'pass on this revision? ')
+ if not res.lower().startswith('y'):
+ print("Please do that")
+ raise SystemExit(2)
+
+ subprocess.check_call(['hg', 'tag', VERSION])
+
+ subprocess.check_call(['hg', 'update', VERSION])
+
+ build_docs()
+ if os.path.isdir('./dist'):
+ shutil.rmtree('./dist')
+ subprocess.check_call([sys.executable, 'setup.py',
+ '-q', 'egg_info', '-RD', '-b', '', 'sdist', 'register',
+ 'upload', 'upload_docs'])
+ upload_bootstrap_script()
+
+ # update to the tip for the next operation
+ subprocess.check_call(['hg', 'update'])
+
+ # we just tagged the current version, bump for the next release.
+ bump_versions()
+ subprocess.check_call(['hg', 'ci', '-m',
+ 'Bumped to {NEXT_VERSION} in preparation for next '
+ 'release.'.format(**globals())])
+
+ # push the changes
+ subprocess.check_call(['hg', 'push'])
+
+ # TODO: update bitbucket milestones and versions
+
+def build_docs():
+ if os.path.isdir('docs/build'):
+ shutil.rmtree('docs/build')
+ subprocess.check_call([
+ 'sphinx-build',
+ '-b', 'html',
+ '-d', 'build/doctrees',
+ '.',
+ 'build/html',
+ ],
+ cwd='docs')
+
+def upload_bootstrap_script():
+ scp_command = 'pscp' if sys.platform.startswith('win') else 'scp'
+ try:
+ subprocess.check_call([scp_command, 'distribute_setup.py',
+ 'pypi@ziade.org:python-distribute.org/'])
+ except:
+ print("Unable to upload bootstrap script. Ask Tarek to do it.")
+
+if __name__ == '__main__':
+ do_release()
diff --git a/release.sh b/release.sh
deleted file mode 100755
index 0da18862..00000000
--- a/release.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-export VERSION="0.6.22"
-
-# tagging
-hg tag $VERSION
-hg ci -m "bumped revision"
-
-# creating the releases
-rm -rf ./dist
-
-# now preparing the source release, pushing it and its doc
-python2.6 setup.py -q egg_info -RDb '' sdist register upload
-cd docs/
-make html
-cd ..
-python2.6 setup.py upload_docs
-
-# pushing the bootstrap script
-scp distribute_setup.py ziade.org:websites/python-distribute.org/
-
-# starting the new dev
-hg push
-
diff --git a/setup.py b/setup.py
index 3e9754c7..f576b520 100755
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@ init_path = convert_path('setuptools/command/__init__.py')
exec(open(init_path).read(), d)
SETUP_COMMANDS = d['__all__']
-VERSION = "0.6.22"
+VERSION = "0.6.26"
from setuptools import setup, find_packages
from setuptools.command.build_py import build_py as _build_py
@@ -172,7 +172,8 @@ dist = setup(
"test_loader = setuptools.dist:check_importable",
"use_2to3 = setuptools.dist:assert_bool",
"convert_2to3_doctests = setuptools.dist:assert_string_list",
- "use_2to3_fixers = setuptools.dist:assert_string_list",
+ "use_2to3_fixers = setuptools.dist:assert_string_list",
+ "use_2to3_exclude_fixers = setuptools.dist:assert_string_list",
],
"egg_info.writers": [
diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py
index ab786f3d..5787753f 100755
--- a/setuptools/archive_util.py
+++ b/setuptools/archive_util.py
@@ -180,19 +180,22 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
try:
tarobj.chown = lambda *args: None # don't do any chowning!
for member in tarobj:
- if member.isfile() or member.isdir():
- name = member.name
- # don't extract absolute paths or ones with .. in them
- if not name.startswith('/') and '..' not in name:
- dst = os.path.join(extract_dir, *name.split('/'))
- dst = progress_filter(name, dst)
- if dst:
- if dst.endswith(os.sep):
- dst = dst[:-1]
- try:
- tarobj._extract_member(member,dst) # XXX Ugh
- except tarfile.ExtractError:
- pass # chown/chmod/mkfifo/mknode/makedev failed
+ name = member.name
+ # don't extract absolute paths or ones with .. in them
+ if not name.startswith('/') and '..' not in name:
+ prelim_dst = os.path.join(extract_dir, *name.split('/'))
+ final_dst = progress_filter(name, prelim_dst)
+ # If progress_filter returns None, then we do not extract
+ # this file
+ # TODO: Do we really need to limit to just these file types?
+ # tarobj.extract() will handle all files on all platforms,
+ # turning file types that aren't allowed on that platform into
+ # regular files.
+ if final_dst and (member.isfile() or member.isdir() or
+ member.islnk() or member.issym()):
+ tarobj.extract(member, extract_dir)
+ if final_dst != prelim_dst:
+ shutil.move(prelim_dst, final_dst)
return True
finally:
tarobj.close()
diff --git a/setuptools/cli-32.exe b/setuptools/cli-32.exe
new file mode 100644
index 00000000..9b7717b7
--- /dev/null
+++ b/setuptools/cli-32.exe
Binary files differ
diff --git a/setuptools/cli-64.exe b/setuptools/cli-64.exe
new file mode 100644
index 00000000..265585af
--- /dev/null
+++ b/setuptools/cli-64.exe
Binary files differ
diff --git a/setuptools/cli.exe b/setuptools/cli.exe
index 8906ff77..9b7717b7 100644
--- a/setuptools/cli.exe
+++ b/setuptools/cli.exe
Binary files differ
diff --git a/setuptools/command/__init__.py b/setuptools/command/__init__.py
index 152406b3..b063fa19 100644
--- a/setuptools/command/__init__.py
+++ b/setuptools/command/__init__.py
@@ -14,7 +14,6 @@ if sys.version>='2.5':
from distutils.command.bdist import bdist
-
if 'egg' not in bdist.format_commands:
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
bdist.format_commands.append('egg')
diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py
index a01e2843..d53960fe 100644
--- a/setuptools/command/build_py.py
+++ b/setuptools/command/build_py.py
@@ -28,13 +28,8 @@ try:
if not files:
return
log.info("Fixing "+" ".join(files))
- if not self.fixer_names:
- self.fixer_names = []
- for p in setuptools.lib2to3_fixer_packages:
- self.fixer_names.extend(get_fixers_from_package(p))
- if self.distribution.use_2to3_fixers is not None:
- for p in self.distribution.use_2to3_fixers:
- self.fixer_names.extend(get_fixers_from_package(p))
+ self.__build_fixer_names()
+ self.__exclude_fixers()
if doctests:
if setuptools.run_2to3_on_doctests:
r = DistutilsRefactoringTool(self.fixer_names)
@@ -42,6 +37,25 @@ try:
else:
_Mixin2to3.run_2to3(self, files)
+ def __build_fixer_names(self):
+ if self.fixer_names: return
+ self.fixer_names = []
+ for p in setuptools.lib2to3_fixer_packages:
+ self.fixer_names.extend(get_fixers_from_package(p))
+ if self.distribution.use_2to3_fixers is not None:
+ for p in self.distribution.use_2to3_fixers:
+ self.fixer_names.extend(get_fixers_from_package(p))
+
+ def __exclude_fixers(self):
+ excluded_fixers = getattr(self, 'exclude_fixers', [])
+ if self.distribution.use_2to3_exclude_fixers is not None:
+ excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers)
+ for fixer_name in excluded_fixers:
+ if fixer_name not in self.fixer_names:
+ log.warn("Excluded fixer %s not found", fixer_name)
+ continue
+ self.fixer_names.remove(fixer_name)
+
except ImportError:
class Mixin2to3:
def run_2to3(self, files, doctests=True):
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 3f1b4228..d200dac1 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -42,6 +42,10 @@ __all__ = [
import site
HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE
+import struct
+def is_64bit():
+ return struct.calcsize("P") == 8
+
def samefile(p1,p2):
if hasattr(os.path,'samefile') and (
os.path.exists(p1) and os.path.exists(p2)
@@ -733,22 +737,26 @@ Please make the appropriate changes for your system and try again.
spec = str(dist.as_requirement())
is_script = is_python_script(script_text, script_name)
- if is_script and dev_path:
- script_text = get_script_header(script_text) + (
- "# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n"
- "__requires__ = %(spec)r\n"
- "from pkg_resources import require; require(%(spec)r)\n"
- "del require\n"
- "__file__ = %(dev_path)r\n"
- "execfile(__file__)\n"
- ) % locals()
- elif is_script:
- script_text = get_script_header(script_text) + (
- "# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n"
- "__requires__ = %(spec)r\n"
- "import pkg_resources\n"
- "pkg_resources.run_script(%(spec)r, %(script_name)r)\n"
- ) % locals()
+ def get_template(filename):
+ """
+ There are a couple of template scripts in the package. This
+ function loads one of them and prepares it for use.
+
+ These templates use triple-quotes to escape variable
+ substitutions so the scripts get the 2to3 treatment when build
+ on Python 3. The templates cannot use triple-quotes naturally.
+ """
+ raw_bytes = resource_string('setuptools', template_name)
+ template_str = raw_bytes.decode('utf-8')
+ clean_template = template_str.replace('"""', '')
+ return clean_template
+
+ if is_script:
+ template_name = 'script template.py'
+ if dev_path:
+ template_name = template_name.replace('.py', ' (dev).py')
+ script_text = (get_script_header(script_text) +
+ get_template(template_name) % locals())
self.write_script(script_name, _to_ascii(script_text), 'b')
def write_script(self, script_name, contents, mode="t", blockers=()):
@@ -1801,7 +1809,10 @@ def get_script_args(dist, executable=sys_executable, wininst=False):
ext, launcher = '-script.py', 'cli.exe'
old = ['.py','.pyc','.pyo']
new_header = re.sub('(?i)pythonw.exe','python.exe',header)
-
+ if is_64bit():
+ launcher = launcher.replace(".", "-64.")
+ else:
+ launcher = launcher.replace(".", "-32.")
if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
hdr = new_header
else:
diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py
index dd95552e..f44b34b5 100755
--- a/setuptools/command/install_egg_info.py
+++ b/setuptools/command/install_egg_info.py
@@ -89,6 +89,8 @@ class install_egg_info(Command):
if not self.dry_run:
f = open(filename,'wt')
for pkg in nsp:
+ # ensure pkg is not a unicode string under Python 2.7
+ pkg = str(pkg)
pth = tuple(pkg.split('.'))
trailer = '\n'
if '.' in pkg:
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index 3442fe4b..c49839cd 100755
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -199,15 +199,25 @@ class sdist(_sdist):
build_scripts = self.get_finalized_command('build_scripts')
self.filelist.extend(build_scripts.get_source_files())
- def read_template(self):
+ def __read_template_hack(self):
+ # This grody hack closes the template file (MANIFEST.in) if an
+ # exception occurs during read_template.
+ # Doing so prevents an error when easy_install attempts to delete the
+ # file.
try:
_sdist.read_template(self)
except:
- # grody hack to close the template file (MANIFEST.in)
- # this prevents easy_install's attempt at deleting the file from
- # dying and thus masking the real error
sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
raise
+ # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle
+ # has been fixed, so only override the method if we're using an earlier
+ # Python.
+ if (
+ sys.version_info < (2,7,2)
+ or (3,0) <= sys.version_info < (3,1,4)
+ or (3,2) <= sys.version_info < (3,2,1)
+ ):
+ read_template = __read_template_hack
def check_readme(self):
alts = ("README", "README.txt")
diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py
index 1f49745e..4bd6021d 100755
--- a/setuptools/command/upload.py
+++ b/setuptools/command/upload.py
@@ -181,3 +181,4 @@ class upload(Command):
log.ERROR)
if self.show_response:
print '-'*75, r.read(), '-'*75
+
diff --git a/setuptools/extension.py b/setuptools/extension.py
index 980ee0a7..eb8b836c 100644
--- a/setuptools/extension.py
+++ b/setuptools/extension.py
@@ -1,40 +1,46 @@
-from distutils.core import Extension as _Extension
+import sys
+import distutils.core
+import distutils.extension
+
from setuptools.dist import _get_unpatched
-_Extension = _get_unpatched(_Extension)
-# Prefer Cython to Pyrex
-pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
-for pyrex_impl in pyrex_impls:
- try:
- # from (pyrex_impl) import build_ext
- build_ext = __import__(pyrex_impl, fromlist=['build_ext']).build_ext
- break
- except:
- pass
-have_pyrex = 'build_ext' in globals()
+_Extension = _get_unpatched(distutils.core.Extension)
+
+def have_pyrex():
+ """
+ Return True if Cython or Pyrex can be imported.
+ """
+ pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
+ for pyrex_impl in pyrex_impls:
+ try:
+ # from (pyrex_impl) import build_ext
+ __import__(pyrex_impl, fromlist=['build_ext']).build_ext
+ return True
+ except Exception:
+ pass
+ return False
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
- if not have_pyrex:
- # convert .pyx extensions to .c
- def __init__(self,*args,**kw):
- _Extension.__init__(self,*args,**kw)
- sources = []
- for s in self.sources:
- if s.endswith('.pyx'):
- sources.append(s[:-3]+'c')
- else:
- sources.append(s)
- self.sources = sources
+ def __init__(self, *args, **kw):
+ _Extension.__init__(self, *args, **kw)
+ if not have_pyrex():
+ self._convert_pyx_sources_to_c()
+
+ def _convert_pyx_sources_to_c(self):
+ "convert .pyx extensions to .c"
+ def pyx_to_c(source):
+ if source.endswith('.pyx'):
+ source = source[:-4] + '.c'
+ return source
+ self.sources = map(pyx_to_c, self.sources)
class Library(Extension):
"""Just like a regular Extension, but built as a library instead"""
-import sys, distutils.core, distutils.extension
distutils.core.Extension = Extension
distutils.extension.Extension = Extension
if 'distutils.command.build_ext' in sys.modules:
sys.modules['distutils.command.build_ext'].Extension = Extension
-
diff --git a/setuptools/gui-32.exe b/setuptools/gui-32.exe
new file mode 100644
index 00000000..3f64af7d
--- /dev/null
+++ b/setuptools/gui-32.exe
Binary files differ
diff --git a/setuptools/gui-64.exe b/setuptools/gui-64.exe
new file mode 100644
index 00000000..3ab4378e
--- /dev/null
+++ b/setuptools/gui-64.exe
Binary files differ
diff --git a/setuptools/gui.exe b/setuptools/gui.exe
index 474838d5..3f64af7d 100644
--- a/setuptools/gui.exe
+++ b/setuptools/gui.exe
Binary files differ
diff --git a/setuptools/package_index.py b/setuptools/package_index.py
index bb0ae129..d0896feb 100755
--- a/setuptools/package_index.py
+++ b/setuptools/package_index.py
@@ -1,5 +1,6 @@
"""PyPI and direct package downloading"""
import sys, os.path, re, urlparse, urllib, urllib2, shutil, random, socket, cStringIO
+import base64
import httplib
from pkg_resources import *
from distutils import log
@@ -756,6 +757,22 @@ def socket_timeout(timeout=15):
return _socket_timeout
return _socket_timeout
+def _encode_auth(auth):
+ """
+ A function compatible with Python 2.3-3.3 that will encode
+ auth from a URL suitable for an HTTP header.
+ >>> _encode_auth('username%3Apassword')
+ u'dXNlcm5hbWU6cGFzc3dvcmQ='
+ """
+ auth_s = urllib2.unquote(auth)
+ # convert to bytes
+ auth_bytes = auth_s.encode()
+ # use the legacy interface for Python 2.3 support
+ encoded_bytes = base64.encodestring(auth_bytes)
+ # convert back to a string
+ encoded = encoded_bytes.decode()
+ # strip the trailing carriage return
+ return encoded.rstrip()
def open_with_auth(url):
"""Open a urllib2 request, handling HTTP authentication"""
@@ -768,7 +785,7 @@ def open_with_auth(url):
auth = None
if auth:
- auth = "Basic " + urllib2.unquote(auth).encode('base64').strip()
+ auth = "Basic " + _encode_auth(auth)
new_url = urlparse.urlunparse((scheme,host,path,params,query,frag))
request = urllib2.Request(new_url)
request.add_header("Authorization", auth)
diff --git a/setuptools/script template (dev).py b/setuptools/script template (dev).py
new file mode 100644
index 00000000..6dd9dd45
--- /dev/null
+++ b/setuptools/script template (dev).py
@@ -0,0 +1,6 @@
+# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = """%(spec)r"""
+from pkg_resources import require; require("""%(spec)r""")
+del require
+__file__ = """%(dev_path)r"""
+execfile(__file__)
diff --git a/setuptools/script template.py b/setuptools/script template.py
new file mode 100644
index 00000000..8dd5d510
--- /dev/null
+++ b/setuptools/script template.py
@@ -0,0 +1,4 @@
+# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = """%(spec)r"""
+import pkg_resources
+pkg_resources.run_script("""%(spec)r""", """%(script_name)r""")
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index 85616605..4150ad10 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -67,7 +67,7 @@ class TestEasyInstallTest(unittest.TestCase):
old_platform = sys.platform
try:
- name, script = get_script_args(dist).next()
+ name, script = [i for i in get_script_args(dist).next()][0:2]
finally:
sys.platform = old_platform
@@ -141,9 +141,13 @@ class TestPTHFileWriter(unittest.TestCase):
self.assert_(pth.dirty)
def test_add_from_site_is_ignored(self):
- pth = PthDistributions('does-not_exist', ['/test/location/does-not-have-to-exist'])
+ if os.name != 'nt':
+ location = '/test/location/does-not-have-to-exist'
+ else:
+ location = 'c:\\does_not_exist'
+ pth = PthDistributions('does-not_exist', [location, ])
self.assert_(not pth.dirty)
- pth.add(PRDistribution('/test/location/does-not-have-to-exist'))
+ pth.add(PRDistribution(location))
self.assert_(not pth.dirty)
@@ -221,7 +225,7 @@ class TestUserInstallTest(unittest.TestCase):
sys.path.append(target)
old_ppath = os.environ.get('PYTHONPATH')
- os.environ['PYTHONPATH'] = ':'.join(sys.path)
+ os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
try:
dist = Distribution()
dist.script_name = 'setup.py'
@@ -234,8 +238,13 @@ class TestUserInstallTest(unittest.TestCase):
self.assertEquals(res.location, new_location)
finally:
sys.path.remove(target)
- shutil.rmtree(new_location)
- shutil.rmtree(target)
+ for basedir in [new_location, target, ]:
+ if not os.path.exists(basedir) or not os.path.isdir(basedir):
+ continue
+ try:
+ shutil.rmtree(basedir)
+ except:
+ pass
if old_ppath is not None:
os.environ['PYTHONPATH'] = old_ppath
else:
diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py
index c10ca210..3e0309f1 100644
--- a/setuptools/tests/test_resources.py
+++ b/setuptools/tests/test_resources.py
@@ -8,6 +8,16 @@ try: frozenset
except NameError:
from sets import ImmutableSet as frozenset
+def safe_repr(obj, short=False):
+ """ copied from Python2.7"""
+ try:
+ result = repr(obj)
+ except Exception:
+ result = object.__repr__(obj)
+ if not short or len(result) < _MAX_LENGTH:
+ return result
+ return result[:_MAX_LENGTH] + ' [truncated]...'
+
class Metadata(EmptyProvider):
"""Mock object to return metadata as if from an on-disk distribution"""
@@ -467,14 +477,13 @@ class ParseTests(TestCase):
p1, p2 = parse_version(s1),parse_version(s2)
self.assertEqual(p1,p2, (s1,s2,p1,p2))
- c('1.2-rc1', '1.2rc1')
c('0.4', '0.4.0')
c('0.4.0.0', '0.4.0')
c('0.4.0-0', '0.4-0')
c('0pl1', '0.0pl1')
c('0pre1', '0.0c1')
c('0.0.0preview1', '0c1')
- c('0.0c1', '0-rc1')
+ c('0.0c1', '0rc1')
c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a')
def testVersionOrdering(self):
@@ -483,11 +492,14 @@ class ParseTests(TestCase):
self.assert_(p1<p2, (s1,s2,p1,p2))
c('2.1','2.1.1')
+ c('2.1.0','2.10')
c('2a1','2b0')
+ c('2b1','2c0')
c('2a1','2.1')
c('2.3a1', '2.3')
c('2.1-1', '2.1-2')
c('2.1-1', '2.1.1')
+ c('2.1', '2.1.1-1')
c('2.1', '2.1pl4')
c('2.1a0-20040501', '2.1')
c('1.1', '02.1')
@@ -498,8 +510,20 @@ class ParseTests(TestCase):
c('0.4', '4.0')
c('0.0.4', '0.4.0')
c('0pl1', '0.4pl1')
- c('2.1.0-rc1','2.1.0')
c('2.1dev','2.1a0')
+ c('2.1.0rc1','2.1.0')
+ c('2.1.0','2.1.0-rc0')
+ c('2.1.0','2.1.0-a')
+ c('2.1.0','2.1.0-alpha')
+ c('2.1.0','2.1.0-foo')
+ c('1.0','1.0-1')
+ c('1.0-1','1.0.1')
+ c('1.0a','1.0b')
+ c('1.0dev','1.0rc1')
+ c('1.0pre','1.0')
+ c('1.0pre','1.0')
+ c('1.0a','1.0-a')
+ c('1.0rc1','1.0-rc1')
torture ="""
0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1
@@ -580,6 +604,13 @@ class NamespaceTests(TestCase):
pkg_resources._namespace_packages = self._ns_pkgs.copy()
sys.path = self._prev_sys_path[:]
+ def _assertIn(self, member, container):
+ """ assertIn and assertTrue does not exist in Python2.3"""
+ if member not in container:
+ standardMsg = '%s not found in %s' % (safe_repr(member),
+ safe_repr(container))
+ self.fail(self._formatMessage(msg, standardMsg))
+
def test_two_levels_deep(self):
"""
Test nested namespace packages
@@ -603,13 +634,13 @@ class NamespaceTests(TestCase):
pkg2_init.write(ns_str)
pkg2_init.close()
import pkg1
- self.assertTrue("pkg1" in pkg_resources._namespace_packages.keys())
+ self._assertIn("pkg1", pkg_resources._namespace_packages.keys())
try:
import pkg1.pkg2
except ImportError, e:
self.fail("Distribute tried to import the parent namespace package")
# check the _namespace_packages dict
- self.assertTrue("pkg1.pkg2" in pkg_resources._namespace_packages.keys())
+ self._assertIn("pkg1.pkg2", pkg_resources._namespace_packages.keys())
self.assertEqual(pkg_resources._namespace_packages["pkg1"], ["pkg1.pkg2"])
# check the __path__ attribute contains both paths
self.assertEqual(pkg1.pkg2.__path__, [