diff -Nru python-setuptools-3.3/bootstrap.py python-setuptools-20.1.1/bootstrap.py --- python-setuptools-3.3/bootstrap.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/bootstrap.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,57 @@ +""" +If setuptools is not already installed in the environment, it's not possible +to invoke setuptools' own commands. This routine will bootstrap this local +environment by creating a minimal egg-info directory and then invoking the +egg-info command to flesh out the egg-info directory. +""" + +import os +import sys +import textwrap +import subprocess + + +minimal_egg_info = textwrap.dedent(""" + [distutils.commands] + egg_info = setuptools.command.egg_info:egg_info + + [distutils.setup_keywords] + include_package_data = setuptools.dist:assert_bool + install_requires = setuptools.dist:check_requirements + extras_require = setuptools.dist:check_extras + entry_points = setuptools.dist:check_entry_points + + [egg_info.writers] + dependency_links.txt = setuptools.command.egg_info:overwrite_arg + entry_points.txt = setuptools.command.egg_info:write_entries + requires.txt = setuptools.command.egg_info:write_requirements + """) + +def ensure_egg_info(): + if os.path.exists('setuptools.egg-info'): + return + print("adding minimal entry_points") + build_egg_info() + + +def build_egg_info(): + """ + Build a minimal egg-info, enough to invoke egg_info + """ + + os.mkdir('setuptools.egg-info') + with open('setuptools.egg-info/entry_points.txt', 'w') as ep: + ep.write(minimal_egg_info) + + +def run_egg_info(): + cmd = [sys.executable, 'setup.py', 'egg_info'] + print("Regenerating egg_info") + subprocess.check_call(cmd) + print("...and again.") + subprocess.check_call(cmd) + + +if __name__ == '__main__': + ensure_egg_info() + run_egg_info() diff -Nru python-setuptools-3.3/CHANGES (links).txt python-setuptools-20.1.1/CHANGES (links).txt --- python-setuptools-3.3/CHANGES (links).txt 2014-03-16 09:04:35.000000000 +0000 +++ python-setuptools-20.1.1/CHANGES (links).txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,1640 +0,0 @@ -======= -CHANGES -======= - ---- -3.3 ---- - -* Add ``include`` parameter to ``setuptools.find_packages()``. - ---- -3.2 ---- - -* `Pull Request #39 `_: Add support for C++ targets from Cython ``.pyx`` files. -* `Issue #162 `_: Update dependency on certifi to 1.0.1. -* `Issue #164 `_: Update dependency on wincertstore to 0.2. - ---- -3.1 ---- - -* `Issue #161 `_: Restore Features functionality to allow backward compatibility - (for Features) until the uses of that functionality is sufficiently removed. - ------ -3.0.2 ------ - -* Correct typo in previous bugfix. - ------ -3.0.1 ------ - -* `Issue #157 `_: Restore support for Python 2.6 in bootstrap script where - ``zipfile.ZipFile`` does not yet have support for context managers. - ---- -3.0 ---- - -* `Issue #125 `_: Prevent Subversion support from creating a ~/.subversion - directory just for checking the presence of a Subversion repository. -* `Issue #12 `_: Namespace packages are now imported lazily. That is, the mere - declaration of a namespace package in an egg on ``sys.path`` no longer - causes it to be imported when ``pkg_resources`` is imported. Note that this - change means that all of a namespace package's ``__init__.py`` files must - include a ``declare_namespace()`` call in order to ensure that they will be - handled properly at runtime. In 2.x it was possible to get away without - including the declaration, but only at the cost of forcing namespace - packages to be imported early, which 3.0 no longer does. -* `Issue #148 `_: When building (bdist_egg), setuptools no longer adds - ``__init__.py`` files to namespace packages. Any packages that rely on this - behavior will need to create ``__init__.py`` files and include the - ``declare_namespace()``. -* `Issue #7 `_: Setuptools itself is now distributed as a zip archive in addition to - tar archive. ez_setup.py now uses zip archive. This approach avoids the potential - security vulnerabilities presented by use of tar archives in ez_setup.py. - It also leverages the security features added to ZipFile.extract in Python 2.7.4. -* `Issue #65 `_: Removed deprecated Features functionality. -* `Pull Request #28 `_: Remove backport of ``_bytecode_filenames`` which is - available in Python 2.6 and later, but also has better compatibility with - Python 3 environments. -* `Issue #156 `_: Fix spelling of __PYVENV_LAUNCHER__ variable. - ---- -2.2 ---- - -* `Issue #141 `_: Restored fix for allowing setup_requires dependencies to - override installed dependencies during setup. -* `Issue #128 `_: Fixed issue where only the first dependency link was honored - in a distribution where multiple dependency links were supplied. - ------ -2.1.2 ------ - -* `Issue #144 `_: Read long_description using codecs module to avoid errors - installing on systems where LANG=C. - ------ -2.1.1 ------ - -* `Issue #139 `_: Fix regression in re_finder for CVS repos (and maybe Git repos - as well). - ---- -2.1 ---- - -* `Issue #129 `_: Suppress inspection of ``*.whl`` files when searching for files - in a zip-imported file. -* `Issue #131 `_: Fix RuntimeError when constructing an egg fetcher. - ------ -2.0.2 ------ - -* Fix NameError during installation with Python implementations (e.g. Jython) - not containing parser module. -* Fix NameError in ``sdist:re_finder``. - ------ -2.0.1 ------ - -* `Issue #124 `_: Fixed error in list detection in upload_docs. - ---- -2.0 ---- - -* `Issue #121 `_: Exempt lib2to3 pickled grammars from DirectorySandbox. -* `Issue #41 `_: Dropped support for Python 2.4 and Python 2.5. Clients requiring - setuptools for those versions of Python should use setuptools 1.x. -* Removed ``setuptools.command.easy_install.HAS_USER_SITE``. Clients - expecting this boolean variable should use ``site.ENABLE_USER_SITE`` - instead. -* Removed ``pkg_resources.ImpWrapper``. Clients that expected this class - should use ``pkgutil.ImpImporter`` instead. - ------ -1.4.2 ------ - -* `Issue #116 `_: Correct TypeError when reading a local package index on Python - 3. - ------ -1.4.1 ------ - -* `Issue #114 `_: Use ``sys.getfilesystemencoding`` for decoding config in - ``bdist_wininst`` distributions. - -* `Issue #105 `_ and `Issue #113 `_: Establish a more robust technique for - determining the terminal encoding:: - - 1. Try ``getpreferredencoding`` - 2. If that returns US_ASCII or None, try the encoding from - ``getdefaultlocale``. If that encoding was a "fallback" because Python - could not figure it out from the environment or OS, encoding remains - unresolved. - 3. If the encoding is resolved, then make sure Python actually implements - the encoding. - 4. On the event of an error or unknown codec, revert to fallbacks - (UTF-8 on Darwin, ASCII on everything else). - 5. On the encoding is 'mac-roman' on Darwin, use UTF-8 as 'mac-roman' was - a bug on older Python releases. - - On a side note, it would seem that the encoding only matters for when SVN - does not yet support ``--xml`` and when getting repository and svn version - numbers. The ``--xml`` technique should yield UTF-8 according to some - messages on the SVN mailing lists. So if the version numbers are always - 7-bit ASCII clean, it may be best to only support the file parsing methods - for legacy SVN releases and support for SVN without the subprocess command - would simple go away as support for the older SVNs does. - ---- -1.4 ---- - -* `Issue #27 `_: ``easy_install`` will now use credentials from .pypirc if - present for connecting to the package index. -* `Pull Request #21 `_: Omit unwanted newlines in ``package_index._encode_auth`` - when the username/password pair length indicates wrapping. - ------ -1.3.2 ------ - -* `Issue #99 `_: Fix filename encoding issues in SVN support. - ------ -1.3.1 ------ - -* Remove exuberant warning in SVN support when SVN is not used. - ---- -1.3 ---- - -* Address security vulnerability in SSL match_hostname check as reported in - `Python #17997 `_. -* Prefer `backports.ssl_match_hostname - `_ for backport - implementation if present. -* Correct NameError in ``ssl_support`` module (``socket.error``). - ---- -1.2 ---- - -* `Issue #26 `_: Add support for SVN 1.7. Special thanks to Philip Thiem for the - contribution. -* `Issue #93 `_: Wheels are now distributed with every release. Note that as - reported in `Issue #108 `_, as of Pip 1.4, scripts aren't installed properly - from wheels. Therefore, if using Pip to install setuptools from a wheel, - the ``easy_install`` command will not be available. -* Setuptools "natural" launcher support, introduced in 1.0, is now officially - supported. - ------ -1.1.7 ------ - -* Fixed behavior of NameError handling in 'script template (dev).py' (script - launcher for 'develop' installs). -* ``ez_setup.py`` now ensures partial downloads are cleaned up following - a failed download. -* `Distribute #363 `_ and `Issue #55 `_: Skip an sdist test that fails on locales - other than UTF-8. - ------ -1.1.6 ------ - -* `Distribute #349 `_: ``sandbox.execfile`` now opens the target file in binary - mode, thus honoring a BOM in the file when compiled. - ------ -1.1.5 ------ - -* `Issue #69 `_: Second attempt at fix (logic was reversed). - ------ -1.1.4 ------ - -* `Issue #77 `_: Fix error in upload command (Python 2.4). - ------ -1.1.3 ------ - -* Fix NameError in previous patch. - ------ -1.1.2 ------ - -* `Issue #69 `_: Correct issue where 404 errors are returned for URLs with - fragments in them (such as #egg=). - ------ -1.1.1 ------ - -* `Issue #75 `_: Add ``--insecure`` option to ez_setup.py to accommodate - environments where a trusted SSL connection cannot be validated. -* `Issue #76 `_: Fix AttributeError in upload command with Python 2.4. - ---- -1.1 ---- - -* `Issue #71 `_ (`Distribute #333 `_): EasyInstall now puts less emphasis on the - condition when a host is blocked via ``--allow-hosts``. -* `Issue #72 `_: Restored Python 2.4 compatibility in ``ez_setup.py``. - ---- -1.0 ---- - -* `Issue #60 `_: On Windows, Setuptools supports deferring to another launcher, - such as Vinay Sajip's `pylauncher `_ - (included with Python 3.3) to launch console and GUI scripts and not install - its own launcher executables. This experimental functionality is currently - only enabled if the ``SETUPTOOLS_LAUNCHER`` environment variable is set to - "natural". In the future, this behavior may become default, but only after - it has matured and seen substantial adoption. The ``SETUPTOOLS_LAUNCHER`` - also accepts "executable" to force the default behavior of creating launcher - executables. -* `Issue #63 `_: Bootstrap script (ez_setup.py) now prefers Powershell, curl, or - wget for retrieving the Setuptools tarball for improved security of the - install. The script will still fall back to a simple ``urlopen`` on - platforms that do not have these tools. -* `Issue #65 `_: Deprecated the ``Features`` functionality. -* `Issue #52 `_: In ``VerifyingHTTPSConn``, handle a tunnelled (proxied) - connection. - -Backward-Incompatible Changes -============================= - -This release includes a couple of backward-incompatible changes, but most if -not all users will find 1.0 a drop-in replacement for 0.9. - -* `Issue #50 `_: Normalized API of environment marker support. Specifically, - removed line number and filename from SyntaxErrors when returned from - `pkg_resources.invalid_marker`. Any clients depending on the specific - string representation of exceptions returned by that function may need to - be updated to account for this change. -* `Issue #50 `_: SyntaxErrors generated by `pkg_resources.invalid_marker` are - normalized for cross-implementation consistency. -* Removed ``--ignore-conflicts-at-my-risk`` and ``--delete-conflicting`` - options to easy_install. These options have been deprecated since 0.6a11. - ------ -0.9.8 ------ - -* `Issue #53 `_: Fix NameErrors in `_vcs_split_rev_from_url`. - ------ -0.9.7 ------ - -* `Issue #49 `_: Correct AttributeError on PyPy where a hashlib.HASH object does - not have a `.name` attribute. -* `Issue #34 `_: Documentation now refers to bootstrap script in code repository - referenced by bookmark. -* Add underscore-separated keys to environment markers (markerlib). - ------ -0.9.6 ------ - -* `Issue #44 `_: Test failure on Python 2.4 when MD5 hash doesn't have a `.name` - attribute. - ------ -0.9.5 ------ - -* `Python #17980 `_: Fix security vulnerability in SSL certificate validation. - ------ -0.9.4 ------ - -* `Issue #43 `_: Fix issue (introduced in 0.9.1) with version resolution when - upgrading over other releases of Setuptools. - ------ -0.9.3 ------ - -* `Issue #42 `_: Fix new ``AttributeError`` introduced in last fix. - ------ -0.9.2 ------ - -* `Issue #42 `_: Fix regression where blank checksums would trigger an - ``AttributeError``. - ------ -0.9.1 ------ - -* `Distribute #386 `_: Allow other positional and keyword arguments to os.open. -* Corrected dependency on certifi mis-referenced in 0.9. - ---- -0.9 ---- - -* `package_index` now validates hashes other than MD5 in download links. - ---- -0.8 ---- - -* Code base now runs on Python 2.4 - Python 3.3 without Python 2to3 - conversion. - ------ -0.7.8 ------ - -* `Distribute #375 `_: Yet another fix for yet another regression. - ------ -0.7.7 ------ - -* `Distribute #375 `_: Repair AttributeError created in last release (redo). -* `Issue #30 `_: Added test for get_cache_path. - ------ -0.7.6 ------ - -* `Distribute #375 `_: Repair AttributeError created in last release. - ------ -0.7.5 ------ - -* `Issue #21 `_: Restore Python 2.4 compatibility in ``test_easy_install``. -* `Distribute #375 `_: Merged additional warning from Distribute 0.6.46. -* Now honor the environment variable - ``SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT`` in addition to the now - deprecated ``DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT``. - ------ -0.7.4 ------ - -* `Issue #20 `_: Fix comparison of parsed SVN version on Python 3. - ------ -0.7.3 ------ - -* `Issue #1 `_: Disable installation of Windows-specific files on non-Windows systems. -* Use new sysconfig module with Python 2.7 or >=3.2. - ------ -0.7.2 ------ - -* `Issue #14 `_: Use markerlib when the `parser` module is not available. -* `Issue #10 `_: ``ez_setup.py`` now uses HTTPS to download setuptools from PyPI. - ------ -0.7.1 ------ - -* Fix NameError (`Issue #3 `_) again - broken in bad merge. - ---- -0.7 ---- - -* Merged Setuptools and Distribute. See docs/merge.txt for details. - -Added several features that were slated for setuptools 0.6c12: - -* Index URL now defaults to HTTPS. -* Added experimental environment marker support. Now clients may designate a - PEP-426 environment marker for "extra" dependencies. Setuptools uses this - feature in ``setup.py`` for optional SSL and certificate validation support - on older platforms. Based on Distutils-SIG discussions, the syntax is - somewhat tentative. There should probably be a PEP with a firmer spec before - the feature should be considered suitable for use. -* Added support for SSL certificate validation when installing packages from - an HTTPS service. - ------ -0.7b4 ------ - -* `Issue #3 `_: Fixed NameError in SSL support. - ------- -0.6.49 ------- - -* Move warning check in ``get_cache_path`` to follow the directory creation - to avoid errors when the cache path does not yet exist. Fixes the error - reported in `Distribute #375 `_. - ------- -0.6.48 ------- - -* Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in - 0.6.46 (redo). - ------- -0.6.47 ------- - -* Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in - 0.6.46. - ------- -0.6.46 ------- - -* `Distribute #375 `_: Issue a warning if the PYTHON_EGG_CACHE or otherwise - customized egg cache location specifies a directory that's group- or - world-writable. - ------- -0.6.45 ------- - -* `Distribute #379 `_: ``distribute_setup.py`` now traps VersionConflict as well, - restoring ability to upgrade from an older setuptools version. - ------- -0.6.44 ------- - -* ``distribute_setup.py`` has been updated to allow Setuptools 0.7 to - satisfy use_setuptools. - ------- -0.6.43 ------- - -* `Distribute #378 `_: Restore support for Python 2.4 Syntax (regression in 0.6.42). - ------- -0.6.42 ------- - -* External links finder no longer yields duplicate links. -* `Distribute #337 `_: Moved site.py to setuptools/site-patch.py (graft of very old - patch from setuptools trunk which inspired PR `#31 `_). - ------- -0.6.41 ------- - -* `Distribute #27 `_: Use public api for loading resources from zip files rather than - the private method `_zip_directory_cache`. -* Added a new function ``easy_install.get_win_launcher`` which may be used by - third-party libraries such as buildout to get a suitable script launcher. - ------- -0.6.40 ------- - -* `Distribute #376 `_: brought back cli.exe and gui.exe that were deleted in the - previous release. - ------- -0.6.39 ------- - -* Add support for console launchers on ARM platforms. -* Fix possible issue in GUI launchers where the subsystem was not supplied to - the linker. -* Launcher build script now refactored for robustness. -* `Distribute #375 `_: Resources extracted from a zip egg to the file system now also - check the contents of the file against the zip contents during each - invocation of get_resource_filename. - ------- -0.6.38 ------- - -* `Distribute #371 `_: The launcher manifest file is now installed properly. - ------- -0.6.37 ------- - -* `Distribute #143 `_: Launcher scripts, including easy_install itself, are now - accompanied by a manifest on 32-bit Windows environments to avoid the - Installer Detection Technology and thus undesirable UAC elevation described - in `this Microsoft article - `_. - ------- -0.6.36 ------- - -* `Pull Request #35 `_: In `Buildout #64 `_, it was reported that - under Python 3, installation of distutils scripts could attempt to copy - the ``__pycache__`` directory as a file, causing an error, apparently only - under Windows. Easy_install now skips all directories when processing - metadata scripts. - ------- -0.6.35 ------- - - -Note this release is backward-incompatible with distribute 0.6.23-0.6.34 in -how it parses version numbers. - -* `Distribute #278 `_: Restored compatibility with distribute 0.6.22 and setuptools - 0.6. Updated the documentation to match more closely with the version - parsing as intended in setuptools 0.6. - ------- -0.6.34 ------- - -* `Distribute #341 `_: 0.6.33 fails to build under Python 2.4. - ------- -0.6.33 ------- - -* Fix 2 errors with Jython 2.5. -* Fix 1 failure with Jython 2.5 and 2.7. -* Disable workaround for Jython scripts on Linux systems. -* `Distribute #336 `_: `setup.py` no longer masks failure exit code when tests fail. -* Fix issue in pkg_resources where try/except around a platform-dependent - import would trigger hook load failures on Mercurial. See pull request 32 - for details. -* `Distribute #341 `_: Fix a ResourceWarning. - ------- -0.6.32 ------- - -* Fix test suite with Python 2.6. -* Fix some DeprecationWarnings and ResourceWarnings. -* `Distribute #335 `_: Backed out `setup_requires` superceding installed requirements - until regression can be addressed. - ------- -0.6.31 ------- - -* `Distribute #303 `_: Make sure the manifest only ever contains UTF-8 in Python 3. -* `Distribute #329 `_: Properly close files created by tests for compatibility with - Jython. -* Work around `Jython #1980 `_ and `Jython #1981 `_. -* `Distribute #334 `_: Provide workaround for packages that reference `sys.__stdout__` - such as numpy does. This change should address - `virtualenv `#359 `_ `_ as long - as the system encoding is UTF-8 or the IO encoding is specified in the - environment, i.e.:: - - PYTHONIOENCODING=utf8 pip install numpy - -* Fix for encoding issue when installing from Windows executable on Python 3. -* `Distribute #323 `_: Allow `setup_requires` requirements to supercede installed - requirements. Added some new keyword arguments to existing pkg_resources - methods. Also had to updated how __path__ is handled for namespace packages - to ensure that when a new egg distribution containing a namespace package is - placed on sys.path, the entries in __path__ are found in the same order they - would have been in had that egg been on the path when pkg_resources was - first imported. - ------- -0.6.30 ------- - -* `Distribute #328 `_: Clean up temporary directories in distribute_setup.py. -* Fix fatal bug in distribute_setup.py. - ------- -0.6.29 ------- - -* `Pull Request #14 `_: Honor file permissions in zip files. -* `Distribute #327 `_: Merged pull request `#24 `_ to fix a dependency problem with pip. -* Merged pull request `#23 `_ to fix https://github.com/pypa/virtualenv/issues/301. -* If Sphinx is installed, the `upload_docs` command now runs `build_sphinx` - to produce uploadable documentation. -* `Distribute #326 `_: `upload_docs` provided mangled auth credentials under Python 3. -* `Distribute #320 `_: Fix check for "createable" in distribute_setup.py. -* `Distribute #305 `_: Remove a warning that was triggered during normal operations. -* `Distribute #311 `_: Print metadata in UTF-8 independent of platform. -* `Distribute #303 `_: Read manifest file with UTF-8 encoding under Python 3. -* `Distribute #301 `_: Allow to run tests of namespace packages when using 2to3. -* `Distribute #304 `_: Prevent import loop in site.py under Python 3.3. -* `Distribute #283 `_: Reenable scanning of `*.pyc` / `*.pyo` files on Python 3.3. -* `Distribute #299 `_: The develop command didn't work on Python 3, when using 2to3, - as the egg link would go to the Python 2 source. Linking to the 2to3'd code - in build/lib makes it work, although you will have to rebuild the module - before testing it. -* `Distribute #306 `_: Even if 2to3 is used, we build in-place under Python 2. -* `Distribute #307 `_: Prints the full path when .svn/entries is broken. -* `Distribute #313 `_: Support for sdist subcommands (Python 2.7) -* `Distribute #314 `_: test_local_index() would fail an OS X. -* `Distribute #310 `_: Non-ascii characters in a namespace __init__.py causes errors. -* `Distribute #218 `_: Improved documentation on behavior of `package_data` and - `include_package_data`. Files indicated by `package_data` are now included - in the manifest. -* `distribute_setup.py` now allows a `--download-base` argument for retrieving - distribute from a specified location. - ------- -0.6.28 ------- - -* `Distribute #294 `_: setup.py can now be invoked from any directory. -* Scripts are now installed honoring the umask. -* Added support for .dist-info directories. -* `Distribute #283 `_: Fix and disable scanning of `*.pyc` / `*.pyo` files on - Python 3.3. - ------- -0.6.27 ------- - -* Support current snapshots of CPython 3.3. -* Distribute now recognizes README.rst as a standard, default readme file. -* Exclude 'encodings' modules when removing modules from sys.modules. - Workaround for `#285 `_. -* `Distribute #231 `_: Don't fiddle with system python when used with buildout - (bootstrap.py) - ------- -0.6.26 ------- - -* `Distribute #183 `_: Symlinked files are now extracted from source distributions. -* `Distribute #227 `_: Easy_install fetch parameters are now passed during the - installation of a source distribution; now fulfillment of setup_requires - dependencies will honor the parameters passed to easy_install. - ------- -0.6.25 ------- - -* `Distribute #258 `_: Workaround a cache issue -* `Distribute #260 `_: distribute_setup.py now accepts the --user parameter for - Python 2.6 and later. -* `Distribute #262 `_: package_index.open_with_auth no longer throws LookupError - on Python 3. -* `Distribute #269 `_: AttributeError when an exception occurs reading Manifest.in - on late releases of Python. -* `Distribute #272 `_: Prevent TypeError when namespace package names are unicode - and single-install-externally-managed is used. Also fixes PIP issue - 449. -* `Distribute #273 `_: Legacy script launchers now install with Python2/3 support. - ------- -0.6.24 ------- - -* `Distribute #249 `_: Added options to exclude 2to3 fixers - ------- -0.6.23 ------- - -* `Distribute #244 `_: Fixed a test -* `Distribute #243 `_: Fixed a test -* `Distribute #239 `_: Fixed a test -* `Distribute #240 `_: Fixed a test -* `Distribute #241 `_: Fixed a test -* `Distribute #237 `_: Fixed a test -* `Distribute #238 `_: easy_install now uses 64bit executable wrappers on 64bit Python -* `Distribute #208 `_: Fixed parsed_versions, it now honors post-releases as noted in the documentation -* `Distribute #207 `_: Windows cli and gui wrappers pass CTRL-C to child python process -* `Distribute #227 `_: easy_install now passes its arguments to setup.py bdist_egg -* `Distribute #225 `_: Fixed a NameError on Python 2.5, 2.4 - ------- -0.6.21 ------- - -* `Distribute #225 `_: FIxed a regression on py2.4 - ------- -0.6.20 ------- - -* `Distribute #135 `_: Include url in warning when processing URLs in package_index. -* `Distribute #212 `_: Fix issue where easy_instal fails on Python 3 on windows installer. -* `Distribute #213 `_: Fix typo in documentation. - ------- -0.6.19 ------- - -* `Distribute #206 `_: AttributeError: 'HTTPMessage' object has no attribute 'getheaders' - ------- -0.6.18 ------- - -* `Distribute #210 `_: Fixed a regression introduced by `Distribute #204 `_ fix. - ------- -0.6.17 ------- - -* Support 'DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT' environment - variable to allow to disable installation of easy_install-${version} script. -* Support Python >=3.1.4 and >=3.2.1. -* `Distribute #204 `_: Don't try to import the parent of a namespace package in - declare_namespace -* `Distribute #196 `_: Tolerate responses with multiple Content-Length headers -* `Distribute #205 `_: Sandboxing doesn't preserve working_set. Leads to setup_requires - problems. - ------- -0.6.16 ------- - -* Builds sdist gztar even on Windows (avoiding `Distribute #193 `_). -* `Distribute #192 `_: Fixed metadata omitted on Windows when package_dir - specified with forward-slash. -* `Distribute #195 `_: Cython build support. -* `Distribute #200 `_: Issues with recognizing 64-bit packages on Windows. - ------- -0.6.15 ------- - -* Fixed typo in bdist_egg -* Several issues under Python 3 has been solved. -* `Distribute #146 `_: Fixed missing DLL files after easy_install of windows exe package. - ------- -0.6.14 ------- - -* `Distribute #170 `_: Fixed unittest failure. Thanks to Toshio. -* `Distribute #171 `_: Fixed race condition in unittests cause deadlocks in test suite. -* `Distribute #143 `_: Fixed a lookup issue with easy_install. - Thanks to David and Zooko. -* `Distribute #174 `_: Fixed the edit mode when its used with setuptools itself - ------- -0.6.13 ------- - -* `Distribute #160 `_: 2.7 gives ValueError("Invalid IPv6 URL") -* `Distribute #150 `_: Fixed using ~/.local even in a --no-site-packages virtualenv -* `Distribute #163 `_: scan index links before external links, and don't use the md5 when - comparing two distributions - ------- -0.6.12 ------- - -* `Distribute #149 `_: Fixed various failures on 2.3/2.4 - ------- -0.6.11 ------- - -* Found another case of SandboxViolation - fixed -* `Distribute #15 `_ and `Distribute #48 `_: Introduced a socket timeout of 15 seconds on url openings -* Added indexsidebar.html into MANIFEST.in -* `Distribute #108 `_: Fixed TypeError with Python3.1 -* `Distribute #121 `_: Fixed --help install command trying to actually install. -* `Distribute #112 `_: Added an os.makedirs so that Tarek's solution will work. -* `Distribute #133 `_: Added --no-find-links to easy_install -* Added easy_install --user -* `Distribute #100 `_: Fixed develop --user not taking '.' in PYTHONPATH into account -* `Distribute #134 `_: removed spurious UserWarnings. Patch by VanLindberg -* `Distribute #138 `_: cant_write_to_target error when setup_requires is used. -* `Distribute #147 `_: respect the sys.dont_write_bytecode flag - ------- -0.6.10 ------- - -* Reverted change made for the DistributionNotFound exception because - zc.buildout uses the exception message to get the name of the - distribution. - ------ -0.6.9 ------ - -* `Distribute #90 `_: unknown setuptools version can be added in the working set -* `Distribute #87 `_: setupt.py doesn't try to convert distribute_setup.py anymore - Initial Patch by arfrever. -* `Distribute #89 `_: added a side bar with a download link to the doc. -* `Distribute #86 `_: fixed missing sentence in pkg_resources doc. -* Added a nicer error message when a DistributionNotFound is raised. -* `Distribute #80 `_: test_develop now works with Python 3.1 -* `Distribute #93 `_: upload_docs now works if there is an empty sub-directory. -* `Distribute #70 `_: exec bit on non-exec files -* `Distribute #99 `_: now the standalone easy_install command doesn't uses a - "setup.cfg" if any exists in the working directory. It will use it - only if triggered by ``install_requires`` from a setup.py call - (install, develop, etc). -* `Distribute #101 `_: Allowing ``os.devnull`` in Sandbox -* `Distribute #92 `_: Fixed the "no eggs" found error with MacPort - (platform.mac_ver() fails) -* `Distribute #103 `_: test_get_script_header_jython_workaround not run - anymore under py3 with C or POSIX local. Contributed by Arfrever. -* `Distribute #104 `_: remvoved the assertion when the installation fails, - with a nicer message for the end user. -* `Distribute #100 `_: making sure there's no SandboxViolation when - the setup script patches setuptools. - ------ -0.6.8 ------ - -* Added "check_packages" in dist. (added in Setuptools 0.6c11) -* Fixed the DONT_PATCH_SETUPTOOLS state. - ------ -0.6.7 ------ - -* `Distribute #58 `_: Added --user support to the develop command -* `Distribute #11 `_: Generated scripts now wrap their call to the script entry point - in the standard "if name == 'main'" -* Added the 'DONT_PATCH_SETUPTOOLS' environment variable, so virtualenv - can drive an installation that doesn't patch a global setuptools. -* Reviewed unladen-swallow specific change from - http://code.google.com/p/unladen-swallow/source/detail?spec=svn875&r=719 - and determined that it no longer applies. Distribute should work fine with - Unladen Swallow 2009Q3. -* `Distribute #21 `_: Allow PackageIndex.open_url to gracefully handle all cases of a - httplib.HTTPException instead of just InvalidURL and BadStatusLine. -* Removed virtual-python.py from this distribution and updated documentation - to point to the actively maintained virtualenv instead. -* `Distribute #64 `_: use_setuptools no longer rebuilds the distribute egg every - time it is run -* use_setuptools now properly respects the requested version -* use_setuptools will no longer try to import a distribute egg for the - wrong Python version -* `Distribute #74 `_: no_fake should be True by default. -* `Distribute #72 `_: avoid a bootstrapping issue with easy_install -U - ------ -0.6.6 ------ - -* Unified the bootstrap file so it works on both py2.x and py3k without 2to3 - (patch by Holger Krekel) - ------ -0.6.5 ------ - -* `Distribute #65 `_: cli.exe and gui.exe are now generated at build time, - depending on the platform in use. - -* `Distribute #67 `_: Fixed doc typo (PEP 381/382) - -* Distribute no longer shadows setuptools if we require a 0.7-series - setuptools. And an error is raised when installing a 0.7 setuptools with - distribute. - -* When run from within buildout, no attempt is made to modify an existing - setuptools egg, whether in a shared egg directory or a system setuptools. - -* Fixed a hole in sandboxing allowing builtin file to write outside of - the sandbox. - ------ -0.6.4 ------ - -* Added the generation of `distribute_setup_3k.py` during the release. - This closes `Distribute #52 `_. - -* Added an upload_docs command to easily upload project documentation to - PyPI's https://pythonhosted.org. This close issue `Distribute #56 `_. - -* Fixed a bootstrap bug on the use_setuptools() API. - ------ -0.6.3 ------ - -setuptools -========== - -* Fixed a bunch of calls to file() that caused crashes on Python 3. - -bootstrapping -============= - -* Fixed a bug in sorting that caused bootstrap to fail on Python 3. - ------ -0.6.2 ------ - -setuptools -========== - -* Added Python 3 support; see docs/python3.txt. - This closes `Old Setuptools #39 `_. - -* Added option to run 2to3 automatically when installing on Python 3. - This closes issue `Distribute #31 `_. - -* Fixed invalid usage of requirement.parse, that broke develop -d. - This closes `Old Setuptools #44 `_. - -* Fixed script launcher for 64-bit Windows. - This closes `Old Setuptools #2 `_. - -* KeyError when compiling extensions. - This closes `Old Setuptools #41 `_. - -bootstrapping -============= - -* Fixed bootstrap not working on Windows. This closes issue `Distribute #49 `_. - -* Fixed 2.6 dependencies. This closes issue `Distribute #50 `_. - -* Make sure setuptools is patched when running through easy_install - This closes `Old Setuptools #40 `_. - ------ -0.6.1 ------ - -setuptools -========== - -* package_index.urlopen now catches BadStatusLine and malformed url errors. - This closes `Distribute #16 `_ and `Distribute #18 `_. - -* zip_ok is now False by default. This closes `Old Setuptools #33 `_. - -* Fixed invalid URL error catching. `Old Setuptools #20 `_. - -* Fixed invalid bootstraping with easy_install installation (`Distribute #40 `_). - Thanks to Florian Schulze for the help. - -* Removed buildout/bootstrap.py. A new repository will create a specific - bootstrap.py script. - - -bootstrapping -============= - -* The boostrap process leave setuptools alone if detected in the system - and --root or --prefix is provided, but is not in the same location. - This closes `Distribute #10 `_. - ---- -0.6 ---- - -setuptools -========== - -* Packages required at build time where not fully present at install time. - This closes `Distribute #12 `_. - -* Protected against failures in tarfile extraction. This closes `Distribute #10 `_. - -* Made Jython api_tests.txt doctest compatible. This closes `Distribute #7 `_. - -* sandbox.py replaced builtin type file with builtin function open. This - closes `Distribute #6 `_. - -* Immediately close all file handles. This closes `Distribute #3 `_. - -* Added compatibility with Subversion 1.6. This references `Distribute #1 `_. - -pkg_resources -============= - -* Avoid a call to /usr/bin/sw_vers on OSX and use the official platform API - instead. Based on a patch from ronaldoussoren. This closes issue `#5 `_. - -* Fixed a SandboxViolation for mkdir that could occur in certain cases. - This closes `Distribute #13 `_. - -* Allow to find_on_path on systems with tight permissions to fail gracefully. - This closes `Distribute #9 `_. - -* Corrected inconsistency between documentation and code of add_entry. - This closes `Distribute #8 `_. - -* Immediately close all file handles. This closes `Distribute #3 `_. - -easy_install -============ - -* Immediately close all file handles. This closes `Distribute #3 `_. - ------ -0.6c9 ------ - - * Fixed a missing files problem when using Windows source distributions on - non-Windows platforms, due to distutils not handling manifest file line - endings correctly. - - * Updated Pyrex support to work with Pyrex 0.9.6 and higher. - - * Minor changes for Jython compatibility, including skipping tests that can't - work on Jython. - - * Fixed not installing eggs in ``install_requires`` if they were also used for - ``setup_requires`` or ``tests_require``. - - * Fixed not fetching eggs in ``install_requires`` when running tests. - - * Allow ``ez_setup.use_setuptools()`` to upgrade existing setuptools - installations when called from a standalone ``setup.py``. - - * Added a warning if a namespace package is declared, but its parent package - is not also declared as a namespace. - - * Support Subversion 1.5 - - * Removed use of deprecated ``md5`` module if ``hashlib`` is available - - * Fixed ``bdist_wininst upload`` trying to upload the ``.exe`` twice - - * Fixed ``bdist_egg`` putting a ``native_libs.txt`` in the source package's - ``.egg-info``, when it should only be in the built egg's ``EGG-INFO``. - - * Ensure that _full_name is set on all shared libs before extensions are - checked for shared lib usage. (Fixes a bug in the experimental shared - library build support.) - - * Fix to allow unpacked eggs containing native libraries to fail more - gracefully under Google App Engine (with an ``ImportError`` loading the - C-based module, instead of getting a ``NameError``). - ------ -0.6c7 ------ - - * Fixed ``distutils.filelist.findall()`` crashing on broken symlinks, and - ``egg_info`` command failing on new, uncommitted SVN directories. - - * Fix import problems with nested namespace packages installed via - ``--root`` or ``--single-version-externally-managed``, due to the - parent package not having the child package as an attribute. - ------ -0.6c6 ------ - - * Added ``--egg-path`` option to ``develop`` command, allowing you to force - ``.egg-link`` files to use relative paths (allowing them to be shared across - platforms on a networked drive). - - * Fix not building binary RPMs correctly. - - * Fix "eggsecutables" (such as setuptools' own egg) only being runnable with - bash-compatible shells. - - * Fix ``#!`` parsing problems in Windows ``.exe`` script wrappers, when there - was whitespace inside a quoted argument or at the end of the ``#!`` line - (a regression introduced in 0.6c4). - - * Fix ``test`` command possibly failing if an older version of the project - being tested was installed on ``sys.path`` ahead of the test source - directory. - - * Fix ``find_packages()`` treating ``ez_setup`` and directories with ``.`` in - their names as packages. - ------ -0.6c5 ------ - - * Fix uploaded ``bdist_rpm`` packages being described as ``bdist_egg`` - packages under Python versions less than 2.5. - - * Fix uploaded ``bdist_wininst`` packages being described as suitable for - "any" version by Python 2.5, even if a ``--target-version`` was specified. - ------ -0.6c4 ------ - - * Overhauled Windows script wrapping to support ``bdist_wininst`` better. - Scripts installed with ``bdist_wininst`` will always use ``#!python.exe`` or - ``#!pythonw.exe`` as the executable name (even when built on non-Windows - platforms!), and the wrappers will look for the executable in the script's - parent directory (which should find the right version of Python). - - * Fix ``upload`` command not uploading files built by ``bdist_rpm`` or - ``bdist_wininst`` under Python 2.3 and 2.4. - - * Add support for "eggsecutable" headers: a ``#!/bin/sh`` script that is - prepended to an ``.egg`` file to allow it to be run as a script on Unix-ish - platforms. (This is mainly so that setuptools itself can have a single-file - installer on Unix, without doing multiple downloads, dealing with firewalls, - etc.) - - * Fix problem with empty revision numbers in Subversion 1.4 ``entries`` files - - * Use cross-platform relative paths in ``easy-install.pth`` when doing - ``develop`` and the source directory is a subdirectory of the installation - target directory. - - * Fix a problem installing eggs with a system packaging tool if the project - contained an implicit namespace package; for example if the ``setup()`` - listed a namespace package ``foo.bar`` without explicitly listing ``foo`` - as a namespace package. - ------ -0.6c3 ------ - - * Fixed breakages caused by Subversion 1.4's new "working copy" format - ------ -0.6c2 ------ - - * The ``ez_setup`` module displays the conflicting version of setuptools (and - its installation location) when a script requests a version that's not - available. - - * Running ``setup.py develop`` on a setuptools-using project will now install - setuptools if needed, instead of only downloading the egg. - ------ -0.6c1 ------ - - * Fixed ``AttributeError`` when trying to download a ``setup_requires`` - dependency when a distribution lacks a ``dependency_links`` setting. - - * Made ``zip-safe`` and ``not-zip-safe`` flag files contain a single byte, so - as to play better with packaging tools that complain about zero-length - files. - - * Made ``setup.py develop`` respect the ``--no-deps`` option, which it - previously was ignoring. - - * Support ``extra_path`` option to ``setup()`` when ``install`` is run in - backward-compatibility mode. - - * Source distributions now always include a ``setup.cfg`` file that explicitly - sets ``egg_info`` options such that they produce an identical version number - to the source distribution's version number. (Previously, the default - version number could be different due to the use of ``--tag-date``, or if - the version was overridden on the command line that built the source - distribution.) - ------ -0.6b4 ------ - - * Fix ``register`` not obeying name/version set by ``egg_info`` command, if - ``egg_info`` wasn't explicitly run first on the same command line. - - * Added ``--no-date`` and ``--no-svn-revision`` options to ``egg_info`` - command, to allow suppressing tags configured in ``setup.cfg``. - - * Fixed redundant warnings about missing ``README`` file(s); it should now - appear only if you are actually a source distribution. - ------ -0.6b3 ------ - - * Fix ``bdist_egg`` not including files in subdirectories of ``.egg-info``. - - * Allow ``.py`` files found by the ``include_package_data`` option to be - automatically included. Remove duplicate data file matches if both - ``include_package_data`` and ``package_data`` are used to refer to the same - files. - ------ -0.6b1 ------ - - * Strip ``module`` from the end of compiled extension modules when computing - the name of a ``.py`` loader/wrapper. (Python's import machinery ignores - this suffix when searching for an extension module.) - ------- -0.6a11 ------- - - * Added ``test_loader`` keyword to support custom test loaders - - * Added ``setuptools.file_finders`` entry point group to allow implementing - revision control plugins. - - * Added ``--identity`` option to ``upload`` command. - - * Added ``dependency_links`` to allow specifying URLs for ``--find-links``. - - * Enhanced test loader to scan packages as well as modules, and call - ``additional_tests()`` if present to get non-unittest tests. - - * Support namespace packages in conjunction with system packagers, by omitting - the installation of any ``__init__.py`` files for namespace packages, and - adding a special ``.pth`` file to create a working package in - ``sys.modules``. - - * Made ``--single-version-externally-managed`` automatic when ``--root`` is - used, so that most system packagers won't require special support for - setuptools. - - * Fixed ``setup_requires``, ``tests_require``, etc. not using ``setup.cfg`` or - other configuration files for their option defaults when installing, and - also made the install use ``--multi-version`` mode so that the project - directory doesn't need to support .pth files. - - * ``MANIFEST.in`` is now forcibly closed when any errors occur while reading - it. Previously, the file could be left open and the actual error would be - masked by problems trying to remove the open file on Windows systems. - ------- -0.6a10 ------- - - * Fixed the ``develop`` command ignoring ``--find-links``. - ------ -0.6a9 ------ - - * The ``sdist`` command no longer uses the traditional ``MANIFEST`` file to - create source distributions. ``MANIFEST.in`` is still read and processed, - as are the standard defaults and pruning. But the manifest is built inside - the project's ``.egg-info`` directory as ``SOURCES.txt``, and it is rebuilt - every time the ``egg_info`` command is run. - - * Added the ``include_package_data`` keyword to ``setup()``, allowing you to - automatically include any package data listed in revision control or - ``MANIFEST.in`` - - * Added the ``exclude_package_data`` keyword to ``setup()``, allowing you to - trim back files included via the ``package_data`` and - ``include_package_data`` options. - - * Fixed ``--tag-svn-revision`` not working when run from a source - distribution. - - * Added warning for namespace packages with missing ``declare_namespace()`` - - * Added ``tests_require`` keyword to ``setup()``, so that e.g. packages - requiring ``nose`` to run unit tests can make this dependency optional - unless the ``test`` command is run. - - * Made all commands that use ``easy_install`` respect its configuration - options, as this was causing some problems with ``setup.py install``. - - * Added an ``unpack_directory()`` driver to ``setuptools.archive_util``, so - that you can process a directory tree through a processing filter as if it - were a zipfile or tarfile. - - * Added an internal ``install_egg_info`` command to use as part of old-style - ``install`` operations, that installs an ``.egg-info`` directory with the - package. - - * Added a ``--single-version-externally-managed`` option to the ``install`` - command so that you can more easily wrap a "flat" egg in a system package. - - * Enhanced ``bdist_rpm`` so that it installs single-version eggs that - don't rely on a ``.pth`` file. The ``--no-egg`` option has been removed, - since all RPMs are now built in a more backwards-compatible format. - - * Support full roundtrip translation of eggs to and from ``bdist_wininst`` - format. Running ``bdist_wininst`` on a setuptools-based package wraps the - egg in an .exe that will safely install it as an egg (i.e., with metadata - and entry-point wrapper scripts), and ``easy_install`` can turn the .exe - back into an ``.egg`` file or directory and install it as such. - - ------ -0.6a8 ------ - - * Fixed some problems building extensions when Pyrex was installed, especially - with Python 2.4 and/or packages using SWIG. - - * Made ``develop`` command accept all the same options as ``easy_install``, - and use the ``easy_install`` command's configuration settings as defaults. - - * Made ``egg_info --tag-svn-revision`` fall back to extracting the revision - number from ``PKG-INFO`` in case it is being run on a source distribution of - a snapshot taken from a Subversion-based project. - - * Automatically detect ``.dll``, ``.so`` and ``.dylib`` files that are being - installed as data, adding them to ``native_libs.txt`` automatically. - - * Fixed some problems with fresh checkouts of projects that don't include - ``.egg-info/PKG-INFO`` under revision control and put the project's source - code directly in the project directory. If such a package had any - requirements that get processed before the ``egg_info`` command can be run, - the setup scripts would fail with a "Missing 'Version:' header and/or - PKG-INFO file" error, because the egg runtime interpreted the unbuilt - metadata in a directory on ``sys.path`` (i.e. the current directory) as - being a corrupted egg. Setuptools now monkeypatches the distribution - metadata cache to pretend that the egg has valid version information, until - it has a chance to make it actually be so (via the ``egg_info`` command). - ------ -0.6a5 ------ - - * Fixed missing gui/cli .exe files in distribution. Fixed bugs in tests. - ------ -0.6a3 ------ - - * Added ``gui_scripts`` entry point group to allow installing GUI scripts - on Windows and other platforms. (The special handling is only for Windows; - other platforms are treated the same as for ``console_scripts``.) - ------ -0.6a2 ------ - - * Added ``console_scripts`` entry point group to allow installing scripts - without the need to create separate script files. On Windows, console - scripts get an ``.exe`` wrapper so you can just type their name. On other - platforms, the scripts are written without a file extension. - ------ -0.6a1 ------ - - * Added support for building "old-style" RPMs that don't install an egg for - the target package, using a ``--no-egg`` option. - - * The ``build_ext`` command now works better when using the ``--inplace`` - option and multiple Python versions. It now makes sure that all extensions - match the current Python version, even if newer copies were built for a - different Python version. - - * The ``upload`` command no longer attaches an extra ``.zip`` when uploading - eggs, as PyPI now supports egg uploads without trickery. - - * The ``ez_setup`` script/module now displays a warning before downloading - the setuptools egg, and attempts to check the downloaded egg against an - internal MD5 checksum table. - - * Fixed the ``--tag-svn-revision`` option of ``egg_info`` not finding the - latest revision number; it was using the revision number of the directory - containing ``setup.py``, not the highest revision number in the project. - - * Added ``eager_resources`` setup argument - - * The ``sdist`` command now recognizes Subversion "deleted file" entries and - does not include them in source distributions. - - * ``setuptools`` now embeds itself more thoroughly into the distutils, so that - other distutils extensions (e.g. py2exe, py2app) will subclass setuptools' - versions of things, rather than the native distutils ones. - - * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``; - ``setup_requires`` allows you to automatically find and download packages - that are needed in order to *build* your project (as opposed to running it). - - * ``setuptools`` now finds its commands, ``setup()`` argument validators, and - metadata writers using entry points, so that they can be extended by - third-party packages. See `Creating distutils Extensions - `_ - for more details. - - * The vestigial ``depends`` command has been removed. It was never finished - or documented, and never would have worked without EasyInstall - which it - pre-dated and was never compatible with. - ------- -0.5a12 ------- - - * The zip-safety scanner now checks for modules that might be used with - ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't - handle ``-m`` on zipped modules. - ------- -0.5a11 ------- - - * Fix breakage of the "develop" command that was caused by the addition of - ``--always-unzip`` to the ``easy_install`` command. - ------ -0.5a9 ------ - - * Include ``svn:externals`` directories in source distributions as well as - normal subversion-controlled files and directories. - - * Added ``exclude=patternlist`` option to ``setuptools.find_packages()`` - - * Changed --tag-svn-revision to include an "r" in front of the revision number - for better readability. - - * Added ability to build eggs without including source files (except for any - scripts, of course), using the ``--exclude-source-files`` option to - ``bdist_egg``. - - * ``setup.py install`` now automatically detects when an "unmanaged" package - or module is going to be on ``sys.path`` ahead of a package being installed, - thereby preventing the newer version from being imported. If this occurs, - a warning message is output to ``sys.stderr``, but installation proceeds - anyway. The warning message informs the user what files or directories - need deleting, and advises them they can also use EasyInstall (with the - ``--delete-conflicting`` option) to do it automatically. - - * The ``egg_info`` command now adds a ``top_level.txt`` file to the metadata - directory that lists all top-level modules and packages in the distribution. - This is used by the ``easy_install`` command to find possibly-conflicting - "unmanaged" packages when installing the distribution. - - * Added ``zip_safe`` and ``namespace_packages`` arguments to ``setup()``. - Added package analysis to determine zip-safety if the ``zip_safe`` flag - is not given, and advise the author regarding what code might need changing. - - * Fixed the swapped ``-d`` and ``-b`` options of ``bdist_egg``. - ------ -0.5a8 ------ - - * The "egg_info" command now always sets the distribution metadata to "safe" - forms of the distribution name and version, so that distribution files will - be generated with parseable names (i.e., ones that don't include '-' in the - name or version). Also, this means that if you use the various ``--tag`` - options of "egg_info", any distributions generated will use the tags in the - version, not just egg distributions. - - * Added support for defining command aliases in distutils configuration files, - under the "[aliases]" section. To prevent recursion and to allow aliases to - call the command of the same name, a given alias can be expanded only once - per command-line invocation. You can define new aliases with the "alias" - command, either for the local, global, or per-user configuration. - - * Added "rotate" command to delete old distribution files, given a set of - patterns to match and the number of files to keep. (Keeps the most - recently-modified distribution files matching each pattern.) - - * Added "saveopts" command that saves all command-line options for the current - invocation to the local, global, or per-user configuration file. Useful for - setting defaults without having to hand-edit a configuration file. - - * Added a "setopt" command that sets a single option in a specified distutils - configuration file. - ------ -0.5a7 ------ - - * Added "upload" support for egg and source distributions, including a bug - fix for "upload" and a temporary workaround for lack of .egg support in - PyPI. - ------ -0.5a6 ------ - - * Beefed up the "sdist" command so that if you don't have a MANIFEST.in, it - will include all files under revision control (CVS or Subversion) in the - current directory, and it will regenerate the list every time you create a - source distribution, not just when you tell it to. This should make the - default "do what you mean" more often than the distutils' default behavior - did, while still retaining the old behavior in the presence of MANIFEST.in. - - * Fixed the "develop" command always updating .pth files, even if you - specified ``-n`` or ``--dry-run``. - - * Slightly changed the format of the generated version when you use - ``--tag-build`` on the "egg_info" command, so that you can make tagged - revisions compare *lower* than the version specified in setup.py (e.g. by - using ``--tag-build=dev``). - ------ -0.5a5 ------ - - * Added ``develop`` command to ``setuptools``-based packages. This command - installs an ``.egg-link`` pointing to the package's source directory, and - script wrappers that ``execfile()`` the source versions of the package's - scripts. This lets you put your development checkout(s) on sys.path without - having to actually install them. (To uninstall the link, use - use ``setup.py develop --uninstall``.) - - * Added ``egg_info`` command to ``setuptools``-based packages. This command - just creates or updates the "projectname.egg-info" directory, without - building an egg. (It's used by the ``bdist_egg``, ``test``, and ``develop`` - commands.) - - * Enhanced the ``test`` command so that it doesn't install the package, but - instead builds any C extensions in-place, updates the ``.egg-info`` - metadata, adds the source directory to ``sys.path``, and runs the tests - directly on the source. This avoids an "unmanaged" installation of the - package to ``site-packages`` or elsewhere. - - * Made ``easy_install`` a standard ``setuptools`` command, moving it from - the ``easy_install`` module to ``setuptools.command.easy_install``. Note - that if you were importing or extending it, you must now change your imports - accordingly. ``easy_install.py`` is still installed as a script, but not as - a module. - ------ -0.5a4 ------ - - * Setup scripts using setuptools can now list their dependencies directly in - the setup.py file, without having to manually create a ``depends.txt`` file. - The ``install_requires`` and ``extras_require`` arguments to ``setup()`` - are used to create a dependencies file automatically. If you are manually - creating ``depends.txt`` right now, please switch to using these setup - arguments as soon as practical, because ``depends.txt`` support will be - removed in the 0.6 release cycle. For documentation on the new arguments, - see the ``setuptools.dist.Distribution`` class. - - * Setup scripts using setuptools now always install using ``easy_install`` - internally, for ease of uninstallation and upgrading. - ------ -0.5a1 ------ - - * Added support for "self-installation" bootstrapping. Packages can now - include ``ez_setup.py`` in their source distribution, and add the following - to their ``setup.py``, in order to automatically bootstrap installation of - setuptools as part of their setup process:: - - from ez_setup import use_setuptools - use_setuptools() - - from setuptools import setup - # etc... - ------ -0.4a2 ------ - - * Added ``ez_setup.py`` installer/bootstrap script to make initial setuptools - installation easier, and to allow distributions using setuptools to avoid - having to include setuptools in their source distribution. - - * All downloads are now managed by the ``PackageIndex`` class (which is now - subclassable and replaceable), so that embedders can more easily override - download logic, give download progress reports, etc. The class has also - been moved to the new ``setuptools.package_index`` module. - - * The ``Installer`` class no longer handles downloading, manages a temporary - directory, or tracks the ``zip_ok`` option. Downloading is now handled - by ``PackageIndex``, and ``Installer`` has become an ``easy_install`` - command class based on ``setuptools.Command``. - - * There is a new ``setuptools.sandbox.run_setup()`` API to invoke a setup - script in a directory sandbox, and a new ``setuptools.archive_util`` module - with an ``unpack_archive()`` API. These were split out of EasyInstall to - allow reuse by other tools and applications. - - * ``setuptools.Command`` now supports reinitializing commands using keyword - arguments to set/reset options. Also, ``Command`` subclasses can now set - their ``command_consumes_arguments`` attribute to ``True`` in order to - receive an ``args`` option containing the rest of the command line. - ------ -0.3a2 ------ - - * Added new options to ``bdist_egg`` to allow tagging the egg's version number - with a subversion revision number, the current date, or an explicit tag - value. Run ``setup.py bdist_egg --help`` to get more information. - - * Misc. bug fixes - ------ -0.3a1 ------ - - * Initial release. diff -Nru python-setuptools-3.3/CHANGES.txt python-setuptools-20.1.1/CHANGES.txt --- python-setuptools-3.3/CHANGES.txt 2014-03-16 08:02:09.000000000 +0000 +++ python-setuptools-20.1.1/CHANGES.txt 2016-02-12 16:10:11.000000000 +0000 @@ -2,13 +2,891 @@ CHANGES ======= +20.1.1 +------ + +* Update ``upload_docs`` command to also honor keyring + for password resolution. + +20.1 +---- + +* Added support for using passwords from keyring in the upload +command. See `the upload docs +`_ +for details. + +20.0 +---- + +* Issue #118: Once again omit the package metadata (egg-info) + from the list of outputs in ``--record``. This version of setuptools + can no longer be used to upgrade pip earlier than 6.0. + +19.7 +---- + +* `Off-project PR `_: + For FreeBSD, also honor root certificates from ca_root_nss. + +19.6.2 +------ + +* Issue #491: Correct regression incurred in 19.4 where + a double-namespace package installed using pip would + cause a TypeError. + +19.6.1 +------ + +* Restore compatibility for PyPy 3 compatibility lost in + 19.4.1 addressing Issue #487. +* ``setuptools.launch`` shim now loads scripts in a new + namespace, avoiding getting relative imports from + the setuptools package on Python 2. + +19.6 +---- + +* Added a new entry script ``setuptools.launch``, + implementing the shim found in + ``pip.util.setuptools_build``. Use this command to launch + distutils-only packages under setuptools in the same way that + pip does, causing the setuptools monkeypatching of distutils + to be invoked prior to invoking a script. Useful for debugging + or otherwise installing a distutils-only package under + setuptools when pip isn't available or otherwise does not + expose the desired functionality. For example:: + + $ python -m setuptools.launch setup.py develop + +* Issue #488: Fix dual manifestation of Extension class in + extension packages installed as dependencies when Cython + is present. + +19.5 +---- + +* Issue #486: Correct TypeError when getfilesystemencoding + returns None. +* Issue #139: Clarified the license as MIT. +* Pull Request #169: Removed special handling of command + spec in scripts for Jython. + +19.4.1 +------ + +* Issue #487: Use direct invocation of ``importlib.machinery`` + in ``pkg_resources`` to avoid missing detection on relevant + platforms. + +19.4 +---- + +* Issue #341: Correct error in path handling of package data + files in ``build_py`` command when package is empty. +* Distribute #323, Issue #141, Issue #207, and + Pull Request #167: Another implementation of + ``pkg_resources.WorkingSet`` and ``pkg_resources.Distribution`` + that supports replacing an extant package with a new one, + allowing for setup_requires dependencies to supersede installed + packages for the session. + +19.3 +---- + +* Issue #229: Implement new technique for readily incorporating + dependencies conditionally from vendored copies or primary + locations. Adds a new dependency on six. + +19.2 +---- + +* Pull Request #163: Add get_command_list method to Distribution. +* Pull Request #162: Add missing whitespace to multiline string + literals. + +19.1.1 +------ + +* Issue #476: Cast version to string (using default encoding) + to avoid creating Unicode types on Python 2 clients. +* Issue #477: In Powershell downloader, use explicit rendering + of strings, rather than rely on ``repr``, which can be + incorrect (especially on Python 2). + +19.1 +---- + +* Issue #215: The bootstrap script ``ez_setup.py`` now + automatically detects + the latest version of setuptools (using PyPI JSON API) rather + than hard-coding a particular value. +* Issue #475: Fix incorrect usage in _translate_metadata2. + +19.0 +---- + +* Issue #442: Use RawConfigParser for parsing .pypirc file. + Interpolated values are no longer honored in .pypirc files. + +18.8.1 +------ + +* Issue #440: Prevent infinite recursion when a SandboxViolation + or other UnpickleableException occurs in a sandbox context + with setuptools hidden. Fixes regression introduced in Setuptools + 12.0. + +18.8 +---- + +* Deprecated ``egg_info.get_pkg_info_revision``. +* Issue #471: Don't rely on repr for an HTML attribute value in + package_index. +* Issue #419: Avoid errors in FileMetadata when the metadata directory + is broken. +* Issue #472: Remove deprecated use of 'U' in mode parameter + when opening files. + +18.7.1 +------ + +* Issue #469: Refactored logic for Issue #419 fix to re-use metadata + loading from Provider. + +18.7 +---- + +* Update dependency on certify. +* Pull Request #160: Improve detection of gui script in + ``easy_install._adjust_header``. +* Made ``test.test_args`` a non-data property; alternate fix + for the issue reported in Pull Request #155. +* Issue #453: In ``ez_setup`` bootstrap module, unload all + ``pkg_resources`` modules following download. +* Pull Request #158: Honor `PEP-488 + `_ when excluding + files for namespace packages. +* Issue #419 and Pull Request #144: Add experimental support for + reading the version info from distutils-installed metadata rather + than using the version in the filename. + +18.6.1 +------ + +* Issue #464: Correct regression in invocation of superclass on old-style + class on Python 2. + +18.6 +---- + +* Issue #439: When installing entry_point scripts under development, + omit the version number of the package, allowing any version of the + package to be used. + +18.5 +---- + +* In preparation for dropping support for Python 3.2, a warning is + now logged when pkg_resources is imported on Python 3.2 or earlier + Python 3 versions. +* `Add support for python_platform_implementation environment marker + `_. +* `Fix dictionary mutation during iteration + `_. + +18.4 +---- + +* Issue #446: Test command now always invokes unittest, even + if no test suite is supplied. + +18.3.2 +------ + +* Correct another regression in setuptools.findall + where the fix for Python #12885 was lost. + +18.3.1 +------ + +* Issue #425: Correct regression in setuptools.findall. + +18.3 +---- + +* Setuptools now allows disabling of the manipulation of the sys.path + during the processing of the easy-install.pth file. To do so, set + the environment variable ``SETUPTOOLS_SYS_PATH_TECHNIQUE`` to + anything but "rewrite" (consider "raw"). During any install operation + with manipulation disabled, setuptools packages will be appended to + sys.path naturally. + + Future versions may change the default behavior to disable + manipulation. If so, the default behavior can be retained by setting + the variable to "rewrite". + +* Issue #257: ``easy_install --version`` now shows more detail + about the installation location and Python version. + +* Refactor setuptools.findall in preparation for re-submission + back to distutils. + +18.2 +---- + +* Issue #412: More efficient directory search in ``find_packages``. + +18.1 +---- + +* Upgrade to vendored packaging 15.3. + +18.0.1 +------ + +* Issue #401: Fix failure in test suite. + +18.0 +---- + +* Dropped support for builds with Pyrex. Only Cython is supported. +* Issue #288: Detect Cython later in the build process, after + ``setup_requires`` dependencies are resolved. + Projects backed by Cython can now be readily built + with a ``setup_requires`` dependency. For example:: + + ext = setuptools.Extension('mylib', ['src/CythonStuff.pyx', 'src/CStuff.c']) + setuptools.setup( + ... + ext_modules=[ext], + setup_requires=['cython'], + ) + + For compatibility with older versions of setuptools, packagers should + still include ``src/CythonMod.c`` in the source distributions or + require that Cython be present before building source distributions. + However, for systems with this build of setuptools, Cython will be + downloaded on demand. +* Issue #396: Fixed test failure on OS X. +* Pull Request #136: Remove excessive quoting from shebang headers + for Jython. + +17.1.1 +------ + +* Backed out unintended changes to pkg_resources, restoring removal of + deprecated imp module (`ref + `_). + +17.1 +---- + +* Issue #380: Add support for range operators on environment + marker evaluation. + +17.0 +---- + +* Issue #378: Do not use internal importlib._bootstrap module. +* Issue #390: Disallow console scripts with path separators in + the name. Removes unintended functionality and brings behavior + into parity with pip. + +16.0 +---- + +* Pull Request #130: Better error messages for errors in + parsed requirements. +* Pull Request #133: Removed ``setuptools.tests`` from the + installed packages. +* Pull Request #129: Address deprecation warning due to usage + of imp module. + +15.2 +---- + +* Issue #373: Provisionally expose + ``pkg_resources._initialize_master_working_set``, allowing for + imperative re-initialization of the master working set. + +15.1 +---- + +* Updated to Packaging 15.1 to address Packaging #28. +* Fix ``setuptools.sandbox._execfile()`` with Python 3.1. + +15.0 +---- + +* Pull Request #126: DistributionNotFound message now lists the package or + packages that required it. E.g.:: + + pkg_resources.DistributionNotFound: The 'colorama>=0.3.1' distribution was not found and is required by smlib.log. + + Note that zc.buildout once dependended on the string rendering of this + message to determine the package that was not found. This expectation + has since been changed, but older versions of buildout may experience + problems. See Buildout #242 for details. + +14.3.1 +------ + +* Issue #307: Removed PEP-440 warning during parsing of versions + in ``pkg_resources.Distribution``. +* Issue #364: Replace deprecated usage with recommended usage of + ``EntryPoint.load``. + +14.3 +---- + +* Issue #254: When creating temporary egg cache on Unix, use mode 755 + for creating the directory to avoid the subsequent warning if + the directory is group writable. + +14.2 +---- + +* Issue #137: Update ``Distribution.hashcmp`` so that Distributions with + None for pyversion or platform can be compared against Distributions + defining those attributes. + +14.1.1 +------ + +* Issue #360: Removed undesirable behavior from test runs, preventing + write tests and installation to system site packages. + +14.1 +---- + +* Pull Request #125: Add ``__ne__`` to Requirement class. +* Various refactoring of easy_install. + +14.0 +---- + +* Bootstrap script now accepts ``--to-dir`` to customize save directory or + allow for re-use of existing repository of setuptools versions. See + Pull Request #112 for background. +* Issue #285: ``easy_install`` no longer will default to installing + packages to the "user site packages" directory if it is itself installed + there. Instead, the user must pass ``--user`` in all cases to install + packages to the user site packages. + This behavior now matches that of "pip install". To configure + an environment to always install to the user site packages, consider + using the "install-dir" and "scripts-dir" parameters to easy_install + through an appropriate distutils config file. + +13.0.2 +------ + +* Issue #359: Include pytest.ini in the sdist so invocation of py.test on the + sdist honors the pytest configuration. + +13.0.1 +------ + +Re-release of 13.0. Intermittent connectivity issues caused the release +process to fail and PyPI uploads no longer accept files for 13.0. + +13.0 +---- + +* Issue #356: Back out Pull Request #119 as it requires Setuptools 10 or later + as the source during an upgrade. +* Removed build_py class from setup.py. According to 892f439d216e, this + functionality was added to support upgrades from old Distribute versions, + 0.6.5 and 0.6.6. + +12.4 +---- + +* Pull Request #119: Restore writing of ``setup_requires`` to metadata + (previously added in 8.4 and removed in 9.0). + +12.3 +---- + +* Documentation is now linked using the rst.linker package. +* Fix ``setuptools.command.easy_install.extract_wininst_cfg()`` + with Python 2.6 and 2.7. +* Issue #354. Added documentation on building setuptools + documentation. + +12.2 +---- + +* Issue #345: Unload all modules under pkg_resources during + ``ez_setup.use_setuptools()``. +* Issue #336: Removed deprecation from ``ez_setup.use_setuptools``, + as it is clearly still used by buildout's bootstrap. ``ez_setup`` + remains deprecated for use by individual packages. +* Simplified implementation of ``ez_setup.use_setuptools``. + +12.1 +---- + +* Pull Request #118: Soften warning for non-normalized versions in + Distribution. + +12.0.5 +------ + +* Issue #339: Correct Attribute reference in ``cant_write_to_target``. +* Issue #336: Deprecated ``ez_setup.use_setuptools``. + +12.0.4 +------ + +* Issue #335: Fix script header generation on Windows. + +12.0.3 +------ + +* Fixed incorrect class attribute in ``install_scripts``. Tests would be nice. + +12.0.2 +------ + +* Issue #331: Fixed ``install_scripts`` command on Windows systems corrupting + the header. + +12.0.1 +------ + +* Restore ``setuptools.command.easy_install.sys_executable`` for pbr + compatibility. For the future, tools should construct a CommandSpec + explicitly. + +12.0 +---- + +* Issue #188: Setuptools now support multiple entities in the value for + ``build.executable``, such that an executable of "/usr/bin/env my-python" may + be specified. This means that systems with a specified executable whose name + has spaces in the path must be updated to escape or quote that value. +* Deprecated ``easy_install.ScriptWriter.get_writer``, replaced by ``.best()`` + with slightly different semantics (no force_windows flag). + +11.3.1 +------ + +* Issue #327: Formalize and restore support for any printable character in an + entry point name. + +11.3 +---- + +* Expose ``EntryPoint.resolve`` in place of EntryPoint._load, implementing the + simple, non-requiring load. Deprecated all uses of ``EntryPoint._load`` + except for calling with no parameters, which is just a shortcut for + ``ep.require(); ep.resolve();``. + + Apps currently invoking ``ep.load(require=False)`` should instead do the + following if wanting to avoid the deprecating warning:: + + getattr(ep, "resolve", lambda: ep.load(require=False))() + +11.2 +---- + +* Pip #2326: Report deprecation warning at stacklevel 2 for easier diagnosis. + +11.1 +---- + +* Issue #281: Since Setuptools 6.1 (Issue #268), a ValueError would be raised + in certain cases where VersionConflict was raised with two arguments, which + occurred in ``pkg_resources.WorkingSet.find``. This release adds support + for indicating the dependent packages while maintaining support for + a VersionConflict when no dependent package context is known. New unit tests + now capture the expected interface. + +11.0 +---- + +* Interop #3: Upgrade to Packaging 15.0; updates to PEP 440 so that >1.7 does + not exclude 1.7.1 but does exclude 1.7.0 and 1.7.0.post1. + +10.2.1 +------ + +* Issue #323: Fix regression in entry point name parsing. + +10.2 +---- + +* Deprecated use of EntryPoint.load(require=False). Passing a boolean to a + function to select behavior is an anti-pattern. Instead use + ``Entrypoint._load()``. +* Substantial refactoring of all unit tests. Tests are now much leaner and + re-use a lot of fixtures and contexts for better clarity of purpose. + +10.1 +---- + +* Issue #320: Added a compatibility implementation of + ``sdist._default_revctrl`` + so that systems relying on that interface do not fail (namely, Ubuntu 12.04 + and similar Debian releases). + +10.0.1 +------ + +* Issue #319: Fixed issue installing pure distutils packages. + +10.0 +---- + +* Issue #313: Removed built-in support for subversion. Projects wishing to + retain support for subversion will need to use a third party library. The + extant implementation is being ported to `setuptools_svn + `_. +* Issue #315: Updated setuptools to hide its own loaded modules during + installation of another package. This change will enable setuptools to + upgrade (or downgrade) itself even when its own metadata and implementation + change. + +9.1 +--- + +* Prefer vendored packaging library `as recommended + `_. + +9.0.1 +----- + +* Issue #312: Restored presence of pkg_resources API tests (doctest) to sdist. + +9.0 +--- + +* Issue #314: Disabled support for ``setup_requires`` metadata to avoid issue + where Setuptools was unable to upgrade over earlier versions. + +8.4 +--- + +* Pull Request #106: Now write ``setup_requires`` metadata. + +8.3 +--- + +* Issue #311: Decoupled pkg_resources from setuptools once again. + ``pkg_resources`` is now a package instead of a module. + +8.2.1 +----- + +* Issue #306: Suppress warnings about Version format except in select scenarios + (such as installation). + +8.2 +--- + +* Pull Request #85: Search egg-base when adding egg-info to manifest. + +8.1 +--- + +* Upgrade ``packaging`` to 14.5, giving preference to "rc" as designator for + release candidates over "c". +* PEP-440 warnings are now raised as their own class, + ``pkg_resources.PEP440Warning``, instead of RuntimeWarning. +* Disabled warnings on empty versions. + +8.0.4 +----- + +* Upgrade ``packaging`` to 14.4, fixing an error where there is a + different result for if 2.0.5 is contained within >2.0dev and >2.0.dev even + though normalization rules should have made them equal. +* Issue #296: Add warning when a version is parsed as legacy. This warning will + make it easier for developers to recognize deprecated version numbers. + +8.0.3 +----- + +* Issue #296: Restored support for ``__hash__`` on parse_version results. + +8.0.2 +----- + +* Issue #296: Restored support for ``__getitem__`` and sort operations on + parse_version result. + +8.0.1 +----- + +* Issue #296: Restore support for iteration over parse_version result, but + deprecated that usage with a warning. Fixes failure with buildout. + +8.0 +--- + +* Implement `PEP 440 `_ within + pkg_resources and setuptools. This change + deprecates some version numbers such that they will no longer be installable + without using the ``===`` escape hatch. See `the changes to test_resources + `_ + for specific examples of version numbers and specifiers that are no longer + supported. Setuptools now "vendors" the `packaging + `_ library. + +7.0 +--- + +* Issue #80, Issue #209: Eggs that are downloaded for ``setup_requires``, + ``test_requires``, etc. are now placed in a ``./.eggs`` directory instead of + directly in the current directory. This choice of location means the files + can be readily managed (removed, ignored). Additionally, + later phases or invocations of setuptools will not detect the package as + already installed and ignore it for permanent install (See #209). + + This change is indicated as backward-incompatible as installations that + depend on the installation in the current directory will need to account for + the new location. Systems that ignore ``*.egg`` will probably need to be + adapted to ignore ``.eggs``. The files will need to be manually moved or + will be retrieved again. Most use cases will require no attention. + +6.1 +--- + +* Issue #268: When resolving package versions, a VersionConflict now reports + which package previously required the conflicting version. + +6.0.2 +----- + +* Issue #262: Fixed regression in pip install due to egg-info directories + being omitted. Re-opens Issue #118. + +6.0.1 +----- + +* Issue #259: Fixed regression with namespace package handling on ``single + version, externally managed`` installs. + +6.0 +--- + +* Issue #100: When building a distribution, Setuptools will no longer match + default files using platform-dependent case sensitivity, but rather will + only match the files if their case matches exactly. As a result, on Windows + and other case-insensitive file systems, files with names such as + 'readme.txt' or 'README.TXT' will be omitted from the distribution and a + warning will be issued indicating that 'README.txt' was not found. Other + filenames affected are: + + - README.rst + - README + - setup.cfg + - setup.py (or the script name) + - test/test*.py + + Any users producing distributions with filenames that match those above + case-insensitively, but not case-sensitively, should rename those files in + their repository for better portability. +* Pull Request #72: When using ``single_version_externally_managed``, the + exclusion list now includes Python 3.2 ``__pycache__`` entries. +* Pull Request #76 and Pull Request #78: lines in top_level.txt are now + ordered deterministically. +* Issue #118: The egg-info directory is now no longer included in the list + of outputs. +* Issue #258: Setuptools now patches distutils msvc9compiler to + recognize the specially-packaged compiler package for easy extension module + support on Python 2.6, 2.7, and 3.2. + +5.8 +--- + +* Issue #237: ``pkg_resources`` now uses explicit detection of Python 2 vs. + Python 3, supporting environments where builtins have been patched to make + Python 3 look more like Python 2. + +5.7 +--- + +* Issue #240: Based on real-world performance measures against 5.4, zip + manifests are now cached in all circumstances. The + ``PKG_RESOURCES_CACHE_ZIP_MANIFESTS`` environment variable is no longer + relevant. The observed "memory increase" referenced in the 5.4 release + notes and detailed in Issue #154 was likely not an increase over the status + quo, but rather only an increase over not storing the zip info at all. + +5.6 +--- + +* Issue #242: Use absolute imports in svn_utils to avoid issues if the + installing package adds an xml module to the path. + +5.5.1 +----- + +* Issue #239: Fix typo in 5.5 such that fix did not take. + +5.5 +--- + +* Issue #239: Setuptools now includes the setup_requires directive on + Distribution objects and validates the syntax just like install_requires + and tests_require directives. + +5.4.2 +----- + +* Issue #236: Corrected regression in execfile implementation for Python 2.6. + +5.4.1 +----- + +* Python #7776: (ssl_support) Correct usage of host for validation when + tunneling for HTTPS. + +5.4 +--- + +* Issue #154: ``pkg_resources`` will now cache the zip manifests rather than + re-processing the same file from disk multiple times, but only if the + environment variable ``PKG_RESOURCES_CACHE_ZIP_MANIFESTS`` is set. Clients + that package many modules in the same zip file will see some improvement + in startup time by enabling this feature. This feature is not enabled by + default because it causes a substantial increase in memory usage. + +5.3 +--- + +* Issue #185: Make svn tagging work on the new style SVN metadata. + Thanks cazabon! +* Prune revision control directories (e.g .svn) from base path + as well as sub-directories. + +5.2 +--- + +* Added a `Developer Guide + `_ to the official + documentation. +* Some code refactoring and cleanup was done with no intended behavioral + changes. +* During install_egg_info, the generated lines for namespace package .pth + files are now processed even during a dry run. + +5.1 +--- + +* Issue #202: Implemented more robust cache invalidation for the ZipImporter, + building on the work in Issue #168. Special thanks to Jurko Gospodnetic and + PJE. + +5.0.2 +----- + +* Issue #220: Restored script templates. + +5.0.1 +----- + +* Renamed script templates to end with .tmpl now that they no longer need + to be processed by 2to3. Fixes spurious syntax errors during build/install. + +5.0 +--- + +* Issue #218: Re-release of 3.8.1 to signal that it supersedes 4.x. +* Incidentally, script templates were updated not to include the triple-quote + escaping. + +3.7.1 and 3.8.1 and 4.0.1 +------------------------- + +* Issue #213: Use legacy StringIO behavior for compatibility under pbr. +* Issue #218: Setuptools 3.8.1 superseded 4.0.1, and 4.x was removed + from the available versions to install. + +4.0 +--- + +* Issue #210: ``setup.py develop`` now copies scripts in binary mode rather + than text mode, matching the behavior of the ``install`` command. + +3.8 +--- + +* Extend Issue #197 workaround to include all Python 3 versions prior to + 3.2.2. + +3.7 +--- + +* Issue #193: Improved handling of Unicode filenames when building manifests. + +3.6 +--- + +* Issue #203: Honor proxy settings for Powershell downloader in the bootstrap + routine. + +3.5.2 +----- + +* Issue #168: More robust handling of replaced zip files and stale caches. + Fixes ZipImportError complaining about a 'bad local header'. + +3.5.1 +----- + +* Issue #199: Restored ``install._install`` for compatibility with earlier + NumPy versions. + +3.5 +--- + +* Issue #195: Follow symbolic links in find_packages (restoring behavior + broken in 3.4). +* Issue #197: On Python 3.1, PKG-INFO is now saved in a UTF-8 encoding instead + of ``sys.getpreferredencoding`` to match the behavior on Python 2.6-3.4. +* Issue #192: Preferred bootstrap location is now + https://bootstrap.pypa.io/ez_setup.py (mirrored from former location). + +3.4.4 +----- + +* Issue #184: Correct failure where find_package over-matched packages + when directory traversal isn't short-circuited. + +3.4.3 +----- + +* Issue #183: Really fix test command with Python 3.1. + +3.4.2 +----- + +* Issue #183: Fix additional regression in test command on Python 3.1. + +3.4.1 +----- + +* Issue #180: Fix regression in test command not caught by py.test-run tests. + +3.4 --- + +* Issue #176: Add parameter to the test command to support a custom test + runner: --test-runner or -r. +* Issue #177: Now assume most common invocation to install command on + platforms/environments without stack support (issuing a warning). Setuptools + now installs naturally on IronPython. Behavior on CPython should be + unchanged. + 3.3 --- * Add ``include`` parameter to ``setuptools.find_packages()``. ---- 3.2 --- @@ -16,27 +894,23 @@ * Issue #162: Update dependency on certifi to 1.0.1. * Issue #164: Update dependency on wincertstore to 0.2. ---- 3.1 --- * Issue #161: Restore Features functionality to allow backward compatibility (for Features) until the uses of that functionality is sufficiently removed. ------ 3.0.2 ----- * Correct typo in previous bugfix. ------ 3.0.1 ----- * Issue #157: Restore support for Python 2.6 in bootstrap script where ``zipfile.ZipFile`` does not yet have support for context managers. ---- 3.0 --- @@ -64,7 +938,6 @@ Python 3 environments. * Issue #156: Fix spelling of __PYVENV_LAUNCHER__ variable. ---- 2.2 --- @@ -73,21 +946,18 @@ * Issue #128: Fixed issue where only the first dependency link was honored in a distribution where multiple dependency links were supplied. ------ 2.1.2 ----- * Issue #144: Read long_description using codecs module to avoid errors installing on systems where LANG=C. ------ 2.1.1 ----- * Issue #139: Fix regression in re_finder for CVS repos (and maybe Git repos as well). ---- 2.1 --- @@ -95,7 +965,6 @@ in a zip-imported file. * Issue #131: Fix RuntimeError when constructing an egg fetcher. ------ 2.0.2 ----- @@ -103,13 +972,11 @@ not containing parser module. * Fix NameError in ``sdist:re_finder``. ------ 2.0.1 ----- * Issue #124: Fixed error in list detection in upload_docs. ---- 2.0 --- @@ -122,14 +989,12 @@ * Removed ``pkg_resources.ImpWrapper``. Clients that expected this class should use ``pkgutil.ImpImporter`` instead. ------ 1.4.2 ----- * Issue #116: Correct TypeError when reading a local package index on Python 3. ------ 1.4.1 ----- @@ -159,7 +1024,6 @@ for legacy SVN releases and support for SVN without the subprocess command would simple go away as support for the older SVNs does. ---- 1.4 --- @@ -168,19 +1032,16 @@ * Pull Request #21: Omit unwanted newlines in ``package_index._encode_auth`` when the username/password pair length indicates wrapping. ------ 1.3.2 ----- * Issue #99: Fix filename encoding issues in SVN support. ------ 1.3.1 ----- * Remove exuberant warning in SVN support when SVN is not used. ---- 1.3 --- @@ -191,7 +1052,6 @@ implementation if present. * Correct NameError in ``ssl_support`` module (``socket.error``). ---- 1.2 --- @@ -204,7 +1064,6 @@ * Setuptools "natural" launcher support, introduced in 1.0, is now officially supported. ------ 1.1.7 ----- @@ -215,39 +1074,33 @@ * Distribute #363 and Issue #55: Skip an sdist test that fails on locales other than UTF-8. ------ 1.1.6 ----- * Distribute #349: ``sandbox.execfile`` now opens the target file in binary mode, thus honoring a BOM in the file when compiled. ------ 1.1.5 ----- * Issue #69: Second attempt at fix (logic was reversed). ------ 1.1.4 ----- * Issue #77: Fix error in upload command (Python 2.4). ------ 1.1.3 ----- * Fix NameError in previous patch. ------ 1.1.2 ----- * Issue #69: Correct issue where 404 errors are returned for URLs with fragments in them (such as #egg=). ------ 1.1.1 ----- @@ -255,7 +1108,6 @@ environments where a trusted SSL connection cannot be validated. * Issue #76: Fix AttributeError in upload command with Python 2.4. ---- 1.1 --- @@ -263,7 +1115,6 @@ condition when a host is blocked via ``--allow-hosts``. * Issue #72: Restored Python 2.4 compatibility in ``ez_setup.py``. ---- 1.0 --- @@ -300,13 +1151,11 @@ * Removed ``--ignore-conflicts-at-my-risk`` and ``--delete-conflicting`` options to easy_install. These options have been deprecated since 0.6a11. ------ 0.9.8 ----- * Issue #53: Fix NameErrors in `_vcs_split_rev_from_url`. ------ 0.9.7 ----- @@ -316,79 +1165,67 @@ referenced by bookmark. * Add underscore-separated keys to environment markers (markerlib). ------ 0.9.6 ----- * Issue #44: Test failure on Python 2.4 when MD5 hash doesn't have a `.name` attribute. ------ 0.9.5 ----- * Python #17980: Fix security vulnerability in SSL certificate validation. ------ 0.9.4 ----- * Issue #43: Fix issue (introduced in 0.9.1) with version resolution when upgrading over other releases of Setuptools. ------ 0.9.3 ----- * Issue #42: Fix new ``AttributeError`` introduced in last fix. ------ 0.9.2 ----- * Issue #42: Fix regression where blank checksums would trigger an ``AttributeError``. ------ 0.9.1 ----- * Distribute #386: Allow other positional and keyword arguments to os.open. * Corrected dependency on certifi mis-referenced in 0.9. ---- 0.9 --- * `package_index` now validates hashes other than MD5 in download links. ---- 0.8 --- * Code base now runs on Python 2.4 - Python 3.3 without Python 2to3 conversion. ------ 0.7.8 ----- * Distribute #375: Yet another fix for yet another regression. ------ 0.7.7 ----- * Distribute #375: Repair AttributeError created in last release (redo). * Issue #30: Added test for get_cache_path. ------ 0.7.6 ----- * Distribute #375: Repair AttributeError created in last release. ------ 0.7.5 ----- @@ -398,33 +1235,28 @@ ``SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT`` in addition to the now deprecated ``DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT``. ------ 0.7.4 ----- * Issue #20: Fix comparison of parsed SVN version on Python 3. ------ 0.7.3 ----- * Issue #1: Disable installation of Windows-specific files on non-Windows systems. * Use new sysconfig module with Python 2.7 or >=3.2. ------ 0.7.2 ----- * Issue #14: Use markerlib when the `parser` module is not available. * Issue #10: ``ez_setup.py`` now uses HTTPS to download setuptools from PyPI. ------ 0.7.1 ----- * Fix NameError (Issue #3) again - broken in bad merge. ---- 0.7 --- @@ -442,13 +1274,11 @@ * Added support for SSL certificate validation when installing packages from an HTTPS service. ------ 0.7b4 ----- * Issue #3: Fixed NameError in SSL support. ------- 0.6.49 ------ @@ -456,21 +1286,18 @@ to avoid errors when the cache path does not yet exist. Fixes the error reported in Distribute #375. ------- 0.6.48 ------ * Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in 0.6.46 (redo). ------- 0.6.47 ------ * Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in 0.6.46. ------- 0.6.46 ------ @@ -478,27 +1305,23 @@ customized egg cache location specifies a directory that's group- or world-writable. ------- 0.6.45 ------ * Distribute #379: ``distribute_setup.py`` now traps VersionConflict as well, restoring ability to upgrade from an older setuptools version. ------- 0.6.44 ------ * ``distribute_setup.py`` has been updated to allow Setuptools 0.7 to satisfy use_setuptools. ------- 0.6.43 ------ * Distribute #378: Restore support for Python 2.4 Syntax (regression in 0.6.42). ------- 0.6.42 ------ @@ -506,7 +1329,6 @@ * Distribute #337: Moved site.py to setuptools/site-patch.py (graft of very old patch from setuptools trunk which inspired PR #31). ------- 0.6.41 ------ @@ -515,14 +1337,12 @@ * Added a new function ``easy_install.get_win_launcher`` which may be used by third-party libraries such as buildout to get a suitable script launcher. ------- 0.6.40 ------ * Distribute #376: brought back cli.exe and gui.exe that were deleted in the previous release. ------- 0.6.39 ------ @@ -534,13 +1354,11 @@ check the contents of the file against the zip contents during each invocation of get_resource_filename. ------- 0.6.38 ------ * Distribute #371: The launcher manifest file is now installed properly. ------- 0.6.37 ------ @@ -550,7 +1368,6 @@ in `this Microsoft article `_. ------- 0.6.36 ------ @@ -560,7 +1377,6 @@ under Windows. Easy_install now skips all directories when processing metadata scripts. ------- 0.6.35 ------ @@ -572,13 +1388,11 @@ 0.6. Updated the documentation to match more closely with the version parsing as intended in setuptools 0.6. ------- 0.6.34 ------ * Distribute #341: 0.6.33 fails to build under Python 2.4. ------- 0.6.33 ------ @@ -591,7 +1405,6 @@ for details. * Distribute #341: Fix a ResourceWarning. ------- 0.6.32 ------ @@ -600,7 +1413,6 @@ * Distribute #335: Backed out `setup_requires` superceding installed requirements until regression can be addressed. ------- 0.6.31 ------ @@ -625,14 +1437,12 @@ would have been in had that egg been on the path when pkg_resources was first imported. ------- 0.6.30 ------ * Distribute #328: Clean up temporary directories in distribute_setup.py. * Fix fatal bug in distribute_setup.py. ------- 0.6.29 ------ @@ -664,7 +1474,6 @@ * `distribute_setup.py` now allows a `--download-base` argument for retrieving distribute from a specified location. ------- 0.6.28 ------ @@ -674,7 +1483,6 @@ * Distribute #283: Fix and disable scanning of `*.pyc` / `*.pyo` files on Python 3.3. ------- 0.6.27 ------ @@ -685,7 +1493,6 @@ * Distribute #231: Don't fiddle with system python when used with buildout (bootstrap.py) ------- 0.6.26 ------ @@ -694,7 +1501,6 @@ installation of a source distribution; now fulfillment of setup_requires dependencies will honor the parameters passed to easy_install. ------- 0.6.25 ------ @@ -710,13 +1516,11 @@ 449. * Distribute #273: Legacy script launchers now install with Python2/3 support. ------- 0.6.24 ------ * Distribute #249: Added options to exclude 2to3 fixers ------- 0.6.23 ------ @@ -732,13 +1536,11 @@ * Distribute #227: easy_install now passes its arguments to setup.py bdist_egg * Distribute #225: Fixed a NameError on Python 2.5, 2.4 ------- 0.6.21 ------ * Distribute #225: FIxed a regression on py2.4 ------- 0.6.20 ------ @@ -746,19 +1548,16 @@ * Distribute #212: Fix issue where easy_instal fails on Python 3 on windows installer. * Distribute #213: Fix typo in documentation. ------- 0.6.19 ------ * Distribute #206: AttributeError: 'HTTPMessage' object has no attribute 'getheaders' ------- 0.6.18 ------ * Distribute #210: Fixed a regression introduced by Distribute #204 fix. ------- 0.6.17 ------ @@ -771,7 +1570,6 @@ * Distribute #205: Sandboxing doesn't preserve working_set. Leads to setup_requires problems. ------- 0.6.16 ------ @@ -781,7 +1579,6 @@ * Distribute #195: Cython build support. * Distribute #200: Issues with recognizing 64-bit packages on Windows. ------- 0.6.15 ------ @@ -789,7 +1586,6 @@ * Several issues under Python 3 has been solved. * Distribute #146: Fixed missing DLL files after easy_install of windows exe package. ------- 0.6.14 ------ @@ -799,7 +1595,6 @@ Thanks to David and Zooko. * Distribute #174: Fixed the edit mode when its used with setuptools itself ------- 0.6.13 ------ @@ -808,13 +1603,11 @@ * Distribute #163: scan index links before external links, and don't use the md5 when comparing two distributions ------- 0.6.12 ------ * Distribute #149: Fixed various failures on 2.3/2.4 ------- 0.6.11 ------ @@ -831,7 +1624,6 @@ * Distribute #138: cant_write_to_target error when setup_requires is used. * Distribute #147: respect the sys.dont_write_bytecode flag ------- 0.6.10 ------ @@ -839,7 +1631,6 @@ zc.buildout uses the exception message to get the name of the distribution. ------ 0.6.9 ----- @@ -866,14 +1657,12 @@ * Distribute #100: making sure there's no SandboxViolation when the setup script patches setuptools. ------ 0.6.8 ----- * Added "check_packages" in dist. (added in Setuptools 0.6c11) * Fixed the DONT_PATCH_SETUPTOOLS state. ------ 0.6.7 ----- @@ -898,14 +1687,12 @@ * Distribute #74: no_fake should be True by default. * Distribute #72: avoid a bootstrapping issue with easy_install -U ------ 0.6.6 ----- * Unified the bootstrap file so it works on both py2.x and py3k without 2to3 (patch by Holger Krekel) ------ 0.6.5 ----- @@ -924,7 +1711,6 @@ * Fixed a hole in sandboxing allowing builtin file to write outside of the sandbox. ------ 0.6.4 ----- @@ -936,7 +1722,6 @@ * Fixed a bootstrap bug on the use_setuptools() API. ------ 0.6.3 ----- @@ -950,7 +1735,6 @@ * Fixed a bug in sorting that caused bootstrap to fail on Python 3. ------ 0.6.2 ----- @@ -982,7 +1766,6 @@ * Make sure setuptools is patched when running through easy_install This closes Old Setuptools #40. ------ 0.6.1 ----- @@ -1010,7 +1793,6 @@ and --root or --prefix is provided, but is not in the same location. This closes Distribute #10. ---- 0.6 --- @@ -1053,7 +1835,6 @@ * Immediately close all file handles. This closes Distribute #3. ------ 0.6c9 ----- @@ -1094,7 +1875,6 @@ gracefully under Google App Engine (with an ``ImportError`` loading the C-based module, instead of getting a ``NameError``). ------ 0.6c7 ----- @@ -1105,7 +1885,6 @@ ``--root`` or ``--single-version-externally-managed``, due to the parent package not having the child package as an attribute. ------ 0.6c6 ----- @@ -1129,7 +1908,6 @@ * Fix ``find_packages()`` treating ``ez_setup`` and directories with ``.`` in their names as packages. ------ 0.6c5 ----- @@ -1139,7 +1917,6 @@ * Fix uploaded ``bdist_wininst`` packages being described as suitable for "any" version by Python 2.5, even if a ``--target-version`` was specified. ------ 0.6c4 ----- @@ -1169,13 +1946,11 @@ listed a namespace package ``foo.bar`` without explicitly listing ``foo`` as a namespace package. ------ 0.6c3 ----- * Fixed breakages caused by Subversion 1.4's new "working copy" format ------ 0.6c2 ----- @@ -1186,7 +1961,6 @@ * Running ``setup.py develop`` on a setuptools-using project will now install setuptools if needed, instead of only downloading the egg. ------ 0.6c1 ----- @@ -1210,7 +1984,6 @@ the version was overridden on the command line that built the source distribution.) ------ 0.6b4 ----- @@ -1223,7 +1996,6 @@ * Fixed redundant warnings about missing ``README`` file(s); it should now appear only if you are actually a source distribution. ------ 0.6b3 ----- @@ -1234,7 +2006,6 @@ ``include_package_data`` and ``package_data`` are used to refer to the same files. ------ 0.6b1 ----- @@ -1242,7 +2013,6 @@ the name of a ``.py`` loader/wrapper. (Python's import machinery ignores this suffix when searching for an extension module.) ------- 0.6a11 ------ @@ -1276,13 +2046,11 @@ it. Previously, the file could be left open and the actual error would be masked by problems trying to remove the open file on Windows systems. ------- 0.6a10 ------ * Fixed the ``develop`` command ignoring ``--find-links``. ------ 0.6a9 ----- @@ -1334,7 +2102,6 @@ back into an ``.egg`` file or directory and install it as such. ------ 0.6a8 ----- @@ -1362,13 +2129,11 @@ metadata cache to pretend that the egg has valid version information, until it has a chance to make it actually be so (via the ``egg_info`` command). ------ 0.6a5 ----- * Fixed missing gui/cli .exe files in distribution. Fixed bugs in tests. ------ 0.6a3 ----- @@ -1376,7 +2141,6 @@ on Windows and other platforms. (The special handling is only for Windows; other platforms are treated the same as for ``console_scripts``.) ------ 0.6a2 ----- @@ -1385,7 +2149,6 @@ scripts get an ``.exe`` wrapper so you can just type their name. On other platforms, the scripts are written without a file extension. ------ 0.6a1 ----- @@ -1431,7 +2194,6 @@ or documented, and never would have worked without EasyInstall - which it pre-dated and was never compatible with. ------- 0.5a12 ------ @@ -1439,14 +2201,12 @@ ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't handle ``-m`` on zipped modules. ------- 0.5a11 ------ * Fix breakage of the "develop" command that was caused by the addition of ``--always-unzip`` to the ``easy_install`` command. ------ 0.5a9 ----- @@ -1481,7 +2241,6 @@ * Fixed the swapped ``-d`` and ``-b`` options of ``bdist_egg``. ------ 0.5a8 ----- @@ -1509,7 +2268,6 @@ * Added a "setopt" command that sets a single option in a specified distutils configuration file. ------ 0.5a7 ----- @@ -1517,7 +2275,6 @@ fix for "upload" and a temporary workaround for lack of .egg support in PyPI. ------ 0.5a6 ----- @@ -1536,7 +2293,6 @@ revisions compare *lower* than the version specified in setup.py (e.g. by using ``--tag-build=dev``). ------ 0.5a5 ----- @@ -1564,7 +2320,6 @@ accordingly. ``easy_install.py`` is still installed as a script, but not as a module. ------ 0.5a4 ----- @@ -1580,7 +2335,6 @@ * Setup scripts using setuptools now always install using ``easy_install`` internally, for ease of uninstallation and upgrading. ------ 0.5a1 ----- @@ -1595,7 +2349,6 @@ from setuptools import setup # etc... ------ 0.4a2 ----- @@ -1623,7 +2376,6 @@ their ``command_consumes_arguments`` attribute to ``True`` in order to receive an ``args`` option containing the rest of the command line. ------ 0.3a2 ----- @@ -1633,8 +2385,8 @@ * Misc. bug fixes ------ 0.3a1 ----- * Initial release. + diff -Nru python-setuptools-3.3/conftest.py python-setuptools-20.1.1/conftest.py --- python-setuptools-3.3/conftest.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/conftest.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1 @@ +pytest_plugins = 'setuptools.tests.fixtures' diff -Nru python-setuptools-3.3/debian/changelog python-setuptools-20.1.1/debian/changelog --- python-setuptools-3.3/debian/changelog 2014-03-23 08:07:18.000000000 +0000 +++ python-setuptools-20.1.1/debian/changelog 2016-03-16 19:56:25.000000000 +0000 @@ -1,12 +1,190 @@ -python-setuptools (3.3-1ubuntu1) trusty; urgency=medium +python-setuptools (20.1.1-1~ubuntu14.04.1~ppa1) trusty; urgency=medium - * Stop building for Python 3.3. + * No-change backport to trusty - -- Matthias Klose Sun, 23 Mar 2014 09:06:50 +0100 + -- Marco Ceppi Wed, 16 Mar 2016 15:56:25 -0400 + +python-setuptools (20.1.1-1) unstable; urgency=medium + + * New upstream version. + * Stop building the -whl package. + + -- Matthias Klose Mon, 15 Feb 2016 19:11:35 +0100 + +python-setuptools (20.0-2) unstable; urgency=medium + + * Use the pkg_resources from the source when building the docs. + + -- Matthias Klose Thu, 11 Feb 2016 13:28:36 +0100 + +python-setuptools (20.0-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Wed, 10 Feb 2016 11:08:25 +0100 + +python-setuptools (18.8-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Sun, 13 Dec 2015 14:51:22 +0100 + +python-setuptools (18.7.1-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Fri, 11 Dec 2015 17:32:09 +0100 + +python-setuptools (18.7-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Tue, 01 Dec 2015 13:14:59 +0100 + +python-setuptools (18.4-2) unstable; urgency=medium + + * Don't install the SOURCES.txt egg-info file when setup.py is called + with --install-layout=deb. Closes: #802792. + + -- Matthias Klose Sat, 24 Oct 2015 16:07:48 +0200 + +python-setuptools (18.4-1) unstable; urgency=medium + + * New upstream version. + * Provide a unified entry_points.txt file. + + -- Matthias Klose Sun, 11 Oct 2015 13:06:42 +0200 + +python-setuptools (18.3.1-2) unstable; urgency=medium + + * Don't blow away egg-info on clean (Stefano Rivera). + * Remove the build dependency on python-setuptools. + + -- Matthias Klose Fri, 11 Sep 2015 20:33:13 +0200 + +python-setuptools (18.3.1-1) unstable; urgency=medium + + * New upstream version. + * Build-depend on python-setuptools. Without this dependency, the scripts + are not installed. Not yet known, why. Closes: #795455. + * Install the upstream changes file, not the empty history file. + Closes: #798078. + * Suggests the python-setuptools-doc package. Closes: #797731. + + -- Matthias Klose Thu, 10 Sep 2015 18:28:54 +0200 + +python-setuptools (18.2-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Fri, 04 Sep 2015 22:29:34 +0200 + +python-setuptools (18.0.1-2) unstable; urgency=medium + + [ Stefano Rivera ] + * Port to pybuild: + - Build-Depend on dh-python. + * Bump debhelper compat to 9 (and Build-Depends to >= 9) + * Replace unnecessary dependencies on python*-all-dev packages with -all. + * Drop deprecated ${python:Versions} and ${python:Provides} substitutions. + * Drop constraints on packages that pre-date oldoldstable. + * Add Suggests: python-setuptools on python-pkg-resources, matching + python3-pkg-resources. + * Drop ancient and irrelevant README.Debian. + * Use dh_sphinxdoc's generated dependencies. + * Replace accidental /usr/share/doc/html symlink with the intended + /usr/share/doc/python3-setuptools/html. + * Drop unnecessary easy_install-X.Y binaries. + Users can use pythonX.Y -m easy_install, instead. + * Drop .pth file. No longer necessary, we don't install eggs. + * Add binary packages for pypy. Requires Build-Depends: pypy. Closes: #735855. + + -- Matthias Klose Mon, 03 Aug 2015 14:21:28 +0200 + +python-setuptools (18.0.1-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Tue, 21 Jul 2015 21:45:52 +0200 + +python-setuptools (17.0-1) unstable; urgency=medium + + * New upstream version. + * Fix another issue with the multiarch patch (which can be dropped once + 3.5 is the only version in the distro). + + -- Matthias Klose Fri, 29 May 2015 15:13:19 +0200 + +python-setuptools (16.0-2) unstable; urgency=medium + + * Fix syntax error in multiarch patch (Brian Warner). Closes: #786446. + + -- Matthias Klose Thu, 21 May 2015 23:43:05 +0200 + +python-setuptools (16.0-1) unstable; urgency=medium + + * New upstream version. Closes: #784364. + * Build for python 3.5. + * Fix lintian warnings. + * Build without the rst.linker plugin, not yet packaged. + * python3-setuptools: Conflict with python3.5 (<< 3.5.0~a4-5). + + -- Matthias Klose Tue, 19 May 2015 11:56:21 +0200 + +python-setuptools (12.2-1) experimental; urgency=medium + + * New upstream version. Closes: #779036, #773969. + + -- Matthias Klose Thu, 26 Feb 2015 15:04:59 +0100 + +python-setuptools (5.5.1-1) unstable; urgency=medium + + * New upstream version. Closes: #754089. + + -- Matthias Klose Tue, 12 Aug 2014 13:50:59 +0200 + +python-setuptools (5.4.1-1) unstable; urgency=medium + + * New upstream version. Closes: #754089. + + -- Matthias Klose Mon, 07 Jul 2014 19:33:26 +0200 + +python-setuptools (5.3-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Wed, 02 Jul 2014 00:18:03 +0200 + +python-setuptools (4.0.1-1) unstable; urgency=medium + + * New upstream version. + * Stop building for python 3.3. Closes: #751070. + + -- Matthias Klose Tue, 10 Jun 2014 17:38:45 +0200 + +python-setuptools (3.6-1) unstable; urgency=medium + + * New upstream version. + * Build a python-setuptools-whl package (Barry Warsaw). Closes: #748299. + * Fix installation of the html documentation. Closes: #737889, #748586. + + -- Matthias Klose Wed, 21 May 2014 11:19:00 +0200 + +python-setuptools (3.4.4-1) unstable; urgency=medium + + * New upstream version. + - Fix #184, build directory included into the package. Closes: #743644. + + -- Matthias Klose Sat, 12 Apr 2014 21:28:18 +0200 + +python-setuptools (3.4.1-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Thu, 03 Apr 2014 22:02:29 +0200 python-setuptools (3.3-1) unstable; urgency=medium - * Non-maintainer upload. * New upstream version. -- Matthias Klose Sat, 22 Mar 2014 18:36:35 +0100 diff -Nru python-setuptools-3.3/debian/compat python-setuptools-20.1.1/debian/compat --- python-setuptools-3.3/debian/compat 2013-05-08 22:05:03.000000000 +0000 +++ python-setuptools-20.1.1/debian/compat 2015-08-03 12:22:39.000000000 +0000 @@ -1 +1 @@ -5 +9 diff -Nru python-setuptools-3.3/debian/control python-setuptools-20.1.1/debian/control --- python-setuptools-3.3/debian/control 2013-12-21 21:37:25.000000000 +0000 +++ python-setuptools-20.1.1/debian/control 2016-02-15 18:12:56.000000000 +0000 @@ -2,20 +2,22 @@ Section: python Priority: optional Maintainer: Matthias Klose -Build-Depends-Indep: python-all-dev (>= 2.6.6-2~), python3-all-dev (>= 3.1.2-8~), - python3.4-dev, - python-sphinx (>= 1.0.7+dfsg) | python3-sphinx -Build-Depends: debhelper (>= 5.0.37.1) -Standards-Version: 3.9.5 +Build-Depends: + debhelper (>= 9), + dh-python, + pypy, + python-all, + python3-all, + python3-sphinx, + python3-wheel +Build-Conflicts: python-setuptools, python3-setuptools +Standards-Version: 3.9.6 Homepage: https://pypi.python.org/pypi/setuptools Package: python-pkg-resources +Suggests: python-setuptools Architecture: all -Depends: ${python:Depends}, ${misc:Depends} -Suggests: python-distribute, python-distribute-doc -Conflicts: python-setuptools (<< 0.6c8-3) -Provides: ${python:Provides} -XB-Python-Version: ${python:Versions} +Depends: ${misc:Depends}, ${python:Depends} Description: Package Discovery and Resource Access using pkg_resources The pkg_resources module provides an API for Python libraries to access their resource files, and for extensible applications and @@ -27,30 +29,27 @@ Package: python-setuptools Architecture: all -Depends: ${python:Depends}, python-pkg-resources (= ${binary:Version}), ${misc:Depends} -Conflicts: python-distribute (<< 0.7) -Replaces: python-distribute (<< 0.6.6) -Provides: ${python:Provides}, python-distribute -XB-Python-Version: ${python:Versions} -Description: Python Distutils Enhancements (setuptools compatibility) +Depends: + python-pkg-resources (= ${binary:Version}), + ${misc:Depends}, + ${python:Depends} +Suggests: python-setuptools-doc +Provides: python-distribute +Description: Python Distutils Enhancements Extensions to the python-distutils for large or complex distributions. Package: python-setuptools-doc Architecture: all Section: doc -Depends: libjs-jquery, ${misc:Depends} -Conflicts: python-distribute-doc -Replaces: python-distribute-doc -Description: Python Distutils Enhancements (based on distribute), documentation +Depends: ${misc:Depends}, ${sphinxdoc:Depends} +Description: Python Distutils Enhancements (documentation) Extensions to the Python distutils for large or complex distributions. The package contains the documentation in html format. Package: python3-pkg-resources Architecture: all -Depends: ${python3:Depends}, ${misc:Depends} -Provides: ${python3:Provides} +Depends: ${misc:Depends}, ${python3:Depends} Suggests: python3-setuptools -Conflicts: python-pkg-resources (= 0.6.10-2) Description: Package Discovery and Resource Access using pkg_resources The pkg_resources module provides an API for Python libraries to access their resource files, and for extensible applications and @@ -62,8 +61,41 @@ Package: python3-setuptools Architecture: all -Depends: ${python3:Depends}, python3-pkg-resources (= ${binary:Version}), ${misc:Depends} -Provides: ${python3:Provides} -Conflicts: python-setuptools (= 0.6.10-2) -Description: Python3 Distutils Enhancements (setuptools compatibility) +Depends: + python3-pkg-resources (= ${binary:Version}), + ${misc:Depends}, + ${python3:Depends} +Suggests: python-setuptools-doc +Description: Python3 Distutils Enhancements Extensions to the python-distutils for large or complex distributions. + +Package: pypy-pkg-resources +Suggests: pypy-setuptools +Architecture: all +Depends: ${misc:Depends}, ${pypy:Depends} +Description: Package Discovery and Resource Access using pkg_resources + The pkg_resources module provides an API for Python libraries to + access their resource files, and for extensible applications and + frameworks to automatically discover plugins. It also provides + runtime support for using C extensions that are inside zipfile-format + eggs, support for merging packages that have separately-distributed + modules or subpackages, and APIs for managing Python's current + "working set" of active packages. + +Package: pypy-setuptools +Architecture: all +Depends: + pypy-pkg-resources (= ${binary:Version}), + ${misc:Depends}, + ${pypy:Depends} +Suggests: python-setuptools-doc +Description: PyPy Distutils Enhancements + Extensions to the python-distutils for large or complex distributions. + +#Package: python-setuptools-whl +#Architecture: all +#Depends: ${misc:Depends} +#Description: Python Distutils Enhancements (wheel package) +# Extensions to the python-distutils for large or complex distributions. +# . +# This package provides setuptools in PEP 427 wheel format. diff -Nru python-setuptools-3.3/debian/patches/fix-changes-link.diff python-setuptools-20.1.1/debian/patches/fix-changes-link.diff --- python-setuptools-3.3/debian/patches/fix-changes-link.diff 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/fix-changes-link.diff 2015-05-19 13:08:46.000000000 +0000 @@ -0,0 +1,10 @@ +Index: b/docs/history.txt +=================================================================== +--- a/docs/history.txt ++++ b/docs/history.txt +@@ -5,4 +5,4 @@ + History + ******* + +-.. include:: ../CHANGES (links).txt ++.. include:: ../CHANGES.txt diff -Nru python-setuptools-3.3/debian/patches/fix-python3.5.diff python-setuptools-20.1.1/debian/patches/fix-python3.5.diff --- python-setuptools-3.3/debian/patches/fix-python3.5.diff 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/fix-python3.5.diff 2016-02-11 07:10:14.000000000 +0000 @@ -0,0 +1,12 @@ +Index: b/setup.py +=================================================================== +--- a/setup.py ++++ b/setup.py +@@ -148,7 +148,6 @@ setup_params = dict( + Topic :: Utilities + """).strip().splitlines(), + extras_require={ +- "ssl:sys_platform=='win32'": "wincertstore==0.2", + "certs": "certifi==2015.11.20", + }, + dependency_links=[ diff -Nru python-setuptools-3.3/debian/patches/install-layout.diff python-setuptools-20.1.1/debian/patches/install-layout.diff --- python-setuptools-3.3/debian/patches/install-layout.diff 2014-03-22 17:39:03.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/install-layout.diff 2016-02-11 07:10:03.000000000 +0000 @@ -1,35 +1,15 @@ -Index: b/setup.py -=================================================================== ---- a/setup.py -+++ b/setup.py -@@ -42,8 +42,13 @@ - ) - if any(os.environ.get(var) not in (None, "", "0") for var in var_names): - return -- yield ("easy_install-{shortver} = setuptools.command.easy_install:main" -- .format(shortver=sys.version[:3])) -+ if 'XPYVERS' in os.environ: -+ for version in os.environ['XPYVERS'].split(): -+ yield ("easy_install-{shortver} = setuptools.command.easy_install:main" -+ .format(shortver=sys.version[:3])) -+ else: -+ yield ("easy_install-{shortver} = setuptools.command.easy_install:main" -+ .format(shortver=sys.version[:3])) - - console_scripts = list(_gen_console_scripts()) - Index: b/setuptools/command/easy_install.py =================================================================== --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py -@@ -123,13 +123,15 @@ +@@ -136,13 +136,15 @@ class easy_install(Command): ('local-snapshots-ok', 'l', - "allow building eggs from local checkouts"), + "allow building eggs from local checkouts"), ('version', None, "print version information and exit"), + ('install-layout=', None, "installation layout to choose (known values: deb)"), + ('force-installation-into-system-dir', '0', "force installation into /usr"), ('no-find-links', None, - "Don't load find-links defined in packages being installed") + "Don't load find-links defined in packages being installed") ] boolean_options = [ 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', @@ -39,7 +19,7 @@ ] if site.ENABLE_USER_SITE: -@@ -180,6 +182,10 @@ +@@ -190,6 +192,10 @@ class easy_install(Command): self.site_dirs = None self.installed_projects = {} self.sitepy_installed = False @@ -50,18 +30,19 @@ # Always read easy_install options, even if we are subclassed, or have # an independent instance created. This ensures that defaults will # always come from the standard configuration file(s)' "easy_install" -@@ -244,6 +250,10 @@ +@@ -258,6 +264,11 @@ class easy_install(Command): self.expand_basedirs() self.expand_dirs() + if self.install_layout: + if not self.install_layout.lower() in ['deb']: -+ raise DistutilsOptionError("unknown value for --install-layout") ++ raise DistutilsOptionError("unknown value for --install-layout") ++ self.install_layout = self.install_layout.lower() + - self._expand('install_dir','script_dir','build_directory','site_dirs') + self._expand('install_dir', 'script_dir', 'build_directory', + 'site_dirs') # If a non-default installation directory was specified, default the - # script directory to match it. -@@ -267,6 +277,15 @@ +@@ -282,6 +293,15 @@ class easy_install(Command): if self.user and self.install_purelib: self.install_dir = self.install_purelib self.script_dir = self.install_scripts @@ -77,9 +58,9 @@ # default --record from the install command self.set_undefined_options('install', ('record', 'record')) # Should this be moved to the if statement below? It's not used -@@ -1207,11 +1226,28 @@ - self.debug_print("os.makedirs('%s', 0700)" % path) - os.makedirs(path, 0x1C0) # 0700 +@@ -1277,11 +1297,28 @@ class easy_install(Command): + self.debug_print("os.makedirs('%s', 0o700)" % path) + os.makedirs(path, 0o700) + if sys.version[:3] in ('2.3', '2.4', '2.5') or 'real_prefix' in sys.__dict__: + sitedir_name = 'site-packages' @@ -87,9 +68,9 @@ + sitedir_name = 'dist-packages' + INSTALL_SCHEMES = dict( - posix = dict( - install_dir = '$base/lib/python$py_version_short/site-packages', - script_dir = '$base/bin', + posix=dict( + install_dir='$base/lib/python$py_version_short/site-packages', + script_dir='$base/bin', ), + unix_local = dict( + install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, @@ -106,13 +87,13 @@ ) DEFAULT_SCHEME = dict( -@@ -1222,11 +1258,18 @@ +@@ -1292,11 +1329,18 @@ class easy_install(Command): def _expand(self, *attrs): config_vars = self.get_finalized_command('install').config_vars - if self.prefix: + if self.prefix or self.install_layout: -+ if self.install_layout and self.install_layout.lower() in ['deb']: ++ if self.install_layout and self.install_layout in ['deb']: + scheme_name = "deb_system" + self.prefix = '/usr' + elif self.prefix or 'real_prefix' in sys.__dict__: @@ -122,14 +103,14 @@ # Set default install_dir/scripts from --prefix config_vars = config_vars.copy() config_vars['base'] = self.prefix -- scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME) +- scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME) + scheme = self.INSTALL_SCHEMES.get(scheme_name,self.DEFAULT_SCHEME) - for attr,val in scheme.items(): - if getattr(self,attr,None) is None: - setattr(self,attr,val) -@@ -1258,9 +1301,14 @@ - "site-packages"), - os.path.join(prefix, "lib", "site-python")]) + for attr, val in scheme.items(): + if getattr(self, attr, None) is None: + setattr(self, attr, val) +@@ -1330,9 +1374,14 @@ def get_site_dirs(): + "site-packages"), + os.path.join(prefix, "lib", "site-python")]) else: + if sys.version[:3] in ('2.3', '2.4', '2.5'): + sdir = "site-packages" @@ -148,16 +129,14 @@ =================================================================== --- a/setuptools/command/install_egg_info.py +++ b/setuptools/command/install_egg_info.py -@@ -1,7 +1,7 @@ - from setuptools import Command - from setuptools.archive_util import unpack_archive +@@ -1,5 +1,5 @@ from distutils import log, dir_util --import os, pkg_resources -+import os, sys, pkg_resources +-import os ++import os, sys + + from setuptools.extern.six.moves import map - class install_egg_info(Command): - """Install an .egg-info directory for the package""" -@@ -14,13 +14,30 @@ +@@ -19,14 +19,31 @@ class install_egg_info(Command): def initialize_options(self): self.install_dir = None @@ -165,19 +144,20 @@ + self.prefix_option = None def finalize_options(self): - self.set_undefined_options('install_lib',('install_dir','install_dir')) + self.set_undefined_options('install_lib', + ('install_dir', 'install_dir')) + self.set_undefined_options('install',('install_layout','install_layout')) + if sys.hexversion > 0x2060000: + self.set_undefined_options('install',('prefix_option','prefix_option')) ei_cmd = self.get_finalized_command("egg_info") basename = pkg_resources.Distribution( None, None, ei_cmd.egg_name, ei_cmd.egg_version - ).egg_name()+'.egg-info' + ).egg_name() + '.egg-info' + + if self.install_layout: + if not self.install_layout.lower() in ['deb']: -+ raise DistutilsOptionError( -+ "unknown value for --install-layout") ++ raise DistutilsOptionError("unknown value for --install-layout") ++ self.install_layout = self.install_layout.lower() + basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') + elif self.prefix_option or 'real_prefix' in sys.__dict__: + # don't modify for virtualenv @@ -187,4 +167,4 @@ + self.source = ei_cmd.egg_info self.target = os.path.join(self.install_dir, basename) - self.outputs = [self.target] + self.outputs = [] diff -Nru python-setuptools-3.3/debian/patches/multiarch-extname.diff python-setuptools-20.1.1/debian/patches/multiarch-extname.diff --- python-setuptools-3.3/debian/patches/multiarch-extname.diff 2014-03-22 17:39:10.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/multiarch-extname.diff 2016-02-11 07:10:08.000000000 +0000 @@ -2,7 +2,7 @@ =================================================================== --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py -@@ -185,6 +185,7 @@ +@@ -195,6 +195,7 @@ class easy_install(Command): # enable custom installation, known values: deb self.install_layout = None self.force_installation_into_system_dir = None @@ -10,67 +10,77 @@ # Always read easy_install options, even if we are subclassed, or have # an independent instance created. This ensures that defaults will -@@ -253,6 +254,9 @@ - if self.install_layout: +@@ -268,7 +269,9 @@ class easy_install(Command): if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") + raise DistutilsOptionError("unknown value for --install-layout") + self.install_layout = self.install_layout.lower() +- + import sysconfig + if sys.version_info[:2] >= (3, 3): + self.multiarch = sysconfig.get_config_var('MULTIARCH') - - self._expand('install_dir','script_dir','build_directory','site_dirs') + self._expand('install_dir', 'script_dir', 'build_directory', + 'site_dirs') # If a non-default installation directory was specified, default the Index: b/setuptools/command/install_lib.py =================================================================== --- a/setuptools/command/install_lib.py +++ b/setuptools/command/install_lib.py -@@ -1,7 +1,20 @@ - from distutils.command.install_lib import install_lib as _install_lib +@@ -1,4 +1,5 @@ import os +import sys + import imp + from itertools import product, starmap + import distutils.command.install_lib as orig +@@ -6,6 +7,18 @@ import distutils.command.install_lib as + class install_lib(orig.install_lib): + """Don't add compiled flags to filenames of non-Python files""" - class install_lib(_install_lib): + def initialize_options(self): -+ _install_lib.initialize_options(self) ++ orig.install_lib.initialize_options(self) + self.multiarch = None + self.install_layout = None + + def finalize_options(self): -+ _install_lib.finalize_options(self) ++ orig.install_lib.finalize_options(self) + self.set_undefined_options('install',('install_layout','install_layout')) + if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): + import sysconfig + self.multiarch = sysconfig.get_config_var('MULTIARCH') + - """Don't add compiled flags to filenames of non-Python files""" - def run(self): -@@ -34,6 +47,8 @@ + self.build() + outfiles = self.install() +@@ -90,6 +103,8 @@ class install_lib(orig.install_lib): exclude = self.get_exclusions() if not exclude: + import distutils.dir_util + distutils.dir_util._multiarch = self.multiarch - return _install_lib.copy_tree(self, infile, outfile) + return orig.install_lib.copy_tree(self, infile, outfile) # Exclude namespace package __init__.py* files from the output -@@ -43,11 +58,19 @@ +@@ -99,12 +114,24 @@ class install_lib(orig.install_lib): outfiles = [] + if self.multiarch: + import sysconfig + ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') -+ new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) ++ if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): ++ new_suffix = None ++ else: ++ new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) + def pf(src, dst): if dst in exclude: - log.warn("Skipping installation of %s (namespace package)",dst) + log.warn("Skipping installation of %s (namespace package)", + dst) return False -+ if self.multiarch and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): ++ if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): + dst = dst.replace(ext_suffix, new_suffix) + log.info("renaming extension to %s", os.path.basename(dst)) ++ log.info("copying %s -> %s", src, os.path.dirname(dst)) outfiles.append(dst) return dst diff -Nru python-setuptools-3.3/debian/patches/multiple-entrypoints.diff python-setuptools-20.1.1/debian/patches/multiple-entrypoints.diff --- python-setuptools-3.3/debian/patches/multiple-entrypoints.diff 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/multiple-entrypoints.diff 2015-10-11 11:52:41.000000000 +0000 @@ -0,0 +1,26 @@ +# this patch is currently not used, not providing entry points for all interpreters + +Index: b/setup.py +=================================================================== +--- a/setup.py ++++ b/setup.py +@@ -43,8 +43,17 @@ def _gen_console_scripts(): + ) + if any(os.environ.get(var) not in (None, "", "0") for var in var_names): + return +- yield ("easy_install-{shortver} = setuptools.command.easy_install:main" +- .format(shortver=sys.version[:3])) ++ if sys.version_info[0] < 3 and 'XPYVERSISONS' in os.environ: ++ for version in os.environ['XPYVERSIONS'].split(): ++ yield ("easy_install-{shortver} = setuptools.command.easy_install:main" ++ .format(shortver=version)) ++ elif sys.version_info[0] >= 3 and 'XPY3VERSIONS' in os.environ: ++ for version in os.environ['XPY3VERSIONS'].split(): ++ yield ("easy_install-{shortver} = setuptools.command.easy_install:main" ++ .format(shortver=version)) ++ else: ++ yield ("easy_install-{shortver} = setuptools.command.easy_install:main" ++ .format(shortver=sys.version[:3])) + + console_scripts = list(_gen_console_scripts()) + diff -Nru python-setuptools-3.3/debian/patches/no-SOURCES.txt-in-egg-ingo.diff python-setuptools-20.1.1/debian/patches/no-SOURCES.txt-in-egg-ingo.diff --- python-setuptools-3.3/debian/patches/no-SOURCES.txt-in-egg-ingo.diff 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/no-SOURCES.txt-in-egg-ingo.diff 2016-02-11 07:10:23.000000000 +0000 @@ -0,0 +1,14 @@ +Index: b/setuptools/command/install_egg_info.py +=================================================================== +--- a/setuptools/command/install_egg_info.py ++++ b/setuptools/command/install_egg_info.py +@@ -73,6 +73,9 @@ class install_egg_info(Command): + for skip in '.svn/', 'CVS/': + if src.startswith(skip) or '/' + skip in src: + return None ++ if self.install_layout and self.install_layout in ['deb'] and src.startswith('SOURCES.txt'): ++ log.info("Skipping SOURCES.txt") ++ return None + self.outputs.append(dst) + log.debug("Copying %s to %s", src, dst) + return dst diff -Nru python-setuptools-3.3/debian/patches/no-sphinx-rst.linker.diff python-setuptools-20.1.1/debian/patches/no-sphinx-rst.linker.diff --- python-setuptools-3.3/debian/patches/no-sphinx-rst.linker.diff 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/no-sphinx-rst.linker.diff 2015-05-19 12:51:02.000000000 +0000 @@ -0,0 +1,13 @@ +Index: b/docs/conf.py +=================================================================== +--- a/docs/conf.py ++++ b/docs/conf.py +@@ -28,7 +28,7 @@ import setup as setup_script + + # Add any Sphinx extension module names here, as strings. They can be extensions + # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +-extensions = ['rst.linker'] ++#extensions = ['rst.linker'] + + # Add any paths that contain templates here, relative to this directory. + templates_path = ['_templates'] diff -Nru python-setuptools-3.3/debian/patches/series python-setuptools-20.1.1/debian/patches/series --- python-setuptools-3.3/debian/patches/series 2013-12-31 11:31:31.000000000 +0000 +++ python-setuptools-20.1.1/debian/patches/series 2015-10-24 14:13:25.000000000 +0000 @@ -1,2 +1,7 @@ install-layout.diff multiarch-extname.diff +fix-python3.5.diff +no-sphinx-rst.linker.diff +fix-changes-link.diff +multiple-entrypoints.diff +no-SOURCES.txt-in-egg-ingo.diff diff -Nru python-setuptools-3.3/debian/pypy-pkg-resources.install python-setuptools-20.1.1/debian/pypy-pkg-resources.install --- python-setuptools-3.3/debian/pypy-pkg-resources.install 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/pypy-pkg-resources.install 2015-08-03 12:23:42.000000000 +0000 @@ -0,0 +1 @@ +/usr/lib/pypy/dist-packages/pkg_resources diff -Nru python-setuptools-3.3/debian/pypy-setuptools.install python-setuptools-20.1.1/debian/pypy-setuptools.install --- python-setuptools-3.3/debian/pypy-setuptools.install 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/pypy-setuptools.install 2015-08-03 12:23:42.000000000 +0000 @@ -0,0 +1,4 @@ +/usr/lib/pypy/dist-packages/_markerlib +/usr/lib/pypy/dist-packages/easy_install* +/usr/lib/pypy/dist-packages/setuptools* +/usr/bin/easy_install-pypy diff -Nru python-setuptools-3.3/debian/python3-pkg-resources.install python-setuptools-20.1.1/debian/python3-pkg-resources.install --- python-setuptools-3.3/debian/python3-pkg-resources.install 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/python3-pkg-resources.install 2015-08-03 12:22:39.000000000 +0000 @@ -0,0 +1 @@ +/usr/lib/python3.*/*-packages/pkg_resources diff -Nru python-setuptools-3.3/debian/python3-setuptools.install python-setuptools-20.1.1/debian/python3-setuptools.install --- python-setuptools-3.3/debian/python3-setuptools.install 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/python3-setuptools.install 2015-08-03 12:22:39.000000000 +0000 @@ -0,0 +1,4 @@ +/usr/lib/python3.*/*-packages/_markerlib +/usr/lib/python3.*/*-packages/easy_install* +/usr/lib/python3.*/*-packages/setuptools* +/usr/bin/easy_install3 diff -Nru python-setuptools-3.3/debian/python-pkg-resources.install python-setuptools-20.1.1/debian/python-pkg-resources.install --- python-setuptools-3.3/debian/python-pkg-resources.install 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/python-pkg-resources.install 2015-08-03 12:22:39.000000000 +0000 @@ -0,0 +1 @@ +/usr/lib/python2.*/*-packages/pkg_resources diff -Nru python-setuptools-3.3/debian/python-setuptools.install python-setuptools-20.1.1/debian/python-setuptools.install --- python-setuptools-3.3/debian/python-setuptools.install 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/debian/python-setuptools.install 2015-08-03 12:22:39.000000000 +0000 @@ -0,0 +1,4 @@ +/usr/lib/python2.*/*-packages/_markerlib +/usr/lib/python2.*/*-packages/easy_install* +/usr/lib/python2.*/*-packages/setuptools* +/usr/bin/easy_install diff -Nru python-setuptools-3.3/debian/README.Debian python-setuptools-20.1.1/debian/README.Debian --- python-setuptools-3.3/debian/README.Debian 2013-05-08 22:05:03.000000000 +0000 +++ python-setuptools-20.1.1/debian/README.Debian 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -python-setuptools for Debian ----------------------------- - -Snapshot, taken from the sandbox CVS. - - -- Matthias Klose , Tue, 14 Dec 2004 12:45:14 +0100 diff -Nru python-setuptools-3.3/debian/rules python-setuptools-20.1.1/debian/rules --- python-setuptools-3.3/debian/rules 2014-03-23 08:08:04.000000000 +0000 +++ python-setuptools-20.1.1/debian/rules 2016-02-15 18:13:42.000000000 +0000 @@ -1,181 +1,63 @@ #!/usr/bin/make -f -# -*- makefile -*- -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 +%: + dh $@ --with python2,python3,pypy,sphinxdoc --buildsystem pybuild -# This has to be exported to make some magic below work. -export DH_OPTIONS +# no versioned easy_install scripts +export SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT = yes -# setuptools doesn't handle translated messages -export LC_ALL=C - -#PYVERS := 2.3 2.5 $(shell pyversions -vr debian/control) -XPYVERS := 2.7 -PYVERS := 2.7 -PYVERS3 := 3.4 -PYVER := $(shell python -c 'import sys; print sys.version[:3]') -SETUPTOOLSVER=1.3.2 -export XPYVERS - -include /usr/share/python3/python.mk - -pname = $(if $(findstring 3.,$(2)),$(subst python-,python3-,$(1)),$(1)) - -p_pkgr = python-pkg-resources -p_setp = python-setuptools -p_doc = python-setuptools-doc - -d_pkgr = debian/$(p_pkgr) -d_setp = debian/$(p_setp) -d_doc = debian/$(p_doc) - -build: build-stamp -build-arch: build-stamp -build-indep: build-stamp build-doc-stamp -build-stamp: $(PYVERS:%=build-python%) $(PYVERS3:%=build-python%) build-doc-stamp - touch $@ -build-doc-stamp: - PYTHONPATH=$(CURDIR) \ - sh -c 'cd docs && sphinx-build -b html -d build/doctrees . build/html' - touch $@ -build-python%: pre-build-stamp - python$* setup.py build - touch $@ -pre-build-stamp: - [ -d setuptools.egg-info.saved ] || cp -a setuptools.egg-info setuptools.egg-info.saved - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-python* build-doc-stamp build-stamp - rm -rf build dist - -find -name __pycache__ | xargs rm -rf - -find -name '*.py[co]' | xargs rm -f - rm -rf docs/build - rm -f template* \(dev\).py - if [ -d setuptools.egg-info.saved ]; then \ - rm -rf setuptools.egg-info; \ - mv setuptools.egg-info.saved setuptools.egg-info; \ - fi - dh_clean - -install: build install-prereq $(PYVERS:%=install-python%) $(PYVERS3:%=install-python%) - find debian -name 'setuptools_boot.py*' | xargs -r rm -f - find debian -name '*.py[co]' | xargs -r rm -f - pkgs=$$(dh_listpackages); cd debian && find $$pkgs -mindepth 1 -type d -empty -print -delete - - rm -f debian/python-*/usr/bin/easy_install-3* - rm -f debian/python3-*/usr/bin/easy_install-2* - mv debian/python3-setuptools/usr/bin/easy_install \ - debian/python3-setuptools/usr/bin/easy_install3 - - : # Replace all '#!' calls to python with $(PYTHON) - : # and make them executable - for i in \ - `find debian/python-*/usr/lib debian/python-*/usr/bin -type f`; \ - do \ - case "$$i" in *-[0-9].[0-9]) continue; esac; \ - sed '1s,#!.*python[^ ]*\(.*\),#! /usr/bin/python\1,' \ - $$i > $$i.temp; \ - if cmp --quiet $$i $$i.temp; then \ - rm -f $$i.temp; \ - else \ - mv -f $$i.temp $$i; \ - chmod 755 $$i; \ - echo "fixed interpreter: $$i"; \ - fi; \ - done - - for i in \ - `find debian/python3-*/usr/lib debian/python3-*/usr/bin -type f`; \ - do \ - case "$$i" in *-[0-9].[0-9]) continue; esac; \ - sed '1s,#!.*python[^ ]*\(.*\),#! /usr/bin/python3\1,' \ - $$i > $$i.temp; \ - if cmp --quiet $$i $$i.temp; then \ - rm -f $$i.temp; \ - else \ - mv -f $$i.temp $$i; \ - chmod 755 $$i; \ - echo "fixed interpreter: $$i"; \ - fi; \ - done - -install-prereq: - dh_testdir - dh_testroot - dh_clean -k - -install-python%: - dh_installdirs -A usr/bin /$(call py_libdir,$*) - python$* setup.py install \ - --root=$(CURDIR)/$(call pname,$(d_setp),$*) --install-layout=deb - - mv $(call pname,$(d_setp),$*)/$(call py_libdir,$*)/pkg_resources.py \ - $(call pname,$(d_pkgr),$*)/$(call py_libdir,$*)/ - -# mv $(call pname,$(d_setp),$*)/$(call py_libdir,$*)/setuptools-$(SETUPTOOLSVER).egg-info \ -# $(call pname,$(d_setp),$*)/$(call py_libdir,$*)/setuptools.egg-info - - echo setuptools-$(SETUPTOOLSVER).egg-info \ - > $(call pname,$(d_setp),$*)/$(call py_libdir,$*)/setuptools.pth - -binary-arch: - -binary-indep: build install - dh_testdir - dh_testroot - dh_installchangelogs -p$(p_setp) CHANGES.txt - dh_installchangelogs -N$(p_setp) - dh_installdocs -N$(p_setp) -N$(p_pkgr) - dh_installdocs -p$(p_pkgr) docs/pkg_resources.txt - dh_installdocs -p$(p_setp) -Xpkg_resources docs/*.txt - mkdir -p $(d_doc)/usr/share/doc/$(p_dist) - cp -pr docs/build/html $(d_doc)/usr/share/doc/$(p_dist)/ - dh_sphinxdoc -p$(p_doc) - dh_link -p$(p_doc) \ - /usr/share/doc/$(p_dist)/html /usr/share/doc/$(p_doc)/html \ - /usr/share/doc/$(p_dist)/html /usr/share/doc/$(p_setp)/html \ - -# /usr/share/javacript/jquery/jquery.js /usr/share/doc/$(p_dist)/html/_static/jquery.js - dh_compress -i - dh_fixperms -i - - for v in $(filter-out 3.%, $(PYVERS)); do \ - sed -i "s/python2\../python$$v/g" $(d_setp)/usr/bin/easy_install-$$v; \ - done -# for v in $(filter-out 2.%, $(PYVERS)); do \ -# sed -i "s/python3\../python$$v/g" debian/$(call pname,$(p_setp),3.1)/usr/bin/easy_install-$$v; \ -# done - - dh_python2 -p$(p_pkgr) -p$(p_setp) #-p$(p_dist) - cat $(d_setp).substvars - ( \ - echo 'python:Versions=2.7'; \ - echo 'python:Provides=python2.7-setuptools'; \ - echo 'python:Depends=python:any (>= 2.7), python:any (<< 2.8)'; \ - ) > $(d_setp).substvars - cp $(d_setp).substvars $(d_pkgr).substvars - - dh_python3 -p$(call pname,$(p_pkgr),3.4) -p$(call pname,$(p_setp),3.4) # -p$(call pname,$(p_dist),3.4) - cat debian/$(call pname,$(p_setp),3.4).substvars - cat debian/$(call pname,$(p_pkgr),3.4).substvars - -## cp $(d_setp).substvars $(d_dist).substvars - - ( \ - echo 'python3:Versions=3.4'; \ - echo 'python3:Provides=python3.4-setuptools'; \ - echo 'python3:Depends=python3:any (>= 3.4), python3:any (<< 3.5)'; \ - ) > $(call pname,$(d_setp),3.4).substvars - cp $(call pname,$(d_setp),3.4).substvars $(call pname,$(d_pkgr),3.4).substvars - - dh_installdeb -i - dh_gencontrol -i - dh_md5sums -i - dh_builddeb -i - -binary: binary-arch binary-indep -.PHONY: build clean binary-indep binary-arch binary install +# versioned easy_install scripts +#export XPYVERSIONS = 2.7 +#export XPY3VERSIONS = 3.4 3.5 + +override_dh_auto_test: + +override_dh_auto_install: + dh_auto_install + + PYTHONPATH=$(CURDIR) $(MAKE) -C docs html + +# mkdir -p debian/python-setuptools-whl/usr/share/python-wheels +# python3 setup.py bdist_wheel --universal \ +# -d debian/python-setuptools-whl/usr/share/python-wheels + + # dh_pypy from dh-python < 1.20150705-1 falls over requires.txt + # and our requires.txt aren't useful + find debian/tmp -name requires.txt -delete + +override_dh_installchangelogs: + dh_installchangelogs CHANGES.txt + +override_dh_auto_clean: + # Keep entry_points, we need it to drive setup.py + -mv setuptools.egg-info/entry_points.txt . + dh_auto_clean + mkdir -p setuptools.egg-info + mv entry_points.txt setuptools.egg-info + + rm -rf .eggs docs/build + +override_dh_install: + sed -i '1 s,.*,#!/usr/bin/python,' debian/tmp/usr/bin/easy_install + sed '1 s/python/python3/' debian/tmp/usr/bin/easy_install > \ + debian/tmp/usr/bin/easy_install3 + sed '1 s/python/pypy/' debian/tmp/usr/bin/easy_install > \ + debian/tmp/usr/bin/easy_install-pypy + dh_install + +override_dh_installdocs: + dh_installdocs -p python-pkg-resources -p python3-pkg-resources \ + -p pypy-pkg-resources \ + docs/pkg_resources.txt + dh_installdocs -p python-setuptools -p python3-setuptools \ + -p pypy-setuptools \ + -X pkg_resources docs/*.txt + dh_installdocs -p python-setuptools-doc docs/build/html + dh_installdocs --remaining-packages + dh_link -p python-setuptools-doc \ + /usr/share/doc/python-setuptools-doc/html \ + /usr/share/doc/python-setuptools/html \ + /usr/share/doc/python-setuptools-doc/html \ + /usr/share/doc/python3-setuptools/html \ + /usr/share/doc/python-setuptools-doc/html \ + /usr/share/doc/pypy-setuptools/html diff -Nru python-setuptools-3.3/debian/watch python-setuptools-20.1.1/debian/watch --- python-setuptools-3.3/debian/watch 2013-05-08 22:05:03.000000000 +0000 +++ python-setuptools-20.1.1/debian/watch 2015-05-19 13:13:35.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://pypi.python.org/packages/source/d/distribute/distribute-([0-9.]*).tar.gz +http://pypi.debian.net/setuptools/setuptools-(.*)\.(?:tar\.gz|zip) diff -Nru python-setuptools-3.3/DEVGUIDE.txt python-setuptools-20.1.1/DEVGUIDE.txt --- python-setuptools-3.3/DEVGUIDE.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/DEVGUIDE.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -============================ -Quick notes for contributors -============================ - -Setuptools is developed using the DVCS Mercurial. - -Grab the code at bitbucket:: - - $ hg clone https://bitbucket.org/pypa/setuptools - -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: - -- add a note in CHANGES.txt - -Please commit bug-fixes against the current maintenance branch and new -features to the default branch. - -You can run the tests via:: - - $ python setup.py test diff -Nru python-setuptools-3.3/docs/conf.py python-setuptools-20.1.1/docs/conf.py --- python-setuptools-3.3/docs/conf.py 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/conf.py 2016-02-07 14:25:06.000000000 +0000 @@ -12,20 +12,23 @@ # autogenerated file. # # All configuration values have a default; values that are commented out -# serve to show the default. - -import setup as setup_script +# serve to show the default # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) + +# Allow Sphinx to find the setup command that is imported below, as referenced above. +import sys, os +sys.path.append(os.path.abspath('..')) + +import setup as setup_script # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] +extensions = ['rst.linker'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -41,7 +44,7 @@ # General information about the project. project = 'Setuptools' -copyright = '2009-2013, The fellowship of the packaging' +copyright = '2009-2014, The fellowship of the packaging' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -195,3 +198,58 @@ # If false, no module index is generated. #latex_use_modindex = True + +link_files = { + 'CHANGES.txt': dict( + using=dict( + BB='https://bitbucket.org', + GH='https://github.com', + ), + replace=[ + dict( + pattern=r"(Issue )?#(?P\d+)", + url='{BB}/pypa/setuptools/issue/{issue}', + ), + dict( + pattern=r"Pull Request ?#(?P\d+)", + url='{BB}/pypa/setuptools/pull-request/{pull_request}', + ), + dict( + pattern=r"Distribute #(?P\d+)", + url='{BB}/tarek/distribute/issue/{distribute}', + ), + dict( + pattern=r"Buildout #(?P\d+)", + url='{GH}/buildout/buildout/issues/{buildout}', + ), + dict( + pattern=r"Old Setuptools #(?P\d+)", + url='http://bugs.python.org/setuptools/issue{old_setuptools}', + ), + dict( + pattern=r"Jython #(?P\d+)", + url='http://bugs.jython.org/issue{jython}', + ), + dict( + pattern=r"Python #(?P\d+)", + url='http://bugs.python.org/issue{python}', + ), + dict( + pattern=r"Interop #(?P\d+)", + url='{GH}/pypa/interoperability-peps/issues/{interop}', + ), + dict( + pattern=r"Pip #(?P\d+)", + url='{GH}/pypa/pip/issues/{pip}', + ), + dict( + pattern=r"Packaging #(?P\d+)", + url='{GH}/pypa/packaging/issues/{packaging}', + ), + dict( + pattern=r"[Pp]ackaging (?P\d+(\.\d+)+)", + url='{GH}/pypa/packaging/blob/{packaging_ver}/CHANGELOG.rst', + ), + ], + ), +} diff -Nru python-setuptools-3.3/docs/developer-guide.txt python-setuptools-20.1.1/docs/developer-guide.txt --- python-setuptools-3.3/docs/developer-guide.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/docs/developer-guide.txt 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,129 @@ +================================ +Developer's Guide for Setuptools +================================ + +If you want to know more about contributing on Setuptools, this is the place. + + +.. contents:: **Table of Contents** + + +------------------- +Recommended Reading +------------------- + +Please read `How to write the perfect pull request +`_ +for some tips on contributing to open source projects. Although the article +is not authoritative, it was authored by the maintainer of Setuptools, so +reflects his opinions and will improve the likelihood of acceptance and +quality of contribution. + +------------------ +Project Management +------------------ + +Setuptools is maintained primarily in Bitbucket at `this home +`_. Setuptools is maintained under the +Python Packaging Authority (PyPA) with several core contributors. All bugs +for Setuptools are filed and the canonical source is maintained in Bitbucket. + +User support and discussions are done through the issue tracker (for specific) +issues, through the distutils-sig mailing list, or on IRC (Freenode) at +#pypa. + +Discussions about development happen on the pypa-dev mailing list or on IRC +(Freenode) at #pypa-dev. + +----------------- +Authoring Tickets +----------------- + +Before authoring any source code, it's often prudent to file a ticket +describing the motivation behind making changes. First search to see if a +ticket already exists for your issue. If not, create one. Try to think from +the perspective of the reader. Explain what behavior you expected, what you +got instead, and what factors might have contributed to the unexpected +behavior. In Bitbucket, surround a block of code or traceback with the triple +backtick "\`\`\`" so that it is formatted nicely. + +Filing a ticket provides a forum for justification, discussion, and +clarification. The ticket provides a record of the purpose for the change and +any hard decisions that were made. It provides a single place for others to +reference when trying to understand why the software operates the way it does +or why certain changes were made. + +Setuptools makes extensive use of hyperlinks to tickets in the changelog so +that system integrators and other users can get a quick summary, but then +jump to the in-depth discussion about any subject referenced. + +----------- +Source Code +----------- + +Grab the code at Bitbucket:: + + $ hg clone https://bitbucket.org/pypa/setuptools + +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: + +- add a note in CHANGES.txt + +Please commit all changes in the 'default' branch against the latest available +commit or for bug-fixes, against an earlier commit or release in which the +bug occurred. + +If you find yourself working on more than one issue at a time, Setuptools +generally prefers Git-style branches, so use Mercurial bookmarks or Git +branches or multiple forks to maintain separate efforts. + +Setuptools also maintains an unofficial `Git mirror in Github +`_. Contributors are welcome to submit +pull requests here, but because they are not integrated with the Bitbucket +Issue tracker, linking pull requests to tickets is more difficult. The +Continuous Integration tests that validate every release are run from this +mirror. + +------- +Testing +------- + +The primary tests are run using py.test. To run the tests:: + + $ python setup.py test + +Or install py.test into your environment and run ``PYTHONPATH=. py.test`` +or ``python -m pytest``. + +Under continuous integration, additional tests may be run. See the +``.travis.yml`` file for full details on the tests run under Travis-CI. + +------------------- +Semantic Versioning +------------------- + +Setuptools follows ``semver`` with some exceptions: + +- Uses two-segment version when three segment version ends in zero +- Omits 'v' prefix for tags. + +.. explain value of reflecting meaning in versions. + +---------------------- +Building Documentation +---------------------- + +Setuptools relies on the Sphinx system for building documentation and in +particular the ``build_sphinx`` distutils command. To build the +documentation, invoke:: + + python setup.py build_sphinx + +from the root of the repository. Setuptools will download a compatible +build of Sphinx and any requisite plugins and then build the +documentation in the build/sphinx directory. + +Setuptools does not support invoking the doc builder from the docs/ +directory as some tools expect. diff -Nru python-setuptools-3.3/docs/development.txt python-setuptools-20.1.1/docs/development.txt --- python-setuptools-3.3/docs/development.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/development.txt 2016-02-07 14:25:06.000000000 +0000 @@ -30,6 +30,6 @@ .. toctree:: :maxdepth: 1 + developer-guide formats releases - diff -Nru python-setuptools-3.3/docs/easy_install.txt python-setuptools-20.1.1/docs/easy_install.txt --- python-setuptools-3.3/docs/easy_install.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/easy_install.txt 2016-01-30 17:43:56.000000000 +0000 @@ -39,7 +39,7 @@ installed in the normal location for Python scripts on your platform. Note that the instructions on the setuptools PyPI page assume that you are -are installling to Python's primary ``site-packages`` directory. If this is +are installing to Python's primary ``site-packages`` directory. If this is not the case, you should consult the section below on `Custom Installation Locations`_ before installing. (And, on Windows, you should not use the ``.exe`` installer when installing to an alternate location.) @@ -915,7 +915,7 @@ domain. The glob patterns must match the *entire* user/host/port section of the target URL(s). For example, ``*.python.org`` will NOT accept a URL like ``http://python.org/foo`` or ``http://www.python.org:8080/``. - Multiple patterns can be specified by separting them with commas. The + Multiple patterns can be specified by separating them with commas. The default pattern is ``*``, which matches anything. In general, this option is mainly useful for blocking EasyInstall's web @@ -1014,7 +1014,7 @@ 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 +creating an isolated location to install 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. @@ -1171,7 +1171,7 @@ * Fixed not HTML-decoding URLs scraped from web pages 0.6c5 - * Fixed ``.dll`` files on Cygwin not having executable permisions when an egg + * Fixed ``.dll`` files on Cygwin not having executable permissions when an egg is installed unzipped. 0.6c4 diff -Nru python-setuptools-3.3/docs/formats.txt python-setuptools-20.1.1/docs/formats.txt --- python-setuptools-3.3/docs/formats.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/formats.txt 2016-02-07 14:25:06.000000000 +0000 @@ -286,6 +286,12 @@ project's core and optional dependencies. +``setup_requires.txt`` +---------------------- + +Much like ``requires.txt`` except represents the requirements +specified by the ``setup_requires`` parameter to the Distribution. + ``dependency_links.txt`` ------------------------ @@ -349,7 +355,7 @@ ``scripts`` keyword to ``setup()``). This is so that they can be reconstituted when an ``.egg`` file is installed. -The scripts are placed here using the disutils' standard +The scripts are placed here using the distutils' standard ``install_scripts`` command, so any ``#!`` lines reflect the Python installation where the egg was built. But instead of copying the scripts to the local script installation directory, EasyInstall writes @@ -397,7 +403,7 @@ These are zero-length files, and either one or the other should exist. If ``zip-safe`` exists, it means that the project will work properly -when installedas an ``.egg`` zipfile, and conversely the existence of +when installed as an ``.egg`` zipfile, and conversely the existence of ``not-zip-safe`` means the project should not be installed as an ``.egg`` file. The ``zip_safe`` option to setuptools' ``setup()`` determines which file will be written. If the option isn't provided, @@ -595,7 +601,7 @@ The net result of these changes is that ``sys.path`` order will be as follows at runtime: -1. The ``sys.argv[0]`` directory, or an emtpy string if no script +1. The ``sys.argv[0]`` directory, or an empty string if no script is being executed. 2. All eggs installed by EasyInstall in any ``.pth`` file in each diff -Nru python-setuptools-3.3/docs/history.txt python-setuptools-20.1.1/docs/history.txt --- python-setuptools-3.3/docs/history.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/docs/history.txt 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,8 @@ +:tocdepth: 2 + +.. _changes: + +History +******* + +.. include:: ../CHANGES (links).txt diff -Nru python-setuptools-3.3/docs/index.txt python-setuptools-20.1.1/docs/index.txt --- python-setuptools-3.3/docs/index.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/index.txt 2016-02-07 14:25:06.000000000 +0000 @@ -16,11 +16,10 @@ .. toctree:: :maxdepth: 2 + history roadmap python3 - using setuptools easy_install pkg_resources development - merge diff -Nru python-setuptools-3.3/docs/merge-faq.txt python-setuptools-20.1.1/docs/merge-faq.txt --- python-setuptools-3.3/docs/merge-faq.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/merge-faq.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -Setuptools/Distribute Merge FAQ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -How do I upgrade from Distribute? -================================= - -Distribute specifically prohibits installation of Setuptools 0.7 from Distribute 0.6. There are then two options for upgrading. - -Note that after upgrading using either technique, the only option to downgrade to either version is to completely uninstall Distribute and Setuptools 0.7 versions before reinstalling an 0.6 release. - -Use Distribute 0.7 ------------------- - -The PYPA has put together a compatibility wrapper, a new release of Distribute version 0.7. This package will install over Distribute 0.6.x installations and will replace Distribute with a simple wrapper that requires Setuptools 0.7 or later. This technique is experimental, but initial results indicate this technique is the easiest upgrade path. - - -Uninstall ---------- - -First, completely uninstall Distribute. Since Distribute does not have an automated installation routine, this process is manual. Follow the instructions in the README for uninstalling. - - -How do I upgrade from Setuptools 0.6? -===================================== - -There are no special instructions for upgrading over older versions of Setuptools. Simply use `easy_install -U` or run the latest `ez_setup.py`. - -Where does the merge occur? -======================================================== - -The merge is occurring between the heads of the default branch of Distribute and the setuptools-0.6 branch of Setuptools. The Setuptools SVN repo has been converted to a Mercurial repo hosted on Bitbucket. The work is still underway, so the exact changesets included may change, although the anticipated merge targets are Setuptools at 0.6c12 and Distribute at 0.6.35. - -What happens to other branches? -======================================================== - -Distribute 0.7 was abandoned long ago and won't be included in the resulting code tree, but may be retained for posterity in the original repo. - -Setuptools default branch (also 0.7 development) may also be abandoned or may be incorporated into the new merged line if desirable (and as resources allow). - -What history is lost/changed? -======================================================== - -As setuptools was not on Mercurial when the fork occurred and as Distribute did not include the full setuptools history (prior to the creation of the setuptools-0.6 branch), the two source trees were not compatible. In order to most effectively communicate the code history, the Distribute code was grafted onto the (originally private) setuptools Mercurial repo. Although this grafting maintained the full code history with names, dates, and changes, it did lose the original hashes of those changes. Therefore, references to changes by hash (including tags) are lost. - -Additionally, any heads that were not actively merged into the Distribute 0.6.35 release were also omitted. As a result, the changesets included in the merge repo are those from the original setuptools repo and all changesets ancestral to the Distribute 0.6.35 release. - -What features will be in the merged code base? -======================================================== - -In general, all "features" added in distribute will be included in setuptools. Where there exist conflicts or undesirable features, we will be explicit about what these limitations are. Changes that are backward-incompatible from setuptools 0.6 to distribute will likely be removed, and these also will be well documented. - -Bootstrapping scripts (ez_setup/distribute_setup) and docs, as with distribute, will be maintained in the repository and built as part of the release process. Documentation and bootstrapping scripts will be hosted at python.org, as they are with distribute now. Documentation at telecommunity will be updated to refer or redirect to the new, merged docs. - -On the whole, the merged setuptools should be largely compatible with the latest releases of both setuptools and distribute and will be an easy transition for users of either library. - -Who is invited to contribute? Who is excluded? -======================================================== - -While we've worked privately to initiate this merge due to the potential sensitivity of the topic, no one is excluded from this effort. We invite all members of the community, especially those most familiar with Python packaging and its challenges to join us in the effort. - -We have lots of ideas for how we'd like to improve the codebase, release process, everything. Like distribute, the post-merge setuptools will have its source hosted on bitbucket. (So if you're currently a distribute contributor, about the only thing that's going to change is the URL of the repository you follow.) Also like distribute, it'll support Python 3, and hopefully we'll soon merge Vinay Sajip's patches to make it run on Python 3 without needing 2to3 to be run on the code first. - -While we've worked privately to initiate this merge due to the potential sensitivity of the topic, no one is excluded from this effort. We invite all members of the community, especially those most familiar with Python packaging and its challenges to join us in the effort. - -Why Setuptools and not Distribute or another name? -======================================================== - -We do, however, understand that this announcement might be unsettling for some. The setuptools name has been subjected to a lot of deprecation in recent years, so the idea that it will now be the preferred name instead of distribute might be somewhat difficult or disorienting for some. We considered use of another name (Distribute or an entirely new name), but that would serve to only complicate matters further. Instead, our goal is to simplify the packaging landscape but without losing any hard-won advancements. We hope that the people who worked to spread the first message will be equally enthusiastic about spreading the new one, and we especially look forward to seeing the new posters and slogans celebrating setuptools. - -What is the timeframe of release? -======================================================== - -There are no hard timeframes for any of this effort, although progress is underway and a draft merge is underway and being tested privately. As an unfunded volunteer effort, our time to put in on it is limited, and we've both had some recent health and other challenges that have made working on this difficult, which in part explains why we haven't met our original deadline of a completed merge before PyCon. - -The final Setuptools 0.7 was cut on June 1, 2013 and will be released to PyPI shortly thereafter. - -What version number can I expect for the new release? -======================================================== - -The new release will roughly follow the previous trend for setuptools and release the new release as 0.7. This number is somewhat arbitrary, but we wanted something other than 0.6 to distinguish it from its ancestor forks but not 1.0 to avoid putting too much emphasis on the release itself and to focus on merging the functionality. In the future, the project will likely adopt a versioning scheme similar to semver to convey semantic meaning about the release in the version number. diff -Nru python-setuptools-3.3/docs/merge.txt python-setuptools-20.1.1/docs/merge.txt --- python-setuptools-3.3/docs/merge.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/merge.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -Merge with Distribute -~~~~~~~~~~~~~~~~~~~~~ - -In 2013, the fork of Distribute was merged back into Setuptools. This -document describes some of the details of the merge. - -.. toctree:: - :maxdepth: 2 - - merge-faq - -Process -======= - -In order to try to accurately reflect the fork and then re-merge of the -projects, the merge process brought both code trees together into one -repository and grafted the Distribute fork onto the Setuptools development -line (as if it had been created as a branch in the first place). - -The rebase to get distribute onto setuptools went something like this:: - - hg phase -d -f -r 26b4c29b62db - hg rebase -s 26b4c29b62db -d 7a5cf59c78d7 - -The technique required a late version of mercurial (2.5) to work correctly. - -The only code that was included was the code that was ancestral to the public -releases of Distribute 0.6. Additionally, because Setuptools was not hosted -on Mercurial at the time of the fork and because the Distribute fork did not -include a complete conversion of the Setuptools history, the Distribute -changesets had to be re-applied to a new, different conversion of the -Setuptools SVN repository. As a result, all of the hashes have changed. - -Distribute was grafted in a 'distribute' branch and the 'setuptools-0.6' -branch was targeted for the merge. The 'setuptools' branch remains with -unreleased code and may be incorporated in the future. - -Reconciling Differences -======================= - -There were both technical and philosophical differences between Setuptools -and Distribute. To reconcile these differences in a manageable way, the -following technique was undertaken: - -Create a 'Setuptools-Distribute merge' branch, based on a late release of -Distribute (0.6.35). This was done with a00b441856c4. - -In that branch, first remove code that is no longer relevant to -Setuptools (such as the setuptools patching code). - -Next, in the the merge branch, create another base from at the point where the -fork occurred (such that the code is still essentially an older but pristine -setuptools). This base can be found as 955792b069d0. This creates two heads -in the merge branch, each with a basis in the fork. - -Then, repeatedly copy changes for a -single file or small group of files from a late revision of that file in the -'setuptools-0.6' branch (1aae1efe5733 was used) and commit those changes on -the setuptools-only head. That head is then merged with the head with -Distribute changes. It is in this Mercurial -merge operation that the fundamental differences between Distribute and -Setuptools are reconciled, but since only a single file or small set of files -are used, the scope is limited. - -Finally, once all the challenging files have been reconciled and merged, the -remaining changes from the setuptools-0.6 branch are merged, deferring to the -reconciled changes (a1fa855a5a62 and 160ccaa46be0). - -Originally, jaraco attempted all of this using anonymous heads in the -Distribute branch, but later realized this technique made for a somewhat -unclear merge process, so the changes were re-committed as described above -for clarity. In this way, the "distribute" and "setuptools" branches can -continue to track the official Distribute changesets. - -Concessions -=========== - -With the merge of Setuptools and Distribute, the following concessions were -made: - -Differences from setuptools 0.6c12: - -Major Changes -------------- - -* Python 3 support. -* Improved support for GAE. -* Support `PEP-370 `_ per-user site - packages. -* Sort order of Distributions in pkg_resources now prefers PyPI to external - links (Distribute issue 163). -* Python 2.4 or greater is required (drop support for Python 2.3). - -Minor Changes -------------- - -* Wording of some output has changed to replace contractions with their - canonical form (i.e. prefer "could not" to "couldn't"). -* Manifest files are only written for 32-bit .exe launchers. - -Differences from Distribute 0.6.36: - -Major Changes -------------- - -* The _distribute property of the setuptools module has been removed. -* Distributions are once again installed as zipped eggs by default, per the - rationale given in `the seminal bug report - `_ indicates that the feature - should remain and no substantial justification was given in the `Distribute - report `_. - -Minor Changes -------------- - -* The patch for `#174 `_ - has been rolled-back, as the comment on the ticket indicates that the patch - addressed a symptom and not the fundamental issue. -* ``easy_install`` (the command) once again honors setup.cfg if found in the - current directory. The "mis-behavior" characterized in `#99 - `_ is actually intended - behavior, and no substantial rationale was given for the deviation. diff -Nru python-setuptools-3.3/docs/pkg_resources.txt python-setuptools-20.1.1/docs/pkg_resources.txt --- python-setuptools-3.3/docs/pkg_resources.txt 2014-03-06 14:48:25.000000000 +0000 +++ python-setuptools-20.1.1/docs/pkg_resources.txt 2016-02-07 14:25:06.000000000 +0000 @@ -62,7 +62,7 @@ pluggable distribution An importable distribution whose filename unambiguously identifies its - release (i.e. project and version), and whose contents unamabiguously + release (i.e. project and version), and whose contents unambiguously specify what releases of other projects will satisfy its runtime requirements. @@ -592,9 +592,9 @@ The syntax of a requirement specifier can be defined in EBNF as follows:: - requirement ::= project_name versionspec? extras? + requirement ::= project_name extras? versionspec? versionspec ::= comparison version (',' comparison version)* - comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' + comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' | '~=' | '===' extras ::= '[' extralist? ']' extralist ::= identifier (',' identifier)* project_name ::= identifier @@ -646,13 +646,10 @@ The ``Requirement`` object's version specifiers (``.specs``) are internally sorted into ascending version order, and used to establish what ranges of versions are acceptable. Adjacent redundant conditions are effectively - consolidated (e.g. ``">1, >2"`` produces the same results as ``">1"``, and - ``"<2,<3"`` produces the same results as``"<3"``). ``"!="`` versions are + consolidated (e.g. ``">1, >2"`` produces the same results as ``">2"``, and + ``"<2,<3"`` produces the same results as``"<2"``). ``"!="`` versions are excised from the ranges they fall within. The version being tested for acceptability is then checked for membership in the resulting ranges. - (Note that providing conflicting conditions for the same version (e.g. - ``"<2,>=2"`` or ``"==2,!=2"``) is meaningless and may therefore produce - bizarre results when compared with actual version number(s).) ``__eq__(other_requirement)`` A requirement compares equal to another requirement if they have @@ -681,10 +678,7 @@ ``specs`` A list of ``(op,version)`` tuples, sorted in ascending parsed-version order. The `op` in each tuple is a comparison operator, represented as - a string. The `version` is the (unparsed) version number. The relative - order of tuples containing the same version numbers is undefined, since - having more than one operator for a given version is either redundant or - self-contradictory. + a string. The `version` is the (unparsed) version number. Entry Points @@ -967,7 +961,7 @@ ``ValueError`` is raised. parsed_version - The ``parsed_version`` is a tuple representing a "parsed" form of the + The ``parsed_version`` is an object representing a "parsed" form of the distribution's ``version``. ``dist.parsed_version`` is a shortcut for calling ``parse_version(dist.version)``. It is used to compare or sort distributions by version. (See the `Parsing Utilities`_ section below for @@ -1434,7 +1428,7 @@ that supports the full `ResourceManager API`_ documented above. ``get_resource_filename(manager, resource_name)`` - Return a true filesystem path for `resource_name`, co-ordinating the + Return a true filesystem path for `resource_name`, coordinating the extraction with `manager`, if the resource must be unpacked to the filesystem. @@ -1541,40 +1535,12 @@ ----------------- ``parse_version(version)`` - Parse a project's version string, returning a value that can be used to - compare versions by chronological order. Semantically, the format is a - rough cross between distutils' ``StrictVersion`` and ``LooseVersion`` - classes; if you give it versions that would work with ``StrictVersion``, - then they will compare the same way. Otherwise, comparisons are more like - a "smarter" form of ``LooseVersion``. It is *possible* to create - pathological version coding schemes that will fool this parser, but they - should be very rare in practice. - - The returned value will be a tuple of strings. Numeric portions of the - version are padded to 8 digits so they will compare numerically, but - without relying on how numbers compare relative to strings. Dots are - dropped, but dashes are retained. Trailing zeros between alpha segments - or dashes are suppressed, so that e.g. "2.4.0" is considered the same as - "2.4". Alphanumeric parts are lower-cased. - - The algorithm assumes that strings like "-" and any alpha string that - alphabetically follows "final" represents a "patch level". So, "2.4-1" - is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is - considered newer than "2.4-1", which in turn is newer than "2.4". - - Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that - come before "final" alphabetically) are assumed to be pre-release versions, - so that the version "2.4" is considered newer than "2.4a1". Any "-" - characters preceding a pre-release indicator are removed. (In versions of - setuptools prior to 0.6a9, "-" characters were not removed, leading to the - unintuitive result that "0.2-rc1" was considered a newer version than - "0.2".) - - Finally, to handle miscellaneous cases, the strings "pre", "preview", and - "rc" are treated as if they were "c", i.e. as though they were release - candidates, and therefore are not as new as a version string that does not - contain them. And the string "dev" is treated as if it were an "@" sign; - that is, a version coming before even "a" or "alpha". + Parsed a project's version string as defined by PEP 440. The returned + value will be an object that represents the version. These objects may + be compared to each other and sorted. The sorting algorithm is as defined + by PEP 440 with the addition that any version which is not a valid PEP 440 + version will be considered less than any valid PEP 440 version and the + invalid versions will continue sorting using the original algorithm. .. _yield_lines(): @@ -1586,7 +1552,7 @@ character is ``#`` are considered comment lines.) If `strs` is not an instance of ``basestring``, it is iterated over, and - each item is passed recursively to ``yield_lines()``, so that an arbitarily + each item is passed recursively to ``yield_lines()``, so that an arbitrarily nested sequence of strings, or sequences of sequences of strings can be flattened out to the lines contained therein. So for example, passing a file object or a list of strings to ``yield_lines`` will both work. @@ -1629,10 +1595,12 @@ See ``to_filename()``. ``safe_version(version)`` - Similar to ``safe_name()`` except that spaces in the input become dots, and - dots are allowed to exist in the output. As with ``safe_name()``, if you - are generating a filename from this you should replace any "-" characters - in the output with underscores. + This will return the normalized form of any PEP 440 version, if the version + string is not PEP 440 compatible than it is similar to ``safe_name()`` + except that spaces in the input become dots, and dots are allowed to exist + in the output. As with ``safe_name()``, if you are generating a filename + from this you should replace any "-" characters in the output with + underscores. ``safe_extra(extra)`` Return a "safe" form of an extra's name, suitable for use in a requirement diff -Nru python-setuptools-3.3/docs/python3.txt python-setuptools-20.1.1/docs/python3.txt --- python-setuptools-3.3/docs/python3.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/python3.txt 2016-02-07 14:25:06.000000000 +0000 @@ -5,16 +5,22 @@ Starting with Distribute version 0.6.2 and Setuptools 0.7, the Setuptools project supported Python 3. Installing and using setuptools for Python 3 code works exactly the same as for Python 2 -code, but Setuptools also helps you to support Python 2 and Python 3 from -the same source code by letting you run 2to3 on the code as a part of the -build process, by setting the keyword parameter ``use_2to3`` to True. +code. - -Setuptools as help during porting -================================= - -Setuptools can make the porting process much easier by automatically running -2to3 as a part of the test running. To do this you need to configure the +Setuptools provides a facility to invoke 2to3 on the code as a part of the +build process, by setting the keyword parameter ``use_2to3`` to True, but +the Setuptools strongly recommends instead developing a unified codebase +using `six `_, +`future `_, or another compatibility +library. + + +Using 2to3 +========== + +Setuptools attempts to make the porting process easier by automatically +running +2to3 as a part of running tests. To do so, you need to configure the setup.py so that you can run the unit tests with ``python setup.py test``. See :ref:`test` for more information on this. @@ -37,23 +43,23 @@ parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be skipped. -A typical setup.py can look something like this:: +An example setup.py might look something like this:: from setuptools import setup setup( name='your.module', - version = '1.0', + version='1.0', description='This is your awesome module', author='You', author_email='your@email', - package_dir = {'': 'src'}, - packages = ['your', 'you.module'], - test_suite = 'your.module.tests', - use_2to3 = True, - convert_2to3_doctests = ['src/your/module/README.txt'], - use_2to3_fixers = ['your.fixers'], - use_2to3_exclude_fixers = ['lib2to3.fixes.fix_import'], + package_dir={'': 'src'}, + packages=['your', 'you.module'], + test_suite='your.module.tests', + use_2to3=True, + convert_2to3_doctests=['src/your/module/README.txt'], + use_2to3_fixers=['your.fixers'], + use_2to3_exclude_fixers=['lib2to3.fixes.fix_import'], ) Differential conversion @@ -69,7 +75,7 @@ and no conversion will happen. In general, if code doesn't seem to be converted, deleting the build directory -and trying again is a good saferguard against the build directory getting +and trying again is a good safeguard against the build directory getting "out of sync" with the source directory. Distributing Python 3 modules @@ -86,39 +92,3 @@ 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``. - -Note on compatibility with older versions of setuptools -======================================================= - -Setuptools earlier than 0.7 does 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 -those versions of setuptools instead of Distribute under Python 2. This output -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 -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', - description='This is your awesome module', - author='You', - author_email='your@email', - package_dir = {'': 'src'}, - packages = ['your', 'you.module'], - test_suite = 'your.module.tests', - **extra - ) - -This way the parameters will only be used under Python 3, where Distribute or -Setuptools 0.7 or later is required. diff -Nru python-setuptools-3.3/docs/releases.txt python-setuptools-20.1.1/docs/releases.txt --- python-setuptools-3.3/docs/releases.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/releases.txt 2016-02-07 14:25:06.000000000 +0000 @@ -10,9 +10,54 @@ the release process. A Setuptools release manager must have maintainer access on PyPI to the -project and administrative access to the BitBucket project. +project and administrative access to the Bitbucket project. + +To make a release, run the following from a Mercurial checkout at the +revision slated for release:: + + python -m jaraco.packaging.release + +Bootstrap Bookmark +------------------ + +Setuptools has a bootstrap script (ez_setup.py) which is hosted in the +repository and must be updated with each release (to bump the default version). +The "published" version of the script is the one indicated by the ``bootstrap`` +bookmark (Mercurial) or branch (Git). + +Therefore, the latest bootstrap script can be retrieved by checking out the +repository at that bookmark. It's also possible to get the bootstrap script for +any particular release by grabbing the script from that tagged release. + +The officially-published location of the bootstrap script is hosted on Python +infrastructure (#python-infra on freenode) at https://bootstrap.pypa.io and +is updated every fifteen minutes from the bootstrap script. Sometimes, +especially when the bootstrap script is rolled back, this +process doesn't work as expected and requires manual intervention. + +Release Frequency +----------------- + +Some have asked why Setuptools is released so frequently. Because Setuptools +uses a mechanical release process, it's very easy to make releases whenever the +code is stable (tests are passing). As a result, the philosophy is to release +early and often. + +While some find the frequent releases somewhat surprising, they only empower +the user. Although releases are made frequently, users can choose the frequency +at which they use those releases. If instead Setuptools contributions were only +released in batches, the user would be constrained to only use Setuptools when +those official releases were made. With frequent releases, the user can govern +exactly how often he wishes to update. + +Frequent releases also then obviate the need for dev or beta releases in most +cases. Because releases are made early and often, bugs are discovered and +corrected quickly, in many cases before other users have yet to encounter them. Release Managers ---------------- -Currently, the project has one release manager, Jason R. Coombs. +Jason R. Coombs is the primary release manager. Additionally, the following +people have access to create releases: + +- Matthew Iversen (Ivoz) diff -Nru python-setuptools-3.3/docs/setuptools.txt python-setuptools-20.1.1/docs/setuptools.txt --- python-setuptools-3.3/docs/setuptools.txt 2014-03-16 08:53:16.000000000 +0000 +++ python-setuptools-20.1.1/docs/setuptools.txt 2016-02-12 04:41:37.000000000 +0000 @@ -15,7 +15,7 @@ automatically download and install ``setuptools`` if the user is building your package from source and doesn't have a suitable version already installed. -.. _bootstrap module: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py +.. _bootstrap module: https://bootstrap.pypa.io/ez_setup.py Feature Highlights: @@ -112,10 +112,16 @@ ) As you can see, it doesn't take much to use setuptools in a project. -Just by doing the above, this project will be able to produce eggs, upload to +Run that script in your project folder, alongside the Python packages +you have developed. + +Invoke that script to produce eggs, upload to PyPI, and automatically include all packages in the directory where the setup.py lives. See the `Command Reference`_ section below to see what -commands you can give to this setup script. +commands you can give to this setup script. For example, +to produce a source distribution, simply invoke:: + + python setup.py sdist Of course, before you release your project to PyPI, you'll want to add a bit more information to your setup script to help people find or learn about your @@ -276,7 +282,7 @@ A boolean (True or False) flag specifying whether the project can be safely installed and run from a zip file. If this argument is not supplied, the ``bdist_egg`` command will have to analyze all of your - project's contents for possible problems each time it buids an egg. + project's contents for possible problems each time it builds an egg. ``install_requires`` A string or list of strings specifying what other distributions need to @@ -308,7 +314,7 @@ (Note: projects listed in ``setup_requires`` will NOT be automatically installed on the system where the setup script is being run. They are - simply downloaded to the setup directory if they're not locally available + simply downloaded to the ./.eggs directory if they're not locally available already. If you want them to be installed, as well as being available when the setup script is run, you should add them to ``install_requires`` **and** ``setup_requires``.) @@ -426,9 +432,9 @@ ``setup()`` arguments, but that's just a normal distutils thing.) Anyway, ``find_packages()`` walks the target directory, filtering by inclusion -patterns, and finds Python -packages by looking for ``__init__.py`` files. It then filters the list of -packages using the exclusion patterns. +patterns, and finds Python packages (any directory). On Python 3.2 and +earlier, packages are only recognized if they include an ``__init__.py`` file. +Finally, exclusion patterns are applied to remove matching packages. Inclusion and exclusion patterns are package names, optionally including wildcards. For @@ -473,13 +479,13 @@ setup( # other arguments here... - entry_points = { + entry_points={ 'console_scripts': [ 'foo = my_package.some_module:main_func', 'bar = other_module:some_func', ], 'gui_scripts': [ - 'baz = my_package_gui.start_func', + 'baz = my_package_gui:start_func', ] } ) @@ -520,7 +526,7 @@ } ) -Any eggs built from the above setup script will include a short excecutable +Any eggs built from the above setup script will include a short executable prelude that imports and calls ``main_func()`` from ``my_package.some_module``. The prelude can be run on Unix-like platforms (including Mac and Linux) by invoking the egg with ``/bin/sh``, or by enabling execute permissions on the @@ -1467,7 +1473,7 @@ over having to manually write a ``MANIFEST.in`` file and try to keep it in sync with your project. So, if you are using CVS or Subversion, and your source distributions only need to include files that you're tracking in -revision control, don't create a a ``MANIFEST.in`` file for your project. +revision control, don't create a ``MANIFEST.in`` file for your project. (And, if you already have one, you might consider deleting it the next time you would otherwise have to change it.) @@ -2180,7 +2186,7 @@ setup.py build --compiler=mingw32 saveopts -The ``saveopts`` command saves all options for every commmand specified on the +The ``saveopts`` command saves all options for every command specified on the command line to the project's local ``setup.cfg`` file, unless you use one of the `configuration file options`_ to change where the options are saved. For example, this command does the same as above, but saves the compiler setting @@ -2322,54 +2328,25 @@ ``upload`` - Upload source and/or egg distributions to PyPI =========================================================== -PyPI now supports uploading project files for redistribution; uploaded files -are easily found by EasyInstall, even if you don't have download links on your -project's home page. - -Although Python 2.5 will support uploading all types of distributions to PyPI, -setuptools only supports source distributions and eggs. (This is partly -because PyPI's upload support is currently broken for various other file -types.) To upload files, you must include the ``upload`` command *after* the -``sdist`` or ``bdist_egg`` commands on the setup command line. For example:: - - setup.py bdist_egg upload # create an egg and upload it - setup.py sdist upload # create a source distro and upload it - setup.py sdist bdist_egg upload # create and upload both - -Note that to upload files for a project, the corresponding version must already -be registered with PyPI, using the distutils ``register`` command. It's -usually a good idea to include the ``register`` command at the start of the -command line, so that any registration problems can be found and fixed before -building and uploading the distributions, e.g.:: - - setup.py register sdist bdist_egg upload - -This will update PyPI's listing for your project's current version. - -Note, by the way, that the metadata in your ``setup()`` call determines what -will be listed in PyPI for your package. Try to fill out as much of it as -possible, as it will save you a lot of trouble manually adding and updating -your PyPI listings. Just put it in ``setup.py`` and use the ``register`` -comamnd to keep PyPI up to date. - -The ``upload`` command has a few options worth noting: - -``--sign, -s`` - Sign each uploaded file using GPG (GNU Privacy Guard). The ``gpg`` program - must be available for execution on the system ``PATH``. - -``--identity=NAME, -i NAME`` - Specify the identity or key name for GPG to use when signing. The value of - this option will be passed through the ``--local-user`` option of the - ``gpg`` program. - -``--show-response`` - Display the full response text from server; this is useful for debugging - PyPI problems. +The ``upload`` command is implemented and `documented +`_ +in distutils. + +Setuptools augments the ``upload`` command with support +for `keyring `_, +allowing the password to be stored in a secure +location and not in plaintext in the .pypirc file. To use +keyring, first install keyring and set the password for +the relevant repository, e.g.:: + + python -m keyring set + Password for '' in '': ******** + +Then, in .pypirc, set the repository configuration as normal, +but omit the password. Thereafter, uploads will use the +password from the keyring. -``--repository=URL, -r URL`` - The URL of the repository to upload to. Defaults to - https://pypi.python.org/pypi (i.e., the main PyPI installation). +New in 20.1: Added keyring support. .. _upload_docs: @@ -2435,7 +2412,7 @@ -------------------------------- -Extending and Reusing Distribute +Extending and Reusing Setuptools -------------------------------- Creating ``distutils`` Extensions @@ -2595,8 +2572,8 @@ Adding Support for Other Revision Control Systems ------------------------------------------------- -If you would like to create a plugin for ``setuptools`` to find files in other -source control systems besides CVS and Subversion, you can do so by adding an +If you would like to create a plugin for ``setuptools`` to find files in +source control systems, you can do so by adding an entry point to the ``setuptools.file_finders`` group. The entry point should be a function accepting a single directory name, and should yield all the filenames within that directory (and any subdirectories thereof) that @@ -2652,9 +2629,7 @@ ----------------------- Sorry, this section isn't written yet, and neither is a lot of what's below -this point, except for the change log. You might want to `subscribe to changes -in this page `_ to see when new documentation is -added or updated. +this point. XXX diff -Nru python-setuptools-3.3/docs/using.txt python-setuptools-20.1.1/docs/using.txt --- python-setuptools-3.3/docs/using.txt 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/docs/using.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -================================ -Using Setuptools in your project -================================ - -To use Setuptools in your project, the recommended way is to ship -`ez_setup.py` alongside your `setup.py` script and call -it at the very beginning of `setup.py` like this:: - - from ez_setup import use_setuptools - use_setuptools() diff -Nru python-setuptools-3.3/ez_setup.py python-setuptools-20.1.1/ez_setup.py --- python-setuptools-3.3/ez_setup.py 2014-03-16 08:01:53.000000000 +0000 +++ python-setuptools-20.1.1/ez_setup.py 2016-02-07 14:25:06.000000000 +0000 @@ -1,18 +1,11 @@ #!/usr/bin/env python -"""Bootstrap setuptools installation -To use setuptools in your package's setup.py, include this -file in the same directory and add this to the top of your setup.py:: - - from ez_setup import use_setuptools - use_setuptools() - -To require a specific version of setuptools, set a download -mirror, or use an alternate download directory, simply supply -the appropriate options to ``use_setuptools()``. +""" +Setuptools bootstrapping installer. -This file can also be run as a script to install or upgrade setuptools. +Run this script to install or upgrade setuptools. """ + import os import shutil import sys @@ -23,19 +16,31 @@ import platform import textwrap import contextlib +import json +import codecs from distutils import log try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + +try: from site import USER_SITE except ImportError: USER_SITE = None -DEFAULT_VERSION = "3.3" +LATEST = object() +DEFAULT_VERSION = LATEST DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" +DEFAULT_SAVE_DIR = os.curdir + def _python_cmd(*args): """ + Execute a command. + Return True if the command succeeded. """ args = (sys.executable,) + args @@ -43,6 +48,7 @@ def _install(archive_filename, install_args=()): + """Install Setuptools.""" with archive_context(archive_filename): # installing log.warn('Installing Setuptools') @@ -54,6 +60,7 @@ def _build_egg(egg, archive_filename, to_dir): + """Build Setuptools egg.""" with archive_context(archive_filename): # building an egg log.warn('Building a Setuptools egg in %s', to_dir) @@ -64,28 +71,36 @@ raise IOError('Could not build the egg.') -def get_zip_class(): - """ - Supplement ZipFile class to support context manager for Python 2.6 - """ - class ContextualZipFile(zipfile.ZipFile): - def __enter__(self): - return self - def __exit__(self, type, value, traceback): - self.close - return zipfile.ZipFile if hasattr(zipfile.ZipFile, '__exit__') else \ - ContextualZipFile +class ContextualZipFile(zipfile.ZipFile): + + """Supplement ZipFile class to support context manager for Python 2.6.""" + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + def __new__(cls, *args, **kwargs): + """Construct a ZipFile or ContextualZipFile as appropriate.""" + if hasattr(zipfile.ZipFile, '__exit__'): + return zipfile.ZipFile(*args, **kwargs) + return super(ContextualZipFile, cls).__new__(cls) @contextlib.contextmanager def archive_context(filename): - # extracting the archive + """ + Unzip filename to a temporary directory, set to the cwd. + + The unzipped target is cleaned up after. + """ tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) - with get_zip_class()(filename) as archive: + with ContextualZipFile(filename) as archive: archive.extractall() # going in the directory @@ -100,6 +115,7 @@ def _do_download(version, download_base, to_dir, download_delay): + """Download Setuptools.""" egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg' % (version, sys.version_info[0], sys.version_info[1])) if not os.path.exists(egg): @@ -111,47 +127,84 @@ # Remove previously-imported pkg_resources if present (see # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details). if 'pkg_resources' in sys.modules: - del sys.modules['pkg_resources'] + _unload_pkg_resources() import setuptools setuptools.bootstrap_install_from = egg -def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, download_delay=15): +def use_setuptools( + version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=DEFAULT_SAVE_DIR, download_delay=15): + """ + Ensure that a setuptools version is installed. + + Return None. Raise SystemExit if the requested version + or later cannot be installed. + """ + version = _resolve_version(version) to_dir = os.path.abspath(to_dir) + + # prior to importing, capture the module state for + # representative modules. rep_modules = 'pkg_resources', 'setuptools' imported = set(sys.modules).intersection(rep_modules) + try: import pkg_resources - except ImportError: - return _do_download(version, download_base, to_dir, download_delay) - try: pkg_resources.require("setuptools>=" + version) + # a suitable version is already installed return + except ImportError: + # pkg_resources not available; setuptools is not installed; download + pass except pkg_resources.DistributionNotFound: - return _do_download(version, download_base, to_dir, download_delay) + # no version of setuptools was found; allow download + pass except pkg_resources.VersionConflict as VC_err: if imported: - msg = textwrap.dedent(""" - The required version of setuptools (>={version}) is not available, - and can't be installed while this script is running. Please - install a more recent version first, using - 'easy_install -U setuptools'. - - (Currently using {VC_err.args[0]!r}) - """).format(VC_err=VC_err, version=version) - sys.stderr.write(msg) - sys.exit(2) - - # otherwise, reload ok - del pkg_resources, sys.modules['pkg_resources'] - return _do_download(version, download_base, to_dir, download_delay) + _conflict_bail(VC_err, version) + + # otherwise, unload pkg_resources to allow the downloaded version to + # take precedence. + del pkg_resources + _unload_pkg_resources() + + return _do_download(version, download_base, to_dir, download_delay) + + +def _conflict_bail(VC_err, version): + """ + Setuptools was imported prior to invocation, so it is + unsafe to unload it. Bail out. + """ + conflict_tmpl = textwrap.dedent(""" + The required version of setuptools (>={version}) is not available, + and can't be installed while this script is running. Please + install a more recent version first, using + 'easy_install -U setuptools'. + + (Currently using {VC_err.args[0]!r}) + """) + msg = conflict_tmpl.format(**locals()) + sys.stderr.write(msg) + sys.exit(2) + + +def _unload_pkg_resources(): + del_modules = [ + name for name in sys.modules + if name.startswith('pkg_resources') + ] + for mod_name in del_modules: + del sys.modules[mod_name] + def _clean_check(cmd, target): """ - Run the command to download target. If the command fails, clean up before - re-raising the error. + Run the command to download target. + + If the command fails, clean up before re-raising the error. """ try: subprocess.check_call(cmd) @@ -160,115 +213,110 @@ os.unlink(target) raise + def download_file_powershell(url, target): """ - Download the file at url to target using Powershell (which will validate - trust). Raise an exception if the command cannot complete. + Download the file at url to target using Powershell. + + Powershell will validate trust. + Raise an exception if the command cannot complete. """ target = os.path.abspath(target) + ps_cmd = ( + "[System.Net.WebRequest]::DefaultWebProxy.Credentials = " + "[System.Net.CredentialCache]::DefaultCredentials; " + '(new-object System.Net.WebClient).DownloadFile("%(url)s", "%(target)s")' + % locals() + ) cmd = [ 'powershell', '-Command', - "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(), + ps_cmd, ] _clean_check(cmd, target) + def has_powershell(): + """Determine if Powershell is available.""" if platform.system() != 'Windows': return False cmd = ['powershell', '-Command', 'echo test'] - devnull = open(os.path.devnull, 'wb') - try: + with open(os.path.devnull, 'wb') as devnull: try: subprocess.check_call(cmd, stdout=devnull, stderr=devnull) - except: + except Exception: return False - finally: - devnull.close() return True - download_file_powershell.viable = has_powershell + def download_file_curl(url, target): cmd = ['curl', url, '--silent', '--output', target] _clean_check(cmd, target) + def has_curl(): cmd = ['curl', '--version'] - devnull = open(os.path.devnull, 'wb') - try: + with open(os.path.devnull, 'wb') as devnull: try: subprocess.check_call(cmd, stdout=devnull, stderr=devnull) - except: + except Exception: return False - finally: - devnull.close() return True - download_file_curl.viable = has_curl + def download_file_wget(url, target): cmd = ['wget', url, '--quiet', '--output-document', target] _clean_check(cmd, target) + def has_wget(): cmd = ['wget', '--version'] - devnull = open(os.path.devnull, 'wb') - try: + with open(os.path.devnull, 'wb') as devnull: try: subprocess.check_call(cmd, stdout=devnull, stderr=devnull) - except: + except Exception: return False - finally: - devnull.close() return True - download_file_wget.viable = has_wget + def download_file_insecure(url, target): - """ - Use Python to download the file, even though it cannot authenticate the - connection. - """ + """Use Python to download the file, without connection authentication.""" + src = urlopen(url) try: - from urllib.request import urlopen - except ImportError: - from urllib2 import urlopen - src = dst = None - try: - src = urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. + # Read all the data in one block. data = src.read() - dst = open(target, "wb") - dst.write(data) finally: - if src: - src.close() - if dst: - dst.close() + src.close() + # Write all the data in one block to avoid creating a partial file. + with open(target, "wb") as dst: + dst.write(data) download_file_insecure.viable = lambda: True + def get_best_downloader(): - downloaders = [ + downloaders = ( download_file_powershell, download_file_curl, download_file_wget, download_file_insecure, - ] + ) + viable_downloaders = (dl for dl in downloaders if dl.viable()) + return next(viable_downloaders, None) - for dl in downloaders: - if dl.viable(): - return dl -def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader): +def download_setuptools( + version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=DEFAULT_SAVE_DIR, delay=15, + downloader_factory=get_best_downloader): """ - Download setuptools from a specified location and return its filename + Download setuptools from a specified location and return its filename. `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end + as an sdist for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. @@ -276,6 +324,7 @@ ``downloader_factory`` should be a function taking no arguments and returning a function for downloading a URL to a target. """ + version = _resolve_version(version) # making sure we use the absolute path to_dir = os.path.abspath(to_dir) zip_name = "setuptools-%s.zip" % version @@ -287,16 +336,38 @@ downloader(url, saveto) return os.path.realpath(saveto) + +def _resolve_version(version): + """ + Resolve LATEST version + """ + if version is not LATEST: + return version + + resp = urlopen('https://pypi.python.org/pypi/setuptools/json') + with contextlib.closing(resp): + try: + charset = resp.info().get_content_charset() + except Exception: + # Python 2 compat; assume UTF-8 + charset = 'UTF-8' + reader = codecs.getreader(charset) + doc = json.load(reader(resp)) + + return str(doc['info']['version']) + + def _build_install_args(options): """ - Build the arguments to 'python setup.py install' on the setuptools package + Build the arguments to 'python setup.py install' on the setuptools package. + + Returns list of command line arguments. """ return ['--user'] if options.user_install else [] + def _parse_args(): - """ - Parse the command line for options - """ + """Parse the command line for options.""" parser = optparse.OptionParser() parser.add_option( '--user', dest='user_install', action='store_true', default=False, @@ -314,18 +385,30 @@ '--version', help="Specify which version to download", default=DEFAULT_VERSION, ) + parser.add_option( + '--to-dir', + help="Directory to save (and re-use) package", + default=DEFAULT_SAVE_DIR, + ) options, args = parser.parse_args() # positional arguments are ignored return options + +def _download_args(options): + """Return args for download_setuptools function from cmdline args.""" + return dict( + version=options.version, + download_base=options.download_base, + downloader_factory=options.downloader_factory, + to_dir=options.to_dir, + ) + + def main(): - """Install or upgrade setuptools and EasyInstall""" + """Install or upgrade setuptools and EasyInstall.""" options = _parse_args() - archive = download_setuptools( - version=options.version, - download_base=options.download_base, - downloader_factory=options.downloader_factory, - ) + archive = download_setuptools(**_download_args(options)) return _install(archive, _build_install_args(options)) if __name__ == '__main__': diff -Nru python-setuptools-3.3/MANIFEST.in python-setuptools-20.1.1/MANIFEST.in --- python-setuptools-3.3/MANIFEST.in 2014-02-12 03:53:21.000000000 +0000 +++ python-setuptools-20.1.1/MANIFEST.in 2016-02-07 14:25:06.000000000 +0000 @@ -1,10 +1,13 @@ -recursive-include setuptools *.py *.txt *.exe *.xml -recursive-include tests *.py *.c *.pyx *.txt -recursive-include setuptools/tests *.html entries* -recursive-include setuptools/tests/svn_data *.zip +recursive-include setuptools *.py *.exe *.xml +recursive-include tests *.py +recursive-include setuptools/tests *.html recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html recursive-include _markerlib *.py +recursive-include setuptools/_vendor * +recursive-include pkg_resources *.py *.txt include *.py include *.txt include MANIFEST.in include launcher.c +include msvc-build-launcher.cmd +include pytest.ini diff -Nru python-setuptools-3.3/msvc-build-launcher.cmd python-setuptools-20.1.1/msvc-build-launcher.cmd --- python-setuptools-3.3/msvc-build-launcher.cmd 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/msvc-build-launcher.cmd 2016-01-30 17:43:56.000000000 +0000 @@ -0,0 +1,55 @@ +@echo off + +REM Use old Windows SDK 6.1 so created .exe will be compatible with +REM old Windows versions. +REM Windows SDK 6.1 may be downloaded at: +REM http://www.microsoft.com/en-us/download/details.aspx?id=11310 +set PATH_OLD=%PATH% + +REM The SDK creates a false install of Visual Studio at one of these locations +set PATH=C:\Program Files\Microsoft Visual Studio 9.0\VC\bin;%PATH% +set PATH=C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin;%PATH% + +REM set up the environment to compile to x86 +call VCVARS32 +if "%ERRORLEVEL%"=="0" ( + cl /D "GUI=0" /D "WIN32_LEAN_AND_MEAN" launcher.c /O2 /link /MACHINE:x86 /SUBSYSTEM:CONSOLE /out:setuptools/cli-32.exe + cl /D "GUI=1" /D "WIN32_LEAN_AND_MEAN" launcher.c /O2 /link /MACHINE:x86 /SUBSYSTEM:WINDOWS /out:setuptools/gui-32.exe +) else ( + echo Windows SDK 6.1 not found to build Windows 32-bit version +) + +REM buildout (and possibly other implementations) currently depend on +REM the 32-bit launcher scripts without the -32 in the filename, so copy them +REM there for now. +copy setuptools/cli-32.exe setuptools/cli.exe +copy setuptools/gui-32.exe setuptools/gui.exe + +REM now for 64-bit +REM Use the x86_amd64 profile, which is the 32-bit cross compiler for amd64 +call VCVARSx86_amd64 +if "%ERRORLEVEL%"=="0" ( + cl /D "GUI=0" /D "WIN32_LEAN_AND_MEAN" launcher.c /O2 /link /MACHINE:x64 /SUBSYSTEM:CONSOLE /out:setuptools/cli-64.exe + cl /D "GUI=1" /D "WIN32_LEAN_AND_MEAN" launcher.c /O2 /link /MACHINE:x64 /SUBSYSTEM:WINDOWS /out:setuptools/gui-64.exe +) else ( + echo Windows SDK 6.1 not found to build Windows 64-bit version +) + +REM Windows RT ARM build requires both freeware +REM "Visual Studio Express 2012 for Windows 8" and +REM "Visual Studio Express 2012 for Windows Desktop" to be installed from +REM http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products +set PATH=%PATH_OLD% +set PATH=C:\Program Files\Microsoft Visual Studio 11.0\VC;%PATH% +set PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC;%PATH% +call VCVARSALL x86_arm >nul 2>&1 +if "%ERRORLEVEL%"=="0" ( + echo Building Windows RT Version ... + cl /D "GUI=0" /D "WIN32_LEAN_AND_MEAN" /D _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE launcher.c /O2 /link /MACHINE:ARM /SUBSYSTEM:CONSOLE /out:setuptools/cli-arm-32.exe + cl /D "GUI=1" /D "WIN32_LEAN_AND_MEAN" /D _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE launcher.c /O2 /link /MACHINE:ARM /SUBSYSTEM:WINDOWS /out:setuptools/gui-arm-32.exe +) else ( + echo Visual Studio ^(Express^) 2012 not found to build Windows RT Version +) + +set PATH=%PATH_OLD% + diff -Nru python-setuptools-3.3/PKG-INFO python-setuptools-20.1.1/PKG-INFO --- python-setuptools-3.3/PKG-INFO 2014-03-16 09:04:38.000000000 +0000 +++ python-setuptools-20.1.1/PKG-INFO 2016-02-12 16:11:11.000000000 +0000 @@ -1,1879 +1,261 @@ -Metadata-Version: 1.1 -Name: setuptools -Version: 3.3 -Summary: Easily download, build, install, upgrade, and uninstall Python packages -Home-page: https://pypi.python.org/pypi/setuptools -Author: Python Packaging Authority -Author-email: distutils-sig@python.org -License: PSF or ZPL -Description: =============================== - Installing and Using Setuptools - =============================== - - .. contents:: **Table of Contents** - - - ------------------------- - Installation Instructions - ------------------------- - - The recommended way to bootstrap setuptools on any system is to download - `ez_setup.py`_ and run it using the target Python environment. Different - operating systems have different recommended techniques to accomplish this - basic routine, so below are some examples to get you started. - - Setuptools requires Python 2.6 or later. To install setuptools - on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x - `_. - - The link provided to ez_setup.py is a bookmark to bootstrap script for the - latest known stable release. - - .. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py - - Windows 8 (Powershell) - ====================== - - For best results, uninstall previous versions FIRST (see `Uninstalling`_). - - Using Windows 8 or later, it's possible to install with one simple Powershell - command. Start up Powershell and paste this command:: - - > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | python - - - You must start the Powershell with Administrative privileges or you may choose - to install a user-local installation:: - - > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | python - --user - - If you have Python 3.3 or later, you can use the ``py`` command to install to - different Python versions. For example, to install to Python 3.3 if you have - Python 2.7 installed:: - - > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | py -3 - - - The recommended way to install setuptools on Windows is to download - `ez_setup.py`_ and run it. The script will download the appropriate .egg - file and install it for you. - - Once installation is complete, you will find an ``easy_install`` program in - your Python ``Scripts`` subdirectory. For simple invocation and best results, - add this directory to your ``PATH`` environment variable, if it is not already - present. If you did a user-local install, the ``Scripts`` subdirectory is - ``$env:APPDATA\Python\Scripts``. - - - Windows 7 (or graphical install) - ================================ - - For Windows 7 and earlier, download `ez_setup.py`_ using your favorite web - browser or other technique and "run" that file. - - - Unix (wget) - =========== - - Most Linux distributions come with wget. - - Download `ez_setup.py`_ and run it using the target Python version. The script - will download the appropriate version and install it for you:: - - > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python - - Note that you will may need to invoke the command with superuser privileges to - install to the system Python:: - - > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | sudo python - - Alternatively, Setuptools may be installed to a user-local path:: - - > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python - --user - - Unix including Mac OS X (curl) - ============================== - - If your system has curl installed, follow the ``wget`` instructions but - replace ``wget`` with ``curl`` and ``-O`` with ``-o``. For example:: - - > curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -o - | python - - - Advanced Installation - ===================== - - For more advanced installation options, such as installing to custom - locations or prefixes, download and extract the source - tarball from `Setuptools on PyPI `_ - and run setup.py with any supported distutils and Setuptools options. - For example:: - - setuptools-x.x$ python setup.py install --prefix=/opt/setuptools - - Use ``--help`` to get a full options list, but we recommend consulting - the `EasyInstall manual`_ for detailed instructions, especially `the section - on custom installation locations`_. - - .. _EasyInstall manual: https://pythonhosted.org/setuptools/EasyInstall - .. _the section on custom installation locations: https://pythonhosted.org/setuptools/EasyInstall#custom-installation-locations - - - Downloads - ========= - - All setuptools downloads can be found at `the project's home page in the Python - Package Index`_. Scroll to the very bottom of the page to find the links. - - .. _the project's home page in the Python Package Index: https://pypi.python.org/pypi/setuptools - - In addition to the PyPI downloads, the development version of ``setuptools`` - is available from the `Bitbucket repo`_, and in-development versions of the - `0.6 branch`_ are available as well. - - .. _Bitbucket repo: https://bitbucket.org/pypa/setuptools/get/default.tar.gz#egg=setuptools-dev - .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 - - Uninstalling - ============ - - On Windows, if Setuptools was installed using an ``.exe`` or ``.msi`` - installer, simply use the uninstall feature of "Add/Remove Programs" in the - Control Panel. - - Otherwise, to uninstall Setuptools or Distribute, regardless of the Python - version, delete all ``setuptools*`` and ``distribute*`` files and - directories from your system's ``site-packages`` directory - (and any other ``sys.path`` directories) FIRST. - - If you are upgrading or otherwise plan to re-install Setuptools or Distribute, - nothing further needs to be done. If you want to completely remove Setuptools, - you may also want to remove the 'easy_install' and 'easy_install-x.x' scripts - and associated executables installed to the Python scripts directory. - - -------------------------------- - Using Setuptools and EasyInstall - -------------------------------- - - Here are some of the available manuals, tutorials, and other resources for - learning about Setuptools, Python Eggs, and EasyInstall: - - * `The EasyInstall user's guide and reference manual`_ - * `The setuptools Developer's Guide`_ - * `The pkg_resources API reference`_ - * `Package Compatibility Notes`_ (user-maintained) - * `The Internal Structure of Python Eggs`_ - - Questions, comments, and bug reports should be directed to the `distutils-sig - mailing list`_. If you have written (or know of) any tutorials, documentation, - plug-ins, or other resources for setuptools users, please let us know about - them there, so this reference list can be updated. If you have working, - *tested* patches to correct problems or add features, you may submit them to - the `setuptools bug tracker`_. - - .. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/issues - .. _Package Compatibility Notes: https://pythonhosted.org/setuptools/PackageNotes - .. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html - .. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html - .. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html - .. _The EasyInstall user's guide and reference manual: https://pythonhosted.org/setuptools/easy_install.html - .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ - - - ------- - Credits - ------- - - * The original design for the ``.egg`` format and the ``pkg_resources`` API was - co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first - version of ``pkg_resources``, and supplied the OS X operating system version - compatibility algorithm. - - * Ian Bicking implemented many early "creature comfort" features of - easy_install, including support for downloading via Sourceforge and - Subversion repositories. Ian's comments on the Web-SIG about WSGI - application deployment also inspired the concept of "entry points" in eggs, - and he has given talks at PyCon and elsewhere to inform and educate the - community about eggs and setuptools. - - * Jim Fulton contributed time and effort to build automated tests of various - aspects of ``easy_install``, and supplied the doctests for the command-line - ``.exe`` wrappers on Windows. - - * Phillip J. Eby is the seminal author of setuptools, and - first proposed the idea of an importable binary distribution format for - Python application plug-ins. - - * Significant parts of the implementation of setuptools were funded by the Open - Source Applications Foundation, to provide a plug-in infrastructure for the - Chandler PIM application. In addition, many OSAF staffers (such as Mike - "Code Bear" Taylor) contributed their time and stress as guinea pigs for the - use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) - - * Tarek Ziadé is the principal author of the Distribute fork, which - re-invigorated the community on the project, encouraged renewed innovation, - and addressed many defects. - - * Since the merge with Distribute, Jason R. Coombs is the - maintainer of setuptools. The project is maintained in coordination with - the Python Packaging Authority (PyPA) and the larger Python community. - - .. _files: - - ======= - CHANGES - ======= - - --- - 3.3 - --- - - * Add ``include`` parameter to ``setuptools.find_packages()``. - - --- - 3.2 - --- - - * `Pull Request #39 `_: Add support for C++ targets from Cython ``.pyx`` files. - * `Issue #162 `_: Update dependency on certifi to 1.0.1. - * `Issue #164 `_: Update dependency on wincertstore to 0.2. - - --- - 3.1 - --- - - * `Issue #161 `_: Restore Features functionality to allow backward compatibility - (for Features) until the uses of that functionality is sufficiently removed. - - ----- - 3.0.2 - ----- - - * Correct typo in previous bugfix. - - ----- - 3.0.1 - ----- - - * `Issue #157 `_: Restore support for Python 2.6 in bootstrap script where - ``zipfile.ZipFile`` does not yet have support for context managers. - - --- - 3.0 - --- - - * `Issue #125 `_: Prevent Subversion support from creating a ~/.subversion - directory just for checking the presence of a Subversion repository. - * `Issue #12 `_: Namespace packages are now imported lazily. That is, the mere - declaration of a namespace package in an egg on ``sys.path`` no longer - causes it to be imported when ``pkg_resources`` is imported. Note that this - change means that all of a namespace package's ``__init__.py`` files must - include a ``declare_namespace()`` call in order to ensure that they will be - handled properly at runtime. In 2.x it was possible to get away without - including the declaration, but only at the cost of forcing namespace - packages to be imported early, which 3.0 no longer does. - * `Issue #148 `_: When building (bdist_egg), setuptools no longer adds - ``__init__.py`` files to namespace packages. Any packages that rely on this - behavior will need to create ``__init__.py`` files and include the - ``declare_namespace()``. - * `Issue #7 `_: Setuptools itself is now distributed as a zip archive in addition to - tar archive. ez_setup.py now uses zip archive. This approach avoids the potential - security vulnerabilities presented by use of tar archives in ez_setup.py. - It also leverages the security features added to ZipFile.extract in Python 2.7.4. - * `Issue #65 `_: Removed deprecated Features functionality. - * `Pull Request #28 `_: Remove backport of ``_bytecode_filenames`` which is - available in Python 2.6 and later, but also has better compatibility with - Python 3 environments. - * `Issue #156 `_: Fix spelling of __PYVENV_LAUNCHER__ variable. - - --- - 2.2 - --- - - * `Issue #141 `_: Restored fix for allowing setup_requires dependencies to - override installed dependencies during setup. - * `Issue #128 `_: Fixed issue where only the first dependency link was honored - in a distribution where multiple dependency links were supplied. - - ----- - 2.1.2 - ----- - - * `Issue #144 `_: Read long_description using codecs module to avoid errors - installing on systems where LANG=C. - - ----- - 2.1.1 - ----- - - * `Issue #139 `_: Fix regression in re_finder for CVS repos (and maybe Git repos - as well). - - --- - 2.1 - --- - - * `Issue #129 `_: Suppress inspection of ``*.whl`` files when searching for files - in a zip-imported file. - * `Issue #131 `_: Fix RuntimeError when constructing an egg fetcher. - - ----- - 2.0.2 - ----- - - * Fix NameError during installation with Python implementations (e.g. Jython) - not containing parser module. - * Fix NameError in ``sdist:re_finder``. - - ----- - 2.0.1 - ----- - - * `Issue #124 `_: Fixed error in list detection in upload_docs. - - --- - 2.0 - --- - - * `Issue #121 `_: Exempt lib2to3 pickled grammars from DirectorySandbox. - * `Issue #41 `_: Dropped support for Python 2.4 and Python 2.5. Clients requiring - setuptools for those versions of Python should use setuptools 1.x. - * Removed ``setuptools.command.easy_install.HAS_USER_SITE``. Clients - expecting this boolean variable should use ``site.ENABLE_USER_SITE`` - instead. - * Removed ``pkg_resources.ImpWrapper``. Clients that expected this class - should use ``pkgutil.ImpImporter`` instead. - - ----- - 1.4.2 - ----- - - * `Issue #116 `_: Correct TypeError when reading a local package index on Python - 3. - - ----- - 1.4.1 - ----- - - * `Issue #114 `_: Use ``sys.getfilesystemencoding`` for decoding config in - ``bdist_wininst`` distributions. - - * `Issue #105 `_ and `Issue #113 `_: Establish a more robust technique for - determining the terminal encoding:: - - 1. Try ``getpreferredencoding`` - 2. If that returns US_ASCII or None, try the encoding from - ``getdefaultlocale``. If that encoding was a "fallback" because Python - could not figure it out from the environment or OS, encoding remains - unresolved. - 3. If the encoding is resolved, then make sure Python actually implements - the encoding. - 4. On the event of an error or unknown codec, revert to fallbacks - (UTF-8 on Darwin, ASCII on everything else). - 5. On the encoding is 'mac-roman' on Darwin, use UTF-8 as 'mac-roman' was - a bug on older Python releases. - - On a side note, it would seem that the encoding only matters for when SVN - does not yet support ``--xml`` and when getting repository and svn version - numbers. The ``--xml`` technique should yield UTF-8 according to some - messages on the SVN mailing lists. So if the version numbers are always - 7-bit ASCII clean, it may be best to only support the file parsing methods - for legacy SVN releases and support for SVN without the subprocess command - would simple go away as support for the older SVNs does. - - --- - 1.4 - --- - - * `Issue #27 `_: ``easy_install`` will now use credentials from .pypirc if - present for connecting to the package index. - * `Pull Request #21 `_: Omit unwanted newlines in ``package_index._encode_auth`` - when the username/password pair length indicates wrapping. - - ----- - 1.3.2 - ----- - - * `Issue #99 `_: Fix filename encoding issues in SVN support. - - ----- - 1.3.1 - ----- - - * Remove exuberant warning in SVN support when SVN is not used. - - --- - 1.3 - --- - - * Address security vulnerability in SSL match_hostname check as reported in - `Python #17997 `_. - * Prefer `backports.ssl_match_hostname - `_ for backport - implementation if present. - * Correct NameError in ``ssl_support`` module (``socket.error``). - - --- - 1.2 - --- - - * `Issue #26 `_: Add support for SVN 1.7. Special thanks to Philip Thiem for the - contribution. - * `Issue #93 `_: Wheels are now distributed with every release. Note that as - reported in `Issue #108 `_, as of Pip 1.4, scripts aren't installed properly - from wheels. Therefore, if using Pip to install setuptools from a wheel, - the ``easy_install`` command will not be available. - * Setuptools "natural" launcher support, introduced in 1.0, is now officially - supported. - - ----- - 1.1.7 - ----- - - * Fixed behavior of NameError handling in 'script template (dev).py' (script - launcher for 'develop' installs). - * ``ez_setup.py`` now ensures partial downloads are cleaned up following - a failed download. - * `Distribute #363 `_ and `Issue #55 `_: Skip an sdist test that fails on locales - other than UTF-8. - - ----- - 1.1.6 - ----- - - * `Distribute #349 `_: ``sandbox.execfile`` now opens the target file in binary - mode, thus honoring a BOM in the file when compiled. - - ----- - 1.1.5 - ----- - - * `Issue #69 `_: Second attempt at fix (logic was reversed). - - ----- - 1.1.4 - ----- - - * `Issue #77 `_: Fix error in upload command (Python 2.4). - - ----- - 1.1.3 - ----- - - * Fix NameError in previous patch. - - ----- - 1.1.2 - ----- - - * `Issue #69 `_: Correct issue where 404 errors are returned for URLs with - fragments in them (such as #egg=). - - ----- - 1.1.1 - ----- - - * `Issue #75 `_: Add ``--insecure`` option to ez_setup.py to accommodate - environments where a trusted SSL connection cannot be validated. - * `Issue #76 `_: Fix AttributeError in upload command with Python 2.4. - - --- - 1.1 - --- - - * `Issue #71 `_ (`Distribute #333 `_): EasyInstall now puts less emphasis on the - condition when a host is blocked via ``--allow-hosts``. - * `Issue #72 `_: Restored Python 2.4 compatibility in ``ez_setup.py``. - - --- - 1.0 - --- - - * `Issue #60 `_: On Windows, Setuptools supports deferring to another launcher, - such as Vinay Sajip's `pylauncher `_ - (included with Python 3.3) to launch console and GUI scripts and not install - its own launcher executables. This experimental functionality is currently - only enabled if the ``SETUPTOOLS_LAUNCHER`` environment variable is set to - "natural". In the future, this behavior may become default, but only after - it has matured and seen substantial adoption. The ``SETUPTOOLS_LAUNCHER`` - also accepts "executable" to force the default behavior of creating launcher - executables. - * `Issue #63 `_: Bootstrap script (ez_setup.py) now prefers Powershell, curl, or - wget for retrieving the Setuptools tarball for improved security of the - install. The script will still fall back to a simple ``urlopen`` on - platforms that do not have these tools. - * `Issue #65 `_: Deprecated the ``Features`` functionality. - * `Issue #52 `_: In ``VerifyingHTTPSConn``, handle a tunnelled (proxied) - connection. - - Backward-Incompatible Changes - ============================= - - This release includes a couple of backward-incompatible changes, but most if - not all users will find 1.0 a drop-in replacement for 0.9. - - * `Issue #50 `_: Normalized API of environment marker support. Specifically, - removed line number and filename from SyntaxErrors when returned from - `pkg_resources.invalid_marker`. Any clients depending on the specific - string representation of exceptions returned by that function may need to - be updated to account for this change. - * `Issue #50 `_: SyntaxErrors generated by `pkg_resources.invalid_marker` are - normalized for cross-implementation consistency. - * Removed ``--ignore-conflicts-at-my-risk`` and ``--delete-conflicting`` - options to easy_install. These options have been deprecated since 0.6a11. - - ----- - 0.9.8 - ----- - - * `Issue #53 `_: Fix NameErrors in `_vcs_split_rev_from_url`. - - ----- - 0.9.7 - ----- - - * `Issue #49 `_: Correct AttributeError on PyPy where a hashlib.HASH object does - not have a `.name` attribute. - * `Issue #34 `_: Documentation now refers to bootstrap script in code repository - referenced by bookmark. - * Add underscore-separated keys to environment markers (markerlib). - - ----- - 0.9.6 - ----- - - * `Issue #44 `_: Test failure on Python 2.4 when MD5 hash doesn't have a `.name` - attribute. - - ----- - 0.9.5 - ----- - - * `Python #17980 `_: Fix security vulnerability in SSL certificate validation. - - ----- - 0.9.4 - ----- - - * `Issue #43 `_: Fix issue (introduced in 0.9.1) with version resolution when - upgrading over other releases of Setuptools. - - ----- - 0.9.3 - ----- - - * `Issue #42 `_: Fix new ``AttributeError`` introduced in last fix. - - ----- - 0.9.2 - ----- - - * `Issue #42 `_: Fix regression where blank checksums would trigger an - ``AttributeError``. - - ----- - 0.9.1 - ----- - - * `Distribute #386 `_: Allow other positional and keyword arguments to os.open. - * Corrected dependency on certifi mis-referenced in 0.9. - - --- - 0.9 - --- - - * `package_index` now validates hashes other than MD5 in download links. - - --- - 0.8 - --- - - * Code base now runs on Python 2.4 - Python 3.3 without Python 2to3 - conversion. - - ----- - 0.7.8 - ----- - - * `Distribute #375 `_: Yet another fix for yet another regression. - - ----- - 0.7.7 - ----- - - * `Distribute #375 `_: Repair AttributeError created in last release (redo). - * `Issue #30 `_: Added test for get_cache_path. - - ----- - 0.7.6 - ----- - - * `Distribute #375 `_: Repair AttributeError created in last release. - - ----- - 0.7.5 - ----- - - * `Issue #21 `_: Restore Python 2.4 compatibility in ``test_easy_install``. - * `Distribute #375 `_: Merged additional warning from Distribute 0.6.46. - * Now honor the environment variable - ``SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT`` in addition to the now - deprecated ``DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT``. - - ----- - 0.7.4 - ----- - - * `Issue #20 `_: Fix comparison of parsed SVN version on Python 3. - - ----- - 0.7.3 - ----- - - * `Issue #1 `_: Disable installation of Windows-specific files on non-Windows systems. - * Use new sysconfig module with Python 2.7 or >=3.2. - - ----- - 0.7.2 - ----- - - * `Issue #14 `_: Use markerlib when the `parser` module is not available. - * `Issue #10 `_: ``ez_setup.py`` now uses HTTPS to download setuptools from PyPI. - - ----- - 0.7.1 - ----- - - * Fix NameError (`Issue #3 `_) again - broken in bad merge. - - --- - 0.7 - --- - - * Merged Setuptools and Distribute. See docs/merge.txt for details. - - Added several features that were slated for setuptools 0.6c12: - - * Index URL now defaults to HTTPS. - * Added experimental environment marker support. Now clients may designate a - PEP-426 environment marker for "extra" dependencies. Setuptools uses this - feature in ``setup.py`` for optional SSL and certificate validation support - on older platforms. Based on Distutils-SIG discussions, the syntax is - somewhat tentative. There should probably be a PEP with a firmer spec before - the feature should be considered suitable for use. - * Added support for SSL certificate validation when installing packages from - an HTTPS service. - - ----- - 0.7b4 - ----- - - * `Issue #3 `_: Fixed NameError in SSL support. - - ------ - 0.6.49 - ------ - - * Move warning check in ``get_cache_path`` to follow the directory creation - to avoid errors when the cache path does not yet exist. Fixes the error - reported in `Distribute #375 `_. - - ------ - 0.6.48 - ------ - - * Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in - 0.6.46 (redo). - - ------ - 0.6.47 - ------ - - * Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in - 0.6.46. - - ------ - 0.6.46 - ------ - - * `Distribute #375 `_: Issue a warning if the PYTHON_EGG_CACHE or otherwise - customized egg cache location specifies a directory that's group- or - world-writable. - - ------ - 0.6.45 - ------ - - * `Distribute #379 `_: ``distribute_setup.py`` now traps VersionConflict as well, - restoring ability to upgrade from an older setuptools version. - - ------ - 0.6.44 - ------ - - * ``distribute_setup.py`` has been updated to allow Setuptools 0.7 to - satisfy use_setuptools. - - ------ - 0.6.43 - ------ - - * `Distribute #378 `_: Restore support for Python 2.4 Syntax (regression in 0.6.42). - - ------ - 0.6.42 - ------ - - * External links finder no longer yields duplicate links. - * `Distribute #337 `_: Moved site.py to setuptools/site-patch.py (graft of very old - patch from setuptools trunk which inspired PR `#31 `_). - - ------ - 0.6.41 - ------ - - * `Distribute #27 `_: Use public api for loading resources from zip files rather than - the private method `_zip_directory_cache`. - * Added a new function ``easy_install.get_win_launcher`` which may be used by - third-party libraries such as buildout to get a suitable script launcher. - - ------ - 0.6.40 - ------ - - * `Distribute #376 `_: brought back cli.exe and gui.exe that were deleted in the - previous release. - - ------ - 0.6.39 - ------ - - * Add support for console launchers on ARM platforms. - * Fix possible issue in GUI launchers where the subsystem was not supplied to - the linker. - * Launcher build script now refactored for robustness. - * `Distribute #375 `_: Resources extracted from a zip egg to the file system now also - check the contents of the file against the zip contents during each - invocation of get_resource_filename. - - ------ - 0.6.38 - ------ - - * `Distribute #371 `_: The launcher manifest file is now installed properly. - - ------ - 0.6.37 - ------ - - * `Distribute #143 `_: Launcher scripts, including easy_install itself, are now - accompanied by a manifest on 32-bit Windows environments to avoid the - Installer Detection Technology and thus undesirable UAC elevation described - in `this Microsoft article - `_. - - ------ - 0.6.36 - ------ - - * `Pull Request #35 `_: In `Buildout #64 `_, it was reported that - under Python 3, installation of distutils scripts could attempt to copy - the ``__pycache__`` directory as a file, causing an error, apparently only - under Windows. Easy_install now skips all directories when processing - metadata scripts. - - ------ - 0.6.35 - ------ - - - Note this release is backward-incompatible with distribute 0.6.23-0.6.34 in - how it parses version numbers. - - * `Distribute #278 `_: Restored compatibility with distribute 0.6.22 and setuptools - 0.6. Updated the documentation to match more closely with the version - parsing as intended in setuptools 0.6. - - ------ - 0.6.34 - ------ - - * `Distribute #341 `_: 0.6.33 fails to build under Python 2.4. - - ------ - 0.6.33 - ------ - - * Fix 2 errors with Jython 2.5. - * Fix 1 failure with Jython 2.5 and 2.7. - * Disable workaround for Jython scripts on Linux systems. - * `Distribute #336 `_: `setup.py` no longer masks failure exit code when tests fail. - * Fix issue in pkg_resources where try/except around a platform-dependent - import would trigger hook load failures on Mercurial. See pull request 32 - for details. - * `Distribute #341 `_: Fix a ResourceWarning. - - ------ - 0.6.32 - ------ - - * Fix test suite with Python 2.6. - * Fix some DeprecationWarnings and ResourceWarnings. - * `Distribute #335 `_: Backed out `setup_requires` superceding installed requirements - until regression can be addressed. - - ------ - 0.6.31 - ------ - - * `Distribute #303 `_: Make sure the manifest only ever contains UTF-8 in Python 3. - * `Distribute #329 `_: Properly close files created by tests for compatibility with - Jython. - * Work around `Jython #1980 `_ and `Jython #1981 `_. - * `Distribute #334 `_: Provide workaround for packages that reference `sys.__stdout__` - such as numpy does. This change should address - `virtualenv `#359 `_ `_ as long - as the system encoding is UTF-8 or the IO encoding is specified in the - environment, i.e.:: - - PYTHONIOENCODING=utf8 pip install numpy - - * Fix for encoding issue when installing from Windows executable on Python 3. - * `Distribute #323 `_: Allow `setup_requires` requirements to supercede installed - requirements. Added some new keyword arguments to existing pkg_resources - methods. Also had to updated how __path__ is handled for namespace packages - to ensure that when a new egg distribution containing a namespace package is - placed on sys.path, the entries in __path__ are found in the same order they - would have been in had that egg been on the path when pkg_resources was - first imported. - - ------ - 0.6.30 - ------ - - * `Distribute #328 `_: Clean up temporary directories in distribute_setup.py. - * Fix fatal bug in distribute_setup.py. - - ------ - 0.6.29 - ------ - - * `Pull Request #14 `_: Honor file permissions in zip files. - * `Distribute #327 `_: Merged pull request `#24 `_ to fix a dependency problem with pip. - * Merged pull request `#23 `_ to fix https://github.com/pypa/virtualenv/issues/301. - * If Sphinx is installed, the `upload_docs` command now runs `build_sphinx` - to produce uploadable documentation. - * `Distribute #326 `_: `upload_docs` provided mangled auth credentials under Python 3. - * `Distribute #320 `_: Fix check for "createable" in distribute_setup.py. - * `Distribute #305 `_: Remove a warning that was triggered during normal operations. - * `Distribute #311 `_: Print metadata in UTF-8 independent of platform. - * `Distribute #303 `_: Read manifest file with UTF-8 encoding under Python 3. - * `Distribute #301 `_: Allow to run tests of namespace packages when using 2to3. - * `Distribute #304 `_: Prevent import loop in site.py under Python 3.3. - * `Distribute #283 `_: Reenable scanning of `*.pyc` / `*.pyo` files on Python 3.3. - * `Distribute #299 `_: The develop command didn't work on Python 3, when using 2to3, - as the egg link would go to the Python 2 source. Linking to the 2to3'd code - in build/lib makes it work, although you will have to rebuild the module - before testing it. - * `Distribute #306 `_: Even if 2to3 is used, we build in-place under Python 2. - * `Distribute #307 `_: Prints the full path when .svn/entries is broken. - * `Distribute #313 `_: Support for sdist subcommands (Python 2.7) - * `Distribute #314 `_: test_local_index() would fail an OS X. - * `Distribute #310 `_: Non-ascii characters in a namespace __init__.py causes errors. - * `Distribute #218 `_: Improved documentation on behavior of `package_data` and - `include_package_data`. Files indicated by `package_data` are now included - in the manifest. - * `distribute_setup.py` now allows a `--download-base` argument for retrieving - distribute from a specified location. - - ------ - 0.6.28 - ------ - - * `Distribute #294 `_: setup.py can now be invoked from any directory. - * Scripts are now installed honoring the umask. - * Added support for .dist-info directories. - * `Distribute #283 `_: Fix and disable scanning of `*.pyc` / `*.pyo` files on - Python 3.3. - - ------ - 0.6.27 - ------ - - * Support current snapshots of CPython 3.3. - * Distribute now recognizes README.rst as a standard, default readme file. - * Exclude 'encodings' modules when removing modules from sys.modules. - Workaround for `#285 `_. - * `Distribute #231 `_: Don't fiddle with system python when used with buildout - (bootstrap.py) - - ------ - 0.6.26 - ------ - - * `Distribute #183 `_: Symlinked files are now extracted from source distributions. - * `Distribute #227 `_: Easy_install fetch parameters are now passed during the - installation of a source distribution; now fulfillment of setup_requires - dependencies will honor the parameters passed to easy_install. - - ------ - 0.6.25 - ------ - - * `Distribute #258 `_: Workaround a cache issue - * `Distribute #260 `_: distribute_setup.py now accepts the --user parameter for - Python 2.6 and later. - * `Distribute #262 `_: package_index.open_with_auth no longer throws LookupError - on Python 3. - * `Distribute #269 `_: AttributeError when an exception occurs reading Manifest.in - on late releases of Python. - * `Distribute #272 `_: Prevent TypeError when namespace package names are unicode - and single-install-externally-managed is used. Also fixes PIP issue - 449. - * `Distribute #273 `_: Legacy script launchers now install with Python2/3 support. - - ------ - 0.6.24 - ------ - - * `Distribute #249 `_: Added options to exclude 2to3 fixers - - ------ - 0.6.23 - ------ - - * `Distribute #244 `_: Fixed a test - * `Distribute #243 `_: Fixed a test - * `Distribute #239 `_: Fixed a test - * `Distribute #240 `_: Fixed a test - * `Distribute #241 `_: Fixed a test - * `Distribute #237 `_: Fixed a test - * `Distribute #238 `_: easy_install now uses 64bit executable wrappers on 64bit Python - * `Distribute #208 `_: Fixed parsed_versions, it now honors post-releases as noted in the documentation - * `Distribute #207 `_: Windows cli and gui wrappers pass CTRL-C to child python process - * `Distribute #227 `_: easy_install now passes its arguments to setup.py bdist_egg - * `Distribute #225 `_: Fixed a NameError on Python 2.5, 2.4 - - ------ - 0.6.21 - ------ - - * `Distribute #225 `_: FIxed a regression on py2.4 - - ------ - 0.6.20 - ------ - - * `Distribute #135 `_: Include url in warning when processing URLs in package_index. - * `Distribute #212 `_: Fix issue where easy_instal fails on Python 3 on windows installer. - * `Distribute #213 `_: Fix typo in documentation. - - ------ - 0.6.19 - ------ - - * `Distribute #206 `_: AttributeError: 'HTTPMessage' object has no attribute 'getheaders' - - ------ - 0.6.18 - ------ - - * `Distribute #210 `_: Fixed a regression introduced by `Distribute #204 `_ fix. - - ------ - 0.6.17 - ------ - - * Support 'DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT' environment - variable to allow to disable installation of easy_install-${version} script. - * Support Python >=3.1.4 and >=3.2.1. - * `Distribute #204 `_: Don't try to import the parent of a namespace package in - declare_namespace - * `Distribute #196 `_: Tolerate responses with multiple Content-Length headers - * `Distribute #205 `_: Sandboxing doesn't preserve working_set. Leads to setup_requires - problems. - - ------ - 0.6.16 - ------ - - * Builds sdist gztar even on Windows (avoiding `Distribute #193 `_). - * `Distribute #192 `_: Fixed metadata omitted on Windows when package_dir - specified with forward-slash. - * `Distribute #195 `_: Cython build support. - * `Distribute #200 `_: Issues with recognizing 64-bit packages on Windows. - - ------ - 0.6.15 - ------ - - * Fixed typo in bdist_egg - * Several issues under Python 3 has been solved. - * `Distribute #146 `_: Fixed missing DLL files after easy_install of windows exe package. - - ------ - 0.6.14 - ------ - - * `Distribute #170 `_: Fixed unittest failure. Thanks to Toshio. - * `Distribute #171 `_: Fixed race condition in unittests cause deadlocks in test suite. - * `Distribute #143 `_: Fixed a lookup issue with easy_install. - Thanks to David and Zooko. - * `Distribute #174 `_: Fixed the edit mode when its used with setuptools itself - - ------ - 0.6.13 - ------ - - * `Distribute #160 `_: 2.7 gives ValueError("Invalid IPv6 URL") - * `Distribute #150 `_: Fixed using ~/.local even in a --no-site-packages virtualenv - * `Distribute #163 `_: scan index links before external links, and don't use the md5 when - comparing two distributions - - ------ - 0.6.12 - ------ - - * `Distribute #149 `_: Fixed various failures on 2.3/2.4 - - ------ - 0.6.11 - ------ - - * Found another case of SandboxViolation - fixed - * `Distribute #15 `_ and `Distribute #48 `_: Introduced a socket timeout of 15 seconds on url openings - * Added indexsidebar.html into MANIFEST.in - * `Distribute #108 `_: Fixed TypeError with Python3.1 - * `Distribute #121 `_: Fixed --help install command trying to actually install. - * `Distribute #112 `_: Added an os.makedirs so that Tarek's solution will work. - * `Distribute #133 `_: Added --no-find-links to easy_install - * Added easy_install --user - * `Distribute #100 `_: Fixed develop --user not taking '.' in PYTHONPATH into account - * `Distribute #134 `_: removed spurious UserWarnings. Patch by VanLindberg - * `Distribute #138 `_: cant_write_to_target error when setup_requires is used. - * `Distribute #147 `_: respect the sys.dont_write_bytecode flag - - ------ - 0.6.10 - ------ - - * Reverted change made for the DistributionNotFound exception because - zc.buildout uses the exception message to get the name of the - distribution. - - ----- - 0.6.9 - ----- - - * `Distribute #90 `_: unknown setuptools version can be added in the working set - * `Distribute #87 `_: setupt.py doesn't try to convert distribute_setup.py anymore - Initial Patch by arfrever. - * `Distribute #89 `_: added a side bar with a download link to the doc. - * `Distribute #86 `_: fixed missing sentence in pkg_resources doc. - * Added a nicer error message when a DistributionNotFound is raised. - * `Distribute #80 `_: test_develop now works with Python 3.1 - * `Distribute #93 `_: upload_docs now works if there is an empty sub-directory. - * `Distribute #70 `_: exec bit on non-exec files - * `Distribute #99 `_: now the standalone easy_install command doesn't uses a - "setup.cfg" if any exists in the working directory. It will use it - only if triggered by ``install_requires`` from a setup.py call - (install, develop, etc). - * `Distribute #101 `_: Allowing ``os.devnull`` in Sandbox - * `Distribute #92 `_: Fixed the "no eggs" found error with MacPort - (platform.mac_ver() fails) - * `Distribute #103 `_: test_get_script_header_jython_workaround not run - anymore under py3 with C or POSIX local. Contributed by Arfrever. - * `Distribute #104 `_: remvoved the assertion when the installation fails, - with a nicer message for the end user. - * `Distribute #100 `_: making sure there's no SandboxViolation when - the setup script patches setuptools. - - ----- - 0.6.8 - ----- - - * Added "check_packages" in dist. (added in Setuptools 0.6c11) - * Fixed the DONT_PATCH_SETUPTOOLS state. - - ----- - 0.6.7 - ----- - - * `Distribute #58 `_: Added --user support to the develop command - * `Distribute #11 `_: Generated scripts now wrap their call to the script entry point - in the standard "if name == 'main'" - * Added the 'DONT_PATCH_SETUPTOOLS' environment variable, so virtualenv - can drive an installation that doesn't patch a global setuptools. - * Reviewed unladen-swallow specific change from - http://code.google.com/p/unladen-swallow/source/detail?spec=svn875&r=719 - and determined that it no longer applies. Distribute should work fine with - Unladen Swallow 2009Q3. - * `Distribute #21 `_: Allow PackageIndex.open_url to gracefully handle all cases of a - httplib.HTTPException instead of just InvalidURL and BadStatusLine. - * Removed virtual-python.py from this distribution and updated documentation - to point to the actively maintained virtualenv instead. - * `Distribute #64 `_: use_setuptools no longer rebuilds the distribute egg every - time it is run - * use_setuptools now properly respects the requested version - * use_setuptools will no longer try to import a distribute egg for the - wrong Python version - * `Distribute #74 `_: no_fake should be True by default. - * `Distribute #72 `_: avoid a bootstrapping issue with easy_install -U - - ----- - 0.6.6 - ----- - - * Unified the bootstrap file so it works on both py2.x and py3k without 2to3 - (patch by Holger Krekel) - - ----- - 0.6.5 - ----- - - * `Distribute #65 `_: cli.exe and gui.exe are now generated at build time, - depending on the platform in use. - - * `Distribute #67 `_: Fixed doc typo (PEP 381/382) - - * Distribute no longer shadows setuptools if we require a 0.7-series - setuptools. And an error is raised when installing a 0.7 setuptools with - distribute. - - * When run from within buildout, no attempt is made to modify an existing - setuptools egg, whether in a shared egg directory or a system setuptools. - - * Fixed a hole in sandboxing allowing builtin file to write outside of - the sandbox. - - ----- - 0.6.4 - ----- - - * Added the generation of `distribute_setup_3k.py` during the release. - This closes `Distribute #52 `_. - - * Added an upload_docs command to easily upload project documentation to - PyPI's https://pythonhosted.org. This close issue `Distribute #56 `_. - - * Fixed a bootstrap bug on the use_setuptools() API. - - ----- - 0.6.3 - ----- - - setuptools - ========== - - * Fixed a bunch of calls to file() that caused crashes on Python 3. - - bootstrapping - ============= - - * Fixed a bug in sorting that caused bootstrap to fail on Python 3. - - ----- - 0.6.2 - ----- - - setuptools - ========== - - * Added Python 3 support; see docs/python3.txt. - This closes `Old Setuptools #39 `_. - - * Added option to run 2to3 automatically when installing on Python 3. - This closes issue `Distribute #31 `_. - - * Fixed invalid usage of requirement.parse, that broke develop -d. - This closes `Old Setuptools #44 `_. - - * Fixed script launcher for 64-bit Windows. - This closes `Old Setuptools #2 `_. - - * KeyError when compiling extensions. - This closes `Old Setuptools #41 `_. - - bootstrapping - ============= - - * Fixed bootstrap not working on Windows. This closes issue `Distribute #49 `_. - - * Fixed 2.6 dependencies. This closes issue `Distribute #50 `_. - - * Make sure setuptools is patched when running through easy_install - This closes `Old Setuptools #40 `_. - - ----- - 0.6.1 - ----- - - setuptools - ========== - - * package_index.urlopen now catches BadStatusLine and malformed url errors. - This closes `Distribute #16 `_ and `Distribute #18 `_. - - * zip_ok is now False by default. This closes `Old Setuptools #33 `_. - - * Fixed invalid URL error catching. `Old Setuptools #20 `_. - - * Fixed invalid bootstraping with easy_install installation (`Distribute #40 `_). - Thanks to Florian Schulze for the help. - - * Removed buildout/bootstrap.py. A new repository will create a specific - bootstrap.py script. - - - bootstrapping - ============= - - * The boostrap process leave setuptools alone if detected in the system - and --root or --prefix is provided, but is not in the same location. - This closes `Distribute #10 `_. - - --- - 0.6 - --- - - setuptools - ========== - - * Packages required at build time where not fully present at install time. - This closes `Distribute #12 `_. - - * Protected against failures in tarfile extraction. This closes `Distribute #10 `_. - - * Made Jython api_tests.txt doctest compatible. This closes `Distribute #7 `_. - - * sandbox.py replaced builtin type file with builtin function open. This - closes `Distribute #6 `_. - - * Immediately close all file handles. This closes `Distribute #3 `_. - - * Added compatibility with Subversion 1.6. This references `Distribute #1 `_. - - pkg_resources - ============= - - * Avoid a call to /usr/bin/sw_vers on OSX and use the official platform API - instead. Based on a patch from ronaldoussoren. This closes issue `#5 `_. - - * Fixed a SandboxViolation for mkdir that could occur in certain cases. - This closes `Distribute #13 `_. - - * Allow to find_on_path on systems with tight permissions to fail gracefully. - This closes `Distribute #9 `_. - - * Corrected inconsistency between documentation and code of add_entry. - This closes `Distribute #8 `_. - - * Immediately close all file handles. This closes `Distribute #3 `_. - - easy_install - ============ - - * Immediately close all file handles. This closes `Distribute #3 `_. - - ----- - 0.6c9 - ----- - - * Fixed a missing files problem when using Windows source distributions on - non-Windows platforms, due to distutils not handling manifest file line - endings correctly. - - * Updated Pyrex support to work with Pyrex 0.9.6 and higher. - - * Minor changes for Jython compatibility, including skipping tests that can't - work on Jython. - - * Fixed not installing eggs in ``install_requires`` if they were also used for - ``setup_requires`` or ``tests_require``. - - * Fixed not fetching eggs in ``install_requires`` when running tests. - - * Allow ``ez_setup.use_setuptools()`` to upgrade existing setuptools - installations when called from a standalone ``setup.py``. - - * Added a warning if a namespace package is declared, but its parent package - is not also declared as a namespace. - - * Support Subversion 1.5 - - * Removed use of deprecated ``md5`` module if ``hashlib`` is available - - * Fixed ``bdist_wininst upload`` trying to upload the ``.exe`` twice - - * Fixed ``bdist_egg`` putting a ``native_libs.txt`` in the source package's - ``.egg-info``, when it should only be in the built egg's ``EGG-INFO``. - - * Ensure that _full_name is set on all shared libs before extensions are - checked for shared lib usage. (Fixes a bug in the experimental shared - library build support.) - - * Fix to allow unpacked eggs containing native libraries to fail more - gracefully under Google App Engine (with an ``ImportError`` loading the - C-based module, instead of getting a ``NameError``). - - ----- - 0.6c7 - ----- - - * Fixed ``distutils.filelist.findall()`` crashing on broken symlinks, and - ``egg_info`` command failing on new, uncommitted SVN directories. - - * Fix import problems with nested namespace packages installed via - ``--root`` or ``--single-version-externally-managed``, due to the - parent package not having the child package as an attribute. - - ----- - 0.6c6 - ----- - - * Added ``--egg-path`` option to ``develop`` command, allowing you to force - ``.egg-link`` files to use relative paths (allowing them to be shared across - platforms on a networked drive). - - * Fix not building binary RPMs correctly. - - * Fix "eggsecutables" (such as setuptools' own egg) only being runnable with - bash-compatible shells. - - * Fix ``#!`` parsing problems in Windows ``.exe`` script wrappers, when there - was whitespace inside a quoted argument or at the end of the ``#!`` line - (a regression introduced in 0.6c4). - - * Fix ``test`` command possibly failing if an older version of the project - being tested was installed on ``sys.path`` ahead of the test source - directory. - - * Fix ``find_packages()`` treating ``ez_setup`` and directories with ``.`` in - their names as packages. - - ----- - 0.6c5 - ----- - - * Fix uploaded ``bdist_rpm`` packages being described as ``bdist_egg`` - packages under Python versions less than 2.5. - - * Fix uploaded ``bdist_wininst`` packages being described as suitable for - "any" version by Python 2.5, even if a ``--target-version`` was specified. - - ----- - 0.6c4 - ----- - - * Overhauled Windows script wrapping to support ``bdist_wininst`` better. - Scripts installed with ``bdist_wininst`` will always use ``#!python.exe`` or - ``#!pythonw.exe`` as the executable name (even when built on non-Windows - platforms!), and the wrappers will look for the executable in the script's - parent directory (which should find the right version of Python). - - * Fix ``upload`` command not uploading files built by ``bdist_rpm`` or - ``bdist_wininst`` under Python 2.3 and 2.4. - - * Add support for "eggsecutable" headers: a ``#!/bin/sh`` script that is - prepended to an ``.egg`` file to allow it to be run as a script on Unix-ish - platforms. (This is mainly so that setuptools itself can have a single-file - installer on Unix, without doing multiple downloads, dealing with firewalls, - etc.) - - * Fix problem with empty revision numbers in Subversion 1.4 ``entries`` files - - * Use cross-platform relative paths in ``easy-install.pth`` when doing - ``develop`` and the source directory is a subdirectory of the installation - target directory. - - * Fix a problem installing eggs with a system packaging tool if the project - contained an implicit namespace package; for example if the ``setup()`` - listed a namespace package ``foo.bar`` without explicitly listing ``foo`` - as a namespace package. - - ----- - 0.6c3 - ----- - - * Fixed breakages caused by Subversion 1.4's new "working copy" format - - ----- - 0.6c2 - ----- - - * The ``ez_setup`` module displays the conflicting version of setuptools (and - its installation location) when a script requests a version that's not - available. - - * Running ``setup.py develop`` on a setuptools-using project will now install - setuptools if needed, instead of only downloading the egg. - - ----- - 0.6c1 - ----- - - * Fixed ``AttributeError`` when trying to download a ``setup_requires`` - dependency when a distribution lacks a ``dependency_links`` setting. - - * Made ``zip-safe`` and ``not-zip-safe`` flag files contain a single byte, so - as to play better with packaging tools that complain about zero-length - files. - - * Made ``setup.py develop`` respect the ``--no-deps`` option, which it - previously was ignoring. - - * Support ``extra_path`` option to ``setup()`` when ``install`` is run in - backward-compatibility mode. - - * Source distributions now always include a ``setup.cfg`` file that explicitly - sets ``egg_info`` options such that they produce an identical version number - to the source distribution's version number. (Previously, the default - version number could be different due to the use of ``--tag-date``, or if - the version was overridden on the command line that built the source - distribution.) - - ----- - 0.6b4 - ----- - - * Fix ``register`` not obeying name/version set by ``egg_info`` command, if - ``egg_info`` wasn't explicitly run first on the same command line. - - * Added ``--no-date`` and ``--no-svn-revision`` options to ``egg_info`` - command, to allow suppressing tags configured in ``setup.cfg``. - - * Fixed redundant warnings about missing ``README`` file(s); it should now - appear only if you are actually a source distribution. - - ----- - 0.6b3 - ----- - - * Fix ``bdist_egg`` not including files in subdirectories of ``.egg-info``. - - * Allow ``.py`` files found by the ``include_package_data`` option to be - automatically included. Remove duplicate data file matches if both - ``include_package_data`` and ``package_data`` are used to refer to the same - files. - - ----- - 0.6b1 - ----- - - * Strip ``module`` from the end of compiled extension modules when computing - the name of a ``.py`` loader/wrapper. (Python's import machinery ignores - this suffix when searching for an extension module.) - - ------ - 0.6a11 - ------ - - * Added ``test_loader`` keyword to support custom test loaders - - * Added ``setuptools.file_finders`` entry point group to allow implementing - revision control plugins. - - * Added ``--identity`` option to ``upload`` command. - - * Added ``dependency_links`` to allow specifying URLs for ``--find-links``. - - * Enhanced test loader to scan packages as well as modules, and call - ``additional_tests()`` if present to get non-unittest tests. - - * Support namespace packages in conjunction with system packagers, by omitting - the installation of any ``__init__.py`` files for namespace packages, and - adding a special ``.pth`` file to create a working package in - ``sys.modules``. - - * Made ``--single-version-externally-managed`` automatic when ``--root`` is - used, so that most system packagers won't require special support for - setuptools. - - * Fixed ``setup_requires``, ``tests_require``, etc. not using ``setup.cfg`` or - other configuration files for their option defaults when installing, and - also made the install use ``--multi-version`` mode so that the project - directory doesn't need to support .pth files. - - * ``MANIFEST.in`` is now forcibly closed when any errors occur while reading - it. Previously, the file could be left open and the actual error would be - masked by problems trying to remove the open file on Windows systems. - - ------ - 0.6a10 - ------ - - * Fixed the ``develop`` command ignoring ``--find-links``. - - ----- - 0.6a9 - ----- - - * The ``sdist`` command no longer uses the traditional ``MANIFEST`` file to - create source distributions. ``MANIFEST.in`` is still read and processed, - as are the standard defaults and pruning. But the manifest is built inside - the project's ``.egg-info`` directory as ``SOURCES.txt``, and it is rebuilt - every time the ``egg_info`` command is run. - - * Added the ``include_package_data`` keyword to ``setup()``, allowing you to - automatically include any package data listed in revision control or - ``MANIFEST.in`` - - * Added the ``exclude_package_data`` keyword to ``setup()``, allowing you to - trim back files included via the ``package_data`` and - ``include_package_data`` options. - - * Fixed ``--tag-svn-revision`` not working when run from a source - distribution. - - * Added warning for namespace packages with missing ``declare_namespace()`` - - * Added ``tests_require`` keyword to ``setup()``, so that e.g. packages - requiring ``nose`` to run unit tests can make this dependency optional - unless the ``test`` command is run. - - * Made all commands that use ``easy_install`` respect its configuration - options, as this was causing some problems with ``setup.py install``. - - * Added an ``unpack_directory()`` driver to ``setuptools.archive_util``, so - that you can process a directory tree through a processing filter as if it - were a zipfile or tarfile. - - * Added an internal ``install_egg_info`` command to use as part of old-style - ``install`` operations, that installs an ``.egg-info`` directory with the - package. - - * Added a ``--single-version-externally-managed`` option to the ``install`` - command so that you can more easily wrap a "flat" egg in a system package. - - * Enhanced ``bdist_rpm`` so that it installs single-version eggs that - don't rely on a ``.pth`` file. The ``--no-egg`` option has been removed, - since all RPMs are now built in a more backwards-compatible format. - - * Support full roundtrip translation of eggs to and from ``bdist_wininst`` - format. Running ``bdist_wininst`` on a setuptools-based package wraps the - egg in an .exe that will safely install it as an egg (i.e., with metadata - and entry-point wrapper scripts), and ``easy_install`` can turn the .exe - back into an ``.egg`` file or directory and install it as such. - - - ----- - 0.6a8 - ----- - - * Fixed some problems building extensions when Pyrex was installed, especially - with Python 2.4 and/or packages using SWIG. - - * Made ``develop`` command accept all the same options as ``easy_install``, - and use the ``easy_install`` command's configuration settings as defaults. - - * Made ``egg_info --tag-svn-revision`` fall back to extracting the revision - number from ``PKG-INFO`` in case it is being run on a source distribution of - a snapshot taken from a Subversion-based project. - - * Automatically detect ``.dll``, ``.so`` and ``.dylib`` files that are being - installed as data, adding them to ``native_libs.txt`` automatically. - - * Fixed some problems with fresh checkouts of projects that don't include - ``.egg-info/PKG-INFO`` under revision control and put the project's source - code directly in the project directory. If such a package had any - requirements that get processed before the ``egg_info`` command can be run, - the setup scripts would fail with a "Missing 'Version:' header and/or - PKG-INFO file" error, because the egg runtime interpreted the unbuilt - metadata in a directory on ``sys.path`` (i.e. the current directory) as - being a corrupted egg. Setuptools now monkeypatches the distribution - metadata cache to pretend that the egg has valid version information, until - it has a chance to make it actually be so (via the ``egg_info`` command). - - ----- - 0.6a5 - ----- - - * Fixed missing gui/cli .exe files in distribution. Fixed bugs in tests. - - ----- - 0.6a3 - ----- - - * Added ``gui_scripts`` entry point group to allow installing GUI scripts - on Windows and other platforms. (The special handling is only for Windows; - other platforms are treated the same as for ``console_scripts``.) - - ----- - 0.6a2 - ----- - - * Added ``console_scripts`` entry point group to allow installing scripts - without the need to create separate script files. On Windows, console - scripts get an ``.exe`` wrapper so you can just type their name. On other - platforms, the scripts are written without a file extension. - - ----- - 0.6a1 - ----- - - * Added support for building "old-style" RPMs that don't install an egg for - the target package, using a ``--no-egg`` option. - - * The ``build_ext`` command now works better when using the ``--inplace`` - option and multiple Python versions. It now makes sure that all extensions - match the current Python version, even if newer copies were built for a - different Python version. - - * The ``upload`` command no longer attaches an extra ``.zip`` when uploading - eggs, as PyPI now supports egg uploads without trickery. - - * The ``ez_setup`` script/module now displays a warning before downloading - the setuptools egg, and attempts to check the downloaded egg against an - internal MD5 checksum table. - - * Fixed the ``--tag-svn-revision`` option of ``egg_info`` not finding the - latest revision number; it was using the revision number of the directory - containing ``setup.py``, not the highest revision number in the project. - - * Added ``eager_resources`` setup argument - - * The ``sdist`` command now recognizes Subversion "deleted file" entries and - does not include them in source distributions. - - * ``setuptools`` now embeds itself more thoroughly into the distutils, so that - other distutils extensions (e.g. py2exe, py2app) will subclass setuptools' - versions of things, rather than the native distutils ones. - - * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``; - ``setup_requires`` allows you to automatically find and download packages - that are needed in order to *build* your project (as opposed to running it). - - * ``setuptools`` now finds its commands, ``setup()`` argument validators, and - metadata writers using entry points, so that they can be extended by - third-party packages. See `Creating distutils Extensions - `_ - for more details. - - * The vestigial ``depends`` command has been removed. It was never finished - or documented, and never would have worked without EasyInstall - which it - pre-dated and was never compatible with. - - ------ - 0.5a12 - ------ - - * The zip-safety scanner now checks for modules that might be used with - ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't - handle ``-m`` on zipped modules. - - ------ - 0.5a11 - ------ - - * Fix breakage of the "develop" command that was caused by the addition of - ``--always-unzip`` to the ``easy_install`` command. - - ----- - 0.5a9 - ----- - - * Include ``svn:externals`` directories in source distributions as well as - normal subversion-controlled files and directories. - - * Added ``exclude=patternlist`` option to ``setuptools.find_packages()`` - - * Changed --tag-svn-revision to include an "r" in front of the revision number - for better readability. - - * Added ability to build eggs without including source files (except for any - scripts, of course), using the ``--exclude-source-files`` option to - ``bdist_egg``. - - * ``setup.py install`` now automatically detects when an "unmanaged" package - or module is going to be on ``sys.path`` ahead of a package being installed, - thereby preventing the newer version from being imported. If this occurs, - a warning message is output to ``sys.stderr``, but installation proceeds - anyway. The warning message informs the user what files or directories - need deleting, and advises them they can also use EasyInstall (with the - ``--delete-conflicting`` option) to do it automatically. - - * The ``egg_info`` command now adds a ``top_level.txt`` file to the metadata - directory that lists all top-level modules and packages in the distribution. - This is used by the ``easy_install`` command to find possibly-conflicting - "unmanaged" packages when installing the distribution. - - * Added ``zip_safe`` and ``namespace_packages`` arguments to ``setup()``. - Added package analysis to determine zip-safety if the ``zip_safe`` flag - is not given, and advise the author regarding what code might need changing. - - * Fixed the swapped ``-d`` and ``-b`` options of ``bdist_egg``. - - ----- - 0.5a8 - ----- - - * The "egg_info" command now always sets the distribution metadata to "safe" - forms of the distribution name and version, so that distribution files will - be generated with parseable names (i.e., ones that don't include '-' in the - name or version). Also, this means that if you use the various ``--tag`` - options of "egg_info", any distributions generated will use the tags in the - version, not just egg distributions. - - * Added support for defining command aliases in distutils configuration files, - under the "[aliases]" section. To prevent recursion and to allow aliases to - call the command of the same name, a given alias can be expanded only once - per command-line invocation. You can define new aliases with the "alias" - command, either for the local, global, or per-user configuration. - - * Added "rotate" command to delete old distribution files, given a set of - patterns to match and the number of files to keep. (Keeps the most - recently-modified distribution files matching each pattern.) - - * Added "saveopts" command that saves all command-line options for the current - invocation to the local, global, or per-user configuration file. Useful for - setting defaults without having to hand-edit a configuration file. - - * Added a "setopt" command that sets a single option in a specified distutils - configuration file. - - ----- - 0.5a7 - ----- - - * Added "upload" support for egg and source distributions, including a bug - fix for "upload" and a temporary workaround for lack of .egg support in - PyPI. - - ----- - 0.5a6 - ----- - - * Beefed up the "sdist" command so that if you don't have a MANIFEST.in, it - will include all files under revision control (CVS or Subversion) in the - current directory, and it will regenerate the list every time you create a - source distribution, not just when you tell it to. This should make the - default "do what you mean" more often than the distutils' default behavior - did, while still retaining the old behavior in the presence of MANIFEST.in. - - * Fixed the "develop" command always updating .pth files, even if you - specified ``-n`` or ``--dry-run``. - - * Slightly changed the format of the generated version when you use - ``--tag-build`` on the "egg_info" command, so that you can make tagged - revisions compare *lower* than the version specified in setup.py (e.g. by - using ``--tag-build=dev``). - - ----- - 0.5a5 - ----- - - * Added ``develop`` command to ``setuptools``-based packages. This command - installs an ``.egg-link`` pointing to the package's source directory, and - script wrappers that ``execfile()`` the source versions of the package's - scripts. This lets you put your development checkout(s) on sys.path without - having to actually install them. (To uninstall the link, use - use ``setup.py develop --uninstall``.) - - * Added ``egg_info`` command to ``setuptools``-based packages. This command - just creates or updates the "projectname.egg-info" directory, without - building an egg. (It's used by the ``bdist_egg``, ``test``, and ``develop`` - commands.) - - * Enhanced the ``test`` command so that it doesn't install the package, but - instead builds any C extensions in-place, updates the ``.egg-info`` - metadata, adds the source directory to ``sys.path``, and runs the tests - directly on the source. This avoids an "unmanaged" installation of the - package to ``site-packages`` or elsewhere. - - * Made ``easy_install`` a standard ``setuptools`` command, moving it from - the ``easy_install`` module to ``setuptools.command.easy_install``. Note - that if you were importing or extending it, you must now change your imports - accordingly. ``easy_install.py`` is still installed as a script, but not as - a module. - - ----- - 0.5a4 - ----- - - * Setup scripts using setuptools can now list their dependencies directly in - the setup.py file, without having to manually create a ``depends.txt`` file. - The ``install_requires`` and ``extras_require`` arguments to ``setup()`` - are used to create a dependencies file automatically. If you are manually - creating ``depends.txt`` right now, please switch to using these setup - arguments as soon as practical, because ``depends.txt`` support will be - removed in the 0.6 release cycle. For documentation on the new arguments, - see the ``setuptools.dist.Distribution`` class. - - * Setup scripts using setuptools now always install using ``easy_install`` - internally, for ease of uninstallation and upgrading. - - ----- - 0.5a1 - ----- - - * Added support for "self-installation" bootstrapping. Packages can now - include ``ez_setup.py`` in their source distribution, and add the following - to their ``setup.py``, in order to automatically bootstrap installation of - setuptools as part of their setup process:: - - from ez_setup import use_setuptools - use_setuptools() - - from setuptools import setup - # etc... - - ----- - 0.4a2 - ----- - - * Added ``ez_setup.py`` installer/bootstrap script to make initial setuptools - installation easier, and to allow distributions using setuptools to avoid - having to include setuptools in their source distribution. - - * All downloads are now managed by the ``PackageIndex`` class (which is now - subclassable and replaceable), so that embedders can more easily override - download logic, give download progress reports, etc. The class has also - been moved to the new ``setuptools.package_index`` module. - - * The ``Installer`` class no longer handles downloading, manages a temporary - directory, or tracks the ``zip_ok`` option. Downloading is now handled - by ``PackageIndex``, and ``Installer`` has become an ``easy_install`` - command class based on ``setuptools.Command``. - - * There is a new ``setuptools.sandbox.run_setup()`` API to invoke a setup - script in a directory sandbox, and a new ``setuptools.archive_util`` module - with an ``unpack_archive()`` API. These were split out of EasyInstall to - allow reuse by other tools and applications. - - * ``setuptools.Command`` now supports reinitializing commands using keyword - arguments to set/reset options. Also, ``Command`` subclasses can now set - their ``command_consumes_arguments`` attribute to ``True`` in order to - receive an ``args`` option containing the rest of the command line. - - ----- - 0.3a2 - ----- - - * Added new options to ``bdist_egg`` to allow tagging the egg's version number - with a subversion revision number, the current date, or an explicit tag - value. Run ``setup.py bdist_egg --help`` to get more information. - - * Misc. bug fixes - - ----- - 0.3a1 - ----- - - * Initial release. - -Keywords: CPAN PyPI distutils eggs package management -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Python Software Foundation License -Classifier: License :: OSI Approved :: Zope Public License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.1 -Classifier: Programming Language :: Python :: 3.2 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Archiving :: Packaging -Classifier: Topic :: System :: Systems Administration -Classifier: Topic :: Utilities +Metadata-Version: 1.1 +Name: setuptools +Version: 20.1.1 +Summary: Easily download, build, install, upgrade, and uninstall Python packages +Home-page: https://bitbucket.org/pypa/setuptools +Author: Python Packaging Authority +Author-email: distutils-sig@python.org +License: UNKNOWN +Description: =============================== + Installing and Using Setuptools + =============================== + + .. contents:: **Table of Contents** + + + `Change History `_. + + ------------------------- + Installation Instructions + ------------------------- + + The recommended way to bootstrap setuptools on any system is to download + `ez_setup.py`_ and run it using the target Python environment. Different + operating systems have different recommended techniques to accomplish this + basic routine, so below are some examples to get you started. + + Setuptools requires Python 2.6 or later. To install setuptools + on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x + `_. + + The link provided to ez_setup.py is a bookmark to bootstrap script for the + latest known stable release. + + .. _ez_setup.py: https://bootstrap.pypa.io/ez_setup.py + + Windows (Powershell 3 or later) + =============================== + + For best results, uninstall previous versions FIRST (see `Uninstalling`_). + + Using Windows 8 (which includes PowerShell 3) or earlier versions of Windows + with PowerShell 3 installed, it's possible to install with one simple + Powershell command. Start up Powershell and paste this command:: + + > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - + + You must start the Powershell with Administrative privileges or you may choose + to install a user-local installation:: + + > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - --user + + If you have Python 3.3 or later, you can use the ``py`` command to install to + different Python versions. For example, to install to Python 3.3 if you have + Python 2.7 installed:: + + > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | py -3 - + + The recommended way to install setuptools on Windows is to download + `ez_setup.py`_ and run it. The script will download the appropriate + distribution file and install it for you. + + Once installation is complete, you will find an ``easy_install`` program in + your Python ``Scripts`` subdirectory. For simple invocation and best results, + add this directory to your ``PATH`` environment variable, if it is not already + present. If you did a user-local install, the ``Scripts`` subdirectory is + ``$env:APPDATA\Python\Scripts``. + + + Windows (simplified) + ==================== + + For Windows without PowerShell 3 or for installation without a command-line, + download `ez_setup.py`_ using your preferred web browser or other technique + and "run" that file. + + + Unix (wget) + =========== + + Most Linux distributions come with wget. + + Download `ez_setup.py`_ and run it using the target Python version. The script + will download the appropriate version and install it for you:: + + > wget https://bootstrap.pypa.io/ez_setup.py -O - | python + + Note that you will may need to invoke the command with superuser privileges to + install to the system Python:: + + > wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python + + Alternatively, Setuptools may be installed to a user-local path:: + + > wget https://bootstrap.pypa.io/ez_setup.py -O - | python - --user + + Note that on some older systems (noted on Debian 6 and CentOS 5 installations), + `wget` may refuse to download `ez_setup.py`, complaining that the certificate common name `*.c.ssl.fastly.net` + does not match the host name `bootstrap.pypa.io`. In addition, the `ez_setup.py` script may then encounter similar problems using + `wget` internally to download `setuptools-x.y.zip`, complaining that the certificate common name of `www.python.org` does not match the + host name `pypi.python.org`. Those are known issues, related to a bug in the older versions of `wget` + (see `Issue 59 `_). If you happen to encounter them, + install Setuptools as follows:: + + > wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py + > python ez_setup.py --insecure + + + Unix including Mac OS X (curl) + ============================== + + If your system has curl installed, follow the ``wget`` instructions but + replace ``wget`` with ``curl`` and ``-O`` with ``-o``. For example:: + + > curl https://bootstrap.pypa.io/ez_setup.py -o - | python + + + Advanced Installation + ===================== + + For more advanced installation options, such as installing to custom + locations or prefixes, download and extract the source + tarball from `Setuptools on PyPI `_ + and run setup.py with any supported distutils and Setuptools options. + For example:: + + setuptools-x.x$ python setup.py install --prefix=/opt/setuptools + + Use ``--help`` to get a full options list, but we recommend consulting + the `EasyInstall manual`_ for detailed instructions, especially `the section + on custom installation locations`_. + + .. _EasyInstall manual: https://pythonhosted.org/setuptools/EasyInstall + .. _the section on custom installation locations: https://pythonhosted.org/setuptools/EasyInstall#custom-installation-locations + + + Downloads + ========= + + All setuptools downloads can be found at `the project's home page in the Python + Package Index`_. Scroll to the very bottom of the page to find the links. + + .. _the project's home page in the Python Package Index: https://pypi.python.org/pypi/setuptools + + In addition to the PyPI downloads, the development version of ``setuptools`` + is available from the `Bitbucket repo`_, and in-development versions of the + `0.6 branch`_ are available as well. + + .. _Bitbucket repo: https://bitbucket.org/pypa/setuptools/get/default.tar.gz#egg=setuptools-dev + .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 + + Uninstalling + ============ + + On Windows, if Setuptools was installed using an ``.exe`` or ``.msi`` + installer, simply use the uninstall feature of "Add/Remove Programs" in the + Control Panel. + + Otherwise, to uninstall Setuptools or Distribute, regardless of the Python + version, delete all ``setuptools*`` and ``distribute*`` files and + directories from your system's ``site-packages`` directory + (and any other ``sys.path`` directories) FIRST. + + If you are upgrading or otherwise plan to re-install Setuptools or Distribute, + nothing further needs to be done. If you want to completely remove Setuptools, + you may also want to remove the 'easy_install' and 'easy_install-x.x' scripts + and associated executables installed to the Python scripts directory. + + -------------------------------- + Using Setuptools and EasyInstall + -------------------------------- + + Here are some of the available manuals, tutorials, and other resources for + learning about Setuptools, Python Eggs, and EasyInstall: + + * `The EasyInstall user's guide and reference manual`_ + * `The setuptools Developer's Guide`_ + * `The pkg_resources API reference`_ + * `The Internal Structure of Python Eggs`_ + + Questions, comments, and bug reports should be directed to the `distutils-sig + mailing list`_. If you have written (or know of) any tutorials, documentation, + plug-ins, or other resources for setuptools users, please let us know about + them there, so this reference list can be updated. If you have working, + *tested* patches to correct problems or add features, you may submit them to + the `setuptools bug tracker`_. + + .. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/issues + .. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html + .. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html + .. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html + .. _The EasyInstall user's guide and reference manual: https://pythonhosted.org/setuptools/easy_install.html + .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ + + + ------- + Credits + ------- + + * The original design for the ``.egg`` format and the ``pkg_resources`` API was + co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first + version of ``pkg_resources``, and supplied the OS X operating system version + compatibility algorithm. + + * Ian Bicking implemented many early "creature comfort" features of + easy_install, including support for downloading via Sourceforge and + Subversion repositories. Ian's comments on the Web-SIG about WSGI + application deployment also inspired the concept of "entry points" in eggs, + and he has given talks at PyCon and elsewhere to inform and educate the + community about eggs and setuptools. + + * Jim Fulton contributed time and effort to build automated tests of various + aspects of ``easy_install``, and supplied the doctests for the command-line + ``.exe`` wrappers on Windows. + + * Phillip J. Eby is the seminal author of setuptools, and + first proposed the idea of an importable binary distribution format for + Python application plug-ins. + + * Significant parts of the implementation of setuptools were funded by the Open + Source Applications Foundation, to provide a plug-in infrastructure for the + Chandler PIM application. In addition, many OSAF staffers (such as Mike + "Code Bear" Taylor) contributed their time and stress as guinea pigs for the + use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) + + * Tarek Ziadé is the principal author of the Distribute fork, which + re-invigorated the community on the project, encouraged renewed innovation, + and addressed many defects. + + * Since the merge with Distribute, Jason R. Coombs is the + maintainer of setuptools. The project is maintained in coordination with + the Python Packaging Authority (PyPA) and the larger Python community. + + .. _files: + + + --------------- + Code of Conduct + --------------- + + Everyone interacting in the setuptools project's codebases, issue trackers, + chat rooms, and mailing lists is expected to follow the + `PyPA Code of Conduct`_. + + .. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/ + +Keywords: CPAN PyPI distutils eggs package management +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities diff -Nru python-setuptools-3.3/pkg_resources/api_tests.txt python-setuptools-20.1.1/pkg_resources/api_tests.txt --- python-setuptools-3.3/pkg_resources/api_tests.txt 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/api_tests.txt 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,425 @@ +Pluggable Distributions of Python Software +========================================== + +Distributions +------------- + +A "Distribution" is a collection of files that represent a "Release" of a +"Project" as of a particular point in time, denoted by a +"Version":: + + >>> import sys, pkg_resources + >>> from pkg_resources import Distribution + >>> Distribution(project_name="Foo", version="1.2") + Foo 1.2 + +Distributions have a location, which can be a filename, URL, or really anything +else you care to use:: + + >>> dist = Distribution( + ... location="http://example.com/something", + ... project_name="Bar", version="0.9" + ... ) + + >>> dist + Bar 0.9 (http://example.com/something) + + +Distributions have various introspectable attributes:: + + >>> dist.location + 'http://example.com/something' + + >>> dist.project_name + 'Bar' + + >>> dist.version + '0.9' + + >>> dist.py_version == sys.version[:3] + True + + >>> print(dist.platform) + None + +Including various computed attributes:: + + >>> from pkg_resources import parse_version + >>> dist.parsed_version == parse_version(dist.version) + True + + >>> dist.key # case-insensitive form of the project name + 'bar' + +Distributions are compared (and hashed) by version first:: + + >>> Distribution(version='1.0') == Distribution(version='1.0') + True + >>> Distribution(version='1.0') == Distribution(version='1.1') + False + >>> Distribution(version='1.0') < Distribution(version='1.1') + True + +but also by project name (case-insensitive), platform, Python version, +location, etc.:: + + >>> Distribution(project_name="Foo",version="1.0") == \ + ... Distribution(project_name="Foo",version="1.0") + True + + >>> Distribution(project_name="Foo",version="1.0") == \ + ... Distribution(project_name="foo",version="1.0") + True + + >>> Distribution(project_name="Foo",version="1.0") == \ + ... Distribution(project_name="Foo",version="1.1") + False + + >>> Distribution(project_name="Foo",py_version="2.3",version="1.0") == \ + ... Distribution(project_name="Foo",py_version="2.4",version="1.0") + False + + >>> Distribution(location="spam",version="1.0") == \ + ... Distribution(location="spam",version="1.0") + True + + >>> Distribution(location="spam",version="1.0") == \ + ... Distribution(location="baz",version="1.0") + False + + + +Hash and compare distribution by prio/plat + +Get version from metadata +provider capabilities +egg_name() +as_requirement() +from_location, from_filename (w/path normalization) + +Releases may have zero or more "Requirements", which indicate +what releases of another project the release requires in order to +function. A Requirement names the other project, expresses some criteria +as to what releases of that project are acceptable, and lists any "Extras" +that the requiring release may need from that project. (An Extra is an +optional feature of a Release, that can only be used if its additional +Requirements are satisfied.) + + + +The Working Set +--------------- + +A collection of active distributions is called a Working Set. Note that a +Working Set can contain any importable distribution, not just pluggable ones. +For example, the Python standard library is an importable distribution that +will usually be part of the Working Set, even though it is not pluggable. +Similarly, when you are doing development work on a project, the files you are +editing are also a Distribution. (And, with a little attention to the +directory names used, and including some additional metadata, such a +"development distribution" can be made pluggable as well.) + + >>> from pkg_resources import WorkingSet + +A working set's entries are the sys.path entries that correspond to the active +distributions. By default, the working set's entries are the items on +``sys.path``:: + + >>> ws = WorkingSet() + >>> ws.entries == sys.path + True + +But you can also create an empty working set explicitly, and add distributions +to it:: + + >>> ws = WorkingSet([]) + >>> ws.add(dist) + >>> ws.entries + ['http://example.com/something'] + >>> dist in ws + True + >>> Distribution('foo',version="") in ws + False + +And you can iterate over its distributions:: + + >>> list(ws) + [Bar 0.9 (http://example.com/something)] + +Adding the same distribution more than once is a no-op:: + + >>> ws.add(dist) + >>> list(ws) + [Bar 0.9 (http://example.com/something)] + +For that matter, adding multiple distributions for the same project also does +nothing, because a working set can only hold one active distribution per +project -- the first one added to it:: + + >>> ws.add( + ... Distribution( + ... 'http://example.com/something', project_name="Bar", + ... version="7.2" + ... ) + ... ) + >>> list(ws) + [Bar 0.9 (http://example.com/something)] + +You can append a path entry to a working set using ``add_entry()``:: + + >>> ws.entries + ['http://example.com/something'] + >>> ws.add_entry(pkg_resources.__file__) + >>> ws.entries + ['http://example.com/something', '...pkg_resources...'] + +Multiple additions result in multiple entries, even if the entry is already in +the working set (because ``sys.path`` can contain the same entry more than +once):: + + >>> ws.add_entry(pkg_resources.__file__) + >>> ws.entries + ['...example.com...', '...pkg_resources...', '...pkg_resources...'] + +And you can specify the path entry a distribution was found under, using the +optional second parameter to ``add()``:: + + >>> ws = WorkingSet([]) + >>> ws.add(dist,"foo") + >>> ws.entries + ['foo'] + +But even if a distribution is found under multiple path entries, it still only +shows up once when iterating the working set: + + >>> ws.add_entry(ws.entries[0]) + >>> list(ws) + [Bar 0.9 (http://example.com/something)] + +You can ask a WorkingSet to ``find()`` a distribution matching a requirement:: + + >>> from pkg_resources import Requirement + >>> print(ws.find(Requirement.parse("Foo==1.0"))) # no match, return None + None + + >>> ws.find(Requirement.parse("Bar==0.9")) # match, return distribution + Bar 0.9 (http://example.com/something) + +Note that asking for a conflicting version of a distribution already in a +working set triggers a ``pkg_resources.VersionConflict`` error: + + >>> try: + ... ws.find(Requirement.parse("Bar==1.0")) + ... except pkg_resources.VersionConflict as exc: + ... print(str(exc)) + ... else: + ... raise AssertionError("VersionConflict was not raised") + (Bar 0.9 (http://example.com/something), Requirement.parse('Bar==1.0')) + +You can subscribe a callback function to receive notifications whenever a new +distribution is added to a working set. The callback is immediately invoked +once for each existing distribution in the working set, and then is called +again for new distributions added thereafter:: + + >>> def added(dist): print("Added %s" % dist) + >>> ws.subscribe(added) + Added Bar 0.9 + >>> foo12 = Distribution(project_name="Foo", version="1.2", location="f12") + >>> ws.add(foo12) + Added Foo 1.2 + +Note, however, that only the first distribution added for a given project name +will trigger a callback, even during the initial ``subscribe()`` callback:: + + >>> foo14 = Distribution(project_name="Foo", version="1.4", location="f14") + >>> ws.add(foo14) # no callback, because Foo 1.2 is already active + + >>> ws = WorkingSet([]) + >>> ws.add(foo12) + >>> ws.add(foo14) + >>> ws.subscribe(added) + Added Foo 1.2 + +And adding a callback more than once has no effect, either:: + + >>> ws.subscribe(added) # no callbacks + + # and no double-callbacks on subsequent additions, either + >>> just_a_test = Distribution(project_name="JustATest", version="0.99") + >>> ws.add(just_a_test) + Added JustATest 0.99 + + +Finding Plugins +--------------- + +``WorkingSet`` objects can be used to figure out what plugins in an +``Environment`` can be loaded without any resolution errors:: + + >>> from pkg_resources import Environment + + >>> plugins = Environment([]) # normally, a list of plugin directories + >>> plugins.add(foo12) + >>> plugins.add(foo14) + >>> plugins.add(just_a_test) + +In the simplest case, we just get the newest version of each distribution in +the plugin environment:: + + >>> ws = WorkingSet([]) + >>> ws.find_plugins(plugins) + ([JustATest 0.99, Foo 1.4 (f14)], {}) + +But if there's a problem with a version conflict or missing requirements, the +method falls back to older versions, and the error info dict will contain an +exception instance for each unloadable plugin:: + + >>> ws.add(foo12) # this will conflict with Foo 1.4 + >>> ws.find_plugins(plugins) + ([JustATest 0.99, Foo 1.2 (f12)], {Foo 1.4 (f14): VersionConflict(...)}) + +But if you disallow fallbacks, the failed plugin will be skipped instead of +trying older versions:: + + >>> ws.find_plugins(plugins, fallback=False) + ([JustATest 0.99], {Foo 1.4 (f14): VersionConflict(...)}) + + + +Platform Compatibility Rules +---------------------------- + +On the Mac, there are potential compatibility issues for modules compiled +on newer versions of Mac OS X than what the user is running. Additionally, +Mac OS X will soon have two platforms to contend with: Intel and PowerPC. + +Basic equality works as on other platforms:: + + >>> from pkg_resources import compatible_platforms as cp + >>> reqd = 'macosx-10.4-ppc' + >>> cp(reqd, reqd) + True + >>> cp("win32", reqd) + False + +Distributions made on other machine types are not compatible:: + + >>> cp("macosx-10.4-i386", reqd) + False + +Distributions made on earlier versions of the OS are compatible, as +long as they are from the same top-level version. The patchlevel version +number does not matter:: + + >>> cp("macosx-10.4-ppc", reqd) + True + >>> cp("macosx-10.3-ppc", reqd) + True + >>> cp("macosx-10.5-ppc", reqd) + False + >>> cp("macosx-9.5-ppc", reqd) + False + +Backwards compatibility for packages made via earlier versions of +setuptools is provided as well:: + + >>> cp("darwin-8.2.0-Power_Macintosh", reqd) + True + >>> cp("darwin-7.2.0-Power_Macintosh", reqd) + True + >>> cp("darwin-8.2.0-Power_Macintosh", "macosx-10.3-ppc") + False + + +Environment Markers +------------------- + + >>> from pkg_resources import invalid_marker as im, evaluate_marker as em + >>> import os + + >>> print(im("sys_platform")) + Comparison or logical expression expected + + >>> print(im("sys_platform==")) + invalid syntax + + >>> print(im("sys_platform=='win32'")) + False + + >>> print(im("sys=='x'")) + Unknown name 'sys' + + >>> print(im("(extra)")) + Comparison or logical expression expected + + >>> print(im("(extra")) + invalid syntax + + >>> print(im("os.open('foo')=='y'")) + Language feature not supported in environment markers + + >>> print(im("'x'=='y' and os.open('foo')=='y'")) # no short-circuit! + Language feature not supported in environment markers + + >>> print(im("'x'=='x' or os.open('foo')=='y'")) # no short-circuit! + Language feature not supported in environment markers + + >>> print(im("'x' < 'y' < 'z'")) + Chained comparison not allowed in environment markers + + >>> print(im("r'x'=='x'")) + Only plain strings allowed in environment markers + + >>> print(im("'''x'''=='x'")) + Only plain strings allowed in environment markers + + >>> print(im('"""x"""=="x"')) + Only plain strings allowed in environment markers + + >>> print(im(r"'x\n'=='x'")) + Only plain strings allowed in environment markers + + >>> print(im("os.open=='y'")) + Language feature not supported in environment markers + + >>> em('"x"=="x"') + True + + >>> em('"x"=="y"') + False + + >>> em('"x"=="y" and "x"=="x"') + False + + >>> em('"x"=="y" or "x"=="x"') + True + + >>> em('"x"=="y" and "x"=="q" or "z"=="z"') + True + + >>> em('"x"=="y" and ("x"=="q" or "z"=="z")') + False + + >>> em('"x"=="y" and "z"=="z" or "x"=="q"') + False + + >>> em('"x"=="x" and "z"=="z" or "x"=="q"') + True + + >>> em("sys_platform=='win32'") == (sys.platform=='win32') + True + + >>> em("'x' in 'yx'") + True + + >>> em("'yx' in 'x'") + False + + >>> em("python_version >= '2.6'") + True + + >>> em("python_version > '2.5'") + True + + >>> im("platform_python_implementation=='CPython'") + False diff -Nru python-setuptools-3.3/pkg_resources/extern/__init__.py python-setuptools-20.1.1/pkg_resources/extern/__init__.py --- python-setuptools-3.3/pkg_resources/extern/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/extern/__init__.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,71 @@ +import sys + + +class VendorImporter: + """ + A PEP 302 meta path importer for finding optionally-vendored + or otherwise naturally-installed packages from root_name. + """ + def __init__(self, root_name, vendored_names=(), vendor_pkg=None): + self.root_name = root_name + self.vendored_names = set(vendored_names) + self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') + + @property + def search_path(self): + """ + Search first the vendor package then as a natural package. + """ + yield self.vendor_pkg + '.' + yield '' + + def find_module(self, fullname, path=None): + """ + Return self when fullname starts with root_name and the + target module is one vendored through this importer. + """ + root, base, target = fullname.partition(self.root_name + '.') + if root: + return + if not any(map(target.startswith, self.vendored_names)): + return + return self + + def load_module(self, fullname): + """ + Iterate over the search path to locate and load fullname. + """ + root, base, target = fullname.partition(self.root_name + '.') + for prefix in self.search_path: + try: + extant = prefix + target + __import__(extant) + mod = sys.modules[extant] + sys.modules[fullname] = mod + # mysterious hack: + # Remove the reference to the extant package/module + # on later Python versions to cause relative imports + # in the vendor package to resolve the same modules + # as those going through this importer. + if sys.version_info > (3, 3): + del sys.modules[extant] + return mod + except ImportError: + pass + else: + raise ImportError( + "The '{target}' package is required; " + "normally this is bundled with this package so if you get " + "this warning, consult the packager of your " + "distribution.".format(**locals()) + ) + + def install(self): + """ + Install this importer into sys.meta_path if not already present. + """ + if self not in sys.meta_path: + sys.meta_path.append(self) + +names = 'packaging', 'six' +VendorImporter(__name__, names).install() diff -Nru python-setuptools-3.3/pkg_resources/__init__.py python-setuptools-20.1.1/pkg_resources/__init__.py --- python-setuptools-3.3/pkg_resources/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/__init__.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,3170 @@ +""" +Package resource API +-------------------- + +A resource is a logical file contained within a package, or a logical +subdirectory thereof. The package resource API expects resource names +to have their path parts separated with ``/``, *not* whatever the local +path separator is. Do not use os.path operations to manipulate resource +names being passed into the API. + +The package resource API is designed to work with normal filesystem packages, +.egg files, and unpacked .egg files. It can also work in a limited way with +.zip files and with custom PEP 302 loaders that support the ``get_data()`` +method. +""" + +from __future__ import absolute_import + +import sys +import os +import io +import time +import re +import types +import zipfile +import zipimport +import warnings +import stat +import functools +import pkgutil +import token +import symbol +import operator +import platform +import collections +import plistlib +import email.parser +import tempfile +import textwrap +from pkgutil import get_importer + +try: + import _imp +except ImportError: + # Python 3.2 compatibility + import imp as _imp + +from pkg_resources.extern import six +from pkg_resources.extern.six.moves import urllib, map, filter + +# capture these to bypass sandboxing +from os import utime +try: + from os import mkdir, rename, unlink + WRITE_SUPPORT = True +except ImportError: + # no write support, probably under GAE + WRITE_SUPPORT = False + +from os import open as os_open +from os.path import isdir, split + +try: + import importlib.machinery as importlib_machinery + # access attribute to force import under delayed import mechanisms. + importlib_machinery.__name__ +except ImportError: + importlib_machinery = None + +try: + import parser +except ImportError: + pass + +from pkg_resources.extern import packaging +__import__('pkg_resources.extern.packaging.version') +__import__('pkg_resources.extern.packaging.specifiers') + + +if (3, 0) < sys.version_info < (3, 3): + msg = ( + "Support for Python 3.0-3.2 has been dropped. Future versions " + "will fail here." + ) + warnings.warn(msg) + +# declare some globals that will be defined later to +# satisfy the linters. +require = None +working_set = None + + +class PEP440Warning(RuntimeWarning): + """ + Used when there is an issue with a version or specifier not complying with + PEP 440. + """ + + +class _SetuptoolsVersionMixin(object): + + def __hash__(self): + return super(_SetuptoolsVersionMixin, self).__hash__() + + def __lt__(self, other): + if isinstance(other, tuple): + return tuple(self) < other + else: + return super(_SetuptoolsVersionMixin, self).__lt__(other) + + def __le__(self, other): + if isinstance(other, tuple): + return tuple(self) <= other + else: + return super(_SetuptoolsVersionMixin, self).__le__(other) + + def __eq__(self, other): + if isinstance(other, tuple): + return tuple(self) == other + else: + return super(_SetuptoolsVersionMixin, self).__eq__(other) + + def __ge__(self, other): + if isinstance(other, tuple): + return tuple(self) >= other + else: + return super(_SetuptoolsVersionMixin, self).__ge__(other) + + def __gt__(self, other): + if isinstance(other, tuple): + return tuple(self) > other + else: + return super(_SetuptoolsVersionMixin, self).__gt__(other) + + def __ne__(self, other): + if isinstance(other, tuple): + return tuple(self) != other + else: + return super(_SetuptoolsVersionMixin, self).__ne__(other) + + def __getitem__(self, key): + return tuple(self)[key] + + def __iter__(self): + component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE) + 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 == '.': + continue + if part[:1] in '0123456789': + # pad for numeric comparison + yield part.zfill(8) + else: + yield '*'+part + + # ensure that alpha/beta/candidate are before final + yield '*final' + + def old_parse_version(s): + parts = [] + for part in _parse_version_parts(s.lower()): + if part.startswith('*'): + # remove '-' before a prerelease tag + if part < '*final': + 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() + parts.append(part) + return tuple(parts) + + # Warn for use of this function + warnings.warn( + "You have iterated over the result of " + "pkg_resources.parse_version. This is a legacy behavior which is " + "inconsistent with the new version class introduced in setuptools " + "8.0. In most cases, conversion to a tuple is unnecessary. For " + "comparison of versions, sort the Version instances directly. If " + "you have another use case requiring the tuple, please file a " + "bug with the setuptools project describing that need.", + RuntimeWarning, + stacklevel=1, + ) + + for part in old_parse_version(str(self)): + yield part + + +class SetuptoolsVersion(_SetuptoolsVersionMixin, packaging.version.Version): + pass + + +class SetuptoolsLegacyVersion(_SetuptoolsVersionMixin, + packaging.version.LegacyVersion): + pass + + +def parse_version(v): + try: + return SetuptoolsVersion(v) + except packaging.version.InvalidVersion: + return SetuptoolsLegacyVersion(v) + + +_state_vars = {} + +def _declare_state(vartype, **kw): + globals().update(kw) + _state_vars.update(dict.fromkeys(kw, vartype)) + +def __getstate__(): + state = {} + g = globals() + for k, v in _state_vars.items(): + state[k] = g['_sget_'+v](g[k]) + return state + +def __setstate__(state): + g = globals() + for k, v in state.items(): + g['_sset_'+_state_vars[k]](k, g[k], v) + return state + +def _sget_dict(val): + return val.copy() + +def _sset_dict(key, ob, state): + ob.clear() + ob.update(state) + +def _sget_object(val): + return val.__getstate__() + +def _sset_object(key, ob, state): + ob.__setstate__(state) + +_sget_none = _sset_none = lambda *args: None + + +def get_supported_platform(): + """Return this platform's maximum compatible version. + + distutils.util.get_platform() normally reports the minimum version + of Mac OS X that would be required to *use* extensions produced by + distutils. But what we want when checking compatibility is to know the + version of Mac OS X that we are *running*. To allow usage of packages that + explicitly require a newer version of Mac OS X, we must also know the + current version of the OS. + + If this condition occurs for any other platform with a version in its + platform strings, this function should be extended accordingly. + """ + plat = get_build_platform() + m = macosVersionString.match(plat) + if m is not None and sys.platform == "darwin": + try: + plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) + except ValueError: + # not Mac OS X + pass + return plat + +__all__ = [ + # Basic resource access and distribution/entry point discovery + 'require', 'run_script', 'get_provider', 'get_distribution', + 'load_entry_point', 'get_entry_map', 'get_entry_info', + 'iter_entry_points', + 'resource_string', 'resource_stream', 'resource_filename', + 'resource_listdir', 'resource_exists', 'resource_isdir', + + # Environmental control + 'declare_namespace', 'working_set', 'add_activation_listener', + 'find_distributions', 'set_extraction_path', 'cleanup_resources', + 'get_default_cache', + + # Primary implementation classes + 'Environment', 'WorkingSet', 'ResourceManager', + 'Distribution', 'Requirement', 'EntryPoint', + + # Exceptions + 'ResolutionError', 'VersionConflict', 'DistributionNotFound', + 'UnknownExtra', 'ExtractionError', + + # Warnings + 'PEP440Warning', + + # Parsing functions and string utilities + 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', + 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', + 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', + + # filesystem utilities + 'ensure_directory', 'normalize_path', + + # Distribution "precedence" constants + 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST', + + # "Provider" interfaces, implementations, and registration/lookup APIs + 'IMetadataProvider', 'IResourceProvider', 'FileMetadata', + 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider', + 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider', + 'register_finder', 'register_namespace_handler', 'register_loader_type', + 'fixup_namespace_packages', 'get_importer', + + # Deprecated/backward compatibility only + 'run_main', 'AvailableDistributions', +] + +class ResolutionError(Exception): + """Abstract base for dependency resolution errors""" + def __repr__(self): + return self.__class__.__name__+repr(self.args) + + +class VersionConflict(ResolutionError): + """ + An already-installed version conflicts with the requested version. + + Should be initialized with the installed Distribution and the requested + Requirement. + """ + + _template = "{self.dist} is installed but {self.req} is required" + + @property + def dist(self): + return self.args[0] + + @property + def req(self): + return self.args[1] + + def report(self): + return self._template.format(**locals()) + + def with_context(self, required_by): + """ + If required_by is non-empty, return a version of self that is a + ContextualVersionConflict. + """ + if not required_by: + return self + args = self.args + (required_by,) + return ContextualVersionConflict(*args) + + +class ContextualVersionConflict(VersionConflict): + """ + A VersionConflict that accepts a third parameter, the set of the + requirements that required the installed Distribution. + """ + + _template = VersionConflict._template + ' by {self.required_by}' + + @property + def required_by(self): + return self.args[2] + + +class DistributionNotFound(ResolutionError): + """A requested distribution was not found""" + + _template = ("The '{self.req}' distribution was not found " + "and is required by {self.requirers_str}") + + @property + def req(self): + return self.args[0] + + @property + def requirers(self): + return self.args[1] + + @property + def requirers_str(self): + if not self.requirers: + return 'the application' + return ', '.join(self.requirers) + + def report(self): + return self._template.format(**locals()) + + def __str__(self): + return self.report() + + +class UnknownExtra(ResolutionError): + """Distribution doesn't have an "extra feature" of the given name""" +_provider_factories = {} + +PY_MAJOR = sys.version[:3] +EGG_DIST = 3 +BINARY_DIST = 2 +SOURCE_DIST = 1 +CHECKOUT_DIST = 0 +DEVELOP_DIST = -1 + +def register_loader_type(loader_type, provider_factory): + """Register `provider_factory` to make providers for `loader_type` + + `loader_type` is the type or class of a PEP 302 ``module.__loader__``, + and `provider_factory` is a function that, passed a *module* object, + returns an ``IResourceProvider`` for that module. + """ + _provider_factories[loader_type] = provider_factory + +def get_provider(moduleOrReq): + """Return an IResourceProvider for the named module or requirement""" + if isinstance(moduleOrReq, Requirement): + return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0] + try: + module = sys.modules[moduleOrReq] + except KeyError: + __import__(moduleOrReq) + module = sys.modules[moduleOrReq] + loader = getattr(module, '__loader__', None) + return _find_adapter(_provider_factories, loader)(module) + +def _macosx_vers(_cache=[]): + if not _cache: + version = platform.mac_ver()[0] + # fallback for MacPorts + if version == '': + plist = '/System/Library/CoreServices/SystemVersion.plist' + if os.path.exists(plist): + if hasattr(plistlib, 'readPlist'): + plist_content = plistlib.readPlist(plist) + if 'ProductVersion' in plist_content: + version = plist_content['ProductVersion'] + + _cache.append(version.split('.')) + return _cache[0] + +def _macosx_arch(machine): + return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine) + +def get_build_platform(): + """Return this platform's string for platform-specific distributions + + XXX Currently this is the same as ``distutils.util.get_platform()``, but it + needs some hacks for Linux and Mac OS X. + """ + try: + # Python 2.7 or >=3.2 + from sysconfig import get_platform + except ImportError: + from distutils.util import get_platform + + plat = get_platform() + if sys.platform == "darwin" and not plat.startswith('macosx-'): + try: + version = _macosx_vers() + machine = os.uname()[4].replace(" ", "_") + return "macosx-%d.%d-%s" % (int(version[0]), int(version[1]), + _macosx_arch(machine)) + except ValueError: + # if someone is running a non-Mac darwin system, this will fall + # through to the default implementation + pass + return plat + +macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)") +darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") +# XXX backward compat +get_platform = get_build_platform + + +def compatible_platforms(provided, required): + """Can code for the `provided` platform run on the `required` platform? + + Returns true if either platform is ``None``, or the platforms are equal. + + XXX Needs compatibility checks for Linux and other unixy OSes. + """ + if provided is None or required is None or provided==required: + # easy case + return True + + # Mac OS X special cases + reqMac = macosVersionString.match(required) + if reqMac: + provMac = macosVersionString.match(provided) + + # is this a Mac package? + if not provMac: + # this is backwards compatibility for packages built before + # setuptools 0.6. All packages built after this point will + # use the new macosx designation. + provDarwin = darwinVersionString.match(provided) + if provDarwin: + dversion = int(provDarwin.group(1)) + macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) + if dversion == 7 and macosversion >= "10.3" or \ + dversion == 8 and macosversion >= "10.4": + return True + # egg isn't macosx or legacy darwin + return False + + # are they the same major version and machine type? + if provMac.group(1) != reqMac.group(1) or \ + provMac.group(3) != reqMac.group(3): + return False + + # is the required OS major update >= the provided one? + if int(provMac.group(2)) > int(reqMac.group(2)): + return False + + return True + + # XXX Linux and other platforms' special cases should go here + return False + + +def run_script(dist_spec, script_name): + """Locate distribution `dist_spec` and run its `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + require(dist_spec)[0].run_script(script_name, ns) + +# backward compatibility +run_main = run_script + +def get_distribution(dist): + """Return a current distribution object for a Requirement or string""" + if isinstance(dist, six.string_types): + dist = Requirement.parse(dist) + if isinstance(dist, Requirement): + dist = get_provider(dist) + if not isinstance(dist, Distribution): + raise TypeError("Expected string, Requirement, or Distribution", dist) + return dist + +def load_entry_point(dist, group, name): + """Return `name` entry point of `group` for `dist` or raise ImportError""" + return get_distribution(dist).load_entry_point(group, name) + +def get_entry_map(dist, group=None): + """Return the entry point map for `group`, or the full entry map""" + return get_distribution(dist).get_entry_map(group) + +def get_entry_info(dist, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return get_distribution(dist).get_entry_info(group, name) + + +class IMetadataProvider: + + def has_metadata(name): + """Does the package's distribution contain the named metadata?""" + + def get_metadata(name): + """The named metadata resource as a string""" + + def get_metadata_lines(name): + """Yield named metadata resource as list of non-blank non-comment lines + + Leading and trailing whitespace is stripped from each line, and lines + with ``#`` as the first non-blank character are omitted.""" + + def metadata_isdir(name): + """Is the named metadata a directory? (like ``os.path.isdir()``)""" + + def metadata_listdir(name): + """List of metadata names in the directory (like ``os.listdir()``)""" + + def run_script(script_name, namespace): + """Execute the named script in the supplied namespace dictionary""" + + +class IResourceProvider(IMetadataProvider): + """An object that provides access to package resources""" + + def get_resource_filename(manager, resource_name): + """Return a true filesystem path for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_stream(manager, resource_name): + """Return a readable file-like object for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_string(manager, resource_name): + """Return a string containing the contents of `resource_name` + + `manager` must be an ``IResourceManager``""" + + def has_resource(resource_name): + """Does the package contain the named resource?""" + + def resource_isdir(resource_name): + """Is the named resource a directory? (like ``os.path.isdir()``)""" + + def resource_listdir(resource_name): + """List of resource names in the directory (like ``os.listdir()``)""" + + +class WorkingSet(object): + """A collection of active distributions on sys.path (or a similar list)""" + + def __init__(self, entries=None): + """Create working set from list of path entries (default=sys.path)""" + self.entries = [] + self.entry_keys = {} + self.by_key = {} + self.callbacks = [] + + if entries is None: + entries = sys.path + + for entry in entries: + self.add_entry(entry) + + @classmethod + def _build_master(cls): + """ + Prepare the master working set. + """ + ws = cls() + try: + from __main__ import __requires__ + except ImportError: + # The main program does not list any requirements + return ws + + # ensure the requirements are met + try: + ws.require(__requires__) + except VersionConflict: + return cls._build_from_requirements(__requires__) + + return ws + + @classmethod + def _build_from_requirements(cls, req_spec): + """ + Build a working set from a requirement spec. Rewrites sys.path. + """ + # try it without defaults already on sys.path + # by starting with an empty path + ws = cls([]) + reqs = parse_requirements(req_spec) + dists = ws.resolve(reqs, Environment()) + for dist in dists: + ws.add(dist) + + # add any missing entries from sys.path + for entry in sys.path: + if entry not in ws.entries: + ws.add_entry(entry) + + # then copy back to sys.path + sys.path[:] = ws.entries + return ws + + def add_entry(self, entry): + """Add a path item to ``.entries``, finding any distributions on it + + ``find_distributions(entry, True)`` is used to find distributions + corresponding to the path entry, and they are added. `entry` is + always appended to ``.entries``, even if it is already present. + (This is because ``sys.path`` can contain the same value more than + once, and the ``.entries`` of the ``sys.path`` WorkingSet should always + equal ``sys.path``.) + """ + self.entry_keys.setdefault(entry, []) + self.entries.append(entry) + for dist in find_distributions(entry, True): + self.add(dist, entry, False) + + def __contains__(self, dist): + """True if `dist` is the active distribution for its project""" + return self.by_key.get(dist.key) == dist + + def find(self, req): + """Find a distribution matching requirement `req` + + If there is an active distribution for the requested project, this + returns it as long as it meets the version requirement specified by + `req`. But, if there is an active distribution for the project and it + does *not* meet the `req` requirement, ``VersionConflict`` is raised. + If there is no active distribution for the requested project, ``None`` + is returned. + """ + dist = self.by_key.get(req.key) + if dist is not None and dist not in req: + # XXX add more info + raise VersionConflict(dist, req) + return dist + + def iter_entry_points(self, group, name=None): + """Yield entry point objects from `group` matching `name` + + If `name` is None, yields all entry points in `group` from all + distributions in the working set, otherwise only ones matching + both `group` and `name` are yielded (in distribution order). + """ + for dist in self: + entries = dist.get_entry_map(group) + if name is None: + for ep in entries.values(): + yield ep + elif name in entries: + yield entries[name] + + def run_script(self, requires, script_name): + """Locate distribution for `requires` and run `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + self.require(requires)[0].run_script(script_name, ns) + + def __iter__(self): + """Yield distributions for non-duplicate projects in the working set + + The yield order is the order in which the items' path entries were + added to the working set. + """ + 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 + yield self.by_key[key] + + def add(self, dist, entry=None, insert=True, replace=False): + """Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to the ``.location`` of `dist`. + On exit from this routine, `entry` is added to the end of the working + set's ``.entries`` (if it wasn't already present). + + `dist` is only added to the working set if it's for a project that + doesn't already have a distribution in the set, unless `replace=True`. + If it's added, any callbacks registered with the ``subscribe()`` method + will be called. + """ + if insert: + dist.insert_on(self.entries, entry, replace=replace) + + if entry is None: + entry = dist.location + keys = self.entry_keys.setdefault(entry,[]) + keys2 = self.entry_keys.setdefault(dist.location,[]) + if not replace and dist.key in self.by_key: + # ignore hidden distros + return + + self.by_key[dist.key] = dist + if dist.key not in keys: + keys.append(dist.key) + if dist.key not in keys2: + keys2.append(dist.key) + self._added_new(dist) + + def resolve(self, requirements, env=None, installer=None, + replace_conflicting=False): + """List all distributions needed to (recursively) meet `requirements` + + `requirements` must be a sequence of ``Requirement`` objects. `env`, + if supplied, should be an ``Environment`` instance. If + not supplied, it defaults to all distributions available within any + entry or distribution in the working set. `installer`, if supplied, + will be invoked with each requirement that cannot be met by an + already-installed distribution; it should return a ``Distribution`` or + ``None``. + + Unless `replace_conflicting=True`, raises a VersionConflict exception if + any requirements are found on the path that have the correct name but + the wrong version. Otherwise, if an `installer` is supplied it will be + invoked to obtain the correct version of the requirement and activate + it. + """ + + # set up the stack + requirements = list(requirements)[::-1] + # set of processed requirements + processed = {} + # key -> dist + best = {} + to_activate = [] + + # Mapping of requirement to set of distributions that required it; + # useful for reporting info about conflicts. + required_by = collections.defaultdict(set) + + while requirements: + # process dependencies breadth-first + req = requirements.pop(0) + if req in processed: + # Ignore cyclic or redundant dependencies + continue + dist = best.get(req.key) + if dist is None: + # Find the best distribution and add it to the map + dist = self.by_key.get(req.key) + if dist is None or (dist not in req and replace_conflicting): + ws = self + if env is None: + if dist is None: + env = Environment(self.entries) + else: + # Use an empty environment and workingset to avoid + # any further conflicts with the conflicting + # distribution + env = Environment([]) + ws = WorkingSet([]) + dist = best[req.key] = env.best_match(req, ws, installer) + if dist is None: + requirers = required_by.get(req, None) + raise DistributionNotFound(req, requirers) + to_activate.append(dist) + if dist not in req: + # Oops, the "best" so far conflicts with a dependency + dependent_req = required_by[req] + raise VersionConflict(dist, req).with_context(dependent_req) + + # push the new requirements onto the stack + new_requirements = dist.requires(req.extras)[::-1] + requirements.extend(new_requirements) + + # Register the new requirements needed by req + for new_requirement in new_requirements: + required_by[new_requirement].add(req.project_name) + + processed[req] = True + + # return list of distros to activate + return to_activate + + def find_plugins(self, plugin_env, full_env=None, installer=None, + fallback=True): + """Find all activatable distributions in `plugin_env` + + Example usage:: + + distributions, errors = working_set.find_plugins( + Environment(plugin_dirlist) + ) + # add plugins+libs to sys.path + map(working_set.add, distributions) + # display errors + print('Could not load', errors) + + The `plugin_env` should be an ``Environment`` instance that contains + only distributions that are in the project's "plugin directory" or + directories. The `full_env`, if supplied, should be an ``Environment`` + contains all currently-available distributions. If `full_env` is not + supplied, one is created automatically from the ``WorkingSet`` this + method is called on, which will typically mean that every directory on + ``sys.path`` will be scanned for distributions. + + `installer` is a standard installer callback as used by the + ``resolve()`` method. The `fallback` flag indicates whether we should + attempt to resolve older versions of a plugin if the newest version + cannot be resolved. + + This method returns a 2-tuple: (`distributions`, `error_info`), where + `distributions` is a list of the distributions found in `plugin_env` + that were loadable, along with any other distributions that are needed + to resolve their dependencies. `error_info` is a dictionary mapping + unloadable plugin distributions to an exception instance describing the + error that occurred. Usually this will be a ``DistributionNotFound`` or + ``VersionConflict`` instance. + """ + + plugin_projects = list(plugin_env) + # scan project names in alphabetic order + plugin_projects.sort() + + error_info = {} + distributions = {} + + if full_env is None: + env = Environment(self.entries) + env += plugin_env + else: + env = full_env + plugin_env + + shadow_set = self.__class__([]) + # put all our entries in shadow_set + list(map(shadow_set.add, self)) + + for project_name in plugin_projects: + + for dist in plugin_env[project_name]: + + req = [dist.as_requirement()] + + try: + resolvees = shadow_set.resolve(req, env, installer) + + except ResolutionError as v: + # save error info + error_info[dist] = v + if fallback: + # try the next older version of project + continue + else: + # give up on this project, keep going + break + + else: + list(map(shadow_set.add, resolvees)) + distributions.update(dict.fromkeys(resolvees)) + + # success, no need to try any more versions of this project + break + + distributions = list(distributions) + distributions.sort() + + return distributions, error_info + + def require(self, *requirements): + """Ensure that distributions matching `requirements` are activated + + `requirements` must be a string or a (possibly-nested) sequence + thereof, specifying the distributions and versions required. The + return value is a sequence of the distributions that needed to be + activated to fulfill the requirements; all relevant distributions are + included, even if they were already activated in this working set. + """ + needed = self.resolve(parse_requirements(requirements)) + + for dist in needed: + self.add(dist) + + return needed + + def subscribe(self, callback): + """Invoke `callback` for all distributions (including existing ones)""" + if callback in self.callbacks: + return + self.callbacks.append(callback) + for dist in self: + callback(dist) + + def _added_new(self, dist): + for callback in self.callbacks: + callback(dist) + + def __getstate__(self): + return ( + self.entries[:], self.entry_keys.copy(), self.by_key.copy(), + self.callbacks[:] + ) + + def __setstate__(self, e_k_b_c): + entries, keys, by_key, callbacks = e_k_b_c + self.entries = entries[:] + self.entry_keys = keys.copy() + self.by_key = by_key.copy() + self.callbacks = callbacks[:] + + +class Environment(object): + """Searchable snapshot of distributions on a search path""" + + def __init__(self, search_path=None, platform=get_supported_platform(), + python=PY_MAJOR): + """Snapshot distributions available on a search path + + Any distributions found on `search_path` are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. + + `platform` is an optional string specifying the name of the platform + that platform-specific distributions must be compatible with. If + unspecified, it defaults to the current platform. `python` is an + optional string naming the desired version of Python (e.g. ``'3.3'``); + it defaults to the current version. + + You may explicitly set `platform` (and/or `python`) to ``None`` if you + wish to map *all* distributions, not just those compatible with the + running platform or Python version. + """ + self._distmap = {} + self.platform = platform + self.python = python + self.scan(search_path) + + def can_add(self, dist): + """Is distribution `dist` acceptable for this environment? + + The distribution must match the platform and python version + requirements specified when this environment was created, or False + is returned. + """ + return (self.python is None or dist.py_version is None + or dist.py_version==self.python) \ + and compatible_platforms(dist.platform, self.platform) + + def remove(self, dist): + """Remove `dist` from the environment""" + self._distmap[dist.key].remove(dist) + + def scan(self, search_path=None): + """Scan `search_path` for distributions usable in this environment + + Any distributions found are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. Only distributions conforming to + the platform/python version defined at initialization are added. + """ + if search_path is None: + search_path = sys.path + + for item in search_path: + for dist in find_distributions(item): + self.add(dist) + + def __getitem__(self, project_name): + """Return a newest-to-oldest list of distributions for `project_name` + + Uses case-insensitive `project_name` comparison, assuming all the + project's distributions use their project's name converted to all + lowercase as their key. + + """ + distribution_key = project_name.lower() + return self._distmap.get(distribution_key, []) + + def add(self, dist): + """Add `dist` if we ``can_add()`` it and it has not already been added + """ + if self.can_add(dist) and dist.has_version(): + dists = self._distmap.setdefault(dist.key, []) + if dist not in dists: + dists.append(dist) + dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) + + def best_match(self, req, working_set, installer=None): + """Find distribution best matching `req` and usable on `working_set` + + This calls the ``find(req)`` method of the `working_set` to see if a + suitable distribution is already active. (This may raise + ``VersionConflict`` if an unsuitable version of the project is already + active in the specified `working_set`.) If a suitable distribution + isn't active, this method returns the newest distribution in the + environment that meets the ``Requirement`` in `req`. If no suitable + distribution is found, and `installer` is supplied, then the result of + calling the environment's ``obtain(req, installer)`` method will be + returned. + """ + dist = working_set.find(req) + if dist is not None: + return dist + for dist in self[req.key]: + if dist in req: + return dist + # try to download/install + return self.obtain(req, installer) + + def obtain(self, requirement, installer=None): + """Obtain a distribution matching `requirement` (e.g. via download) + + Obtain a distro that matches requirement (e.g. via download). In the + base ``Environment`` class, this routine just returns + ``installer(requirement)``, unless `installer` is None, in which case + None is returned instead. This method is a hook that allows subclasses + to attempt other ways of obtaining a distribution before falling back + to the `installer` argument.""" + if installer is not None: + return installer(requirement) + + def __iter__(self): + """Yield the unique project names of the available distributions""" + for key in self._distmap.keys(): + if self[key]: + yield key + + def __iadd__(self, other): + """In-place addition of a distribution or environment""" + if isinstance(other, Distribution): + self.add(other) + elif isinstance(other, Environment): + for project in other: + for dist in other[project]: + self.add(dist) + else: + raise TypeError("Can't add %r to environment" % (other,)) + return self + + def __add__(self, other): + """Add an environment or distribution to an environment""" + new = self.__class__([], platform=None, python=None) + for env in self, other: + new += env + return new + + +# XXX backward compatibility +AvailableDistributions = Environment + + +class ExtractionError(RuntimeError): + """An error occurred extracting a resource + + The following attributes are available from instances of this exception: + + manager + The resource manager that raised this exception + + cache_path + The base directory for resource extraction + + original_error + The exception instance that caused extraction to fail + """ + + +class ResourceManager: + """Manage resource extraction and packages""" + extraction_path = None + + def __init__(self): + self.cached_files = {} + + def resource_exists(self, package_or_requirement, resource_name): + """Does the named resource exist?""" + return get_provider(package_or_requirement).has_resource(resource_name) + + def resource_isdir(self, package_or_requirement, resource_name): + """Is the named resource an existing directory?""" + return get_provider(package_or_requirement).resource_isdir( + resource_name + ) + + def resource_filename(self, package_or_requirement, resource_name): + """Return a true filesystem path for specified resource""" + return get_provider(package_or_requirement).get_resource_filename( + self, resource_name + ) + + def resource_stream(self, package_or_requirement, resource_name): + """Return a readable file-like object for specified resource""" + return get_provider(package_or_requirement).get_resource_stream( + self, resource_name + ) + + def resource_string(self, package_or_requirement, resource_name): + """Return specified resource as a string""" + return get_provider(package_or_requirement).get_resource_string( + self, resource_name + ) + + def resource_listdir(self, package_or_requirement, resource_name): + """List the contents of the named resource directory""" + return get_provider(package_or_requirement).resource_listdir( + resource_name + ) + + def extraction_error(self): + """Give an error message for problems extracting file(s)""" + + old_exc = sys.exc_info()[1] + cache_path = self.extraction_path or get_default_cache() + + tmpl = textwrap.dedent(""" + Can't extract file(s) to egg cache + + The following error occurred while trying to extract file(s) to the Python egg + cache: + + {old_exc} + + The Python egg cache directory is currently set to: + + {cache_path} + + Perhaps your account does not have write access to this directory? You can + change the cache directory by setting the PYTHON_EGG_CACHE environment + variable to point to an accessible directory. + """).lstrip() + err = ExtractionError(tmpl.format(**locals())) + err.manager = self + err.cache_path = cache_path + err.original_error = old_exc + raise err + + def get_cache_path(self, archive_name, names=()): + """Return absolute location in cache for `archive_name` and `names` + + The parent directory of the resulting path will be created if it does + not already exist. `archive_name` should be the base filename of the + enclosing egg (which may not be the name of the enclosing zipfile!), + including its ".egg" extension. `names`, if provided, should be a + sequence of path name parts "under" the egg's extraction location. + + This method should only be called by resource providers that need to + obtain an extraction location, and only for names they intend to + extract, as it tracks the generated names for possible cleanup later. + """ + extract_path = self.extraction_path or get_default_cache() + target_path = os.path.join(extract_path, archive_name+'-tmp', *names) + try: + _bypass_ensure_directory(target_path) + except: + self.extraction_error() + + self._warn_unsafe_extraction_path(extract_path) + + self.cached_files[target_path] = 1 + return target_path + + @staticmethod + def _warn_unsafe_extraction_path(path): + """ + If the default extraction path is overridden and set to an insecure + location, such as /tmp, it opens up an opportunity for an attacker to + replace an extracted file with an unauthorized payload. Warn the user + if a known insecure location is used. + + See Distribute #375 for more details. + """ + if os.name == 'nt' and not path.startswith(os.environ['windir']): + # On Windows, permissions are generally restrictive by default + # and temp directories are not writable by other users, so + # bypass the warning. + return + mode = os.stat(path).st_mode + if mode & stat.S_IWOTH or mode & stat.S_IWGRP: + msg = ("%s is writable by group/others and vulnerable to attack " + "when " + "used with get_resource_filename. Consider a more secure " + "location (set with .set_extraction_path or the " + "PYTHON_EGG_CACHE environment variable)." % path) + warnings.warn(msg, UserWarning) + + def postprocess(self, tempname, filename): + """Perform any platform-specific postprocessing of `tempname` + + This is where Mac header rewrites should be done; other platforms don't + have anything special they should do. + + Resource providers should call this method ONLY after successfully + extracting a compressed resource. They must NOT call it on resources + that are already in the filesystem. + + `tempname` is the current (temporary) name of the file, and `filename` + is the name it will be renamed to by the caller after this routine + returns. + """ + + if os.name == 'posix': + # Make the resource executable + mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777 + os.chmod(tempname, mode) + + def set_extraction_path(self, path): + """Set the base path where resources will be extracted to, if needed. + + If you do not call this routine before any extractions take place, the + path defaults to the return value of ``get_default_cache()``. (Which + is based on the ``PYTHON_EGG_CACHE`` environment variable, with various + platform-specific fallbacks. See that routine's documentation for more + details.) + + Resources are extracted to subdirectories of this path based upon + information given by the ``IResourceProvider``. You may set this to a + temporary directory, but then you must call ``cleanup_resources()`` to + delete the extracted files when done. There is no guarantee that + ``cleanup_resources()`` will be able to remove all extracted files. + + (Note: you may not change the extraction path for a given resource + manager once resources have been extracted, unless you first call + ``cleanup_resources()``.) + """ + if self.cached_files: + raise ValueError( + "Can't change extraction path, files already extracted" + ) + + self.extraction_path = path + + def cleanup_resources(self, force=False): + """ + Delete all extracted resource files and directories, returning a list + of the file and directory names that could not be successfully removed. + This function does not have any concurrency protection, so it should + generally only be called when the extraction path is a temporary + directory exclusive to a single process. This method is not + automatically called; you must call it explicitly or register it as an + ``atexit`` function if you wish to ensure cleanup of a temporary + directory used for extractions. + """ + # XXX + +def get_default_cache(): + """Determine the default cache location + + This returns the ``PYTHON_EGG_CACHE`` environment variable, if set. + Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of the + "Application Data" directory. On all other systems, it's "~/.python-eggs". + """ + try: + return os.environ['PYTHON_EGG_CACHE'] + except KeyError: + pass + + if os.name!='nt': + return os.path.expanduser('~/.python-eggs') + + # XXX this may be locale-specific! + app_data = 'Application Data' + app_homes = [ + # best option, should be locale-safe + (('APPDATA',), None), + (('USERPROFILE',), app_data), + (('HOMEDRIVE','HOMEPATH'), app_data), + (('HOMEPATH',), app_data), + (('HOME',), None), + # 95/98/ME + (('WINDIR',), app_data), + ] + + for keys, subdir in app_homes: + dirname = '' + for key in keys: + if key in os.environ: + dirname = os.path.join(dirname, os.environ[key]) + else: + break + else: + if subdir: + dirname = os.path.join(dirname, subdir) + return os.path.join(dirname, 'Python-Eggs') + else: + raise RuntimeError( + "Please set the PYTHON_EGG_CACHE enviroment variable" + ) + +def safe_name(name): + """Convert an arbitrary string to a standard distribution name + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub('[^A-Za-z0-9.]+', '-', name) + + +def safe_version(version): + """ + Convert an arbitrary string to a standard version string + """ + try: + # normalize the version + return str(packaging.version.Version(version)) + except packaging.version.InvalidVersion: + version = version.replace(' ','.') + return re.sub('[^A-Za-z0-9.]+', '-', version) + + +def safe_extra(extra): + """Convert an arbitrary string to a standard 'extra' name + + Any runs of non-alphanumeric characters are replaced with a single '_', + and the result is always lowercased. + """ + return re.sub('[^A-Za-z0-9.]+', '_', extra).lower() + + +def to_filename(name): + """Convert a project or version name to its filename-escaped form + + Any '-' characters are currently replaced with '_'. + """ + return name.replace('-','_') + + +class MarkerEvaluation(object): + values = { + 'os_name': lambda: os.name, + 'sys_platform': lambda: sys.platform, + 'python_full_version': platform.python_version, + 'python_version': lambda: platform.python_version()[:3], + 'platform_version': platform.version, + 'platform_machine': platform.machine, + 'platform_python_implementation': platform.python_implementation, + 'python_implementation': platform.python_implementation, + } + + @classmethod + def is_invalid_marker(cls, text): + """ + Validate text as a PEP 426 environment marker; return an exception + if invalid or False otherwise. + """ + try: + cls.evaluate_marker(text) + except SyntaxError as e: + return cls.normalize_exception(e) + return False + + @staticmethod + def normalize_exception(exc): + """ + Given a SyntaxError from a marker evaluation, normalize the error + message: + - Remove indications of filename and line number. + - Replace platform-specific error messages with standard error + messages. + """ + subs = { + 'unexpected EOF while parsing': 'invalid syntax', + 'parenthesis is never closed': 'invalid syntax', + } + exc.filename = None + exc.lineno = None + exc.msg = subs.get(exc.msg, exc.msg) + return exc + + @classmethod + def and_test(cls, nodelist): + # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! + items = [ + cls.interpret(nodelist[i]) + for i in range(1, len(nodelist), 2) + ] + return functools.reduce(operator.and_, items) + + @classmethod + def test(cls, nodelist): + # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! + items = [ + cls.interpret(nodelist[i]) + for i in range(1, len(nodelist), 2) + ] + return functools.reduce(operator.or_, items) + + @classmethod + def atom(cls, nodelist): + t = nodelist[1][0] + if t == token.LPAR: + if nodelist[2][0] == token.RPAR: + raise SyntaxError("Empty parentheses") + return cls.interpret(nodelist[2]) + msg = "Language feature not supported in environment markers" + raise SyntaxError(msg) + + @classmethod + def comparison(cls, nodelist): + if len(nodelist) > 4: + msg = "Chained comparison not allowed in environment markers" + raise SyntaxError(msg) + comp = nodelist[2][1] + cop = comp[1] + if comp[0] == token.NAME: + if len(nodelist[2]) == 3: + if cop == 'not': + cop = 'not in' + else: + cop = 'is not' + try: + cop = cls.get_op(cop) + except KeyError: + msg = repr(cop) + " operator not allowed in environment markers" + raise SyntaxError(msg) + return cop(cls.evaluate(nodelist[1]), cls.evaluate(nodelist[3])) + + @classmethod + def get_op(cls, op): + ops = { + symbol.test: cls.test, + symbol.and_test: cls.and_test, + symbol.atom: cls.atom, + symbol.comparison: cls.comparison, + 'not in': lambda x, y: x not in y, + 'in': lambda x, y: x in y, + '==': operator.eq, + '!=': operator.ne, + '<': operator.lt, + '>': operator.gt, + '<=': operator.le, + '>=': operator.ge, + } + if hasattr(symbol, 'or_test'): + ops[symbol.or_test] = cls.test + return ops[op] + + @classmethod + def evaluate_marker(cls, text, extra=None): + """ + Evaluate a PEP 426 environment marker on CPython 2.4+. + Return a boolean indicating the marker result in this environment. + Raise SyntaxError if marker is invalid. + + This implementation uses the 'parser' module, which is not implemented + on + Jython and has been superseded by the 'ast' module in Python 2.6 and + later. + """ + return cls.interpret(parser.expr(text).totuple(1)[1]) + + @staticmethod + def _translate_metadata2(env): + """ + Markerlib implements Metadata 1.2 (PEP 345) environment markers. + Translate the variables to Metadata 2.0 (PEP 426). + """ + return dict( + (key.replace('.', '_'), value) + for key, value in env.items() + ) + + @classmethod + def _markerlib_evaluate(cls, text): + """ + Evaluate a PEP 426 environment marker using markerlib. + Return a boolean indicating the marker result in this environment. + Raise SyntaxError if marker is invalid. + """ + import _markerlib + + env = cls._translate_metadata2(_markerlib.default_environment()) + try: + result = _markerlib.interpret(text, env) + except NameError as e: + raise SyntaxError(e.args[0]) + return result + + if 'parser' not in globals(): + # Fall back to less-complete _markerlib implementation if 'parser' module + # is not available. + evaluate_marker = _markerlib_evaluate + + @classmethod + def interpret(cls, nodelist): + while len(nodelist)==2: nodelist = nodelist[1] + try: + op = cls.get_op(nodelist[0]) + except KeyError: + raise SyntaxError("Comparison or logical expression expected") + return op(nodelist) + + @classmethod + def evaluate(cls, nodelist): + while len(nodelist)==2: nodelist = nodelist[1] + kind = nodelist[0] + name = nodelist[1] + if kind==token.NAME: + try: + op = cls.values[name] + except KeyError: + raise SyntaxError("Unknown name %r" % name) + return op() + if kind==token.STRING: + s = nodelist[1] + if not cls._safe_string(s): + raise SyntaxError( + "Only plain strings allowed in environment markers") + return s[1:-1] + msg = "Language feature not supported in environment markers" + raise SyntaxError(msg) + + @staticmethod + def _safe_string(cand): + return ( + cand[:1] in "'\"" and + not cand.startswith('"""') and + not cand.startswith("'''") and + '\\' not in cand + ) + +invalid_marker = MarkerEvaluation.is_invalid_marker +evaluate_marker = MarkerEvaluation.evaluate_marker + +class NullProvider: + """Try to implement resources and metadata for arbitrary PEP 302 loaders""" + + egg_name = None + egg_info = None + loader = None + + def __init__(self, module): + self.loader = getattr(module, '__loader__', None) + self.module_path = os.path.dirname(getattr(module, '__file__', '')) + + def get_resource_filename(self, manager, resource_name): + return self._fn(self.module_path, resource_name) + + def get_resource_stream(self, manager, resource_name): + return io.BytesIO(self.get_resource_string(manager, resource_name)) + + def get_resource_string(self, manager, resource_name): + return self._get(self._fn(self.module_path, resource_name)) + + def has_resource(self, resource_name): + return self._has(self._fn(self.module_path, resource_name)) + + def has_metadata(self, name): + return self.egg_info and self._has(self._fn(self.egg_info, name)) + + if sys.version_info <= (3,): + def get_metadata(self, name): + if not self.egg_info: + return "" + return self._get(self._fn(self.egg_info, name)) + else: + def get_metadata(self, name): + if not self.egg_info: + return "" + return self._get(self._fn(self.egg_info, name)).decode("utf-8") + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + def resource_isdir(self, resource_name): + return self._isdir(self._fn(self.module_path, resource_name)) + + def metadata_isdir(self, name): + return self.egg_info and self._isdir(self._fn(self.egg_info, name)) + + def resource_listdir(self, resource_name): + return self._listdir(self._fn(self.module_path, resource_name)) + + def metadata_listdir(self, name): + if self.egg_info: + return self._listdir(self._fn(self.egg_info, name)) + return [] + + def run_script(self, script_name, namespace): + script = 'scripts/'+script_name + if not self.has_metadata(script): + raise ResolutionError("No script named %r" % script_name) + script_text = self.get_metadata(script).replace('\r\n', '\n') + script_text = script_text.replace('\r', '\n') + script_filename = self._fn(self.egg_info, script) + namespace['__file__'] = script_filename + if os.path.exists(script_filename): + source = open(script_filename).read() + code = compile(source, script_filename, 'exec') + exec(code, namespace, namespace) + else: + from linecache import cache + cache[script_filename] = ( + len(script_text), 0, script_text.split('\n'), script_filename + ) + script_code = compile(script_text, script_filename,'exec') + exec(script_code, namespace, namespace) + + def _has(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _isdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _listdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _fn(self, base, resource_name): + if resource_name: + return os.path.join(base, *resource_name.split('/')) + return base + + def _get(self, path): + if hasattr(self.loader, 'get_data'): + return self.loader.get_data(path) + raise NotImplementedError( + "Can't perform this operation for loaders without 'get_data()'" + ) + +register_loader_type(object, NullProvider) + + +class EggProvider(NullProvider): + """Provider based on a virtual filesystem""" + + def __init__(self, module): + NullProvider.__init__(self, module) + self._setup_prefix() + + def _setup_prefix(self): + # we assume here that our metadata may be nested inside a "basket" + # of multiple eggs; that's why we use module_path instead of .archive + path = self.module_path + old = None + while path!=old: + if _is_unpacked_egg(path): + self.egg_name = os.path.basename(path) + self.egg_info = os.path.join(path, 'EGG-INFO') + self.egg_root = path + break + old = path + path, base = os.path.split(path) + +class DefaultProvider(EggProvider): + """Provides access to package resources in the filesystem""" + + def _has(self, path): + return os.path.exists(path) + + def _isdir(self, path): + return os.path.isdir(path) + + def _listdir(self, path): + return os.listdir(path) + + def get_resource_stream(self, manager, resource_name): + return open(self._fn(self.module_path, resource_name), 'rb') + + def _get(self, path): + with open(path, 'rb') as stream: + return stream.read() + + @classmethod + def _register(cls): + loader_cls = getattr(importlib_machinery, 'SourceFileLoader', + type(None)) + register_loader_type(loader_cls, cls) + +DefaultProvider._register() + + +class EmptyProvider(NullProvider): + """Provider that returns nothing for all requests""" + + _isdir = _has = lambda self, path: False + _get = lambda self, path: '' + _listdir = lambda self, path: [] + module_path = None + + def __init__(self): + pass + +empty_provider = EmptyProvider() + + +class ZipManifests(dict): + """ + zip manifest builder + """ + + @classmethod + def build(cls, path): + """ + Build a dictionary similar to the zipimport directory + caches, except instead of tuples, store ZipInfo objects. + + Use a platform-specific path separator (os.sep) for the path keys + for compatibility with pypy on Windows. + """ + with ContextualZipFile(path) as zfile: + items = ( + ( + name.replace('/', os.sep), + zfile.getinfo(name), + ) + for name in zfile.namelist() + ) + return dict(items) + + load = build + + +class MemoizedZipManifests(ZipManifests): + """ + Memoized zipfile manifests. + """ + manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') + + def load(self, path): + """ + Load a manifest at path or return a suitable manifest already loaded. + """ + path = os.path.normpath(path) + mtime = os.stat(path).st_mtime + + if path not in self or self[path].mtime != mtime: + manifest = self.build(path) + self[path] = self.manifest_mod(manifest, mtime) + + return self[path].manifest + + +class ContextualZipFile(zipfile.ZipFile): + """ + Supplement ZipFile class to support context manager for Python 2.6 + """ + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + def __new__(cls, *args, **kwargs): + """ + Construct a ZipFile or ContextualZipFile as appropriate + """ + if hasattr(zipfile.ZipFile, '__exit__'): + return zipfile.ZipFile(*args, **kwargs) + return super(ContextualZipFile, cls).__new__(cls) + + +class ZipProvider(EggProvider): + """Resource support for zips and eggs""" + + eagers = None + _zip_manifests = MemoizedZipManifests() + + def __init__(self, module): + EggProvider.__init__(self, module) + self.zip_pre = self.loader.archive+os.sep + + def _zipinfo_name(self, fspath): + # Convert a virtual filename (full path to file) into a zipfile subpath + # usable with the zipimport directory cache for our target archive + if fspath.startswith(self.zip_pre): + return fspath[len(self.zip_pre):] + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.zip_pre) + ) + + def _parts(self, zip_path): + # Convert a zipfile subpath into an egg-relative path part list. + # pseudo-fs path + fspath = self.zip_pre+zip_path + if fspath.startswith(self.egg_root+os.sep): + return fspath[len(self.egg_root)+1:].split(os.sep) + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.egg_root) + ) + + @property + def zipinfo(self): + return self._zip_manifests.load(self.loader.archive) + + def get_resource_filename(self, manager, resource_name): + if not self.egg_name: + raise NotImplementedError( + "resource_filename() only supported for .egg, not .zip" + ) + # no need to lock for extraction, since we use temp names + zip_path = self._resource_to_zip(resource_name) + eagers = self._get_eager_resources() + if '/'.join(self._parts(zip_path)) in eagers: + for name in eagers: + self._extract_resource(manager, self._eager_to_zip(name)) + return self._extract_resource(manager, zip_path) + + @staticmethod + def _get_date_and_size(zip_stat): + size = zip_stat.file_size + # ymdhms+wday, yday, dst + date_time = zip_stat.date_time + (0, 0, -1) + # 1980 offset already done + timestamp = time.mktime(date_time) + return timestamp, size + + def _extract_resource(self, manager, zip_path): + + if zip_path in self._index(): + for name in self._index()[zip_path]: + last = self._extract_resource( + manager, os.path.join(zip_path, name) + ) + # return the extracted directory name + return os.path.dirname(last) + + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + + if not WRITE_SUPPORT: + raise IOError('"os.rename" and "os.unlink" are not supported ' + 'on this platform') + try: + + real_path = manager.get_cache_path( + self.egg_name, self._parts(zip_path) + ) + + if self._is_current(real_path, zip_path): + return real_path + + outf, tmpnam = _mkstemp(".$extract", dir=os.path.dirname(real_path)) + os.write(outf, self.loader.get_data(zip_path)) + os.close(outf) + utime(tmpnam, (timestamp, timestamp)) + manager.postprocess(tmpnam, real_path) + + try: + rename(tmpnam, real_path) + + except os.error: + if os.path.isfile(real_path): + if self._is_current(real_path, zip_path): + # the file became current since it was checked above, + # so proceed. + return real_path + # Windows, del old file and retry + elif os.name=='nt': + unlink(real_path) + rename(tmpnam, real_path) + return real_path + raise + + except os.error: + # report a user-friendly error + manager.extraction_error() + + return real_path + + def _is_current(self, file_path, zip_path): + """ + Return True if the file_path is current for this zip_path + """ + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + if not os.path.isfile(file_path): + return False + stat = os.stat(file_path) + if stat.st_size!=size or stat.st_mtime!=timestamp: + return False + # check that the contents match + zip_contents = self.loader.get_data(zip_path) + with open(file_path, 'rb') as f: + file_contents = f.read() + return zip_contents == file_contents + + def _get_eager_resources(self): + if self.eagers is None: + eagers = [] + for name in ('native_libs.txt', 'eager_resources.txt'): + if self.has_metadata(name): + eagers.extend(self.get_metadata_lines(name)) + self.eagers = eagers + return self.eagers + + def _index(self): + try: + return self._dirindex + except AttributeError: + ind = {} + for path in self.zipinfo: + parts = path.split(os.sep) + while parts: + parent = os.sep.join(parts[:-1]) + if parent in ind: + ind[parent].append(parts[-1]) + break + else: + ind[parent] = [parts.pop()] + self._dirindex = ind + return ind + + def _has(self, fspath): + zip_path = self._zipinfo_name(fspath) + return zip_path in self.zipinfo or zip_path in self._index() + + def _isdir(self, fspath): + return self._zipinfo_name(fspath) in self._index() + + def _listdir(self, fspath): + return list(self._index().get(self._zipinfo_name(fspath), ())) + + def _eager_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.egg_root, resource_name)) + + def _resource_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.module_path, resource_name)) + +register_loader_type(zipimport.zipimporter, ZipProvider) + + +class FileMetadata(EmptyProvider): + """Metadata handler for standalone PKG-INFO files + + Usage:: + + metadata = FileMetadata("/path/to/PKG-INFO") + + This provider rejects all data and metadata requests except for PKG-INFO, + which is treated as existing, and will be the contents of the file at + the provided location. + """ + + def __init__(self, path): + self.path = path + + def has_metadata(self, name): + return name=='PKG-INFO' and os.path.isfile(self.path) + + def get_metadata(self, name): + if name=='PKG-INFO': + with io.open(self.path, encoding='utf-8') as f: + metadata = f.read() + return metadata + raise KeyError("No metadata except PKG-INFO is available") + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + +class PathMetadata(DefaultProvider): + """Metadata provider for egg directories + + Usage:: + + # Development eggs: + + egg_info = "/path/to/PackageName.egg-info" + base_dir = os.path.dirname(egg_info) + metadata = PathMetadata(base_dir, egg_info) + dist_name = os.path.splitext(os.path.basename(egg_info))[0] + dist = Distribution(basedir, project_name=dist_name, metadata=metadata) + + # Unpacked egg directories: + + egg_path = "/path/to/PackageName-ver-pyver-etc.egg" + metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO')) + dist = Distribution.from_filename(egg_path, metadata=metadata) + """ + + def __init__(self, path, egg_info): + self.module_path = path + self.egg_info = egg_info + + +class EggMetadata(ZipProvider): + """Metadata provider for .egg files""" + + def __init__(self, importer): + """Create a metadata provider from a zipimporter""" + + self.zip_pre = importer.archive+os.sep + self.loader = importer + if importer.prefix: + self.module_path = os.path.join(importer.archive, importer.prefix) + else: + self.module_path = importer.archive + self._setup_prefix() + +_declare_state('dict', _distribution_finders = {}) + +def register_finder(importer_type, distribution_finder): + """Register `distribution_finder` to find distributions in sys.path items + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `distribution_finder` is a callable that, passed a path + item and the importer instance, yields ``Distribution`` instances found on + that path item. See ``pkg_resources.find_on_path`` for an example.""" + _distribution_finders[importer_type] = distribution_finder + + +def find_distributions(path_item, only=False): + """Yield distributions accessible via `path_item`""" + importer = get_importer(path_item) + finder = _find_adapter(_distribution_finders, importer) + return finder(importer, path_item, only) + +def find_eggs_in_zip(importer, path_item, only=False): + """ + Find eggs in zip files; possibly multiple nested eggs. + """ + if importer.archive.endswith('.whl'): + # wheels are not supported with this finder + # they don't have PKG-INFO metadata, and won't ever contain eggs + return + metadata = EggMetadata(importer) + if metadata.has_metadata('PKG-INFO'): + yield Distribution.from_filename(path_item, metadata=metadata) + if only: + # don't yield nested distros + return + for subitem in metadata.resource_listdir('/'): + if _is_unpacked_egg(subitem): + subpath = os.path.join(path_item, subitem) + for dist in find_eggs_in_zip(zipimport.zipimporter(subpath), subpath): + yield dist + +register_finder(zipimport.zipimporter, find_eggs_in_zip) + +def find_nothing(importer, path_item, only=False): + return () +register_finder(object, find_nothing) + +def find_on_path(importer, path_item, only=False): + """Yield distributions accessible on a sys.path directory""" + path_item = _normalize_cached(path_item) + + if os.path.isdir(path_item) and os.access(path_item, os.R_OK): + if _is_unpacked_egg(path_item): + yield Distribution.from_filename( + path_item, metadata=PathMetadata( + path_item, os.path.join(path_item,'EGG-INFO') + ) + ) + else: + # scan for .egg and .egg-info in directory + for entry in os.listdir(path_item): + lower = entry.lower() + if lower.endswith('.egg-info') or lower.endswith('.dist-info'): + fullpath = os.path.join(path_item, entry) + if os.path.isdir(fullpath): + # egg-info directory, allow getting metadata + metadata = PathMetadata(path_item, fullpath) + else: + metadata = FileMetadata(fullpath) + yield Distribution.from_location( + path_item, entry, metadata, precedence=DEVELOP_DIST + ) + elif not only and _is_unpacked_egg(entry): + dists = find_distributions(os.path.join(path_item, entry)) + for dist in dists: + yield dist + elif not only and lower.endswith('.egg-link'): + with open(os.path.join(path_item, entry)) as entry_file: + entry_lines = entry_file.readlines() + for line in entry_lines: + if not line.strip(): + continue + path = os.path.join(path_item, line.rstrip()) + dists = find_distributions(path) + for item in dists: + yield item + break +register_finder(pkgutil.ImpImporter, find_on_path) + +if hasattr(importlib_machinery, 'FileFinder'): + register_finder(importlib_machinery.FileFinder, find_on_path) + +_declare_state('dict', _namespace_handlers={}) +_declare_state('dict', _namespace_packages={}) + + +def register_namespace_handler(importer_type, namespace_handler): + """Register `namespace_handler` to declare namespace packages + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `namespace_handler` is a callable like this:: + + def namespace_handler(importer, path_entry, moduleName, module): + # return a path_entry to use for child packages + + Namespace handlers are only called if the importer object has already + agreed that it can handle the relevant path item, and they should only + return a subpath if the module __path__ does not already contain an + equivalent subpath. For an example namespace handler, see + ``pkg_resources.file_ns_handler``. + """ + _namespace_handlers[importer_type] = namespace_handler + +def _handle_ns(packageName, path_item): + """Ensure that named package includes a subpath of path_item (if needed)""" + + importer = get_importer(path_item) + if importer is None: + return None + loader = importer.find_module(packageName) + if loader is None: + return None + module = sys.modules.get(packageName) + if module is None: + module = sys.modules[packageName] = types.ModuleType(packageName) + module.__path__ = [] + _set_parent_ns(packageName) + elif not hasattr(module,'__path__'): + raise TypeError("Not a package:", packageName) + handler = _find_adapter(_namespace_handlers, importer) + subpath = handler(importer, path_item, packageName, module) + if subpath is not None: + path = module.__path__ + path.append(subpath) + loader.load_module(packageName) + _rebuild_mod_path(path, packageName, module) + return subpath + + +def _rebuild_mod_path(orig_path, package_name, module): + """ + Rebuild module.__path__ ensuring that all entries are ordered + corresponding to their sys.path order + """ + sys_path = [_normalize_cached(p) for p in sys.path] + def position_in_sys_path(p): + """ + Return the ordinal of the path based on its position in sys.path + """ + parts = p.split(os.sep) + parts = parts[:-(package_name.count('.') + 1)] + return sys_path.index(_normalize_cached(os.sep.join(parts))) + + orig_path.sort(key=position_in_sys_path) + module.__path__[:] = [_normalize_cached(p) for p in orig_path] + + +def declare_namespace(packageName): + """Declare that package 'packageName' is a namespace package""" + + _imp.acquire_lock() + try: + if packageName in _namespace_packages: + return + + path, parent = sys.path, None + if '.' in packageName: + parent = '.'.join(packageName.split('.')[:-1]) + declare_namespace(parent) + if parent not in _namespace_packages: + __import__(parent) + try: + path = sys.modules[parent].__path__ + except AttributeError: + raise TypeError("Not a package:", parent) + + # Track what packages are namespaces, so when new path items are added, + # they can be updated + _namespace_packages.setdefault(parent,[]).append(packageName) + _namespace_packages.setdefault(packageName,[]) + + for path_item in path: + # Ensure all the parent's path items are reflected in the child, + # if they apply + _handle_ns(packageName, path_item) + + finally: + _imp.release_lock() + +def fixup_namespace_packages(path_item, parent=None): + """Ensure that previously-declared namespace packages include path_item""" + _imp.acquire_lock() + try: + for package in _namespace_packages.get(parent,()): + subpath = _handle_ns(package, path_item) + if subpath: + fixup_namespace_packages(subpath, package) + finally: + _imp.release_lock() + +def file_ns_handler(importer, path_item, packageName, module): + """Compute an ns-package subpath for a filesystem or zipfile importer""" + + subpath = os.path.join(path_item, packageName.split('.')[-1]) + normalized = _normalize_cached(subpath) + for item in module.__path__: + if _normalize_cached(item)==normalized: + break + else: + # Only return the path if it's not already there + return subpath + +register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) +register_namespace_handler(zipimport.zipimporter, file_ns_handler) + +if hasattr(importlib_machinery, 'FileFinder'): + register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) + + +def null_ns_handler(importer, path_item, packageName, module): + return None + +register_namespace_handler(object, null_ns_handler) + + +def normalize_path(filename): + """Normalize a file/dir name for comparison purposes""" + return os.path.normcase(os.path.realpath(filename)) + +def _normalize_cached(filename, _cache={}): + try: + return _cache[filename] + except KeyError: + _cache[filename] = result = normalize_path(filename) + return result + +def _is_unpacked_egg(path): + """ + Determine if given path appears to be an unpacked egg. + """ + return ( + path.lower().endswith('.egg') + ) + +def _set_parent_ns(packageName): + parts = packageName.split('.') + name = parts.pop() + if parts: + parent = '.'.join(parts) + setattr(sys.modules[parent], name, sys.modules[packageName]) + + +def yield_lines(strs): + """Yield non-empty/non-comment lines of a string or sequence""" + if isinstance(strs, six.string_types): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + +# whitespace and comment +LINE_END = re.compile(r"\s*(#.*)?$").match +# line continuation +CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match +# Distribution or extra +DISTRO = re.compile(r"\s*((\w|[-.])+)").match +# ver. info +VERSION = re.compile(r"\s*(<=?|>=?|===?|!=|~=)\s*((\w|[-.*_!+])+)").match +# comma between items +COMMA = re.compile(r"\s*,").match +OBRACKET = re.compile(r"\s*\[").match +CBRACKET = re.compile(r"\s*\]").match +MODULE = re.compile(r"\w+(\.\w+)*$").match +EGG_NAME = re.compile( + r""" + (?P[^-]+) ( + -(?P[^-]+) ( + -py(?P[^-]+) ( + -(?P.+) + )? + )? + )? + """, + re.VERBOSE | re.IGNORECASE, +).match + + +class EntryPoint(object): + """Object representing an advertised importable object""" + + def __init__(self, name, module_name, attrs=(), extras=(), dist=None): + if not MODULE(module_name): + raise ValueError("Invalid module name", module_name) + self.name = name + self.module_name = module_name + self.attrs = tuple(attrs) + self.extras = Requirement.parse(("x[%s]" % ','.join(extras))).extras + self.dist = dist + + def __str__(self): + s = "%s = %s" % (self.name, self.module_name) + if self.attrs: + s += ':' + '.'.join(self.attrs) + if self.extras: + s += ' [%s]' % ','.join(self.extras) + return s + + def __repr__(self): + return "EntryPoint.parse(%r)" % str(self) + + def load(self, require=True, *args, **kwargs): + """ + Require packages for this EntryPoint, then resolve it. + """ + if not require or args or kwargs: + warnings.warn( + "Parameters to load are deprecated. Call .resolve and " + ".require separately.", + DeprecationWarning, + stacklevel=2, + ) + if require: + self.require(*args, **kwargs) + return self.resolve() + + def resolve(self): + """ + Resolve the entry point from its module and attrs. + """ + module = __import__(self.module_name, fromlist=['__name__'], level=0) + try: + return functools.reduce(getattr, self.attrs, module) + except AttributeError as exc: + raise ImportError(str(exc)) + + def require(self, env=None, installer=None): + if self.extras and not self.dist: + raise UnknownExtra("Can't require() without a distribution", self) + reqs = self.dist.requires(self.extras) + items = working_set.resolve(reqs, env, installer) + list(map(working_set.add, items)) + + pattern = re.compile( + r'\s*' + r'(?P.+?)\s*' + r'=\s*' + r'(?P[\w.]+)\s*' + r'(:\s*(?P[\w.]+))?\s*' + r'(?P\[.*\])?\s*$' + ) + + @classmethod + def parse(cls, src, dist=None): + """Parse a single entry point from string `src` + + Entry point syntax follows the form:: + + name = some.module:some.attr [extra1, extra2] + + The entry name and module name are required, but the ``:attrs`` and + ``[extras]`` parts are optional + """ + m = cls.pattern.match(src) + if not m: + msg = "EntryPoint must be in 'name=module:attrs [extras]' format" + raise ValueError(msg, src) + res = m.groupdict() + extras = cls._parse_extras(res['extras']) + attrs = res['attr'].split('.') if res['attr'] else () + return cls(res['name'], res['module'], attrs, extras, dist) + + @classmethod + def _parse_extras(cls, extras_spec): + if not extras_spec: + return () + req = Requirement.parse('x' + extras_spec) + if req.specs: + raise ValueError() + return req.extras + + @classmethod + def parse_group(cls, group, lines, dist=None): + """Parse an entry point group""" + if not MODULE(group): + raise ValueError("Invalid group name", group) + this = {} + for line in yield_lines(lines): + ep = cls.parse(line, dist) + if ep.name in this: + raise ValueError("Duplicate entry point", group, ep.name) + this[ep.name]=ep + return this + + @classmethod + def parse_map(cls, data, dist=None): + """Parse a map of entry point groups""" + if isinstance(data, dict): + data = data.items() + else: + data = split_sections(data) + maps = {} + for group, lines in data: + if group is None: + if not lines: + continue + raise ValueError("Entry points must be listed in groups") + group = group.strip() + if group in maps: + raise ValueError("Duplicate group name", group) + maps[group] = cls.parse_group(group, lines, dist) + return maps + + +def _remove_md5_fragment(location): + if not location: + return '' + parsed = urllib.parse.urlparse(location) + if parsed[-1].startswith('md5='): + return urllib.parse.urlunparse(parsed[:-1] + ('',)) + return location + + +def _version_from_file(lines): + """ + Given an iterable of lines from a Metadata file, return + the value of the Version field, if present, or None otherwise. + """ + is_version_line = lambda line: line.lower().startswith('version:') + version_lines = filter(is_version_line, lines) + line = next(iter(version_lines), '') + _, _, value = line.partition(':') + return safe_version(value.strip()) or None + + +class Distribution(object): + """Wrap an actual or potential sys.path entry w/metadata""" + PKG_INFO = 'PKG-INFO' + + def __init__(self, location=None, metadata=None, project_name=None, + version=None, py_version=PY_MAJOR, platform=None, + precedence=EGG_DIST): + self.project_name = safe_name(project_name or 'Unknown') + if version is not None: + self._version = safe_version(version) + self.py_version = py_version + self.platform = platform + self.location = location + self.precedence = precedence + self._provider = metadata or empty_provider + + @classmethod + def from_location(cls, location, basename, metadata=None, **kw): + project_name, version, py_version, platform = [None]*4 + basename, ext = os.path.splitext(basename) + if ext.lower() in _distributionImpl: + cls = _distributionImpl[ext.lower()] + + match = EGG_NAME(basename) + if match: + project_name, version, py_version, platform = match.group( + 'name', 'ver', 'pyver', 'plat' + ) + return cls( + location, metadata, project_name=project_name, version=version, + py_version=py_version, platform=platform, **kw + )._reload_version() + + def _reload_version(self): + return self + + @property + def hashcmp(self): + return ( + self.parsed_version, + self.precedence, + self.key, + _remove_md5_fragment(self.location), + self.py_version or '', + self.platform or '', + ) + + def __hash__(self): + return hash(self.hashcmp) + + def __lt__(self, other): + return self.hashcmp < other.hashcmp + + def __le__(self, other): + return self.hashcmp <= other.hashcmp + + def __gt__(self, other): + return self.hashcmp > other.hashcmp + + def __ge__(self, other): + return self.hashcmp >= other.hashcmp + + def __eq__(self, other): + if not isinstance(other, self.__class__): + # It's not a Distribution, so they are not equal + return False + return self.hashcmp == other.hashcmp + + def __ne__(self, other): + return not self == other + + # These properties have to be lazy so that we don't have to load any + # metadata until/unless it's actually needed. (i.e., some distributions + # may not know their name or version without loading PKG-INFO) + + @property + def key(self): + try: + return self._key + except AttributeError: + self._key = key = self.project_name.lower() + return key + + @property + def parsed_version(self): + if not hasattr(self, "_parsed_version"): + self._parsed_version = parse_version(self.version) + + return self._parsed_version + + def _warn_legacy_version(self): + LV = packaging.version.LegacyVersion + is_legacy = isinstance(self._parsed_version, LV) + if not is_legacy: + return + + # While an empty version is technically a legacy version and + # is not a valid PEP 440 version, it's also unlikely to + # actually come from someone and instead it is more likely that + # it comes from setuptools attempting to parse a filename and + # including it in the list. So for that we'll gate this warning + # on if the version is anything at all or not. + if not self.version: + return + + tmpl = textwrap.dedent(""" + '{project_name} ({version})' is being parsed as a legacy, + non PEP 440, + version. You may find odd behavior and sort order. + In particular it will be sorted as less than 0.0. It + is recommended to migrate to PEP 440 compatible + versions. + """).strip().replace('\n', ' ') + + warnings.warn(tmpl.format(**vars(self)), PEP440Warning) + + @property + def version(self): + try: + return self._version + except AttributeError: + version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if version is None: + tmpl = "Missing 'Version:' header and/or %s file" + raise ValueError(tmpl % self.PKG_INFO, self) + return version + + @property + def _dep_map(self): + try: + return self.__dep_map + except AttributeError: + dm = self.__dep_map = {None: []} + for name in 'requires.txt', 'depends.txt': + for extra, reqs in split_sections(self._get_metadata(name)): + if extra: + if ':' in extra: + extra, marker = extra.split(':', 1) + if invalid_marker(marker): + # XXX warn + reqs=[] + elif not evaluate_marker(marker): + reqs=[] + extra = safe_extra(extra) or None + dm.setdefault(extra,[]).extend(parse_requirements(reqs)) + return dm + + def requires(self, extras=()): + """List of Requirements needed for this distro if `extras` are used""" + dm = self._dep_map + deps = [] + deps.extend(dm.get(None, ())) + for ext in extras: + try: + deps.extend(dm[safe_extra(ext)]) + except KeyError: + raise UnknownExtra( + "%s has no such extra feature %r" % (self, ext) + ) + return deps + + def _get_metadata(self, name): + if self.has_metadata(name): + for line in self.get_metadata_lines(name): + yield line + + def activate(self, path=None): + """Ensure distribution is importable on `path` (default=sys.path)""" + if path is None: + path = sys.path + self.insert_on(path, replace=True) + if path is sys.path: + fixup_namespace_packages(self.location) + for pkg in self._get_metadata('namespace_packages.txt'): + if pkg in sys.modules: + declare_namespace(pkg) + + def egg_name(self): + """Return what this distribution's standard .egg filename should be""" + filename = "%s-%s-py%s" % ( + to_filename(self.project_name), to_filename(self.version), + self.py_version or PY_MAJOR + ) + + if self.platform: + filename += '-' + self.platform + return filename + + def __repr__(self): + if self.location: + return "%s (%s)" % (self, self.location) + else: + return str(self) + + def __str__(self): + try: + version = getattr(self, 'version', None) + except ValueError: + version = None + version = version or "[unknown version]" + return "%s %s" % (self.project_name, version) + + def __getattr__(self, attr): + """Delegate all unrecognized public attributes to .metadata provider""" + if attr.startswith('_'): + raise AttributeError(attr) + return getattr(self._provider, attr) + + @classmethod + def from_filename(cls, filename, metadata=None, **kw): + return cls.from_location( + _normalize_cached(filename), os.path.basename(filename), metadata, + **kw + ) + + def as_requirement(self): + """Return a ``Requirement`` that matches this distribution exactly""" + if isinstance(self.parsed_version, packaging.version.Version): + spec = "%s==%s" % (self.project_name, self.parsed_version) + else: + spec = "%s===%s" % (self.project_name, self.parsed_version) + + return Requirement.parse(spec) + + def load_entry_point(self, group, name): + """Return the `name` entry point of `group` or raise ImportError""" + ep = self.get_entry_info(group, name) + if ep is None: + raise ImportError("Entry point %r not found" % ((group, name),)) + return ep.load() + + def get_entry_map(self, group=None): + """Return the entry point map for `group`, or the full entry map""" + try: + ep_map = self._ep_map + except AttributeError: + ep_map = self._ep_map = EntryPoint.parse_map( + self._get_metadata('entry_points.txt'), self + ) + if group is not None: + return ep_map.get(group,{}) + return ep_map + + def get_entry_info(self, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return self.get_entry_map(group).get(name) + + def insert_on(self, path, loc=None, replace=False): + """Insert self.location in path before its nearest parent directory""" + + loc = loc or self.location + if not loc: + return + + nloc = _normalize_cached(loc) + bdir = os.path.dirname(nloc) + npath= [(p and _normalize_cached(p) or p) for p in path] + + for p, item in enumerate(npath): + if item == nloc: + break + elif item == bdir and self.precedence == EGG_DIST: + # if it's an .egg, give it precedence over its directory + if path is sys.path: + self.check_version_conflict() + path.insert(p, loc) + npath.insert(p, nloc) + break + else: + if path is sys.path: + self.check_version_conflict() + if replace: + path.insert(0, loc) + else: + path.append(loc) + return + + # p is the spot where we found or inserted loc; now remove duplicates + while True: + try: + np = npath.index(nloc, p+1) + except ValueError: + break + else: + del npath[np], path[np] + # ha! + p = np + + return + + def check_version_conflict(self): + if self.key == 'setuptools': + # ignore the inevitable setuptools self-conflicts :( + return + + nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt')) + loc = normalize_path(self.location) + for modname in self._get_metadata('top_level.txt'): + if (modname not in sys.modules or modname in nsp + or modname in _namespace_packages): + continue + if modname in ('pkg_resources', 'setuptools', 'site'): + continue + fn = getattr(sys.modules[modname], '__file__', None) + if fn and (normalize_path(fn).startswith(loc) or + fn.startswith(self.location)): + continue + issue_warning( + "Module %s was already imported from %s, but %s is being added" + " to sys.path" % (modname, fn, self.location), + ) + + def has_version(self): + try: + self.version + except ValueError: + issue_warning("Unbuilt egg for " + repr(self)) + return False + return True + + def clone(self,**kw): + """Copy this distribution, substituting in any changed keyword args""" + names = 'project_name version py_version platform location precedence' + for attr in names.split(): + kw.setdefault(attr, getattr(self, attr, None)) + kw.setdefault('metadata', self._provider) + return self.__class__(**kw) + + @property + def extras(self): + return [dep for dep in self._dep_map if dep] + + +class EggInfoDistribution(Distribution): + + def _reload_version(self): + """ + Packages installed by distutils (e.g. numpy or scipy), + which uses an old safe_version, and so + their version numbers can get mangled when + converted to filenames (e.g., 1.11.0.dev0+2329eae to + 1.11.0.dev0_2329eae). These distributions will not be + parsed properly + downstream by Distribution and safe_version, so + take an extra step and try to get the version number from + the metadata file itself instead of the filename. + """ + md_version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if md_version: + self._version = md_version + return self + + +class DistInfoDistribution(Distribution): + """Wrap an actual or potential sys.path entry w/metadata, .dist-info style""" + PKG_INFO = 'METADATA' + EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") + + @property + def _parsed_pkg_info(self): + """Parse and cache metadata""" + try: + return self._pkg_info + except AttributeError: + metadata = self.get_metadata(self.PKG_INFO) + self._pkg_info = email.parser.Parser().parsestr(metadata) + return self._pkg_info + + @property + def _dep_map(self): + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._compute_dependencies() + return self.__dep_map + + def _preparse_requirement(self, requires_dist): + """Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz') + Split environment marker, add == prefix to version specifiers as + necessary, and remove parenthesis. + """ + parts = requires_dist.split(';', 1) + [''] + distvers = parts[0].strip() + mark = parts[1].strip() + distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers) + distvers = distvers.replace('(', '').replace(')', '') + return (distvers, mark) + + def _compute_dependencies(self): + """Recompute this distribution's dependencies.""" + from _markerlib import compile as compile_marker + dm = self.__dep_map = {None: []} + + reqs = [] + # Including any condition expressions + for req in self._parsed_pkg_info.get_all('Requires-Dist') or []: + distvers, mark = self._preparse_requirement(req) + parsed = next(parse_requirements(distvers)) + parsed.marker_fn = compile_marker(mark) + reqs.append(parsed) + + def reqs_for_extra(extra): + for req in reqs: + if req.marker_fn(override={'extra':extra}): + yield req + + common = frozenset(reqs_for_extra(None)) + dm[None].extend(common) + + for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []: + extra = safe_extra(extra.strip()) + dm[extra] = list(frozenset(reqs_for_extra(extra)) - common) + + return dm + + +_distributionImpl = { + '.egg': Distribution, + '.egg-info': EggInfoDistribution, + '.dist-info': DistInfoDistribution, + } + + +def issue_warning(*args,**kw): + level = 1 + g = globals() + try: + # find the first stack frame that is *not* code in + # the pkg_resources module, to use for the warning + while sys._getframe(level).f_globals is g: + level += 1 + except ValueError: + pass + warnings.warn(stacklevel=level + 1, *args, **kw) + + +class RequirementParseError(ValueError): + def __str__(self): + return ' '.join(self.args) + + +def parse_requirements(strs): + """Yield ``Requirement`` objects for each specification in `strs` + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + # create a steppable iterator, so we can handle \-continuations + lines = iter(yield_lines(strs)) + + def scan_list(ITEM, TERMINATOR, line, p, groups, item_name): + + items = [] + + while not TERMINATOR(line, p): + if CONTINUE(line, p): + try: + line = next(lines) + p = 0 + except StopIteration: + msg = "\\ must not appear on the last nonblank line" + raise RequirementParseError(msg) + + match = ITEM(line, p) + if not match: + msg = "Expected " + item_name + " in" + raise RequirementParseError(msg, line, "at", line[p:]) + + items.append(match.group(*groups)) + p = match.end() + + match = COMMA(line, p) + if match: + # skip the comma + p = match.end() + elif not TERMINATOR(line, p): + msg = "Expected ',' or end-of-list in" + raise RequirementParseError(msg, line, "at", line[p:]) + + match = TERMINATOR(line, p) + # skip the terminator, if any + if match: + p = match.end() + return line, p, items + + for line in lines: + match = DISTRO(line) + if not match: + raise RequirementParseError("Missing distribution spec", line) + project_name = match.group(1) + p = match.end() + extras = [] + + match = OBRACKET(line, p) + if match: + p = match.end() + line, p, extras = scan_list( + DISTRO, CBRACKET, line, p, (1,), "'extra' name" + ) + + line, p, specs = scan_list(VERSION, LINE_END, line, p, (1, 2), + "version spec") + specs = [(op, val) for op, val in specs] + yield Requirement(project_name, specs, extras) + + +class Requirement: + def __init__(self, project_name, specs, extras): + """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" + self.unsafe_name, project_name = project_name, safe_name(project_name) + self.project_name, self.key = project_name, project_name.lower() + self.specifier = packaging.specifiers.SpecifierSet( + ",".join(["".join([x, y]) for x, y in specs]) + ) + self.specs = specs + self.extras = tuple(map(safe_extra, extras)) + self.hashCmp = ( + self.key, + self.specifier, + frozenset(self.extras), + ) + self.__hash = hash(self.hashCmp) + + def __str__(self): + extras = ','.join(self.extras) + if extras: + extras = '[%s]' % extras + return '%s%s%s' % (self.project_name, extras, self.specifier) + + def __eq__(self, other): + return ( + isinstance(other, Requirement) and + self.hashCmp == other.hashCmp + ) + + def __ne__(self, other): + return not self == other + + def __contains__(self, item): + if isinstance(item, Distribution): + if item.key != self.key: + return False + + item = item.version + + # Allow prereleases always in order to match the previous behavior of + # this method. In the future this should be smarter and follow PEP 440 + # more accurately. + return self.specifier.contains(item, prereleases=True) + + def __hash__(self): + return self.__hash + + def __repr__(self): return "Requirement.parse(%r)" % str(self) + + @staticmethod + def parse(s): + req, = parse_requirements(s) + return req + + +def _get_mro(cls): + """Get an mro for a type or classic class""" + if not isinstance(cls, type): + class cls(cls, object): pass + return cls.__mro__[1:] + return cls.__mro__ + +def _find_adapter(registry, ob): + """Return an adapter factory for `ob` from `registry`""" + for t in _get_mro(getattr(ob, '__class__', type(ob))): + if t in registry: + return registry[t] + + +def ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + +def _bypass_ensure_directory(path): + """Sandbox-bypassing version of ensure_directory()""" + if not WRITE_SUPPORT: + raise IOError('"os.mkdir" not supported on this platform.') + dirname, filename = split(path) + if dirname and filename and not isdir(dirname): + _bypass_ensure_directory(dirname) + mkdir(dirname, 0o755) + + +def split_sections(s): + """Split a string or iterable thereof into (section, content) pairs + + Each ``section`` is a stripped version of the section header ("[section]") + and each ``content`` is a list of stripped lines excluding blank lines and + comment-only lines. If there are any such lines before the first section + header, they're returned in a first ``section`` of ``None``. + """ + section = None + content = [] + for line in yield_lines(s): + if line.startswith("["): + if line.endswith("]"): + if section or content: + yield section, content + section = line[1:-1].strip() + content = [] + else: + raise ValueError("Invalid section heading", line) + else: + content.append(line) + + # wrap up last segment + yield section, content + +def _mkstemp(*args,**kw): + old_open = os.open + try: + # temporarily bypass sandboxing + os.open = os_open + return tempfile.mkstemp(*args,**kw) + finally: + # and then put it back + os.open = old_open + + +# Silence the PEP440Warning by default, so that end users don't get hit by it +# randomly just because they use pkg_resources. We want to append the rule +# because we want earlier uses of filterwarnings to take precedence over this +# one. +warnings.filterwarnings("ignore", category=PEP440Warning, append=True) + + +# from jaraco.functools 1.3 +def _call_aside(f, *args, **kwargs): + f(*args, **kwargs) + return f + + +@_call_aside +def _initialize(g=globals()): + "Set up global resource manager (deliberately not state-saved)" + manager = ResourceManager() + g['_manager'] = manager + for name in dir(manager): + if not name.startswith('_'): + g[name] = getattr(manager, name) + + +@_call_aside +def _initialize_master_working_set(): + """ + Prepare the master working set and make the ``require()`` + API available. + + This function has explicit effects on the global state + of pkg_resources. It is intended to be invoked once at + the initialization of this module. + + Invocation by other packages is unsupported and done + at their own risk. + """ + working_set = WorkingSet._build_master() + _declare_state('object', working_set=working_set) + + require = working_set.require + iter_entry_points = working_set.iter_entry_points + add_activation_listener = working_set.subscribe + run_script = working_set.run_script + # backward compatibility + run_main = run_script + # Activate all distributions already on sys.path, and ensure that + # all distributions added to the working set in the future (e.g. by + # calling ``require()``) will get activated as well. + add_activation_listener(lambda dist: dist.activate()) + working_set.entries=[] + # match order + list(map(working_set.add_entry, sys.path)) + globals().update(locals()) diff -Nru python-setuptools-3.3/pkg_resources/tests/test_markers.py python-setuptools-20.1.1/pkg_resources/tests/test_markers.py --- python-setuptools-3.3/pkg_resources/tests/test_markers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/tests/test_markers.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,16 @@ +try: + import unittest.mock as mock +except ImportError: + import mock + +from pkg_resources import evaluate_marker + + +@mock.patch.dict('pkg_resources.MarkerEvaluation.values', + python_full_version=mock.Mock(return_value='2.7.10')) +def test_lexicographic_ordering(): + """ + Although one might like 2.7.10 to be greater than 2.7.3, + the marker spec only supports lexicographic ordering. + """ + assert evaluate_marker("python_full_version > '2.7.3'") is False diff -Nru python-setuptools-3.3/pkg_resources/tests/test_pkg_resources.py python-setuptools-20.1.1/pkg_resources/tests/test_pkg_resources.py --- python-setuptools-3.3/pkg_resources/tests/test_pkg_resources.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/tests/test_pkg_resources.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,169 @@ +# coding: utf-8 +from __future__ import unicode_literals + +import sys +import tempfile +import os +import zipfile +import datetime +import time +import subprocess +import stat +import distutils.dist +import distutils.command.install_egg_info + +from pkg_resources.extern.six.moves import map + +import pytest + +import pkg_resources + + +try: + unicode +except NameError: + unicode = str + +def timestamp(dt): + """ + Return a timestamp for a local, naive datetime instance. + """ + try: + return dt.timestamp() + except AttributeError: + # Python 3.2 and earlier + return time.mktime(dt.timetuple()) + +class EggRemover(unicode): + def __call__(self): + if self in sys.path: + sys.path.remove(self) + if os.path.exists(self): + os.remove(self) + +class TestZipProvider(object): + finalizers = [] + + ref_time = datetime.datetime(2013, 5, 12, 13, 25, 0) + "A reference time for a file modification" + + @classmethod + def setup_class(cls): + "create a zip egg and add it to sys.path" + egg = tempfile.NamedTemporaryFile(suffix='.egg', delete=False) + zip_egg = zipfile.ZipFile(egg, 'w') + zip_info = zipfile.ZipInfo() + zip_info.filename = 'mod.py' + zip_info.date_time = cls.ref_time.timetuple() + zip_egg.writestr(zip_info, 'x = 3\n') + zip_info = zipfile.ZipInfo() + zip_info.filename = 'data.dat' + zip_info.date_time = cls.ref_time.timetuple() + zip_egg.writestr(zip_info, 'hello, world!') + zip_egg.close() + egg.close() + + sys.path.append(egg.name) + cls.finalizers.append(EggRemover(egg.name)) + + @classmethod + def teardown_class(cls): + for finalizer in cls.finalizers: + finalizer() + + def test_resource_filename_rewrites_on_change(self): + """ + If a previous call to get_resource_filename has saved the file, but + the file has been subsequently mutated with different file of the + same size and modification time, it should not be overwritten on a + subsequent call to get_resource_filename. + """ + import mod + manager = pkg_resources.ResourceManager() + zp = pkg_resources.ZipProvider(mod) + filename = zp.get_resource_filename(manager, 'data.dat') + actual = datetime.datetime.fromtimestamp(os.stat(filename).st_mtime) + assert actual == self.ref_time + f = open(filename, 'w') + f.write('hello, world?') + f.close() + ts = timestamp(self.ref_time) + os.utime(filename, (ts, ts)) + filename = zp.get_resource_filename(manager, 'data.dat') + f = open(filename) + assert f.read() == 'hello, world!' + manager.cleanup_resources() + +class TestResourceManager(object): + def test_get_cache_path(self): + mgr = pkg_resources.ResourceManager() + path = mgr.get_cache_path('foo') + type_ = str(type(path)) + message = "Unexpected type from get_cache_path: " + type_ + assert isinstance(path, (unicode, str)), message + + +class TestIndependence: + """ + Tests to ensure that pkg_resources runs independently from setuptools. + """ + def test_setuptools_not_imported(self): + """ + In a separate Python environment, import pkg_resources and assert + that action doesn't cause setuptools to be imported. + """ + lines = ( + 'import pkg_resources', + 'import sys', + 'assert "setuptools" not in sys.modules, ' + '"setuptools was imported"', + ) + cmd = [sys.executable, '-c', '; '.join(lines)] + subprocess.check_call(cmd) + + + +class TestDeepVersionLookupDistutils(object): + + @pytest.fixture + def env(self, tmpdir): + """ + Create a package environment, similar to a virtualenv, + in which packages are installed. + """ + class Environment(str): + pass + + env = Environment(tmpdir) + tmpdir.chmod(stat.S_IRWXU) + subs = 'home', 'lib', 'scripts', 'data', 'egg-base' + env.paths = dict( + (dirname, str(tmpdir / dirname)) + for dirname in subs + ) + list(map(os.mkdir, env.paths.values())) + return env + + def create_foo_pkg(self, env, version): + """ + Create a foo package installed (distutils-style) to env.paths['lib'] + as version. + """ + ld = "This package has unicode metadata! ❄" + attrs = dict(name='foo', version=version, long_description=ld) + dist = distutils.dist.Distribution(attrs) + iei_cmd = distutils.command.install_egg_info.install_egg_info(dist) + iei_cmd.initialize_options() + iei_cmd.install_dir = env.paths['lib'] + iei_cmd.finalize_options() + iei_cmd.run() + + def test_version_resolved_from_egg_info(self, env): + version = '1.11.0.dev0+2329eae' + self.create_foo_pkg(env, version) + + # this requirement parsing will raise a VersionConflict unless the + # .egg-info file is parsed (see #419 on BitBucket) + req = pkg_resources.Requirement.parse('foo>=1.9') + dist = pkg_resources.WorkingSet([env.paths['lib']]).find(req) + assert dist.version == version diff -Nru python-setuptools-3.3/pkg_resources/tests/test_resources.py python-setuptools-20.1.1/pkg_resources/tests/test_resources.py --- python-setuptools-3.3/pkg_resources/tests/test_resources.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/tests/test_resources.py 2016-02-07 14:38:32.000000000 +0000 @@ -0,0 +1,718 @@ +from __future__ import unicode_literals + +import os +import sys +import string + +from pkg_resources.extern.six.moves import map + +import pytest +from pkg_resources.extern import packaging + +import pkg_resources +from pkg_resources import (parse_requirements, VersionConflict, parse_version, + Distribution, EntryPoint, Requirement, safe_version, safe_name, + WorkingSet) + + +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) < pkg_resources._MAX_LENGTH: + return result + return result[:pkg_resources._MAX_LENGTH] + ' [truncated]...' + + +class Metadata(pkg_resources.EmptyProvider): + """Mock object to return metadata as if from an on-disk distribution""" + + def __init__(self, *pairs): + self.metadata = dict(pairs) + + def has_metadata(self, name): + return name in self.metadata + + def get_metadata(self, name): + return self.metadata[name] + + def get_metadata_lines(self, name): + return pkg_resources.yield_lines(self.get_metadata(name)) + + +dist_from_fn = pkg_resources.Distribution.from_filename + +class TestDistro: + + def testCollection(self): + # empty path should produce no distributions + ad = pkg_resources.Environment([], platform=None, python=None) + assert list(ad) == [] + assert ad['FooPkg'] == [] + ad.add(dist_from_fn("FooPkg-1.3_1.egg")) + ad.add(dist_from_fn("FooPkg-1.4-py2.4-win32.egg")) + ad.add(dist_from_fn("FooPkg-1.2-py2.4.egg")) + + # Name is in there now + assert ad['FooPkg'] + # But only 1 package + assert list(ad) == ['foopkg'] + + # Distributions sort by version + assert [dist.version for dist in ad['FooPkg']] == ['1.4','1.3-1','1.2'] + + # Removing a distribution leaves sequence alone + ad.remove(ad['FooPkg'][1]) + assert [dist.version for dist in ad['FooPkg']] == ['1.4','1.2'] + + # And inserting adds them in order + ad.add(dist_from_fn("FooPkg-1.9.egg")) + assert [dist.version for dist in ad['FooPkg']] == ['1.9','1.4','1.2'] + + ws = WorkingSet([]) + foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg") + foo14 = dist_from_fn("FooPkg-1.4-py2.4-win32.egg") + req, = parse_requirements("FooPkg>=1.3") + + # Nominal case: no distros on path, should yield all applicable + assert ad.best_match(req, ws).version == '1.9' + # If a matching distro is already installed, should return only that + ws.add(foo14) + assert ad.best_match(req, ws).version == '1.4' + + # If the first matching distro is unsuitable, it's a version conflict + ws = WorkingSet([]) + ws.add(foo12) + ws.add(foo14) + with pytest.raises(VersionConflict): + ad.best_match(req, ws) + + # If more than one match on the path, the first one takes precedence + ws = WorkingSet([]) + ws.add(foo14) + ws.add(foo12) + ws.add(foo14) + assert ad.best_match(req, ws).version == '1.4' + + def checkFooPkg(self,d): + assert d.project_name == "FooPkg" + assert d.key == "foopkg" + assert d.version == "1.3.post1" + assert d.py_version == "2.4" + assert d.platform == "win32" + assert d.parsed_version == parse_version("1.3-1") + + def testDistroBasics(self): + d = Distribution( + "/some/path", + project_name="FooPkg",version="1.3-1",py_version="2.4",platform="win32" + ) + self.checkFooPkg(d) + + d = Distribution("/some/path") + assert d.py_version == sys.version[:3] + assert d.platform == None + + def testDistroParse(self): + d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg") + self.checkFooPkg(d) + d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg-info") + self.checkFooPkg(d) + + def testDistroMetadata(self): + d = Distribution( + "/some/path", project_name="FooPkg", py_version="2.4", platform="win32", + metadata = Metadata( + ('PKG-INFO',"Metadata-Version: 1.0\nVersion: 1.3-1\n") + ) + ) + self.checkFooPkg(d) + + def distRequires(self, txt): + return Distribution("/foo", metadata=Metadata(('depends.txt', txt))) + + def checkRequires(self, dist, txt, extras=()): + assert list(dist.requires(extras)) == list(parse_requirements(txt)) + + def testDistroDependsSimple(self): + for v in "Twisted>=1.5", "Twisted>=1.5\nZConfig>=2.0": + self.checkRequires(self.distRequires(v), v) + + def testResolve(self): + ad = pkg_resources.Environment([]) + ws = WorkingSet([]) + # Resolving no requirements -> nothing to install + assert list(ws.resolve([], ad)) == [] + # Request something not in the collection -> DistributionNotFound + with pytest.raises(pkg_resources.DistributionNotFound): + ws.resolve(parse_requirements("Foo"), ad) + + Foo = Distribution.from_filename( + "/foo_dir/Foo-1.2.egg", + metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")) + ) + ad.add(Foo) + ad.add(Distribution.from_filename("Foo-0.9.egg")) + + # Request thing(s) that are available -> list to activate + for i in range(3): + targets = list(ws.resolve(parse_requirements("Foo"), ad)) + assert targets == [Foo] + list(map(ws.add, targets)) + with pytest.raises(VersionConflict): + ws.resolve(parse_requirements("Foo==0.9"), ad) + ws = WorkingSet([]) # reset + + # Request an extra that causes an unresolved dependency for "Baz" + with pytest.raises(pkg_resources.DistributionNotFound): + ws.resolve(parse_requirements("Foo[bar]"), ad) + Baz = Distribution.from_filename( + "/foo_dir/Baz-2.1.egg", metadata=Metadata(('depends.txt', "Foo")) + ) + ad.add(Baz) + + # Activation list now includes resolved dependency + assert list(ws.resolve(parse_requirements("Foo[bar]"), ad)) ==[Foo,Baz] + # Requests for conflicting versions produce VersionConflict + with pytest.raises(VersionConflict) as vc: + ws.resolve(parse_requirements("Foo==1.2\nFoo!=1.2"), ad) + + msg = 'Foo 0.9 is installed but Foo==1.2 is required' + assert vc.value.report() == msg + + def testDistroDependsOptions(self): + d = self.distRequires(""" + Twisted>=1.5 + [docgen] + ZConfig>=2.0 + docutils>=0.3 + [fastcgi] + fcgiapp>=0.1""") + self.checkRequires(d,"Twisted>=1.5") + self.checkRequires( + d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3".split(), ["docgen"] + ) + self.checkRequires( + d,"Twisted>=1.5 fcgiapp>=0.1".split(), ["fastcgi"] + ) + self.checkRequires( + d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3 fcgiapp>=0.1".split(), + ["docgen","fastcgi"] + ) + self.checkRequires( + d,"Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), + ["fastcgi", "docgen"] + ) + with pytest.raises(pkg_resources.UnknownExtra): + d.requires(["foo"]) + + +class TestWorkingSet: + def test_find_conflicting(self): + ws = WorkingSet([]) + Foo = Distribution.from_filename("/foo_dir/Foo-1.2.egg") + ws.add(Foo) + + # create a requirement that conflicts with Foo 1.2 + req = next(parse_requirements("Foo<1.2")) + + with pytest.raises(VersionConflict) as vc: + ws.find(req) + + msg = 'Foo 1.2 is installed but Foo<1.2 is required' + assert vc.value.report() == msg + + def test_resolve_conflicts_with_prior(self): + """ + A ContextualVersionConflict should be raised when a requirement + conflicts with a prior requirement for a different package. + """ + # Create installation where Foo depends on Baz 1.0 and Bar depends on + # Baz 2.0. + ws = WorkingSet([]) + md = Metadata(('depends.txt', "Baz==1.0")) + Foo = Distribution.from_filename("/foo_dir/Foo-1.0.egg", metadata=md) + ws.add(Foo) + md = Metadata(('depends.txt', "Baz==2.0")) + Bar = Distribution.from_filename("/foo_dir/Bar-1.0.egg", metadata=md) + ws.add(Bar) + Baz = Distribution.from_filename("/foo_dir/Baz-1.0.egg") + ws.add(Baz) + Baz = Distribution.from_filename("/foo_dir/Baz-2.0.egg") + ws.add(Baz) + + with pytest.raises(VersionConflict) as vc: + ws.resolve(parse_requirements("Foo\nBar\n")) + + msg = "Baz 1.0 is installed but Baz==2.0 is required by " + msg += repr(set(['Bar'])) + assert vc.value.report() == msg + + +class TestEntryPoints: + + def assertfields(self, ep): + assert ep.name == "foo" + assert ep.module_name == "pkg_resources.tests.test_resources" + assert ep.attrs == ("TestEntryPoints",) + assert ep.extras == ("x",) + assert ep.load() is TestEntryPoints + expect = "foo = pkg_resources.tests.test_resources:TestEntryPoints [x]" + assert str(ep) == expect + + def setup_method(self, method): + self.dist = Distribution.from_filename( + "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt','[x]'))) + + def testBasics(self): + ep = EntryPoint( + "foo", "pkg_resources.tests.test_resources", ["TestEntryPoints"], + ["x"], self.dist + ) + self.assertfields(ep) + + def testParse(self): + s = "foo = pkg_resources.tests.test_resources:TestEntryPoints [x]" + ep = EntryPoint.parse(s, self.dist) + self.assertfields(ep) + + ep = EntryPoint.parse("bar baz= spammity[PING]") + assert ep.name == "bar baz" + assert ep.module_name == "spammity" + assert ep.attrs == () + assert ep.extras == ("ping",) + + ep = EntryPoint.parse(" fizzly = wocka:foo") + assert ep.name == "fizzly" + assert ep.module_name == "wocka" + assert ep.attrs == ("foo",) + assert ep.extras == () + + # plus in the name + spec = "html+mako = mako.ext.pygmentplugin:MakoHtmlLexer" + ep = EntryPoint.parse(spec) + assert ep.name == 'html+mako' + + reject_specs = "foo", "x=a:b:c", "q=x/na", "fez=pish:tush-z", "x=f[a]>2" + @pytest.mark.parametrize("reject_spec", reject_specs) + def test_reject_spec(self, reject_spec): + with pytest.raises(ValueError): + EntryPoint.parse(reject_spec) + + def test_printable_name(self): + """ + Allow any printable character in the name. + """ + # Create a name with all printable characters; strip the whitespace. + name = string.printable.strip() + spec = "{name} = module:attr".format(**locals()) + ep = EntryPoint.parse(spec) + assert ep.name == name + + def checkSubMap(self, m): + assert len(m) == len(self.submap_expect) + for key, ep in self.submap_expect.items(): + assert repr(m.get(key)) == repr(ep) + + submap_expect = dict( + feature1=EntryPoint('feature1', 'somemodule', ['somefunction']), + feature2=EntryPoint('feature2', 'another.module', ['SomeClass'], ['extra1','extra2']), + feature3=EntryPoint('feature3', 'this.module', extras=['something']) + ) + submap_str = """ + # define features for blah blah + feature1 = somemodule:somefunction + feature2 = another.module:SomeClass [extra1,extra2] + feature3 = this.module [something] + """ + + def testParseList(self): + self.checkSubMap(EntryPoint.parse_group("xyz", self.submap_str)) + with pytest.raises(ValueError): + EntryPoint.parse_group("x a", "foo=bar") + with pytest.raises(ValueError): + EntryPoint.parse_group("x", ["foo=baz", "foo=bar"]) + + def testParseMap(self): + m = EntryPoint.parse_map({'xyz':self.submap_str}) + self.checkSubMap(m['xyz']) + assert list(m.keys()) == ['xyz'] + m = EntryPoint.parse_map("[xyz]\n"+self.submap_str) + self.checkSubMap(m['xyz']) + assert list(m.keys()) == ['xyz'] + with pytest.raises(ValueError): + EntryPoint.parse_map(["[xyz]", "[xyz]"]) + with pytest.raises(ValueError): + EntryPoint.parse_map(self.submap_str) + +class TestRequirements: + + def testBasics(self): + r = Requirement.parse("Twisted>=1.2") + assert str(r) == "Twisted>=1.2" + assert repr(r) == "Requirement.parse('Twisted>=1.2')" + assert r == Requirement("Twisted", [('>=','1.2')], ()) + assert r == Requirement("twisTed", [('>=','1.2')], ()) + assert r != Requirement("Twisted", [('>=','2.0')], ()) + assert r != Requirement("Zope", [('>=','1.2')], ()) + assert r != Requirement("Zope", [('>=','3.0')], ()) + assert r != Requirement.parse("Twisted[extras]>=1.2") + + def testOrdering(self): + r1 = Requirement("Twisted", [('==','1.2c1'),('>=','1.2')], ()) + r2 = Requirement("Twisted", [('>=','1.2'),('==','1.2c1')], ()) + assert r1 == r2 + assert str(r1) == str(r2) + assert str(r2) == "Twisted==1.2c1,>=1.2" + + def testBasicContains(self): + r = Requirement("Twisted", [('>=','1.2')], ()) + foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg") + twist11 = Distribution.from_filename("Twisted-1.1.egg") + twist12 = Distribution.from_filename("Twisted-1.2.egg") + assert parse_version('1.2') in r + assert parse_version('1.1') not in r + assert '1.2' in r + assert '1.1' not in r + assert foo_dist not in r + assert twist11 not in r + assert twist12 in r + + def testOptionsAndHashing(self): + r1 = Requirement.parse("Twisted[foo,bar]>=1.2") + r2 = Requirement.parse("Twisted[bar,FOO]>=1.2") + assert r1 == r2 + assert r1.extras == ("foo","bar") + assert r2.extras == ("bar","foo") # extras are normalized + assert hash(r1) == hash(r2) + assert ( + hash(r1) + == + hash(( + "twisted", + packaging.specifiers.SpecifierSet(">=1.2"), + frozenset(["foo","bar"]), + )) + ) + + def testVersionEquality(self): + r1 = Requirement.parse("foo==0.3a2") + r2 = Requirement.parse("foo!=0.3a4") + d = Distribution.from_filename + + assert d("foo-0.3a4.egg") not in r1 + assert d("foo-0.3a1.egg") not in r1 + assert d("foo-0.3a4.egg") not in r2 + + assert d("foo-0.3a2.egg") in r1 + assert d("foo-0.3a2.egg") in r2 + assert d("foo-0.3a3.egg") in r2 + assert d("foo-0.3a5.egg") in r2 + + def testSetuptoolsProjectName(self): + """ + The setuptools project should implement the setuptools package. + """ + + assert ( + Requirement.parse('setuptools').project_name == 'setuptools') + # setuptools 0.7 and higher means setuptools. + assert ( + Requirement.parse('setuptools == 0.7').project_name == 'setuptools') + assert ( + Requirement.parse('setuptools == 0.7a1').project_name == 'setuptools') + assert ( + Requirement.parse('setuptools >= 0.7').project_name == 'setuptools') + + +class TestParsing: + + def testEmptyParse(self): + assert list(parse_requirements('')) == [] + + def testYielding(self): + for inp,out in [ + ([], []), ('x',['x']), ([[]],[]), (' x\n y', ['x','y']), + (['x\n\n','y'], ['x','y']), + ]: + assert list(pkg_resources.yield_lines(inp)) == out + + def testSplitting(self): + sample = """ + x + [Y] + z + + a + [b ] + # foo + c + [ d] + [q] + v + """ + assert ( + list(pkg_resources.split_sections(sample)) + == + [ + (None, ["x"]), + ("Y", ["z", "a"]), + ("b", ["c"]), + ("d", []), + ("q", ["v"]), + ] + ) + with pytest.raises(ValueError): + list(pkg_resources.split_sections("[foo")) + + def testSafeName(self): + assert safe_name("adns-python") == "adns-python" + assert safe_name("WSGI Utils") == "WSGI-Utils" + assert safe_name("WSGI Utils") == "WSGI-Utils" + assert safe_name("Money$$$Maker") == "Money-Maker" + assert safe_name("peak.web") != "peak-web" + + def testSafeVersion(self): + assert safe_version("1.2-1") == "1.2.post1" + assert safe_version("1.2 alpha") == "1.2.alpha" + assert safe_version("2.3.4 20050521") == "2.3.4.20050521" + assert safe_version("Money$$$Maker") == "Money-Maker" + assert safe_version("peak.web") == "peak.web" + + def testSimpleRequirements(self): + assert ( + list(parse_requirements('Twis-Ted>=1.2-1')) + == + [Requirement('Twis-Ted',[('>=','1.2-1')], ())] + ) + assert ( + list(parse_requirements('Twisted >=1.2, \ # more\n<2.0')) + == + [Requirement('Twisted',[('>=','1.2'),('<','2.0')], ())] + ) + assert ( + Requirement.parse("FooBar==1.99a3") + == + Requirement("FooBar", [('==','1.99a3')], ()) + ) + with pytest.raises(ValueError): + Requirement.parse(">=2.3") + with pytest.raises(ValueError): + Requirement.parse("x\\") + with pytest.raises(ValueError): + Requirement.parse("x==2 q") + with pytest.raises(ValueError): + Requirement.parse("X==1\nY==2") + with pytest.raises(ValueError): + Requirement.parse("#") + + def testVersionEquality(self): + def c(s1,s2): + p1, p2 = parse_version(s1),parse_version(s2) + assert 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('0post1', '0.0post1') + c('0pre1', '0.0c1') + c('0.0.0preview1', '0c1') + c('0.0c1', '0-rc1') + c('1.2a1', '1.2.a.1') + c('1.2.a', '1.2a') + + def testVersionOrdering(self): + def c(s1,s2): + p1, p2 = parse_version(s1),parse_version(s2) + assert p1 tuple(parse_version("2.0")) + assert parse_version("3.0") >= tuple(parse_version("2.0")) + assert parse_version("3.0") != tuple(parse_version("2.0")) + assert not (parse_version("3.0") != tuple(parse_version("3.0"))) + + def testVersionHashable(self): + """ + Ensure that our versions stay hashable even though we've subclassed + them and added some shim code to them. + """ + assert ( + hash(parse_version("1.0")) + == + hash(parse_version("1.0")) + ) + + +class TestNamespaces: + + ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" + + @pytest.yield_fixture + def symlinked_tmpdir(self, tmpdir): + """ + Where available, return the tempdir as a symlink, + which as revealed in #231 is more fragile than + a natural tempdir. + """ + if not hasattr(os, 'symlink'): + yield str(tmpdir) + return + + link_name = str(tmpdir) + '-linked' + os.symlink(str(tmpdir), link_name) + try: + yield type(tmpdir)(link_name) + finally: + os.unlink(link_name) + + @pytest.yield_fixture(autouse=True) + def patched_path(self, tmpdir): + """ + Patch sys.path to include the 'site-pkgs' dir. Also + restore pkg_resources._namespace_packages to its + former state. + """ + saved_ns_pkgs = pkg_resources._namespace_packages.copy() + saved_sys_path = sys.path[:] + site_pkgs = tmpdir.mkdir('site-pkgs') + sys.path.append(str(site_pkgs)) + try: + yield + finally: + pkg_resources._namespace_packages = saved_ns_pkgs + sys.path = saved_sys_path + + def test_two_levels_deep(self, symlinked_tmpdir): + """ + Test nested namespace packages + Create namespace packages in the following tree : + site-packages-1/pkg1/pkg2 + site-packages-2/pkg1/pkg2 + Check both are in the _namespace_packages dict and that their __path__ + is correct + """ + real_tmpdir = symlinked_tmpdir.realpath() + tmpdir = symlinked_tmpdir + sys.path.append(str(tmpdir / 'site-pkgs2')) + site_dirs = tmpdir / 'site-pkgs', tmpdir / 'site-pkgs2' + for site in site_dirs: + pkg1 = site / 'pkg1' + pkg2 = pkg1 / 'pkg2' + pkg2.ensure_dir() + (pkg1 / '__init__.py').write_text(self.ns_str, encoding='utf-8') + (pkg2 / '__init__.py').write_text(self.ns_str, encoding='utf-8') + import pkg1 + assert "pkg1" in pkg_resources._namespace_packages + # attempt to import pkg2 from site-pkgs2 + import pkg1.pkg2 + # check the _namespace_packages dict + assert "pkg1.pkg2" in pkg_resources._namespace_packages + assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"] + # check the __path__ attribute contains both paths + expected = [ + str(real_tmpdir / "site-pkgs" / "pkg1" / "pkg2"), + str(real_tmpdir / "site-pkgs2" / "pkg1" / "pkg2"), + ] + assert pkg1.pkg2.__path__ == expected + + def test_path_order(self, symlinked_tmpdir): + """ + Test that if multiple versions of the same namespace package subpackage + are on different sys.path entries, that only the one earliest on + sys.path is imported, and that the namespace package's __path__ is in + the correct order. + + Regression test for https://bitbucket.org/pypa/setuptools/issues/207 + """ + + tmpdir = symlinked_tmpdir + site_dirs = ( + tmpdir / "site-pkgs", + tmpdir / "site-pkgs2", + tmpdir / "site-pkgs3", + ) + + vers_str = "__version__ = %r" + + for number, site in enumerate(site_dirs, 1): + if number > 1: + sys.path.append(str(site)) + nspkg = site / 'nspkg' + subpkg = nspkg / 'subpkg' + subpkg.ensure_dir() + (nspkg / '__init__.py').write_text(self.ns_str, encoding='utf-8') + (subpkg / '__init__.py').write_text(vers_str % number, encoding='utf-8') + + import nspkg.subpkg + import nspkg + expected = [ + str(site.realpath() / 'nspkg') + for site in site_dirs + ] + assert nspkg.__path__ == expected + assert nspkg.subpkg.__version__ == 1 diff -Nru python-setuptools-3.3/pkg_resources/_vendor/packaging/__about__.py python-setuptools-20.1.1/pkg_resources/_vendor/packaging/__about__.py --- python-setuptools-3.3/pkg_resources/_vendor/packaging/__about__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/_vendor/packaging/__about__.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,31 @@ +# Copyright 2014 Donald Stufft +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "15.3" + +__author__ = "Donald Stufft" +__email__ = "donald@stufft.io" + +__license__ = "Apache License, Version 2.0" +__copyright__ = "Copyright 2014 %s" % __author__ diff -Nru python-setuptools-3.3/pkg_resources/_vendor/packaging/_compat.py python-setuptools-20.1.1/pkg_resources/_vendor/packaging/_compat.py --- python-setuptools-3.3/pkg_resources/_vendor/packaging/_compat.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/_vendor/packaging/_compat.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,40 @@ +# Copyright 2014 Donald Stufft +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +import sys + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +# flake8: noqa + +if PY3: + string_types = str, +else: + string_types = basestring, + + +def with_metaclass(meta, *bases): + """ + Create a base class with a metaclass. + """ + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) diff -Nru python-setuptools-3.3/pkg_resources/_vendor/packaging/__init__.py python-setuptools-20.1.1/pkg_resources/_vendor/packaging/__init__.py --- python-setuptools-3.3/pkg_resources/_vendor/packaging/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/_vendor/packaging/__init__.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,24 @@ +# Copyright 2014 Donald Stufft +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__ +) + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] diff -Nru python-setuptools-3.3/pkg_resources/_vendor/packaging/specifiers.py python-setuptools-20.1.1/pkg_resources/_vendor/packaging/specifiers.py --- python-setuptools-3.3/pkg_resources/_vendor/packaging/specifiers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/_vendor/packaging/specifiers.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,784 @@ +# Copyright 2014 Donald Stufft +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +import abc +import functools +import itertools +import re + +from ._compat import string_types, with_metaclass +from .version import Version, LegacyVersion, parse + + +class InvalidSpecifier(ValueError): + """ + An invalid specifier was found, users should refer to PEP 440. + """ + + +class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): + + @abc.abstractmethod + def __str__(self): + """ + Returns the str representation of this Specifier like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Returns a hash value for this Specifier like object. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are equal. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are not equal. + """ + + @abc.abstractproperty + def prereleases(self): + """ + Returns whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @prereleases.setter + def prereleases(self, value): + """ + Sets whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @abc.abstractmethod + def contains(self, item, prereleases=None): + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter(self, iterable, prereleases=None): + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class _IndividualSpecifier(BaseSpecifier): + + _operators = {} + + def __init__(self, spec="", prereleases=None): + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) + + self._spec = ( + match.group("operator").strip(), + match.group("version").strip(), + ) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<{0}({1!r}{2})>".format( + self.__class__.__name__, + str(self), + pre, + ) + + def __str__(self): + return "{0}{1}".format(*self._spec) + + def __hash__(self): + return hash(self._spec) + + def __eq__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec == other._spec + + def __ne__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec != other._spec + + def _get_operator(self, op): + return getattr(self, "_compare_{0}".format(self._operators[op])) + + def _coerce_version(self, version): + if not isinstance(version, (LegacyVersion, Version)): + version = parse(version) + return version + + @property + def operator(self): + return self._spec[0] + + @property + def version(self): + return self._spec[1] + + @property + def prereleases(self): + return self._prereleases + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version or LegacyVersion, this allows us to have + # a shortcut for ``"2.0" in Specifier(">=2") + item = self._coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + return self._get_operator(self.operator)(item, self.version) + + def filter(self, iterable, prereleases=None): + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = self._coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later incase nothing + # else matches this specifier. + if (parsed_version.is_prerelease + and not (prereleases or self.prereleases)): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the begining. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +class LegacySpecifier(_IndividualSpecifier): + + _regex = re.compile( + r""" + ^ + \s* + (?P(==|!=|<=|>=|<|>)) + \s* + (?P + [^\s]* # We just match everything, except for whitespace since this + # is a "legacy" specifier and the version string can be just + # about anything. + ) + \s* + $ + """, + re.VERBOSE | re.IGNORECASE, + ) + + _operators = { + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + } + + def _coerce_version(self, version): + if not isinstance(version, LegacyVersion): + version = LegacyVersion(str(version)) + return version + + def _compare_equal(self, prospective, spec): + return prospective == self._coerce_version(spec) + + def _compare_not_equal(self, prospective, spec): + return prospective != self._coerce_version(spec) + + def _compare_less_than_equal(self, prospective, spec): + return prospective <= self._coerce_version(spec) + + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= self._coerce_version(spec) + + def _compare_less_than(self, prospective, spec): + return prospective < self._coerce_version(spec) + + def _compare_greater_than(self, prospective, spec): + return prospective > self._coerce_version(spec) + + +def _require_version_compare(fn): + @functools.wraps(fn) + def wrapped(self, prospective, spec): + if not isinstance(prospective, Version): + return False + return fn(self, prospective, spec) + return wrapped + + +class Specifier(_IndividualSpecifier): + + _regex = re.compile( + r""" + ^ + \s* + (?P(~=|==|!=|<=|>=|<|>|===)) + (?P + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s]* # We just match everything, except for whitespace + # since we are only testing for strict identity. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + + # You cannot use a wild card and a dev or local version + # together so group them with a | and make them optional. + (?: + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + | + \.\* # Wild card syntax of .* + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + @_require_version_compare + def _compare_compatible(self, prospective, spec): + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore post and dev releases and we want to treat the pre-release as + # it's own separate segment. + prefix = ".".join( + list( + itertools.takewhile( + lambda x: (not x.startswith("post") + and not x.startswith("dev")), + _version_split(spec), + ) + )[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return (self._get_operator(">=")(prospective, spec) + and self._get_operator("==")(prospective, prefix)) + + @_require_version_compare + def _compare_equal(self, prospective, spec): + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # Split the spec out by dots, and pretend that there is an implicit + # dot in between a release segment and a pre-release segment. + spec = _version_split(spec[:-2]) # Remove the trailing .* + + # Split the prospective version out by dots, and pretend that there + # is an implicit dot in between a release segment and a pre-release + # segment. + prospective = _version_split(str(prospective)) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + prospective = prospective[:len(spec)] + + # Pad out our two sides with zeros so that they both equal the same + # length. + spec, prospective = _pad_version(spec, prospective) + else: + # Convert our spec string into a Version + spec = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec.local: + prospective = Version(prospective.public) + + return prospective == spec + + @_require_version_compare + def _compare_not_equal(self, prospective, spec): + return not self._compare_equal(prospective, spec) + + @_require_version_compare + def _compare_less_than_equal(self, prospective, spec): + return prospective <= Version(spec) + + @_require_version_compare + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= Version(spec) + + @_require_version_compare + def _compare_less_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + @_require_version_compare + def _compare_greater_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is techincally greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective, spec): + return str(prospective).lower() == str(spec).lower() + + @property + def prereleases(self): + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "==="]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if parse(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version): + result = [] + for item in version.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _pad_version(left, right): + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split):]) + right_split.append(left[len(right_split):]) + + # Insert our padding + left_split.insert( + 1, + ["0"] * max(0, len(right_split[0]) - len(left_split[0])), + ) + right_split.insert( + 1, + ["0"] * max(0, len(left_split[0]) - len(right_split[0])), + ) + + return ( + list(itertools.chain(*left_split)), + list(itertools.chain(*right_split)), + ) + + +class SpecifierSet(BaseSpecifier): + + def __init__(self, specifiers="", prereleases=None): + # Split on , to break each indidivual specifier into it's own item, and + # strip each item to remove leading/trailing whitespace. + specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Parsed each individual specifier, attempting first to make it a + # Specifier and falling back to a LegacySpecifier. + parsed = set() + for specifier in specifiers: + try: + parsed.add(Specifier(specifier)) + except InvalidSpecifier: + parsed.add(LegacySpecifier(specifier)) + + # Turn our parsed specifiers into a frozen set and save them for later. + self._specs = frozenset(parsed) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "".format(str(self), pre) + + def __str__(self): + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self): + return hash(self._specs) + + def __and__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __ne__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs != other._specs + + def __len__(self): + return len(self._specs) + + def __iter__(self): + return iter(self._specs) + + @property + def prereleases(self): + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Ensure that our item is a Version or LegacyVersion instance. + if not isinstance(item, (LegacyVersion, Version)): + item = parse(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all( + s.contains(item, prereleases=prereleases) + for s in self._specs + ) + + def filter(self, iterable, prereleases=None): + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iterable + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases, and which will filter out LegacyVersion in general. + else: + filtered = [] + found_prereleases = [] + + for item in iterable: + # Ensure that we some kind of Version class for this item. + if not isinstance(item, (LegacyVersion, Version)): + parsed_version = parse(item) + else: + parsed_version = item + + # Filter out any item which is parsed as a LegacyVersion + if isinstance(parsed_version, LegacyVersion): + continue + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return found_prereleases + + return filtered diff -Nru python-setuptools-3.3/pkg_resources/_vendor/packaging/_structures.py python-setuptools-20.1.1/pkg_resources/_vendor/packaging/_structures.py --- python-setuptools-3.3/pkg_resources/_vendor/packaging/_structures.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/_vendor/packaging/_structures.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,78 @@ +# Copyright 2014 Donald Stufft +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + + +class Infinity(object): + + def __repr__(self): + return "Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return False + + def __le__(self, other): + return False + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return True + + def __ge__(self, other): + return True + + def __neg__(self): + return NegativeInfinity + +Infinity = Infinity() + + +class NegativeInfinity(object): + + def __repr__(self): + return "-Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return True + + def __le__(self, other): + return True + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return False + + def __ge__(self, other): + return False + + def __neg__(self): + return Infinity + +NegativeInfinity = NegativeInfinity() diff -Nru python-setuptools-3.3/pkg_resources/_vendor/packaging/version.py python-setuptools-20.1.1/pkg_resources/_vendor/packaging/version.py --- python-setuptools-3.3/pkg_resources/_vendor/packaging/version.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/pkg_resources/_vendor/packaging/version.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,403 @@ +# Copyright 2014 Donald Stufft +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +import collections +import itertools +import re + +from ._structures import Infinity + + +__all__ = [ + "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN" +] + + +_Version = collections.namedtuple( + "_Version", + ["epoch", "release", "dev", "pre", "post", "local"], +) + + +def parse(version): + """ + Parse the given version string and return either a :class:`Version` object + or a :class:`LegacyVersion` object depending on if the given version is + a valid PEP 440 version or a legacy version. + """ + try: + return Version(version) + except InvalidVersion: + return LegacyVersion(version) + + +class InvalidVersion(ValueError): + """ + An invalid version was found, users should refer to PEP 440. + """ + + +class _BaseVersion(object): + + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, _BaseVersion): + return NotImplemented + + return method(self._key, other._key) + + +class LegacyVersion(_BaseVersion): + + def __init__(self, version): + self._version = str(version) + self._key = _legacy_cmpkey(self._version) + + def __str__(self): + return self._version + + def __repr__(self): + return "".format(repr(str(self))) + + @property + def public(self): + return self._version + + @property + def base_version(self): + return self._version + + @property + def local(self): + return None + + @property + def is_prerelease(self): + return False + + @property + def is_postrelease(self): + return False + + +_legacy_version_component_re = re.compile( + r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE, +) + +_legacy_version_replacement_map = { + "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@", +} + + +def _parse_version_parts(s): + for part in _legacy_version_component_re.split(s): + part = _legacy_version_replacement_map.get(part, part) + + if not part or part == ".": + continue + + if part[:1] in "0123456789": + # pad for numeric comparison + yield part.zfill(8) + else: + yield "*" + part + + # ensure that alpha/beta/candidate are before final + yield "*final" + + +def _legacy_cmpkey(version): + # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch + # greater than or equal to 0. This will effectively put the LegacyVersion, + # which uses the defacto standard originally implemented by setuptools, + # as before all PEP 440 versions. + epoch = -1 + + # This scheme is taken from pkg_resources.parse_version setuptools prior to + # it's adoption of the packaging library. + parts = [] + for part in _parse_version_parts(version.lower()): + if part.startswith("*"): + # remove "-" before a prerelease tag + if part < "*final": + 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() + + parts.append(part) + parts = tuple(parts) + + return epoch, parts + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +VERSION_PATTERN = r""" + v? + (?: + (?:(?P[0-9]+)!)? # epoch + (?P[0-9]+(?:\.[0-9]+)*) # release segment + (?P
                                          # pre-release
+            [-_\.]?
+            (?P(a|b|c|rc|alpha|beta|pre|preview))
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+        (?P                                         # post release
+            (?:-(?P[0-9]+))
+            |
+            (?:
+                [-_\.]?
+                (?Ppost|rev|r)
+                [-_\.]?
+                (?P[0-9]+)?
+            )
+        )?
+        (?P                                          # dev release
+            [-_\.]?
+            (?Pdev)
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+    )
+    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
+"""
+
+
+class Version(_BaseVersion):
+
+    _regex = re.compile(
+        r"^\s*" + VERSION_PATTERN + r"\s*$",
+        re.VERBOSE | re.IGNORECASE,
+    )
+
+    def __init__(self, version):
+        # Validate the version and parse it into pieces
+        match = self._regex.search(version)
+        if not match:
+            raise InvalidVersion("Invalid version: '{0}'".format(version))
+
+        # Store the parsed out pieces of the version
+        self._version = _Version(
+            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
+            release=tuple(int(i) for i in match.group("release").split(".")),
+            pre=_parse_letter_version(
+                match.group("pre_l"),
+                match.group("pre_n"),
+            ),
+            post=_parse_letter_version(
+                match.group("post_l"),
+                match.group("post_n1") or match.group("post_n2"),
+            ),
+            dev=_parse_letter_version(
+                match.group("dev_l"),
+                match.group("dev_n"),
+            ),
+            local=_parse_local_version(match.group("local")),
+        )
+
+        # Generate a key which will be used for sorting
+        self._key = _cmpkey(
+            self._version.epoch,
+            self._version.release,
+            self._version.pre,
+            self._version.post,
+            self._version.dev,
+            self._version.local,
+        )
+
+    def __repr__(self):
+        return "".format(repr(str(self)))
+
+    def __str__(self):
+        parts = []
+
+        # Epoch
+        if self._version.epoch != 0:
+            parts.append("{0}!".format(self._version.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self._version.release))
+
+        # Pre-release
+        if self._version.pre is not None:
+            parts.append("".join(str(x) for x in self._version.pre))
+
+        # Post-release
+        if self._version.post is not None:
+            parts.append(".post{0}".format(self._version.post[1]))
+
+        # Development release
+        if self._version.dev is not None:
+            parts.append(".dev{0}".format(self._version.dev[1]))
+
+        # Local version segment
+        if self._version.local is not None:
+            parts.append(
+                "+{0}".format(".".join(str(x) for x in self._version.local))
+            )
+
+        return "".join(parts)
+
+    @property
+    def public(self):
+        return str(self).split("+", 1)[0]
+
+    @property
+    def base_version(self):
+        parts = []
+
+        # Epoch
+        if self._version.epoch != 0:
+            parts.append("{0}!".format(self._version.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self._version.release))
+
+        return "".join(parts)
+
+    @property
+    def local(self):
+        version_string = str(self)
+        if "+" in version_string:
+            return version_string.split("+", 1)[1]
+
+    @property
+    def is_prerelease(self):
+        return bool(self._version.dev or self._version.pre)
+
+    @property
+    def is_postrelease(self):
+        return bool(self._version.post)
+
+
+def _parse_letter_version(letter, number):
+    if letter:
+        # We consider there to be an implicit 0 in a pre-release if there is
+        # not a numeral associated with it.
+        if number is None:
+            number = 0
+
+        # We normalize any letters to their lower case form
+        letter = letter.lower()
+
+        # We consider some words to be alternate spellings of other words and
+        # in those cases we want to normalize the spellings to our preferred
+        # spelling.
+        if letter == "alpha":
+            letter = "a"
+        elif letter == "beta":
+            letter = "b"
+        elif letter in ["c", "pre", "preview"]:
+            letter = "rc"
+        elif letter in ["rev", "r"]:
+            letter = "post"
+
+        return letter, int(number)
+    if not letter and number:
+        # We assume if we are given a number, but we are not given a letter
+        # then this is using the implicit post release syntax (e.g. 1.0-1)
+        letter = "post"
+
+        return letter, int(number)
+
+
+_local_version_seperators = re.compile(r"[\._-]")
+
+
+def _parse_local_version(local):
+    """
+    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
+    """
+    if local is not None:
+        return tuple(
+            part.lower() if not part.isdigit() else int(part)
+            for part in _local_version_seperators.split(local)
+        )
+
+
+def _cmpkey(epoch, release, pre, post, dev, local):
+    # When we compare a release version, we want to compare it with all of the
+    # trailing zeros removed. So we'll use a reverse the list, drop all the now
+    # leading zeros until we come to something non zero, then take the rest
+    # re-reverse it back into the correct order and make it a tuple and use
+    # that for our sorting key.
+    release = tuple(
+        reversed(list(
+            itertools.dropwhile(
+                lambda x: x == 0,
+                reversed(release),
+            )
+        ))
+    )
+
+    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
+    # We'll do this by abusing the pre segment, but we _only_ want to do this
+    # if there is not a pre or a post segment. If we have one of those then
+    # the normal sorting rules will handle this case correctly.
+    if pre is None and post is None and dev is not None:
+        pre = -Infinity
+    # Versions without a pre-release (except as noted above) should sort after
+    # those with one.
+    elif pre is None:
+        pre = Infinity
+
+    # Versions without a post segment should sort before those with one.
+    if post is None:
+        post = -Infinity
+
+    # Versions without a development segment should sort after those with one.
+    if dev is None:
+        dev = Infinity
+
+    if local is None:
+        # Versions without a local segment should sort before those with one.
+        local = -Infinity
+    else:
+        # Versions with a local segment need that segment parsed to implement
+        # the sorting rules in PEP440.
+        # - Alpha numeric segments sort before numeric segments
+        # - Alpha numeric segments sort lexicographically
+        # - Numeric segments sort numerically
+        # - Shorter versions sort before longer versions when the prefixes
+        #   match exactly
+        local = tuple(
+            (i, "") if isinstance(i, int) else (-Infinity, i)
+            for i in local
+        )
+
+    return epoch, release, pre, post, dev, local
diff -Nru python-setuptools-3.3/pkg_resources/_vendor/six.py python-setuptools-20.1.1/pkg_resources/_vendor/six.py
--- python-setuptools-3.3/pkg_resources/_vendor/six.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/pkg_resources/_vendor/six.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,868 @@
+"""Utilities for writing code that runs on Python 2 and 3"""
+
+# Copyright (c) 2010-2015 Benjamin Peterson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from __future__ import absolute_import
+
+import functools
+import itertools
+import operator
+import sys
+import types
+
+__author__ = "Benjamin Peterson "
+__version__ = "1.10.0"
+
+
+# Useful for very coarse version differentiation.
+PY2 = sys.version_info[0] == 2
+PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
+
+if PY3:
+    string_types = str,
+    integer_types = int,
+    class_types = type,
+    text_type = str
+    binary_type = bytes
+
+    MAXSIZE = sys.maxsize
+else:
+    string_types = basestring,
+    integer_types = (int, long)
+    class_types = (type, types.ClassType)
+    text_type = unicode
+    binary_type = str
+
+    if sys.platform.startswith("java"):
+        # Jython always uses 32 bits.
+        MAXSIZE = int((1 << 31) - 1)
+    else:
+        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
+        class X(object):
+
+            def __len__(self):
+                return 1 << 31
+        try:
+            len(X())
+        except OverflowError:
+            # 32-bit
+            MAXSIZE = int((1 << 31) - 1)
+        else:
+            # 64-bit
+            MAXSIZE = int((1 << 63) - 1)
+        del X
+
+
+def _add_doc(func, doc):
+    """Add documentation to a function."""
+    func.__doc__ = doc
+
+
+def _import_module(name):
+    """Import module, returning the module after the last dot."""
+    __import__(name)
+    return sys.modules[name]
+
+
+class _LazyDescr(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __get__(self, obj, tp):
+        result = self._resolve()
+        setattr(obj, self.name, result)  # Invokes __set__.
+        try:
+            # This is a bit ugly, but it avoids running this again by
+            # removing this descriptor.
+            delattr(obj.__class__, self.name)
+        except AttributeError:
+            pass
+        return result
+
+
+class MovedModule(_LazyDescr):
+
+    def __init__(self, name, old, new=None):
+        super(MovedModule, self).__init__(name)
+        if PY3:
+            if new is None:
+                new = name
+            self.mod = new
+        else:
+            self.mod = old
+
+    def _resolve(self):
+        return _import_module(self.mod)
+
+    def __getattr__(self, attr):
+        _module = self._resolve()
+        value = getattr(_module, attr)
+        setattr(self, attr, value)
+        return value
+
+
+class _LazyModule(types.ModuleType):
+
+    def __init__(self, name):
+        super(_LazyModule, self).__init__(name)
+        self.__doc__ = self.__class__.__doc__
+
+    def __dir__(self):
+        attrs = ["__doc__", "__name__"]
+        attrs += [attr.name for attr in self._moved_attributes]
+        return attrs
+
+    # Subclasses should override this
+    _moved_attributes = []
+
+
+class MovedAttribute(_LazyDescr):
+
+    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
+        super(MovedAttribute, self).__init__(name)
+        if PY3:
+            if new_mod is None:
+                new_mod = name
+            self.mod = new_mod
+            if new_attr is None:
+                if old_attr is None:
+                    new_attr = name
+                else:
+                    new_attr = old_attr
+            self.attr = new_attr
+        else:
+            self.mod = old_mod
+            if old_attr is None:
+                old_attr = name
+            self.attr = old_attr
+
+    def _resolve(self):
+        module = _import_module(self.mod)
+        return getattr(module, self.attr)
+
+
+class _SixMetaPathImporter(object):
+
+    """
+    A meta path importer to import six.moves and its submodules.
+
+    This class implements a PEP302 finder and loader. It should be compatible
+    with Python 2.5 and all existing versions of Python3
+    """
+
+    def __init__(self, six_module_name):
+        self.name = six_module_name
+        self.known_modules = {}
+
+    def _add_module(self, mod, *fullnames):
+        for fullname in fullnames:
+            self.known_modules[self.name + "." + fullname] = mod
+
+    def _get_module(self, fullname):
+        return self.known_modules[self.name + "." + fullname]
+
+    def find_module(self, fullname, path=None):
+        if fullname in self.known_modules:
+            return self
+        return None
+
+    def __get_module(self, fullname):
+        try:
+            return self.known_modules[fullname]
+        except KeyError:
+            raise ImportError("This loader does not know module " + fullname)
+
+    def load_module(self, fullname):
+        try:
+            # in case of a reload
+            return sys.modules[fullname]
+        except KeyError:
+            pass
+        mod = self.__get_module(fullname)
+        if isinstance(mod, MovedModule):
+            mod = mod._resolve()
+        else:
+            mod.__loader__ = self
+        sys.modules[fullname] = mod
+        return mod
+
+    def is_package(self, fullname):
+        """
+        Return true, if the named module is a package.
+
+        We need this method to get correct spec objects with
+        Python 3.4 (see PEP451)
+        """
+        return hasattr(self.__get_module(fullname), "__path__")
+
+    def get_code(self, fullname):
+        """Return None
+
+        Required, if is_package is implemented"""
+        self.__get_module(fullname)  # eventually raises ImportError
+        return None
+    get_source = get_code  # same as get_code
+
+_importer = _SixMetaPathImporter(__name__)
+
+
+class _MovedItems(_LazyModule):
+
+    """Lazy loading of moved objects"""
+    __path__ = []  # mark as package
+
+
+_moved_attributes = [
+    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
+    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
+    MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
+    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("intern", "__builtin__", "sys"),
+    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
+    MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
+    MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
+    MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
+    MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
+    MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("UserDict", "UserDict", "collections"),
+    MovedAttribute("UserList", "UserList", "collections"),
+    MovedAttribute("UserString", "UserString", "collections"),
+    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
+    MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
+    MovedModule("builtins", "__builtin__"),
+    MovedModule("configparser", "ConfigParser"),
+    MovedModule("copyreg", "copy_reg"),
+    MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
+    MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
+    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
+    MovedModule("http_cookies", "Cookie", "http.cookies"),
+    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
+    MovedModule("html_parser", "HTMLParser", "html.parser"),
+    MovedModule("http_client", "httplib", "http.client"),
+    MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
+    MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
+    MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
+    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
+    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
+    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
+    MovedModule("cPickle", "cPickle", "pickle"),
+    MovedModule("queue", "Queue"),
+    MovedModule("reprlib", "repr"),
+    MovedModule("socketserver", "SocketServer"),
+    MovedModule("_thread", "thread", "_thread"),
+    MovedModule("tkinter", "Tkinter"),
+    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
+    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
+    MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
+    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
+    MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
+    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
+    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
+    MovedModule("tkinter_colorchooser", "tkColorChooser",
+                "tkinter.colorchooser"),
+    MovedModule("tkinter_commondialog", "tkCommonDialog",
+                "tkinter.commondialog"),
+    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
+    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
+    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
+                "tkinter.simpledialog"),
+    MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
+    MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
+    MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
+    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
+    MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
+    MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
+]
+# Add windows specific modules.
+if sys.platform == "win32":
+    _moved_attributes += [
+        MovedModule("winreg", "_winreg"),
+    ]
+
+for attr in _moved_attributes:
+    setattr(_MovedItems, attr.name, attr)
+    if isinstance(attr, MovedModule):
+        _importer._add_module(attr, "moves." + attr.name)
+del attr
+
+_MovedItems._moved_attributes = _moved_attributes
+
+moves = _MovedItems(__name__ + ".moves")
+_importer._add_module(moves, "moves")
+
+
+class Module_six_moves_urllib_parse(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_parse"""
+
+
+_urllib_parse_moved_attributes = [
+    MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
+    MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
+    MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
+    MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
+    MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
+    MovedAttribute("urljoin", "urlparse", "urllib.parse"),
+    MovedAttribute("urlparse", "urlparse", "urllib.parse"),
+    MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
+    MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
+    MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
+    MovedAttribute("quote", "urllib", "urllib.parse"),
+    MovedAttribute("quote_plus", "urllib", "urllib.parse"),
+    MovedAttribute("unquote", "urllib", "urllib.parse"),
+    MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
+    MovedAttribute("urlencode", "urllib", "urllib.parse"),
+    MovedAttribute("splitquery", "urllib", "urllib.parse"),
+    MovedAttribute("splittag", "urllib", "urllib.parse"),
+    MovedAttribute("splituser", "urllib", "urllib.parse"),
+    MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_params", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_query", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
+]
+for attr in _urllib_parse_moved_attributes:
+    setattr(Module_six_moves_urllib_parse, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
+                      "moves.urllib_parse", "moves.urllib.parse")
+
+
+class Module_six_moves_urllib_error(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_error"""
+
+
+_urllib_error_moved_attributes = [
+    MovedAttribute("URLError", "urllib2", "urllib.error"),
+    MovedAttribute("HTTPError", "urllib2", "urllib.error"),
+    MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
+]
+for attr in _urllib_error_moved_attributes:
+    setattr(Module_six_moves_urllib_error, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
+                      "moves.urllib_error", "moves.urllib.error")
+
+
+class Module_six_moves_urllib_request(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_request"""
+
+
+_urllib_request_moved_attributes = [
+    MovedAttribute("urlopen", "urllib2", "urllib.request"),
+    MovedAttribute("install_opener", "urllib2", "urllib.request"),
+    MovedAttribute("build_opener", "urllib2", "urllib.request"),
+    MovedAttribute("pathname2url", "urllib", "urllib.request"),
+    MovedAttribute("url2pathname", "urllib", "urllib.request"),
+    MovedAttribute("getproxies", "urllib", "urllib.request"),
+    MovedAttribute("Request", "urllib2", "urllib.request"),
+    MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
+    MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
+    MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
+    MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
+    MovedAttribute("FileHandler", "urllib2", "urllib.request"),
+    MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
+    MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
+    MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
+    MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
+    MovedAttribute("urlretrieve", "urllib", "urllib.request"),
+    MovedAttribute("urlcleanup", "urllib", "urllib.request"),
+    MovedAttribute("URLopener", "urllib", "urllib.request"),
+    MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
+    MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
+]
+for attr in _urllib_request_moved_attributes:
+    setattr(Module_six_moves_urllib_request, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
+                      "moves.urllib_request", "moves.urllib.request")
+
+
+class Module_six_moves_urllib_response(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_response"""
+
+
+_urllib_response_moved_attributes = [
+    MovedAttribute("addbase", "urllib", "urllib.response"),
+    MovedAttribute("addclosehook", "urllib", "urllib.response"),
+    MovedAttribute("addinfo", "urllib", "urllib.response"),
+    MovedAttribute("addinfourl", "urllib", "urllib.response"),
+]
+for attr in _urllib_response_moved_attributes:
+    setattr(Module_six_moves_urllib_response, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
+                      "moves.urllib_response", "moves.urllib.response")
+
+
+class Module_six_moves_urllib_robotparser(_LazyModule):
+
+    """Lazy loading of moved objects in six.moves.urllib_robotparser"""
+
+
+_urllib_robotparser_moved_attributes = [
+    MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
+]
+for attr in _urllib_robotparser_moved_attributes:
+    setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
+del attr
+
+Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
+
+_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
+                      "moves.urllib_robotparser", "moves.urllib.robotparser")
+
+
+class Module_six_moves_urllib(types.ModuleType):
+
+    """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
+    __path__ = []  # mark as package
+    parse = _importer._get_module("moves.urllib_parse")
+    error = _importer._get_module("moves.urllib_error")
+    request = _importer._get_module("moves.urllib_request")
+    response = _importer._get_module("moves.urllib_response")
+    robotparser = _importer._get_module("moves.urllib_robotparser")
+
+    def __dir__(self):
+        return ['parse', 'error', 'request', 'response', 'robotparser']
+
+_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
+                      "moves.urllib")
+
+
+def add_move(move):
+    """Add an item to six.moves."""
+    setattr(_MovedItems, move.name, move)
+
+
+def remove_move(name):
+    """Remove item from six.moves."""
+    try:
+        delattr(_MovedItems, name)
+    except AttributeError:
+        try:
+            del moves.__dict__[name]
+        except KeyError:
+            raise AttributeError("no such move, %r" % (name,))
+
+
+if PY3:
+    _meth_func = "__func__"
+    _meth_self = "__self__"
+
+    _func_closure = "__closure__"
+    _func_code = "__code__"
+    _func_defaults = "__defaults__"
+    _func_globals = "__globals__"
+else:
+    _meth_func = "im_func"
+    _meth_self = "im_self"
+
+    _func_closure = "func_closure"
+    _func_code = "func_code"
+    _func_defaults = "func_defaults"
+    _func_globals = "func_globals"
+
+
+try:
+    advance_iterator = next
+except NameError:
+    def advance_iterator(it):
+        return it.next()
+next = advance_iterator
+
+
+try:
+    callable = callable
+except NameError:
+    def callable(obj):
+        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
+
+
+if PY3:
+    def get_unbound_function(unbound):
+        return unbound
+
+    create_bound_method = types.MethodType
+
+    def create_unbound_method(func, cls):
+        return func
+
+    Iterator = object
+else:
+    def get_unbound_function(unbound):
+        return unbound.im_func
+
+    def create_bound_method(func, obj):
+        return types.MethodType(func, obj, obj.__class__)
+
+    def create_unbound_method(func, cls):
+        return types.MethodType(func, None, cls)
+
+    class Iterator(object):
+
+        def next(self):
+            return type(self).__next__(self)
+
+    callable = callable
+_add_doc(get_unbound_function,
+         """Get the function out of a possibly unbound function""")
+
+
+get_method_function = operator.attrgetter(_meth_func)
+get_method_self = operator.attrgetter(_meth_self)
+get_function_closure = operator.attrgetter(_func_closure)
+get_function_code = operator.attrgetter(_func_code)
+get_function_defaults = operator.attrgetter(_func_defaults)
+get_function_globals = operator.attrgetter(_func_globals)
+
+
+if PY3:
+    def iterkeys(d, **kw):
+        return iter(d.keys(**kw))
+
+    def itervalues(d, **kw):
+        return iter(d.values(**kw))
+
+    def iteritems(d, **kw):
+        return iter(d.items(**kw))
+
+    def iterlists(d, **kw):
+        return iter(d.lists(**kw))
+
+    viewkeys = operator.methodcaller("keys")
+
+    viewvalues = operator.methodcaller("values")
+
+    viewitems = operator.methodcaller("items")
+else:
+    def iterkeys(d, **kw):
+        return d.iterkeys(**kw)
+
+    def itervalues(d, **kw):
+        return d.itervalues(**kw)
+
+    def iteritems(d, **kw):
+        return d.iteritems(**kw)
+
+    def iterlists(d, **kw):
+        return d.iterlists(**kw)
+
+    viewkeys = operator.methodcaller("viewkeys")
+
+    viewvalues = operator.methodcaller("viewvalues")
+
+    viewitems = operator.methodcaller("viewitems")
+
+_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
+_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
+_add_doc(iteritems,
+         "Return an iterator over the (key, value) pairs of a dictionary.")
+_add_doc(iterlists,
+         "Return an iterator over the (key, [values]) pairs of a dictionary.")
+
+
+if PY3:
+    def b(s):
+        return s.encode("latin-1")
+
+    def u(s):
+        return s
+    unichr = chr
+    import struct
+    int2byte = struct.Struct(">B").pack
+    del struct
+    byte2int = operator.itemgetter(0)
+    indexbytes = operator.getitem
+    iterbytes = iter
+    import io
+    StringIO = io.StringIO
+    BytesIO = io.BytesIO
+    _assertCountEqual = "assertCountEqual"
+    if sys.version_info[1] <= 1:
+        _assertRaisesRegex = "assertRaisesRegexp"
+        _assertRegex = "assertRegexpMatches"
+    else:
+        _assertRaisesRegex = "assertRaisesRegex"
+        _assertRegex = "assertRegex"
+else:
+    def b(s):
+        return s
+    # Workaround for standalone backslash
+
+    def u(s):
+        return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
+    unichr = unichr
+    int2byte = chr
+
+    def byte2int(bs):
+        return ord(bs[0])
+
+    def indexbytes(buf, i):
+        return ord(buf[i])
+    iterbytes = functools.partial(itertools.imap, ord)
+    import StringIO
+    StringIO = BytesIO = StringIO.StringIO
+    _assertCountEqual = "assertItemsEqual"
+    _assertRaisesRegex = "assertRaisesRegexp"
+    _assertRegex = "assertRegexpMatches"
+_add_doc(b, """Byte literal""")
+_add_doc(u, """Text literal""")
+
+
+def assertCountEqual(self, *args, **kwargs):
+    return getattr(self, _assertCountEqual)(*args, **kwargs)
+
+
+def assertRaisesRegex(self, *args, **kwargs):
+    return getattr(self, _assertRaisesRegex)(*args, **kwargs)
+
+
+def assertRegex(self, *args, **kwargs):
+    return getattr(self, _assertRegex)(*args, **kwargs)
+
+
+if PY3:
+    exec_ = getattr(moves.builtins, "exec")
+
+    def reraise(tp, value, tb=None):
+        if value is None:
+            value = tp()
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+
+else:
+    def exec_(_code_, _globs_=None, _locs_=None):
+        """Execute code in a namespace."""
+        if _globs_ is None:
+            frame = sys._getframe(1)
+            _globs_ = frame.f_globals
+            if _locs_ is None:
+                _locs_ = frame.f_locals
+            del frame
+        elif _locs_ is None:
+            _locs_ = _globs_
+        exec("""exec _code_ in _globs_, _locs_""")
+
+    exec_("""def reraise(tp, value, tb=None):
+    raise tp, value, tb
+""")
+
+
+if sys.version_info[:2] == (3, 2):
+    exec_("""def raise_from(value, from_value):
+    if from_value is None:
+        raise value
+    raise value from from_value
+""")
+elif sys.version_info[:2] > (3, 2):
+    exec_("""def raise_from(value, from_value):
+    raise value from from_value
+""")
+else:
+    def raise_from(value, from_value):
+        raise value
+
+
+print_ = getattr(moves.builtins, "print", None)
+if print_ is None:
+    def print_(*args, **kwargs):
+        """The new-style print function for Python 2.4 and 2.5."""
+        fp = kwargs.pop("file", sys.stdout)
+        if fp is None:
+            return
+
+        def write(data):
+            if not isinstance(data, basestring):
+                data = str(data)
+            # If the file has an encoding, encode unicode with it.
+            if (isinstance(fp, file) and
+                    isinstance(data, unicode) and
+                    fp.encoding is not None):
+                errors = getattr(fp, "errors", None)
+                if errors is None:
+                    errors = "strict"
+                data = data.encode(fp.encoding, errors)
+            fp.write(data)
+        want_unicode = False
+        sep = kwargs.pop("sep", None)
+        if sep is not None:
+            if isinstance(sep, unicode):
+                want_unicode = True
+            elif not isinstance(sep, str):
+                raise TypeError("sep must be None or a string")
+        end = kwargs.pop("end", None)
+        if end is not None:
+            if isinstance(end, unicode):
+                want_unicode = True
+            elif not isinstance(end, str):
+                raise TypeError("end must be None or a string")
+        if kwargs:
+            raise TypeError("invalid keyword arguments to print()")
+        if not want_unicode:
+            for arg in args:
+                if isinstance(arg, unicode):
+                    want_unicode = True
+                    break
+        if want_unicode:
+            newline = unicode("\n")
+            space = unicode(" ")
+        else:
+            newline = "\n"
+            space = " "
+        if sep is None:
+            sep = space
+        if end is None:
+            end = newline
+        for i, arg in enumerate(args):
+            if i:
+                write(sep)
+            write(arg)
+        write(end)
+if sys.version_info[:2] < (3, 3):
+    _print = print_
+
+    def print_(*args, **kwargs):
+        fp = kwargs.get("file", sys.stdout)
+        flush = kwargs.pop("flush", False)
+        _print(*args, **kwargs)
+        if flush and fp is not None:
+            fp.flush()
+
+_add_doc(reraise, """Reraise an exception.""")
+
+if sys.version_info[0:2] < (3, 4):
+    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
+              updated=functools.WRAPPER_UPDATES):
+        def wrapper(f):
+            f = functools.wraps(wrapped, assigned, updated)(f)
+            f.__wrapped__ = wrapped
+            return f
+        return wrapper
+else:
+    wraps = functools.wraps
+
+
+def with_metaclass(meta, *bases):
+    """Create a base class with a metaclass."""
+    # This requires a bit of explanation: the basic idea is to make a dummy
+    # metaclass for one level of class instantiation that replaces itself with
+    # the actual metaclass.
+    class metaclass(meta):
+
+        def __new__(cls, name, this_bases, d):
+            return meta(name, bases, d)
+    return type.__new__(metaclass, 'temporary_class', (), {})
+
+
+def add_metaclass(metaclass):
+    """Class decorator for creating a class with a metaclass."""
+    def wrapper(cls):
+        orig_vars = cls.__dict__.copy()
+        slots = orig_vars.get('__slots__')
+        if slots is not None:
+            if isinstance(slots, str):
+                slots = [slots]
+            for slots_var in slots:
+                orig_vars.pop(slots_var)
+        orig_vars.pop('__dict__', None)
+        orig_vars.pop('__weakref__', None)
+        return metaclass(cls.__name__, cls.__bases__, orig_vars)
+    return wrapper
+
+
+def python_2_unicode_compatible(klass):
+    """
+    A decorator that defines __unicode__ and __str__ methods under Python 2.
+    Under Python 3 it does nothing.
+
+    To support Python 2 and 3 with a single code base, define a __str__ method
+    returning text and apply this decorator to the class.
+    """
+    if PY2:
+        if '__str__' not in klass.__dict__:
+            raise ValueError("@python_2_unicode_compatible cannot be applied "
+                             "to %s because it doesn't define __str__()." %
+                             klass.__name__)
+        klass.__unicode__ = klass.__str__
+        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
+    return klass
+
+
+# Complete the moves implementation.
+# This code is at the end of this module to speed up module loading.
+# Turn this module into a package.
+__path__ = []  # required for PEP 302 and PEP 451
+__package__ = __name__  # see PEP 366 @ReservedAssignment
+if globals().get("__spec__") is not None:
+    __spec__.submodule_search_locations = []  # PEP 451 @UndefinedVariable
+# Remove other six meta path importers, since they cause problems. This can
+# happen if six is removed from sys.modules and then reloaded. (Setuptools does
+# this for some reason.)
+if sys.meta_path:
+    for i, importer in enumerate(sys.meta_path):
+        # Here's some real nastiness: Another "instance" of the six module might
+        # be floating around. Therefore, we can't use isinstance() to check for
+        # the six meta path importer, since the other six instance will have
+        # inserted an importer with different class.
+        if (type(importer).__name__ == "_SixMetaPathImporter" and
+                importer.name == __name__):
+            del sys.meta_path[i]
+            break
+    del i, importer
+# Finally, add the importer to the meta path import hook.
+sys.meta_path.append(_importer)
diff -Nru python-setuptools-3.3/pkg_resources/_vendor/vendored.txt python-setuptools-20.1.1/pkg_resources/_vendor/vendored.txt
--- python-setuptools-3.3/pkg_resources/_vendor/vendored.txt	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/pkg_resources/_vendor/vendored.txt	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,2 @@
+packaging==15.3
+six==1.10.0
diff -Nru python-setuptools-3.3/pkg_resources.py python-setuptools-20.1.1/pkg_resources.py
--- python-setuptools-3.3/pkg_resources.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/pkg_resources.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,2762 +0,0 @@
-"""
-Package resource API
---------------------
-
-A resource is a logical file contained within a package, or a logical
-subdirectory thereof.  The package resource API expects resource names
-to have their path parts separated with ``/``, *not* whatever the local
-path separator is.  Do not use os.path operations to manipulate resource
-names being passed into the API.
-
-The package resource API is designed to work with normal filesystem packages,
-.egg files, and unpacked .egg files.  It can also work in a limited way with
-.zip files and with custom PEP 302 loaders that support the ``get_data()``
-method.
-"""
-
-import sys
-import os
-import time
-import re
-import imp
-import zipfile
-import zipimport
-import warnings
-import stat
-import functools
-import pkgutil
-import token
-import symbol
-import operator
-import platform
-from pkgutil import get_importer
-
-try:
-    from urlparse import urlparse, urlunparse
-except ImportError:
-    from urllib.parse import urlparse, urlunparse
-
-try:
-    frozenset
-except NameError:
-    from sets import ImmutableSet as frozenset
-try:
-    basestring
-    next = lambda o: o.next()
-    from cStringIO import StringIO as BytesIO
-except NameError:
-    basestring = str
-    from io import BytesIO
-    def execfile(fn, globs=None, locs=None):
-        if globs is None:
-            globs = globals()
-        if locs is None:
-            locs = globs
-        exec(compile(open(fn).read(), fn, 'exec'), globs, locs)
-
-# capture these to bypass sandboxing
-from os import utime
-try:
-    from os import mkdir, rename, unlink
-    WRITE_SUPPORT = True
-except ImportError:
-    # no write support, probably under GAE
-    WRITE_SUPPORT = False
-
-from os import open as os_open
-from os.path import isdir, split
-
-# Avoid try/except due to potential problems with delayed import mechanisms.
-if sys.version_info >= (3, 3) and sys.implementation.name == "cpython":
-    import importlib._bootstrap as importlib_bootstrap
-else:
-    importlib_bootstrap = None
-
-try:
-    import parser
-except ImportError:
-    pass
-
-def _bypass_ensure_directory(name, mode=0x1FF):  # 0777
-    # Sandbox-bypassing version of ensure_directory()
-    if not WRITE_SUPPORT:
-        raise IOError('"os.mkdir" not supported on this platform.')
-    dirname, filename = split(name)
-    if dirname and filename and not isdir(dirname):
-        _bypass_ensure_directory(dirname)
-        mkdir(dirname, mode)
-
-
-_state_vars = {}
-
-def _declare_state(vartype, **kw):
-    globals().update(kw)
-    _state_vars.update(dict.fromkeys(kw, vartype))
-
-def __getstate__():
-    state = {}
-    g = globals()
-    for k, v in _state_vars.items():
-        state[k] = g['_sget_'+v](g[k])
-    return state
-
-def __setstate__(state):
-    g = globals()
-    for k, v in state.items():
-        g['_sset_'+_state_vars[k]](k, g[k], v)
-    return state
-
-def _sget_dict(val):
-    return val.copy()
-
-def _sset_dict(key, ob, state):
-    ob.clear()
-    ob.update(state)
-
-def _sget_object(val):
-    return val.__getstate__()
-
-def _sset_object(key, ob, state):
-    ob.__setstate__(state)
-
-_sget_none = _sset_none = lambda *args: None
-
-
-def get_supported_platform():
-    """Return this platform's maximum compatible version.
-
-    distutils.util.get_platform() normally reports the minimum version
-    of Mac OS X that would be required to *use* extensions produced by
-    distutils.  But what we want when checking compatibility is to know the
-    version of Mac OS X that we are *running*.  To allow usage of packages that
-    explicitly require a newer version of Mac OS X, we must also know the
-    current version of the OS.
-
-    If this condition occurs for any other platform with a version in its
-    platform strings, this function should be extended accordingly.
-    """
-    plat = get_build_platform()
-    m = macosVersionString.match(plat)
-    if m is not None and sys.platform == "darwin":
-        try:
-            plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3))
-        except ValueError:
-            pass    # not Mac OS X
-    return plat
-
-__all__ = [
-    # Basic resource access and distribution/entry point discovery
-    'require', 'run_script', 'get_provider',  'get_distribution',
-    'load_entry_point', 'get_entry_map', 'get_entry_info', 'iter_entry_points',
-    'resource_string', 'resource_stream', 'resource_filename',
-    'resource_listdir', 'resource_exists', 'resource_isdir',
-
-    # Environmental control
-    'declare_namespace', 'working_set', 'add_activation_listener',
-    'find_distributions', 'set_extraction_path', 'cleanup_resources',
-    'get_default_cache',
-
-    # Primary implementation classes
-    'Environment', 'WorkingSet', 'ResourceManager',
-    'Distribution', 'Requirement', 'EntryPoint',
-
-    # Exceptions
-    'ResolutionError','VersionConflict','DistributionNotFound','UnknownExtra',
-    'ExtractionError',
-
-    # Parsing functions and string utilities
-    'parse_requirements', 'parse_version', 'safe_name', 'safe_version',
-    'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections',
-    'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker',
-
-    # filesystem utilities
-    'ensure_directory', 'normalize_path',
-
-    # Distribution "precedence" constants
-    'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST',
-
-    # "Provider" interfaces, implementations, and registration/lookup APIs
-    'IMetadataProvider', 'IResourceProvider', 'FileMetadata',
-    'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider',
-    'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider',
-    'register_finder', 'register_namespace_handler', 'register_loader_type',
-    'fixup_namespace_packages', 'get_importer',
-
-    # Deprecated/backward compatibility only
-    'run_main', 'AvailableDistributions',
-]
-
-class ResolutionError(Exception):
-    """Abstract base for dependency resolution errors"""
-    def __repr__(self):
-        return self.__class__.__name__+repr(self.args)
-
-class VersionConflict(ResolutionError):
-    """An already-installed version conflicts with the requested version"""
-
-class DistributionNotFound(ResolutionError):
-    """A requested distribution was not found"""
-
-class UnknownExtra(ResolutionError):
-    """Distribution doesn't have an "extra feature" of the given name"""
-_provider_factories = {}
-
-PY_MAJOR = sys.version[:3]
-EGG_DIST = 3
-BINARY_DIST = 2
-SOURCE_DIST = 1
-CHECKOUT_DIST = 0
-DEVELOP_DIST = -1
-
-def register_loader_type(loader_type, provider_factory):
-    """Register `provider_factory` to make providers for `loader_type`
-
-    `loader_type` is the type or class of a PEP 302 ``module.__loader__``,
-    and `provider_factory` is a function that, passed a *module* object,
-    returns an ``IResourceProvider`` for that module.
-    """
-    _provider_factories[loader_type] = provider_factory
-
-def get_provider(moduleOrReq):
-    """Return an IResourceProvider for the named module or requirement"""
-    if isinstance(moduleOrReq,Requirement):
-        return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
-    try:
-        module = sys.modules[moduleOrReq]
-    except KeyError:
-        __import__(moduleOrReq)
-        module = sys.modules[moduleOrReq]
-    loader = getattr(module, '__loader__', None)
-    return _find_adapter(_provider_factories, loader)(module)
-
-def _macosx_vers(_cache=[]):
-    if not _cache:
-        import platform
-        version = platform.mac_ver()[0]
-        # fallback for MacPorts
-        if version == '':
-            import plistlib
-            plist = '/System/Library/CoreServices/SystemVersion.plist'
-            if os.path.exists(plist):
-                if hasattr(plistlib, 'readPlist'):
-                    plist_content = plistlib.readPlist(plist)
-                    if 'ProductVersion' in plist_content:
-                        version = plist_content['ProductVersion']
-
-        _cache.append(version.split('.'))
-    return _cache[0]
-
-def _macosx_arch(machine):
-    return {'PowerPC':'ppc', 'Power_Macintosh':'ppc'}.get(machine,machine)
-
-def get_build_platform():
-    """Return this platform's string for platform-specific distributions
-
-    XXX Currently this is the same as ``distutils.util.get_platform()``, but it
-    needs some hacks for Linux and Mac OS X.
-    """
-    try:
-        # Python 2.7 or >=3.2
-        from sysconfig import get_platform
-    except ImportError:
-        from distutils.util import get_platform
-
-    plat = get_platform()
-    if sys.platform == "darwin" and not plat.startswith('macosx-'):
-        try:
-            version = _macosx_vers()
-            machine = os.uname()[4].replace(" ", "_")
-            return "macosx-%d.%d-%s" % (int(version[0]), int(version[1]),
-                _macosx_arch(machine))
-        except ValueError:
-            # if someone is running a non-Mac darwin system, this will fall
-            # through to the default implementation
-            pass
-    return plat
-
-macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
-darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
-get_platform = get_build_platform   # XXX backward compat
-
-
-def compatible_platforms(provided,required):
-    """Can code for the `provided` platform run on the `required` platform?
-
-    Returns true if either platform is ``None``, or the platforms are equal.
-
-    XXX Needs compatibility checks for Linux and other unixy OSes.
-    """
-    if provided is None or required is None or provided==required:
-        return True     # easy case
-
-    # Mac OS X special cases
-    reqMac = macosVersionString.match(required)
-    if reqMac:
-        provMac = macosVersionString.match(provided)
-
-        # is this a Mac package?
-        if not provMac:
-            # this is backwards compatibility for packages built before
-            # setuptools 0.6. All packages built after this point will
-            # use the new macosx designation.
-            provDarwin = darwinVersionString.match(provided)
-            if provDarwin:
-                dversion = int(provDarwin.group(1))
-                macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
-                if dversion == 7 and macosversion >= "10.3" or \
-                        dversion == 8 and macosversion >= "10.4":
-
-                    #import warnings
-                    #warnings.warn("Mac eggs should be rebuilt to "
-                    #    "use the macosx designation instead of darwin.",
-                    #    category=DeprecationWarning)
-                    return True
-            return False    # egg isn't macosx or legacy darwin
-
-        # are they the same major version and machine type?
-        if provMac.group(1) != reqMac.group(1) or \
-                provMac.group(3) != reqMac.group(3):
-            return False
-
-        # is the required OS major update >= the provided one?
-        if int(provMac.group(2)) > int(reqMac.group(2)):
-            return False
-
-        return True
-
-    # XXX Linux and other platforms' special cases should go here
-    return False
-
-
-def run_script(dist_spec, script_name):
-    """Locate distribution `dist_spec` and run its `script_name` script"""
-    ns = sys._getframe(1).f_globals
-    name = ns['__name__']
-    ns.clear()
-    ns['__name__'] = name
-    require(dist_spec)[0].run_script(script_name, ns)
-
-run_main = run_script   # backward compatibility
-
-def get_distribution(dist):
-    """Return a current distribution object for a Requirement or string"""
-    if isinstance(dist,basestring): dist = Requirement.parse(dist)
-    if isinstance(dist,Requirement): dist = get_provider(dist)
-    if not isinstance(dist,Distribution):
-        raise TypeError("Expected string, Requirement, or Distribution", dist)
-    return dist
-
-def load_entry_point(dist, group, name):
-    """Return `name` entry point of `group` for `dist` or raise ImportError"""
-    return get_distribution(dist).load_entry_point(group, name)
-
-def get_entry_map(dist, group=None):
-    """Return the entry point map for `group`, or the full entry map"""
-    return get_distribution(dist).get_entry_map(group)
-
-def get_entry_info(dist, group, name):
-    """Return the EntryPoint object for `group`+`name`, or ``None``"""
-    return get_distribution(dist).get_entry_info(group, name)
-
-
-class IMetadataProvider:
-
-    def has_metadata(name):
-        """Does the package's distribution contain the named metadata?"""
-
-    def get_metadata(name):
-        """The named metadata resource as a string"""
-
-    def get_metadata_lines(name):
-        """Yield named metadata resource as list of non-blank non-comment lines
-
-       Leading and trailing whitespace is stripped from each line, and lines
-       with ``#`` as the first non-blank character are omitted."""
-
-    def metadata_isdir(name):
-        """Is the named metadata a directory?  (like ``os.path.isdir()``)"""
-
-    def metadata_listdir(name):
-        """List of metadata names in the directory (like ``os.listdir()``)"""
-
-    def run_script(script_name, namespace):
-        """Execute the named script in the supplied namespace dictionary"""
-
-
-class IResourceProvider(IMetadataProvider):
-    """An object that provides access to package resources"""
-
-    def get_resource_filename(manager, resource_name):
-        """Return a true filesystem path for `resource_name`
-
-        `manager` must be an ``IResourceManager``"""
-
-    def get_resource_stream(manager, resource_name):
-        """Return a readable file-like object for `resource_name`
-
-        `manager` must be an ``IResourceManager``"""
-
-    def get_resource_string(manager, resource_name):
-        """Return a string containing the contents of `resource_name`
-
-        `manager` must be an ``IResourceManager``"""
-
-    def has_resource(resource_name):
-        """Does the package contain the named resource?"""
-
-    def resource_isdir(resource_name):
-        """Is the named resource a directory?  (like ``os.path.isdir()``)"""
-
-    def resource_listdir(resource_name):
-        """List of resource names in the directory (like ``os.listdir()``)"""
-
-
-class WorkingSet(object):
-    """A collection of active distributions on sys.path (or a similar list)"""
-
-    def __init__(self, entries=None):
-        """Create working set from list of path entries (default=sys.path)"""
-        self.entries = []
-        self.entry_keys = {}
-        self.by_key = {}
-        self.callbacks = []
-
-        if entries is None:
-            entries = sys.path
-
-        for entry in entries:
-            self.add_entry(entry)
-
-    @classmethod
-    def _build_master(cls):
-        """
-        Prepare the master working set.
-        """
-        ws = cls()
-        try:
-            from __main__ import __requires__
-        except ImportError:
-            # The main program does not list any requirements
-            return ws
-
-        # ensure the requirements are met
-        try:
-            ws.require(__requires__)
-        except VersionConflict:
-            return cls._build_from_requirements(__requires__)
-
-        return ws
-
-    @classmethod
-    def _build_from_requirements(cls, req_spec):
-        """
-        Build a working set from a requirement spec. Rewrites sys.path.
-        """
-        # try it without defaults already on sys.path
-        # by starting with an empty path
-        ws = cls([])
-        reqs = parse_requirements(req_spec)
-        dists = ws.resolve(reqs, Environment())
-        for dist in dists:
-            ws.add(dist)
-
-        # add any missing entries from sys.path
-        for entry in sys.path:
-            if entry not in ws.entries:
-                ws.add_entry(entry)
-
-        # then copy back to sys.path
-        sys.path[:] = ws.entries
-        return ws
-
-    def add_entry(self, entry):
-        """Add a path item to ``.entries``, finding any distributions on it
-
-        ``find_distributions(entry, True)`` is used to find distributions
-        corresponding to the path entry, and they are added.  `entry` is
-        always appended to ``.entries``, even if it is already present.
-        (This is because ``sys.path`` can contain the same value more than
-        once, and the ``.entries`` of the ``sys.path`` WorkingSet should always
-        equal ``sys.path``.)
-        """
-        self.entry_keys.setdefault(entry, [])
-        self.entries.append(entry)
-        for dist in find_distributions(entry, True):
-            self.add(dist, entry, False)
-
-    def __contains__(self,dist):
-        """True if `dist` is the active distribution for its project"""
-        return self.by_key.get(dist.key) == dist
-
-    def find(self, req):
-        """Find a distribution matching requirement `req`
-
-        If there is an active distribution for the requested project, this
-        returns it as long as it meets the version requirement specified by
-        `req`.  But, if there is an active distribution for the project and it
-        does *not* meet the `req` requirement, ``VersionConflict`` is raised.
-        If there is no active distribution for the requested project, ``None``
-        is returned.
-        """
-        dist = self.by_key.get(req.key)
-        if dist is not None and dist not in req:
-            raise VersionConflict(dist,req)     # XXX add more info
-        else:
-            return dist
-
-    def iter_entry_points(self, group, name=None):
-        """Yield entry point objects from `group` matching `name`
-
-        If `name` is None, yields all entry points in `group` from all
-        distributions in the working set, otherwise only ones matching
-        both `group` and `name` are yielded (in distribution order).
-        """
-        for dist in self:
-            entries = dist.get_entry_map(group)
-            if name is None:
-                for ep in entries.values():
-                    yield ep
-            elif name in entries:
-                yield entries[name]
-
-    def run_script(self, requires, script_name):
-        """Locate distribution for `requires` and run `script_name` script"""
-        ns = sys._getframe(1).f_globals
-        name = ns['__name__']
-        ns.clear()
-        ns['__name__'] = name
-        self.require(requires)[0].run_script(script_name, ns)
-
-    def __iter__(self):
-        """Yield distributions for non-duplicate projects in the working set
-
-        The yield order is the order in which the items' path entries were
-        added to the working set.
-        """
-        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
-                    yield self.by_key[key]
-
-    def add(self, dist, entry=None, insert=True, replace=False):
-        """Add `dist` to working set, associated with `entry`
-
-        If `entry` is unspecified, it defaults to the ``.location`` of `dist`.
-        On exit from this routine, `entry` is added to the end of the working
-        set's ``.entries`` (if it wasn't already present).
-
-        `dist` is only added to the working set if it's for a project that
-        doesn't already have a distribution in the set, unless `replace=True`.
-        If it's added, any callbacks registered with the ``subscribe()`` method
-        will be called.
-        """
-        if insert:
-            dist.insert_on(self.entries, entry)
-
-        if entry is None:
-            entry = dist.location
-        keys = self.entry_keys.setdefault(entry,[])
-        keys2 = self.entry_keys.setdefault(dist.location,[])
-        if not replace and dist.key in self.by_key:
-            return      # ignore hidden distros
-
-        self.by_key[dist.key] = dist
-        if dist.key not in keys:
-            keys.append(dist.key)
-        if dist.key not in keys2:
-            keys2.append(dist.key)
-        self._added_new(dist)
-
-    def resolve(self, requirements, env=None, installer=None,
-            replace_conflicting=False):
-        """List all distributions needed to (recursively) meet `requirements`
-
-        `requirements` must be a sequence of ``Requirement`` objects.  `env`,
-        if supplied, should be an ``Environment`` instance.  If
-        not supplied, it defaults to all distributions available within any
-        entry or distribution in the working set.  `installer`, if supplied,
-        will be invoked with each requirement that cannot be met by an
-        already-installed distribution; it should return a ``Distribution`` or
-        ``None``.
-
-        Unless `replace_conflicting=True`, raises a VersionConflict exception if
-        any requirements are found on the path that have the correct name but
-        the wrong version.  Otherwise, if an `installer` is supplied it will be
-        invoked to obtain the correct version of the requirement and activate
-        it.
-        """
-
-        requirements = list(requirements)[::-1]  # set up the stack
-        processed = {}  # set of processed requirements
-        best = {}  # key -> dist
-        to_activate = []
-
-        while requirements:
-            req = requirements.pop(0)   # process dependencies breadth-first
-            if req in processed:
-                # Ignore cyclic or redundant dependencies
-                continue
-            dist = best.get(req.key)
-            if dist is None:
-                # Find the best distribution and add it to the map
-                dist = self.by_key.get(req.key)
-                if dist is None or (dist not in req and replace_conflicting):
-                    ws = self
-                    if env is None:
-                        if dist is None:
-                            env = Environment(self.entries)
-                        else:
-                            # Use an empty environment and workingset to avoid
-                            # any further conflicts with the conflicting
-                            # distribution
-                            env = Environment([])
-                            ws = WorkingSet([])
-                    dist = best[req.key] = env.best_match(req, ws, installer)
-                    if dist is None:
-                        #msg = ("The '%s' distribution was not found on this "
-                        #       "system, and is required by this application.")
-                        #raise DistributionNotFound(msg % req)
-
-                        # unfortunately, zc.buildout uses a str(err)
-                        # to get the name of the distribution here..
-                        raise DistributionNotFound(req)
-                to_activate.append(dist)
-            if dist not in req:
-                # Oops, the "best" so far conflicts with a dependency
-                raise VersionConflict(dist,req) # XXX put more info here
-            requirements.extend(dist.requires(req.extras)[::-1])
-            processed[req] = True
-
-        return to_activate    # return list of distros to activate
-
-    def find_plugins(self, plugin_env, full_env=None, installer=None,
-            fallback=True):
-        """Find all activatable distributions in `plugin_env`
-
-        Example usage::
-
-            distributions, errors = working_set.find_plugins(
-                Environment(plugin_dirlist)
-            )
-            map(working_set.add, distributions)  # add plugins+libs to sys.path
-            print 'Could not load', errors        # display errors
-
-        The `plugin_env` should be an ``Environment`` instance that contains
-        only distributions that are in the project's "plugin directory" or
-        directories. The `full_env`, if supplied, should be an ``Environment``
-        contains all currently-available distributions.  If `full_env` is not
-        supplied, one is created automatically from the ``WorkingSet`` this
-        method is called on, which will typically mean that every directory on
-        ``sys.path`` will be scanned for distributions.
-
-        `installer` is a standard installer callback as used by the
-        ``resolve()`` method. The `fallback` flag indicates whether we should
-        attempt to resolve older versions of a plugin if the newest version
-        cannot be resolved.
-
-        This method returns a 2-tuple: (`distributions`, `error_info`), where
-        `distributions` is a list of the distributions found in `plugin_env`
-        that were loadable, along with any other distributions that are needed
-        to resolve their dependencies.  `error_info` is a dictionary mapping
-        unloadable plugin distributions to an exception instance describing the
-        error that occurred. Usually this will be a ``DistributionNotFound`` or
-        ``VersionConflict`` instance.
-        """
-
-        plugin_projects = list(plugin_env)
-        plugin_projects.sort()  # scan project names in alphabetic order
-
-        error_info = {}
-        distributions = {}
-
-        if full_env is None:
-            env = Environment(self.entries)
-            env += plugin_env
-        else:
-            env = full_env + plugin_env
-
-        shadow_set = self.__class__([])
-        list(map(shadow_set.add, self))   # put all our entries in shadow_set
-
-        for project_name in plugin_projects:
-
-            for dist in plugin_env[project_name]:
-
-                req = [dist.as_requirement()]
-
-                try:
-                    resolvees = shadow_set.resolve(req, env, installer)
-
-                except ResolutionError:
-                    v = sys.exc_info()[1]
-                    error_info[dist] = v    # save error info
-                    if fallback:
-                        continue    # try the next older version of project
-                    else:
-                        break       # give up on this project, keep going
-
-                else:
-                    list(map(shadow_set.add, resolvees))
-                    distributions.update(dict.fromkeys(resolvees))
-
-                    # success, no need to try any more versions of this project
-                    break
-
-        distributions = list(distributions)
-        distributions.sort()
-
-        return distributions, error_info
-
-    def require(self, *requirements):
-        """Ensure that distributions matching `requirements` are activated
-
-        `requirements` must be a string or a (possibly-nested) sequence
-        thereof, specifying the distributions and versions required.  The
-        return value is a sequence of the distributions that needed to be
-        activated to fulfill the requirements; all relevant distributions are
-        included, even if they were already activated in this working set.
-        """
-        needed = self.resolve(parse_requirements(requirements))
-
-        for dist in needed:
-            self.add(dist)
-
-        return needed
-
-    def subscribe(self, callback):
-        """Invoke `callback` for all distributions (including existing ones)"""
-        if callback in self.callbacks:
-            return
-        self.callbacks.append(callback)
-        for dist in self:
-            callback(dist)
-
-    def _added_new(self, dist):
-        for callback in self.callbacks:
-            callback(dist)
-
-    def __getstate__(self):
-        return (
-            self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
-            self.callbacks[:]
-        )
-
-    def __setstate__(self, e_k_b_c):
-        entries, keys, by_key, callbacks = e_k_b_c
-        self.entries = entries[:]
-        self.entry_keys = keys.copy()
-        self.by_key = by_key.copy()
-        self.callbacks = callbacks[:]
-
-
-class Environment(object):
-    """Searchable snapshot of distributions on a search path"""
-
-    def __init__(self, search_path=None, platform=get_supported_platform(), python=PY_MAJOR):
-        """Snapshot distributions available on a search path
-
-        Any distributions found on `search_path` are added to the environment.
-        `search_path` should be a sequence of ``sys.path`` items.  If not
-        supplied, ``sys.path`` is used.
-
-        `platform` is an optional string specifying the name of the platform
-        that platform-specific distributions must be compatible with.  If
-        unspecified, it defaults to the current platform.  `python` is an
-        optional string naming the desired version of Python (e.g. ``'3.3'``);
-        it defaults to the current version.
-
-        You may explicitly set `platform` (and/or `python`) to ``None`` if you
-        wish to map *all* distributions, not just those compatible with the
-        running platform or Python version.
-        """
-        self._distmap = {}
-        self._cache = {}
-        self.platform = platform
-        self.python = python
-        self.scan(search_path)
-
-    def can_add(self, dist):
-        """Is distribution `dist` acceptable for this environment?
-
-        The distribution must match the platform and python version
-        requirements specified when this environment was created, or False
-        is returned.
-        """
-        return (self.python is None or dist.py_version is None
-            or dist.py_version==self.python) \
-            and compatible_platforms(dist.platform,self.platform)
-
-    def remove(self, dist):
-        """Remove `dist` from the environment"""
-        self._distmap[dist.key].remove(dist)
-
-    def scan(self, search_path=None):
-        """Scan `search_path` for distributions usable in this environment
-
-        Any distributions found are added to the environment.
-        `search_path` should be a sequence of ``sys.path`` items.  If not
-        supplied, ``sys.path`` is used.  Only distributions conforming to
-        the platform/python version defined at initialization are added.
-        """
-        if search_path is None:
-            search_path = sys.path
-
-        for item in search_path:
-            for dist in find_distributions(item):
-                self.add(dist)
-
-    def __getitem__(self,project_name):
-        """Return a newest-to-oldest list of distributions for `project_name`
-        """
-        try:
-            return self._cache[project_name]
-        except KeyError:
-            project_name = project_name.lower()
-            if project_name not in self._distmap:
-                return []
-
-        if project_name not in self._cache:
-            dists = self._cache[project_name] = self._distmap[project_name]
-            _sort_dists(dists)
-
-        return self._cache[project_name]
-
-    def add(self,dist):
-        """Add `dist` if we ``can_add()`` it and it isn't already added"""
-        if self.can_add(dist) and dist.has_version():
-            dists = self._distmap.setdefault(dist.key,[])
-            if dist not in dists:
-                dists.append(dist)
-                if dist.key in self._cache:
-                    _sort_dists(self._cache[dist.key])
-
-    def best_match(self, req, working_set, installer=None):
-        """Find distribution best matching `req` and usable on `working_set`
-
-        This calls the ``find(req)`` method of the `working_set` to see if a
-        suitable distribution is already active.  (This may raise
-        ``VersionConflict`` if an unsuitable version of the project is already
-        active in the specified `working_set`.)  If a suitable distribution
-        isn't active, this method returns the newest distribution in the
-        environment that meets the ``Requirement`` in `req`.  If no suitable
-        distribution is found, and `installer` is supplied, then the result of
-        calling the environment's ``obtain(req, installer)`` method will be
-        returned.
-        """
-        dist = working_set.find(req)
-        if dist is not None:
-            return dist
-        for dist in self[req.key]:
-            if dist in req:
-                return dist
-        return self.obtain(req, installer) # try and download/install
-
-    def obtain(self, requirement, installer=None):
-        """Obtain a distribution matching `requirement` (e.g. via download)
-
-        Obtain a distro that matches requirement (e.g. via download).  In the
-        base ``Environment`` class, this routine just returns
-        ``installer(requirement)``, unless `installer` is None, in which case
-        None is returned instead.  This method is a hook that allows subclasses
-        to attempt other ways of obtaining a distribution before falling back
-        to the `installer` argument."""
-        if installer is not None:
-            return installer(requirement)
-
-    def __iter__(self):
-        """Yield the unique project names of the available distributions"""
-        for key in self._distmap.keys():
-            if self[key]: yield key
-
-    def __iadd__(self, other):
-        """In-place addition of a distribution or environment"""
-        if isinstance(other,Distribution):
-            self.add(other)
-        elif isinstance(other,Environment):
-            for project in other:
-                for dist in other[project]:
-                    self.add(dist)
-        else:
-            raise TypeError("Can't add %r to environment" % (other,))
-        return self
-
-    def __add__(self, other):
-        """Add an environment or distribution to an environment"""
-        new = self.__class__([], platform=None, python=None)
-        for env in self, other:
-            new += env
-        return new
-
-
-AvailableDistributions = Environment    # XXX backward compatibility
-
-
-class ExtractionError(RuntimeError):
-    """An error occurred extracting a resource
-
-    The following attributes are available from instances of this exception:
-
-    manager
-        The resource manager that raised this exception
-
-    cache_path
-        The base directory for resource extraction
-
-    original_error
-        The exception instance that caused extraction to fail
-    """
-
-
-class ResourceManager:
-    """Manage resource extraction and packages"""
-    extraction_path = None
-
-    def __init__(self):
-        self.cached_files = {}
-
-    def resource_exists(self, package_or_requirement, resource_name):
-        """Does the named resource exist?"""
-        return get_provider(package_or_requirement).has_resource(resource_name)
-
-    def resource_isdir(self, package_or_requirement, resource_name):
-        """Is the named resource an existing directory?"""
-        return get_provider(package_or_requirement).resource_isdir(
-            resource_name
-        )
-
-    def resource_filename(self, package_or_requirement, resource_name):
-        """Return a true filesystem path for specified resource"""
-        return get_provider(package_or_requirement).get_resource_filename(
-            self, resource_name
-        )
-
-    def resource_stream(self, package_or_requirement, resource_name):
-        """Return a readable file-like object for specified resource"""
-        return get_provider(package_or_requirement).get_resource_stream(
-            self, resource_name
-        )
-
-    def resource_string(self, package_or_requirement, resource_name):
-        """Return specified resource as a string"""
-        return get_provider(package_or_requirement).get_resource_string(
-            self, resource_name
-        )
-
-    def resource_listdir(self, package_or_requirement, resource_name):
-        """List the contents of the named resource directory"""
-        return get_provider(package_or_requirement).resource_listdir(
-            resource_name
-        )
-
-    def extraction_error(self):
-        """Give an error message for problems extracting file(s)"""
-
-        old_exc = sys.exc_info()[1]
-        cache_path = self.extraction_path or get_default_cache()
-
-        err = ExtractionError("""Can't extract file(s) to egg cache
-
-The following error occurred while trying to extract file(s) to the Python egg
-cache:
-
-  %s
-
-The Python egg cache directory is currently set to:
-
-  %s
-
-Perhaps your account does not have write access to this directory?  You can
-change the cache directory by setting the PYTHON_EGG_CACHE environment
-variable to point to an accessible directory.
-""" % (old_exc, cache_path)
-        )
-        err.manager = self
-        err.cache_path = cache_path
-        err.original_error = old_exc
-        raise err
-
-    def get_cache_path(self, archive_name, names=()):
-        """Return absolute location in cache for `archive_name` and `names`
-
-        The parent directory of the resulting path will be created if it does
-        not already exist.  `archive_name` should be the base filename of the
-        enclosing egg (which may not be the name of the enclosing zipfile!),
-        including its ".egg" extension.  `names`, if provided, should be a
-        sequence of path name parts "under" the egg's extraction location.
-
-        This method should only be called by resource providers that need to
-        obtain an extraction location, and only for names they intend to
-        extract, as it tracks the generated names for possible cleanup later.
-        """
-        extract_path = self.extraction_path or get_default_cache()
-        target_path = os.path.join(extract_path, archive_name+'-tmp', *names)
-        try:
-            _bypass_ensure_directory(target_path)
-        except:
-            self.extraction_error()
-
-        self._warn_unsafe_extraction_path(extract_path)
-
-        self.cached_files[target_path] = 1
-        return target_path
-
-    @staticmethod
-    def _warn_unsafe_extraction_path(path):
-        """
-        If the default extraction path is overridden and set to an insecure
-        location, such as /tmp, it opens up an opportunity for an attacker to
-        replace an extracted file with an unauthorized payload. Warn the user
-        if a known insecure location is used.
-
-        See Distribute #375 for more details.
-        """
-        if os.name == 'nt' and not path.startswith(os.environ['windir']):
-            # On Windows, permissions are generally restrictive by default
-            #  and temp directories are not writable by other users, so
-            #  bypass the warning.
-            return
-        mode = os.stat(path).st_mode
-        if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
-            msg = ("%s is writable by group/others and vulnerable to attack "
-                "when "
-                "used with get_resource_filename. Consider a more secure "
-                "location (set with .set_extraction_path or the "
-                "PYTHON_EGG_CACHE environment variable)." % path)
-            warnings.warn(msg, UserWarning)
-
-    def postprocess(self, tempname, filename):
-        """Perform any platform-specific postprocessing of `tempname`
-
-        This is where Mac header rewrites should be done; other platforms don't
-        have anything special they should do.
-
-        Resource providers should call this method ONLY after successfully
-        extracting a compressed resource.  They must NOT call it on resources
-        that are already in the filesystem.
-
-        `tempname` is the current (temporary) name of the file, and `filename`
-        is the name it will be renamed to by the caller after this routine
-        returns.
-        """
-
-        if os.name == 'posix':
-            # Make the resource executable
-            mode = ((os.stat(tempname).st_mode) | 0x16D) & 0xFFF # 0555, 07777
-            os.chmod(tempname, mode)
-
-    def set_extraction_path(self, path):
-        """Set the base path where resources will be extracted to, if needed.
-
-        If you do not call this routine before any extractions take place, the
-        path defaults to the return value of ``get_default_cache()``.  (Which
-        is based on the ``PYTHON_EGG_CACHE`` environment variable, with various
-        platform-specific fallbacks.  See that routine's documentation for more
-        details.)
-
-        Resources are extracted to subdirectories of this path based upon
-        information given by the ``IResourceProvider``.  You may set this to a
-        temporary directory, but then you must call ``cleanup_resources()`` to
-        delete the extracted files when done.  There is no guarantee that
-        ``cleanup_resources()`` will be able to remove all extracted files.
-
-        (Note: you may not change the extraction path for a given resource
-        manager once resources have been extracted, unless you first call
-        ``cleanup_resources()``.)
-        """
-        if self.cached_files:
-            raise ValueError(
-                "Can't change extraction path, files already extracted"
-            )
-
-        self.extraction_path = path
-
-    def cleanup_resources(self, force=False):
-        """
-        Delete all extracted resource files and directories, returning a list
-        of the file and directory names that could not be successfully removed.
-        This function does not have any concurrency protection, so it should
-        generally only be called when the extraction path is a temporary
-        directory exclusive to a single process.  This method is not
-        automatically called; you must call it explicitly or register it as an
-        ``atexit`` function if you wish to ensure cleanup of a temporary
-        directory used for extractions.
-        """
-        # XXX
-
-def get_default_cache():
-    """Determine the default cache location
-
-    This returns the ``PYTHON_EGG_CACHE`` environment variable, if set.
-    Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of the
-    "Application Data" directory.  On all other systems, it's "~/.python-eggs".
-    """
-    try:
-        return os.environ['PYTHON_EGG_CACHE']
-    except KeyError:
-        pass
-
-    if os.name!='nt':
-        return os.path.expanduser('~/.python-eggs')
-
-    app_data = 'Application Data'   # XXX this may be locale-specific!
-    app_homes = [
-        (('APPDATA',), None),       # best option, should be locale-safe
-        (('USERPROFILE',), app_data),
-        (('HOMEDRIVE','HOMEPATH'), app_data),
-        (('HOMEPATH',), app_data),
-        (('HOME',), None),
-        (('WINDIR',), app_data),    # 95/98/ME
-    ]
-
-    for keys, subdir in app_homes:
-        dirname = ''
-        for key in keys:
-            if key in os.environ:
-                dirname = os.path.join(dirname, os.environ[key])
-            else:
-                break
-        else:
-            if subdir:
-                dirname = os.path.join(dirname,subdir)
-            return os.path.join(dirname, 'Python-Eggs')
-    else:
-        raise RuntimeError(
-            "Please set the PYTHON_EGG_CACHE enviroment variable"
-        )
-
-def safe_name(name):
-    """Convert an arbitrary string to a standard distribution name
-
-    Any runs of non-alphanumeric/. characters are replaced with a single '-'.
-    """
-    return re.sub('[^A-Za-z0-9.]+', '-', name)
-
-
-def safe_version(version):
-    """Convert an arbitrary string to a standard version string
-
-    Spaces become dots, and all other non-alphanumeric characters become
-    dashes, with runs of multiple dashes condensed to a single dash.
-    """
-    version = version.replace(' ','.')
-    return re.sub('[^A-Za-z0-9.]+', '-', version)
-
-
-def safe_extra(extra):
-    """Convert an arbitrary string to a standard 'extra' name
-
-    Any runs of non-alphanumeric characters are replaced with a single '_',
-    and the result is always lowercased.
-    """
-    return re.sub('[^A-Za-z0-9.]+', '_', extra).lower()
-
-
-def to_filename(name):
-    """Convert a project or version name to its filename-escaped form
-
-    Any '-' characters are currently replaced with '_'.
-    """
-    return name.replace('-','_')
-
-
-class MarkerEvaluation(object):
-    values = {
-        'os_name': lambda: os.name,
-        'sys_platform': lambda: sys.platform,
-        'python_full_version': lambda: sys.version.split()[0],
-        'python_version': lambda:'%s.%s' % (sys.version_info[0], sys.version_info[1]),
-        'platform_version': platform.version,
-        'platform_machine': platform.machine,
-        'python_implementation': platform.python_implementation,
-    }
-
-    @classmethod
-    def is_invalid_marker(cls, text):
-        """
-        Validate text as a PEP 426 environment marker; return an exception
-        if invalid or False otherwise.
-        """
-        try:
-            cls.evaluate_marker(text)
-        except SyntaxError:
-            return cls.normalize_exception(sys.exc_info()[1])
-        return False
-
-    @staticmethod
-    def normalize_exception(exc):
-        """
-        Given a SyntaxError from a marker evaluation, normalize the error message:
-         - Remove indications of filename and line number.
-         - Replace platform-specific error messages with standard error messages.
-        """
-        subs = {
-            'unexpected EOF while parsing': 'invalid syntax',
-            'parenthesis is never closed': 'invalid syntax',
-        }
-        exc.filename = None
-        exc.lineno = None
-        exc.msg = subs.get(exc.msg, exc.msg)
-        return exc
-
-    @classmethod
-    def and_test(cls, nodelist):
-        # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
-        return functools.reduce(operator.and_, [cls.interpret(nodelist[i]) for i in range(1,len(nodelist),2)])
-
-    @classmethod
-    def test(cls, nodelist):
-        # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
-        return functools.reduce(operator.or_, [cls.interpret(nodelist[i]) for i in range(1,len(nodelist),2)])
-
-    @classmethod
-    def atom(cls, nodelist):
-        t = nodelist[1][0]
-        if t == token.LPAR:
-            if nodelist[2][0] == token.RPAR:
-                raise SyntaxError("Empty parentheses")
-            return cls.interpret(nodelist[2])
-        raise SyntaxError("Language feature not supported in environment markers")
-
-    @classmethod
-    def comparison(cls, nodelist):
-        if len(nodelist)>4:
-            raise SyntaxError("Chained comparison not allowed in environment markers")
-        comp = nodelist[2][1]
-        cop = comp[1]
-        if comp[0] == token.NAME:
-            if len(nodelist[2]) == 3:
-                if cop == 'not':
-                    cop = 'not in'
-                else:
-                    cop = 'is not'
-        try:
-            cop = cls.get_op(cop)
-        except KeyError:
-            raise SyntaxError(repr(cop)+" operator not allowed in environment markers")
-        return cop(cls.evaluate(nodelist[1]), cls.evaluate(nodelist[3]))
-
-    @classmethod
-    def get_op(cls, op):
-        ops = {
-            symbol.test: cls.test,
-            symbol.and_test: cls.and_test,
-            symbol.atom: cls.atom,
-            symbol.comparison: cls.comparison,
-            'not in': lambda x, y: x not in y,
-            'in': lambda x, y: x in y,
-            '==': operator.eq,
-            '!=': operator.ne,
-        }
-        if hasattr(symbol, 'or_test'):
-            ops[symbol.or_test] = cls.test
-        return ops[op]
-
-    @classmethod
-    def evaluate_marker(cls, text, extra=None):
-        """
-        Evaluate a PEP 426 environment marker on CPython 2.4+.
-        Return a boolean indicating the marker result in this environment.
-        Raise SyntaxError if marker is invalid.
-
-        This implementation uses the 'parser' module, which is not implemented on
-        Jython and has been superseded by the 'ast' module in Python 2.6 and
-        later.
-        """
-        return cls.interpret(parser.expr(text).totuple(1)[1])
-
-    @classmethod
-    def _markerlib_evaluate(cls, text):
-        """
-        Evaluate a PEP 426 environment marker using markerlib.
-        Return a boolean indicating the marker result in this environment.
-        Raise SyntaxError if marker is invalid.
-        """
-        import _markerlib
-        # markerlib implements Metadata 1.2 (PEP 345) environment markers.
-        # Translate the variables to Metadata 2.0 (PEP 426).
-        env = _markerlib.default_environment()
-        for key in env.keys():
-            new_key = key.replace('.', '_')
-            env[new_key] = env.pop(key)
-        try:
-            result = _markerlib.interpret(text, env)
-        except NameError:
-            e = sys.exc_info()[1]
-            raise SyntaxError(e.args[0])
-        return result
-
-    if 'parser' not in globals():
-        # Fall back to less-complete _markerlib implementation if 'parser' module
-        # is not available.
-        evaluate_marker = _markerlib_evaluate
-
-    @classmethod
-    def interpret(cls, nodelist):
-        while len(nodelist)==2: nodelist = nodelist[1]
-        try:
-            op = cls.get_op(nodelist[0])
-        except KeyError:
-            raise SyntaxError("Comparison or logical expression expected")
-        return op(nodelist)
-
-    @classmethod
-    def evaluate(cls, nodelist):
-        while len(nodelist)==2: nodelist = nodelist[1]
-        kind = nodelist[0]
-        name = nodelist[1]
-        if kind==token.NAME:
-            try:
-                op = cls.values[name]
-            except KeyError:
-                raise SyntaxError("Unknown name %r" % name)
-            return op()
-        if kind==token.STRING:
-            s = nodelist[1]
-            if s[:1] not in "'\"" or s.startswith('"""') or s.startswith("'''") \
-                    or '\\' in s:
-                raise SyntaxError(
-                    "Only plain strings allowed in environment markers")
-            return s[1:-1]
-        raise SyntaxError("Language feature not supported in environment markers")
-
-invalid_marker = MarkerEvaluation.is_invalid_marker
-evaluate_marker = MarkerEvaluation.evaluate_marker
-
-class NullProvider:
-    """Try to implement resources and metadata for arbitrary PEP 302 loaders"""
-
-    egg_name = None
-    egg_info = None
-    loader = None
-
-    def __init__(self, module):
-        self.loader = getattr(module, '__loader__', None)
-        self.module_path = os.path.dirname(getattr(module, '__file__', ''))
-
-    def get_resource_filename(self, manager, resource_name):
-        return self._fn(self.module_path, resource_name)
-
-    def get_resource_stream(self, manager, resource_name):
-        return BytesIO(self.get_resource_string(manager, resource_name))
-
-    def get_resource_string(self, manager, resource_name):
-        return self._get(self._fn(self.module_path, resource_name))
-
-    def has_resource(self, resource_name):
-        return self._has(self._fn(self.module_path, resource_name))
-
-    def has_metadata(self, name):
-        return self.egg_info and self._has(self._fn(self.egg_info,name))
-
-    if sys.version_info <= (3,):
-        def get_metadata(self, name):
-            if not self.egg_info:
-                return ""
-            return self._get(self._fn(self.egg_info,name))
-    else:
-        def get_metadata(self, name):
-            if not self.egg_info:
-                return ""
-            return self._get(self._fn(self.egg_info,name)).decode("utf-8")
-
-    def get_metadata_lines(self, name):
-        return yield_lines(self.get_metadata(name))
-
-    def resource_isdir(self,resource_name):
-        return self._isdir(self._fn(self.module_path, resource_name))
-
-    def metadata_isdir(self,name):
-        return self.egg_info and self._isdir(self._fn(self.egg_info,name))
-
-    def resource_listdir(self,resource_name):
-        return self._listdir(self._fn(self.module_path,resource_name))
-
-    def metadata_listdir(self,name):
-        if self.egg_info:
-            return self._listdir(self._fn(self.egg_info,name))
-        return []
-
-    def run_script(self,script_name,namespace):
-        script = 'scripts/'+script_name
-        if not self.has_metadata(script):
-            raise ResolutionError("No script named %r" % script_name)
-        script_text = self.get_metadata(script).replace('\r\n','\n')
-        script_text = script_text.replace('\r','\n')
-        script_filename = self._fn(self.egg_info,script)
-        namespace['__file__'] = script_filename
-        if os.path.exists(script_filename):
-            execfile(script_filename, namespace, namespace)
-        else:
-            from linecache import cache
-            cache[script_filename] = (
-                len(script_text), 0, script_text.split('\n'), script_filename
-            )
-            script_code = compile(script_text,script_filename,'exec')
-            exec(script_code, namespace, namespace)
-
-    def _has(self, path):
-        raise NotImplementedError(
-            "Can't perform this operation for unregistered loader type"
-        )
-
-    def _isdir(self, path):
-        raise NotImplementedError(
-            "Can't perform this operation for unregistered loader type"
-        )
-
-    def _listdir(self, path):
-        raise NotImplementedError(
-            "Can't perform this operation for unregistered loader type"
-        )
-
-    def _fn(self, base, resource_name):
-        if resource_name:
-            return os.path.join(base, *resource_name.split('/'))
-        return base
-
-    def _get(self, path):
-        if hasattr(self.loader, 'get_data'):
-            return self.loader.get_data(path)
-        raise NotImplementedError(
-            "Can't perform this operation for loaders without 'get_data()'"
-        )
-
-register_loader_type(object, NullProvider)
-
-
-class EggProvider(NullProvider):
-    """Provider based on a virtual filesystem"""
-
-    def __init__(self,module):
-        NullProvider.__init__(self,module)
-        self._setup_prefix()
-
-    def _setup_prefix(self):
-        # we assume here that our metadata may be nested inside a "basket"
-        # of multiple eggs; that's why we use module_path instead of .archive
-        path = self.module_path
-        old = None
-        while path!=old:
-            if path.lower().endswith('.egg'):
-                self.egg_name = os.path.basename(path)
-                self.egg_info = os.path.join(path, 'EGG-INFO')
-                self.egg_root = path
-                break
-            old = path
-            path, base = os.path.split(path)
-
-class DefaultProvider(EggProvider):
-    """Provides access to package resources in the filesystem"""
-
-    def _has(self, path):
-        return os.path.exists(path)
-
-    def _isdir(self,path):
-        return os.path.isdir(path)
-
-    def _listdir(self,path):
-        return os.listdir(path)
-
-    def get_resource_stream(self, manager, resource_name):
-        return open(self._fn(self.module_path, resource_name), 'rb')
-
-    def _get(self, path):
-        stream = open(path, 'rb')
-        try:
-            return stream.read()
-        finally:
-            stream.close()
-
-register_loader_type(type(None), DefaultProvider)
-
-if importlib_bootstrap is not None:
-    register_loader_type(importlib_bootstrap.SourceFileLoader, DefaultProvider)
-
-
-class EmptyProvider(NullProvider):
-    """Provider that returns nothing for all requests"""
-
-    _isdir = _has = lambda self,path: False
-    _get = lambda self,path: ''
-    _listdir = lambda self,path: []
-    module_path = None
-
-    def __init__(self):
-        pass
-
-empty_provider = EmptyProvider()
-
-
-def build_zipmanifest(path):
-    """
-    This builds a similar dictionary to the zipimport directory
-    caches.  However instead of tuples, ZipInfo objects are stored.
-
-    The translation of the tuple is as follows:
-      * [0] - zipinfo.filename on stock pythons this needs "/" --> os.sep
-              on pypy it is the same (one reason why distribute did work
-              in some cases on pypy and win32).
-      * [1] - zipinfo.compress_type
-      * [2] - zipinfo.compress_size
-      * [3] - zipinfo.file_size
-      * [4] - len(utf-8 encoding of filename) if zipinfo & 0x800
-              len(ascii encoding of filename) otherwise
-      * [5] - (zipinfo.date_time[0] - 1980) << 9 |
-               zipinfo.date_time[1] << 5 | zipinfo.date_time[2]
-      * [6] - (zipinfo.date_time[3] - 1980) << 11 |
-               zipinfo.date_time[4] << 5 | (zipinfo.date_time[5] // 2)
-      * [7] - zipinfo.CRC
-    """
-    zipinfo = dict()
-    zfile = zipfile.ZipFile(path)
-    #Got ZipFile has not __exit__ on python 3.1
-    try:
-        for zitem in zfile.namelist():
-            zpath = zitem.replace('/', os.sep)
-            zipinfo[zpath] = zfile.getinfo(zitem)
-            assert zipinfo[zpath] is not None
-    finally:
-        zfile.close()
-    return zipinfo
-
-
-class ZipProvider(EggProvider):
-    """Resource support for zips and eggs"""
-
-    eagers = None
-
-    def __init__(self, module):
-        EggProvider.__init__(self,module)
-        self.zipinfo = build_zipmanifest(self.loader.archive)
-        self.zip_pre = self.loader.archive+os.sep
-
-    def _zipinfo_name(self, fspath):
-        # Convert a virtual filename (full path to file) into a zipfile subpath
-        # usable with the zipimport directory cache for our target archive
-        if fspath.startswith(self.zip_pre):
-            return fspath[len(self.zip_pre):]
-        raise AssertionError(
-            "%s is not a subpath of %s" % (fspath,self.zip_pre)
-        )
-
-    def _parts(self,zip_path):
-        # Convert a zipfile subpath into an egg-relative path part list
-        fspath = self.zip_pre+zip_path  # pseudo-fs path
-        if fspath.startswith(self.egg_root+os.sep):
-            return fspath[len(self.egg_root)+1:].split(os.sep)
-        raise AssertionError(
-            "%s is not a subpath of %s" % (fspath,self.egg_root)
-        )
-
-    def get_resource_filename(self, manager, resource_name):
-        if not self.egg_name:
-            raise NotImplementedError(
-                "resource_filename() only supported for .egg, not .zip"
-            )
-        # no need to lock for extraction, since we use temp names
-        zip_path = self._resource_to_zip(resource_name)
-        eagers = self._get_eager_resources()
-        if '/'.join(self._parts(zip_path)) in eagers:
-            for name in eagers:
-                self._extract_resource(manager, self._eager_to_zip(name))
-        return self._extract_resource(manager, zip_path)
-
-    @staticmethod
-    def _get_date_and_size(zip_stat):
-        size = zip_stat.file_size
-        date_time = zip_stat.date_time + (0, 0, -1)  # ymdhms+wday, yday, dst
-        #1980 offset already done
-        timestamp = time.mktime(date_time)
-        return timestamp, size
-
-    def _extract_resource(self, manager, zip_path):
-
-        if zip_path in self._index():
-            for name in self._index()[zip_path]:
-                last = self._extract_resource(
-                    manager, os.path.join(zip_path, name)
-                )
-            return os.path.dirname(last)  # return the extracted directory name
-
-        timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
-
-        if not WRITE_SUPPORT:
-            raise IOError('"os.rename" and "os.unlink" are not supported '
-                          'on this platform')
-        try:
-
-            real_path = manager.get_cache_path(
-                self.egg_name, self._parts(zip_path)
-            )
-
-            if self._is_current(real_path, zip_path):
-                return real_path
-
-            outf, tmpnam = _mkstemp(".$extract", dir=os.path.dirname(real_path))
-            os.write(outf, self.loader.get_data(zip_path))
-            os.close(outf)
-            utime(tmpnam, (timestamp,timestamp))
-            manager.postprocess(tmpnam, real_path)
-
-            try:
-                rename(tmpnam, real_path)
-
-            except os.error:
-                if os.path.isfile(real_path):
-                    if self._is_current(real_path, zip_path):
-                        # the file became current since it was checked above,
-                        #  so proceed.
-                        return real_path
-                    elif os.name=='nt':     # Windows, del old file and retry
-                        unlink(real_path)
-                        rename(tmpnam, real_path)
-                        return real_path
-                raise
-
-        except os.error:
-            manager.extraction_error()  # report a user-friendly error
-
-        return real_path
-
-    def _is_current(self, file_path, zip_path):
-        """
-        Return True if the file_path is current for this zip_path
-        """
-        timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
-        if not os.path.isfile(file_path):
-            return False
-        stat = os.stat(file_path)
-        if stat.st_size!=size or stat.st_mtime!=timestamp:
-            return False
-        # check that the contents match
-        zip_contents = self.loader.get_data(zip_path)
-        f = open(file_path, 'rb')
-        file_contents = f.read()
-        f.close()
-        return zip_contents == file_contents
-
-    def _get_eager_resources(self):
-        if self.eagers is None:
-            eagers = []
-            for name in ('native_libs.txt', 'eager_resources.txt'):
-                if self.has_metadata(name):
-                    eagers.extend(self.get_metadata_lines(name))
-            self.eagers = eagers
-        return self.eagers
-
-    def _index(self):
-        try:
-            return self._dirindex
-        except AttributeError:
-            ind = {}
-            for path in self.zipinfo:
-                parts = path.split(os.sep)
-                while parts:
-                    parent = os.sep.join(parts[:-1])
-                    if parent in ind:
-                        ind[parent].append(parts[-1])
-                        break
-                    else:
-                        ind[parent] = [parts.pop()]
-            self._dirindex = ind
-            return ind
-
-    def _has(self, fspath):
-        zip_path = self._zipinfo_name(fspath)
-        return zip_path in self.zipinfo or zip_path in self._index()
-
-    def _isdir(self,fspath):
-        return self._zipinfo_name(fspath) in self._index()
-
-    def _listdir(self,fspath):
-        return list(self._index().get(self._zipinfo_name(fspath), ()))
-
-    def _eager_to_zip(self,resource_name):
-        return self._zipinfo_name(self._fn(self.egg_root,resource_name))
-
-    def _resource_to_zip(self,resource_name):
-        return self._zipinfo_name(self._fn(self.module_path,resource_name))
-
-register_loader_type(zipimport.zipimporter, ZipProvider)
-
-
-class FileMetadata(EmptyProvider):
-    """Metadata handler for standalone PKG-INFO files
-
-    Usage::
-
-        metadata = FileMetadata("/path/to/PKG-INFO")
-
-    This provider rejects all data and metadata requests except for PKG-INFO,
-    which is treated as existing, and will be the contents of the file at
-    the provided location.
-    """
-
-    def __init__(self,path):
-        self.path = path
-
-    def has_metadata(self,name):
-        return name=='PKG-INFO'
-
-    def get_metadata(self,name):
-        if name=='PKG-INFO':
-            f = open(self.path,'rU')
-            metadata = f.read()
-            f.close()
-            return metadata
-        raise KeyError("No metadata except PKG-INFO is available")
-
-    def get_metadata_lines(self,name):
-        return yield_lines(self.get_metadata(name))
-
-
-class PathMetadata(DefaultProvider):
-    """Metadata provider for egg directories
-
-    Usage::
-
-        # Development eggs:
-
-        egg_info = "/path/to/PackageName.egg-info"
-        base_dir = os.path.dirname(egg_info)
-        metadata = PathMetadata(base_dir, egg_info)
-        dist_name = os.path.splitext(os.path.basename(egg_info))[0]
-        dist = Distribution(basedir,project_name=dist_name,metadata=metadata)
-
-        # Unpacked egg directories:
-
-        egg_path = "/path/to/PackageName-ver-pyver-etc.egg"
-        metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO'))
-        dist = Distribution.from_filename(egg_path, metadata=metadata)
-    """
-
-    def __init__(self, path, egg_info):
-        self.module_path = path
-        self.egg_info = egg_info
-
-
-class EggMetadata(ZipProvider):
-    """Metadata provider for .egg files"""
-
-    def __init__(self, importer):
-        """Create a metadata provider from a zipimporter"""
-
-        self.zipinfo = build_zipmanifest(importer.archive)
-        self.zip_pre = importer.archive+os.sep
-        self.loader = importer
-        if importer.prefix:
-            self.module_path = os.path.join(importer.archive, importer.prefix)
-        else:
-            self.module_path = importer.archive
-        self._setup_prefix()
-
-_declare_state('dict', _distribution_finders = {})
-
-def register_finder(importer_type, distribution_finder):
-    """Register `distribution_finder` to find distributions in sys.path items
-
-    `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
-    handler), and `distribution_finder` is a callable that, passed a path
-    item and the importer instance, yields ``Distribution`` instances found on
-    that path item.  See ``pkg_resources.find_on_path`` for an example."""
-    _distribution_finders[importer_type] = distribution_finder
-
-
-def find_distributions(path_item, only=False):
-    """Yield distributions accessible via `path_item`"""
-    importer = get_importer(path_item)
-    finder = _find_adapter(_distribution_finders, importer)
-    return finder(importer, path_item, only)
-
-def find_eggs_in_zip(importer, path_item, only=False):
-    """
-    Find eggs in zip files; possibly multiple nested eggs.
-    """
-    if importer.archive.endswith('.whl'):
-        # wheels are not supported with this finder
-        # they don't have PKG-INFO metadata, and won't ever contain eggs
-        return
-    metadata = EggMetadata(importer)
-    if metadata.has_metadata('PKG-INFO'):
-        yield Distribution.from_filename(path_item, metadata=metadata)
-    if only:
-        return  # don't yield nested distros
-    for subitem in metadata.resource_listdir('/'):
-        if subitem.endswith('.egg'):
-            subpath = os.path.join(path_item, subitem)
-            for dist in find_eggs_in_zip(zipimport.zipimporter(subpath), subpath):
-                yield dist
-
-register_finder(zipimport.zipimporter, find_eggs_in_zip)
-
-def find_nothing(importer, path_item, only=False):
-    return ()
-register_finder(object,find_nothing)
-
-def find_on_path(importer, path_item, only=False):
-    """Yield distributions accessible on a sys.path directory"""
-    path_item = _normalize_cached(path_item)
-
-    if os.path.isdir(path_item) and os.access(path_item, os.R_OK):
-        if path_item.lower().endswith('.egg'):
-            # unpacked egg
-            yield Distribution.from_filename(
-                path_item, metadata=PathMetadata(
-                    path_item, os.path.join(path_item,'EGG-INFO')
-                )
-            )
-        else:
-            # scan for .egg and .egg-info in directory
-            for entry in os.listdir(path_item):
-                lower = entry.lower()
-                if lower.endswith('.egg-info') or lower.endswith('.dist-info'):
-                    fullpath = os.path.join(path_item, entry)
-                    if os.path.isdir(fullpath):
-                        # egg-info directory, allow getting metadata
-                        metadata = PathMetadata(path_item, fullpath)
-                    else:
-                        metadata = FileMetadata(fullpath)
-                    yield Distribution.from_location(
-                        path_item,entry,metadata,precedence=DEVELOP_DIST
-                    )
-                elif not only and lower.endswith('.egg'):
-                    for dist in find_distributions(os.path.join(path_item, entry)):
-                        yield dist
-                elif not only and lower.endswith('.egg-link'):
-                    entry_file = open(os.path.join(path_item, entry))
-                    try:
-                        entry_lines = entry_file.readlines()
-                    finally:
-                        entry_file.close()
-                    for line in entry_lines:
-                        if not line.strip(): continue
-                        for item in find_distributions(os.path.join(path_item,line.rstrip())):
-                            yield item
-                        break
-register_finder(pkgutil.ImpImporter,find_on_path)
-
-if importlib_bootstrap is not None:
-    register_finder(importlib_bootstrap.FileFinder, find_on_path)
-
-_declare_state('dict', _namespace_handlers={})
-_declare_state('dict', _namespace_packages={})
-
-
-def register_namespace_handler(importer_type, namespace_handler):
-    """Register `namespace_handler` to declare namespace packages
-
-    `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
-    handler), and `namespace_handler` is a callable like this::
-
-        def namespace_handler(importer,path_entry,moduleName,module):
-            # return a path_entry to use for child packages
-
-    Namespace handlers are only called if the importer object has already
-    agreed that it can handle the relevant path item, and they should only
-    return a subpath if the module __path__ does not already contain an
-    equivalent subpath.  For an example namespace handler, see
-    ``pkg_resources.file_ns_handler``.
-    """
-    _namespace_handlers[importer_type] = namespace_handler
-
-def _handle_ns(packageName, path_item):
-    """Ensure that named package includes a subpath of path_item (if needed)"""
-
-    importer = get_importer(path_item)
-    if importer is None:
-        return None
-    loader = importer.find_module(packageName)
-    if loader is None:
-        return None
-    module = sys.modules.get(packageName)
-    if module is None:
-        module = sys.modules[packageName] = imp.new_module(packageName)
-        module.__path__ = []
-        _set_parent_ns(packageName)
-    elif not hasattr(module,'__path__'):
-        raise TypeError("Not a package:", packageName)
-    handler = _find_adapter(_namespace_handlers, importer)
-    subpath = handler(importer, path_item, packageName, module)
-    if subpath is not None:
-        path = module.__path__
-        path.append(subpath)
-        loader.load_module(packageName)
-        for path_item in path:
-            if path_item not in module.__path__:
-                module.__path__.append(path_item)
-    return subpath
-
-def declare_namespace(packageName):
-    """Declare that package 'packageName' is a namespace package"""
-
-    imp.acquire_lock()
-    try:
-        if packageName in _namespace_packages:
-            return
-
-        path, parent = sys.path, None
-        if '.' in packageName:
-            parent = '.'.join(packageName.split('.')[:-1])
-            declare_namespace(parent)
-            if parent not in _namespace_packages:
-                __import__(parent)
-            try:
-                path = sys.modules[parent].__path__
-            except AttributeError:
-                raise TypeError("Not a package:", parent)
-
-        # Track what packages are namespaces, so when new path items are added,
-        # they can be updated
-        _namespace_packages.setdefault(parent,[]).append(packageName)
-        _namespace_packages.setdefault(packageName,[])
-
-        for path_item in path:
-            # Ensure all the parent's path items are reflected in the child,
-            # if they apply
-            _handle_ns(packageName, path_item)
-
-    finally:
-        imp.release_lock()
-
-def fixup_namespace_packages(path_item, parent=None):
-    """Ensure that previously-declared namespace packages include path_item"""
-    imp.acquire_lock()
-    try:
-        for package in _namespace_packages.get(parent,()):
-            subpath = _handle_ns(package, path_item)
-            if subpath: fixup_namespace_packages(subpath,package)
-    finally:
-        imp.release_lock()
-
-def file_ns_handler(importer, path_item, packageName, module):
-    """Compute an ns-package subpath for a filesystem or zipfile importer"""
-
-    subpath = os.path.join(path_item, packageName.split('.')[-1])
-    normalized = _normalize_cached(subpath)
-    for item in module.__path__:
-        if _normalize_cached(item)==normalized:
-            break
-    else:
-        # Only return the path if it's not already there
-        return subpath
-
-register_namespace_handler(pkgutil.ImpImporter,file_ns_handler)
-register_namespace_handler(zipimport.zipimporter,file_ns_handler)
-
-if importlib_bootstrap is not None:
-    register_namespace_handler(importlib_bootstrap.FileFinder, file_ns_handler)
-
-
-def null_ns_handler(importer, path_item, packageName, module):
-    return None
-
-register_namespace_handler(object,null_ns_handler)
-
-
-def normalize_path(filename):
-    """Normalize a file/dir name for comparison purposes"""
-    return os.path.normcase(os.path.realpath(filename))
-
-def _normalize_cached(filename,_cache={}):
-    try:
-        return _cache[filename]
-    except KeyError:
-        _cache[filename] = result = normalize_path(filename)
-        return result
-
-def _set_parent_ns(packageName):
-    parts = packageName.split('.')
-    name = parts.pop()
-    if parts:
-        parent = '.'.join(parts)
-        setattr(sys.modules[parent], name, sys.modules[packageName])
-
-
-def yield_lines(strs):
-    """Yield non-empty/non-comment lines of a ``basestring`` or sequence"""
-    if isinstance(strs,basestring):
-        for s in strs.splitlines():
-            s = s.strip()
-            if s and not s.startswith('#'):     # skip blank lines/comments
-                yield s
-    else:
-        for ss in strs:
-            for s in yield_lines(ss):
-                yield s
-
-LINE_END = re.compile(r"\s*(#.*)?$").match         # whitespace and comment
-CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match    # line continuation
-DISTRO = re.compile(r"\s*((\w|[-.])+)").match    # Distribution or extra
-VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|[-.])+)").match  # ver. info
-COMMA = re.compile(r"\s*,").match               # comma between items
-OBRACKET = re.compile(r"\s*\[").match
-CBRACKET = re.compile(r"\s*\]").match
-MODULE = re.compile(r"\w+(\.\w+)*$").match
-EGG_NAME = re.compile(
-    r"(?P[^-]+)"
-    r"( -(?P[^-]+) (-py(?P[^-]+) (-(?P.+))? )? )?",
-    re.VERBOSE | re.IGNORECASE
-).match
-
-component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
-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=='.':
-            continue
-        if part[:1] in '0123456789':
-            yield part.zfill(8)    # pad for numeric comparison
-        else:
-            yield '*'+part
-
-    yield '*final'  # ensure that alpha/beta/candidate are before final
-
-def parse_version(s):
-    """Convert a version string to a chronologically-sortable key
-
-    This is a rough cross between distutils' StrictVersion and LooseVersion;
-    if you give it versions that would work with StrictVersion, then it behaves
-    the same; otherwise it acts like a slightly-smarter LooseVersion. It is
-    *possible* to create pathological version coding schemes that will fool
-    this parser, but they should be very rare in practice.
-
-    The returned value will be a tuple of strings.  Numeric portions of the
-    version are padded to 8 digits so they will compare numerically, but
-    without relying on how numbers compare relative to strings.  Dots are
-    dropped, but dashes are retained.  Trailing zeros between alpha segments
-    or dashes are suppressed, so that e.g. "2.4.0" is considered the same as
-    "2.4". Alphanumeric parts are lower-cased.
-
-    The algorithm assumes that strings like "-" and any alpha string that
-    alphabetically follows "final"  represents a "patch level".  So, "2.4-1"
-    is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is
-    considered newer than "2.4-1", which in turn is newer than "2.4".
-
-    Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that
-    come before "final" alphabetically) are assumed to be pre-release versions,
-    so that the version "2.4" is considered newer than "2.4a1".
-
-    Finally, to handle miscellaneous cases, the strings "pre", "preview", and
-    "rc" are treated as if they were "c", i.e. as though they were release
-    candidates, and therefore are not as new as a version string that does not
-    contain them, and "dev" is replaced with an '@' so that it sorts lower than
-    than any other pre-release tag.
-    """
-    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()
-        parts.append(part)
-    return tuple(parts)
-class EntryPoint(object):
-    """Object representing an advertised importable object"""
-
-    def __init__(self, name, module_name, attrs=(), extras=(), dist=None):
-        if not MODULE(module_name):
-            raise ValueError("Invalid module name", module_name)
-        self.name = name
-        self.module_name = module_name
-        self.attrs = tuple(attrs)
-        self.extras = Requirement.parse(("x[%s]" % ','.join(extras))).extras
-        self.dist = dist
-
-    def __str__(self):
-        s = "%s = %s" % (self.name, self.module_name)
-        if self.attrs:
-            s += ':' + '.'.join(self.attrs)
-        if self.extras:
-            s += ' [%s]' % ','.join(self.extras)
-        return s
-
-    def __repr__(self):
-        return "EntryPoint.parse(%r)" % str(self)
-
-    def load(self, require=True, env=None, installer=None):
-        if require: self.require(env, installer)
-        entry = __import__(self.module_name, globals(),globals(), ['__name__'])
-        for attr in self.attrs:
-            try:
-                entry = getattr(entry,attr)
-            except AttributeError:
-                raise ImportError("%r has no %r attribute" % (entry,attr))
-        return entry
-
-    def require(self, env=None, installer=None):
-        if self.extras and not self.dist:
-            raise UnknownExtra("Can't require() without a distribution", self)
-        list(map(working_set.add,
-            working_set.resolve(self.dist.requires(self.extras),env,installer)))
-
-    @classmethod
-    def parse(cls, src, dist=None):
-        """Parse a single entry point from string `src`
-
-        Entry point syntax follows the form::
-
-            name = some.module:some.attr [extra1,extra2]
-
-        The entry name and module name are required, but the ``:attrs`` and
-        ``[extras]`` parts are optional
-        """
-        try:
-            attrs = extras = ()
-            name,value = src.split('=',1)
-            if '[' in value:
-                value,extras = value.split('[',1)
-                req = Requirement.parse("x["+extras)
-                if req.specs: raise ValueError
-                extras = req.extras
-            if ':' in value:
-                value,attrs = value.split(':',1)
-                if not MODULE(attrs.rstrip()):
-                    raise ValueError
-                attrs = attrs.rstrip().split('.')
-        except ValueError:
-            raise ValueError(
-                "EntryPoint must be in 'name=module:attrs [extras]' format",
-                src
-            )
-        else:
-            return cls(name.strip(), value.strip(), attrs, extras, dist)
-
-    @classmethod
-    def parse_group(cls, group, lines, dist=None):
-        """Parse an entry point group"""
-        if not MODULE(group):
-            raise ValueError("Invalid group name", group)
-        this = {}
-        for line in yield_lines(lines):
-            ep = cls.parse(line, dist)
-            if ep.name in this:
-                raise ValueError("Duplicate entry point", group, ep.name)
-            this[ep.name]=ep
-        return this
-
-    @classmethod
-    def parse_map(cls, data, dist=None):
-        """Parse a map of entry point groups"""
-        if isinstance(data,dict):
-            data = data.items()
-        else:
-            data = split_sections(data)
-        maps = {}
-        for group, lines in data:
-            if group is None:
-                if not lines:
-                    continue
-                raise ValueError("Entry points must be listed in groups")
-            group = group.strip()
-            if group in maps:
-                raise ValueError("Duplicate group name", group)
-            maps[group] = cls.parse_group(group, lines, dist)
-        return maps
-
-
-def _remove_md5_fragment(location):
-    if not location:
-        return ''
-    parsed = urlparse(location)
-    if parsed[-1].startswith('md5='):
-        return urlunparse(parsed[:-1] + ('',))
-    return location
-
-
-class Distribution(object):
-    """Wrap an actual or potential sys.path entry w/metadata"""
-    PKG_INFO = 'PKG-INFO'
-
-    def __init__(self, location=None, metadata=None, project_name=None,
-            version=None, py_version=PY_MAJOR, platform=None,
-            precedence=EGG_DIST):
-        self.project_name = safe_name(project_name or 'Unknown')
-        if version is not None:
-            self._version = safe_version(version)
-        self.py_version = py_version
-        self.platform = platform
-        self.location = location
-        self.precedence = precedence
-        self._provider = metadata or empty_provider
-
-    @classmethod
-    def from_location(cls,location,basename,metadata=None,**kw):
-        project_name, version, py_version, platform = [None]*4
-        basename, ext = os.path.splitext(basename)
-        if ext.lower() in _distributionImpl:
-            # .dist-info gets much metadata differently
-            match = EGG_NAME(basename)
-            if match:
-                project_name, version, py_version, platform = match.group(
-                    'name','ver','pyver','plat'
-                )
-            cls = _distributionImpl[ext.lower()]
-        return cls(
-            location, metadata, project_name=project_name, version=version,
-            py_version=py_version, platform=platform, **kw
-        )
-
-    hashcmp = property(
-        lambda self: (
-            getattr(self,'parsed_version',()),
-            self.precedence,
-            self.key,
-            _remove_md5_fragment(self.location),
-            self.py_version,
-            self.platform
-        )
-    )
-    def __hash__(self): return hash(self.hashcmp)
-    def __lt__(self, other):
-        return self.hashcmp < other.hashcmp
-    def __le__(self, other):
-        return self.hashcmp <= other.hashcmp
-    def __gt__(self, other):
-        return self.hashcmp > other.hashcmp
-    def __ge__(self, other):
-        return self.hashcmp >= other.hashcmp
-    def __eq__(self, other):
-        if not isinstance(other, self.__class__):
-            # It's not a Distribution, so they are not equal
-            return False
-        return self.hashcmp == other.hashcmp
-    def __ne__(self, other):
-        return not self == other
-
-    # These properties have to be lazy so that we don't have to load any
-    # metadata until/unless it's actually needed.  (i.e., some distributions
-    # may not know their name or version without loading PKG-INFO)
-
-    @property
-    def key(self):
-        try:
-            return self._key
-        except AttributeError:
-            self._key = key = self.project_name.lower()
-            return key
-
-    @property
-    def parsed_version(self):
-        try:
-            return self._parsed_version
-        except AttributeError:
-            self._parsed_version = pv = parse_version(self.version)
-            return pv
-
-    @property
-    def version(self):
-        try:
-            return self._version
-        except AttributeError:
-            for line in self._get_metadata(self.PKG_INFO):
-                if line.lower().startswith('version:'):
-                    self._version = safe_version(line.split(':',1)[1].strip())
-                    return self._version
-            else:
-                raise ValueError(
-                    "Missing 'Version:' header and/or %s file" % self.PKG_INFO, self
-                )
-
-    @property
-    def _dep_map(self):
-        try:
-            return self.__dep_map
-        except AttributeError:
-            dm = self.__dep_map = {None: []}
-            for name in 'requires.txt', 'depends.txt':
-                for extra,reqs in split_sections(self._get_metadata(name)):
-                    if extra:
-                        if ':' in extra:
-                            extra, marker = extra.split(':',1)
-                            if invalid_marker(marker):
-                                reqs=[] # XXX warn
-                            elif not evaluate_marker(marker):
-                                reqs=[]
-                        extra = safe_extra(extra) or None
-                    dm.setdefault(extra,[]).extend(parse_requirements(reqs))
-            return dm
-
-    def requires(self,extras=()):
-        """List of Requirements needed for this distro if `extras` are used"""
-        dm = self._dep_map
-        deps = []
-        deps.extend(dm.get(None,()))
-        for ext in extras:
-            try:
-                deps.extend(dm[safe_extra(ext)])
-            except KeyError:
-                raise UnknownExtra(
-                    "%s has no such extra feature %r" % (self, ext)
-                )
-        return deps
-
-    def _get_metadata(self,name):
-        if self.has_metadata(name):
-            for line in self.get_metadata_lines(name):
-                yield line
-
-    def activate(self,path=None):
-        """Ensure distribution is importable on `path` (default=sys.path)"""
-        if path is None: path = sys.path
-        self.insert_on(path)
-        if path is sys.path:
-            fixup_namespace_packages(self.location)
-            for pkg in self._get_metadata('namespace_packages.txt'):
-                if pkg in sys.modules:
-                    declare_namespace(pkg)
-
-    def egg_name(self):
-        """Return what this distribution's standard .egg filename should be"""
-        filename = "%s-%s-py%s" % (
-            to_filename(self.project_name), to_filename(self.version),
-            self.py_version or PY_MAJOR
-        )
-
-        if self.platform:
-            filename += '-'+self.platform
-        return filename
-
-    def __repr__(self):
-        if self.location:
-            return "%s (%s)" % (self,self.location)
-        else:
-            return str(self)
-
-    def __str__(self):
-        try: version = getattr(self,'version',None)
-        except ValueError: version = None
-        version = version or "[unknown version]"
-        return "%s %s" % (self.project_name,version)
-
-    def __getattr__(self,attr):
-        """Delegate all unrecognized public attributes to .metadata provider"""
-        if attr.startswith('_'):
-            raise AttributeError(attr)
-        return getattr(self._provider, attr)
-
-    @classmethod
-    def from_filename(cls,filename,metadata=None, **kw):
-        return cls.from_location(
-            _normalize_cached(filename), os.path.basename(filename), metadata,
-            **kw
-        )
-
-    def as_requirement(self):
-        """Return a ``Requirement`` that matches this distribution exactly"""
-        return Requirement.parse('%s==%s' % (self.project_name, self.version))
-
-    def load_entry_point(self, group, name):
-        """Return the `name` entry point of `group` or raise ImportError"""
-        ep = self.get_entry_info(group,name)
-        if ep is None:
-            raise ImportError("Entry point %r not found" % ((group,name),))
-        return ep.load()
-
-    def get_entry_map(self, group=None):
-        """Return the entry point map for `group`, or the full entry map"""
-        try:
-            ep_map = self._ep_map
-        except AttributeError:
-            ep_map = self._ep_map = EntryPoint.parse_map(
-                self._get_metadata('entry_points.txt'), self
-            )
-        if group is not None:
-            return ep_map.get(group,{})
-        return ep_map
-
-    def get_entry_info(self, group, name):
-        """Return the EntryPoint object for `group`+`name`, or ``None``"""
-        return self.get_entry_map(group).get(name)
-
-    def insert_on(self, path, loc = None):
-        """Insert self.location in path before its nearest parent directory"""
-
-        loc = loc or self.location
-        if not loc:
-            return
-
-        nloc = _normalize_cached(loc)
-        bdir = os.path.dirname(nloc)
-        npath= [(p and _normalize_cached(p) or p) for p in path]
-
-        for p, item in enumerate(npath):
-            if item==nloc:
-                break
-            elif item==bdir and self.precedence==EGG_DIST:
-                # if it's an .egg, give it precedence over its directory
-                if path is sys.path:
-                    self.check_version_conflict()
-                path.insert(p, loc)
-                npath.insert(p, nloc)
-                break
-        else:
-            if path is sys.path:
-                self.check_version_conflict()
-            path.append(loc)
-            return
-
-        # p is the spot where we found or inserted loc; now remove duplicates
-        while 1:
-            try:
-                np = npath.index(nloc, p+1)
-            except ValueError:
-                break
-            else:
-                del npath[np], path[np]
-                p = np  # ha!
-
-        return
-
-    def check_version_conflict(self):
-        if self.key=='setuptools':
-            return      # ignore the inevitable setuptools self-conflicts  :(
-
-        nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
-        loc = normalize_path(self.location)
-        for modname in self._get_metadata('top_level.txt'):
-            if (modname not in sys.modules or modname in nsp
-                    or modname in _namespace_packages):
-                continue
-            if modname in ('pkg_resources', 'setuptools', 'site'):
-                continue
-            fn = getattr(sys.modules[modname], '__file__', None)
-            if fn and (normalize_path(fn).startswith(loc) or
-                       fn.startswith(self.location)):
-                continue
-            issue_warning(
-                "Module %s was already imported from %s, but %s is being added"
-                " to sys.path" % (modname, fn, self.location),
-            )
-
-    def has_version(self):
-        try:
-            self.version
-        except ValueError:
-            issue_warning("Unbuilt egg for "+repr(self))
-            return False
-        return True
-
-    def clone(self,**kw):
-        """Copy this distribution, substituting in any changed keyword args"""
-        for attr in (
-            'project_name', 'version', 'py_version', 'platform', 'location',
-            'precedence'
-        ):
-            kw.setdefault(attr, getattr(self,attr,None))
-        kw.setdefault('metadata', self._provider)
-        return self.__class__(**kw)
-
-    @property
-    def extras(self):
-        return [dep for dep in self._dep_map if dep]
-
-
-class DistInfoDistribution(Distribution):
-    """Wrap an actual or potential sys.path entry w/metadata, .dist-info style"""
-    PKG_INFO = 'METADATA'
-    EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
-
-    @property
-    def _parsed_pkg_info(self):
-        """Parse and cache metadata"""
-        try:
-            return self._pkg_info
-        except AttributeError:
-            from email.parser import Parser
-            self._pkg_info = Parser().parsestr(self.get_metadata(self.PKG_INFO))
-            return self._pkg_info
-
-    @property
-    def _dep_map(self):
-        try:
-            return self.__dep_map
-        except AttributeError:
-            self.__dep_map = self._compute_dependencies()
-            return self.__dep_map
-
-    def _preparse_requirement(self, requires_dist):
-        """Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz')
-        Split environment marker, add == prefix to version specifiers as
-        necessary, and remove parenthesis.
-        """
-        parts = requires_dist.split(';', 1) + ['']
-        distvers = parts[0].strip()
-        mark = parts[1].strip()
-        distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers)
-        distvers = distvers.replace('(', '').replace(')', '')
-        return (distvers, mark)
-
-    def _compute_dependencies(self):
-        """Recompute this distribution's dependencies."""
-        from _markerlib import compile as compile_marker
-        dm = self.__dep_map = {None: []}
-
-        reqs = []
-        # Including any condition expressions
-        for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
-            distvers, mark = self._preparse_requirement(req)
-            parsed = next(parse_requirements(distvers))
-            parsed.marker_fn = compile_marker(mark)
-            reqs.append(parsed)
-
-        def reqs_for_extra(extra):
-            for req in reqs:
-                if req.marker_fn(override={'extra':extra}):
-                    yield req
-
-        common = frozenset(reqs_for_extra(None))
-        dm[None].extend(common)
-
-        for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
-            extra = safe_extra(extra.strip())
-            dm[extra] = list(frozenset(reqs_for_extra(extra)) - common)
-
-        return dm
-
-
-_distributionImpl = {
-    '.egg': Distribution,
-    '.egg-info': Distribution,
-    '.dist-info': DistInfoDistribution,
-    }
-
-
-def issue_warning(*args,**kw):
-    level = 1
-    g = globals()
-    try:
-        # find the first stack frame that is *not* code in
-        # the pkg_resources module, to use for the warning
-        while sys._getframe(level).f_globals is g:
-            level += 1
-    except ValueError:
-        pass
-    from warnings import warn
-    warn(stacklevel = level+1, *args, **kw)
-
-
-def parse_requirements(strs):
-    """Yield ``Requirement`` objects for each specification in `strs`
-
-    `strs` must be an instance of ``basestring``, or a (possibly-nested)
-    iterable thereof.
-    """
-    # create a steppable iterator, so we can handle \-continuations
-    lines = iter(yield_lines(strs))
-
-    def scan_list(ITEM,TERMINATOR,line,p,groups,item_name):
-
-        items = []
-
-        while not TERMINATOR(line,p):
-            if CONTINUE(line,p):
-                try:
-                    line = next(lines)
-                    p = 0
-                except StopIteration:
-                    raise ValueError(
-                        "\\ must not appear on the last nonblank line"
-                    )
-
-            match = ITEM(line,p)
-            if not match:
-                raise ValueError("Expected "+item_name+" in",line,"at",line[p:])
-
-            items.append(match.group(*groups))
-            p = match.end()
-
-            match = COMMA(line,p)
-            if match:
-                p = match.end() # skip the comma
-            elif not TERMINATOR(line,p):
-                raise ValueError(
-                    "Expected ',' or end-of-list in",line,"at",line[p:]
-                )
-
-        match = TERMINATOR(line,p)
-        if match: p = match.end()   # skip the terminator, if any
-        return line, p, items
-
-    for line in lines:
-        match = DISTRO(line)
-        if not match:
-            raise ValueError("Missing distribution spec", line)
-        project_name = match.group(1)
-        p = match.end()
-        extras = []
-
-        match = OBRACKET(line,p)
-        if match:
-            p = match.end()
-            line, p, extras = scan_list(
-                DISTRO, CBRACKET, line, p, (1,), "'extra' name"
-            )
-
-        line, p, specs = scan_list(VERSION,LINE_END,line,p,(1,2),"version spec")
-        specs = [(op,safe_version(val)) for op,val in specs]
-        yield Requirement(project_name, specs, extras)
-
-
-def _sort_dists(dists):
-    tmp = [(dist.hashcmp,dist) for dist in dists]
-    tmp.sort()
-    dists[::-1] = [d for hc,d in tmp]
-
-
-class Requirement:
-    def __init__(self, project_name, specs, extras):
-        """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
-        self.unsafe_name, project_name = project_name, safe_name(project_name)
-        self.project_name, self.key = project_name, project_name.lower()
-        index = [(parse_version(v),state_machine[op],op,v) for op,v in specs]
-        index.sort()
-        self.specs = [(op,ver) for parsed,trans,op,ver in index]
-        self.index, self.extras = index, tuple(map(safe_extra,extras))
-        self.hashCmp = (
-            self.key, tuple([(op,parsed) for parsed,trans,op,ver in index]),
-            frozenset(self.extras)
-        )
-        self.__hash = hash(self.hashCmp)
-
-    def __str__(self):
-        specs = ','.join([''.join(s) for s in self.specs])
-        extras = ','.join(self.extras)
-        if extras: extras = '[%s]' % extras
-        return '%s%s%s' % (self.project_name, extras, specs)
-
-    def __eq__(self,other):
-        return isinstance(other,Requirement) and self.hashCmp==other.hashCmp
-
-    def __contains__(self,item):
-        if isinstance(item,Distribution):
-            if item.key != self.key: return False
-            if self.index: item = item.parsed_version  # only get if we need it
-        elif isinstance(item,basestring):
-            item = parse_version(item)
-        last = None
-        compare = lambda a, b: (a > b) - (a < b) # -1, 0, 1
-        for parsed,trans,op,ver in self.index:
-            action = trans[compare(item,parsed)] # Indexing: 0, 1, -1
-            if action=='F':
-                return False
-            elif action=='T':
-                return True
-            elif action=='+':
-                last = True
-            elif action=='-' or last is None:   last = False
-        if last is None: last = True    # no rules encountered
-        return last
-
-    def __hash__(self):
-        return self.__hash
-
-    def __repr__(self): return "Requirement.parse(%r)" % str(self)
-
-    @staticmethod
-    def parse(s):
-        reqs = list(parse_requirements(s))
-        if reqs:
-            if len(reqs)==1:
-                return reqs[0]
-            raise ValueError("Expected only one requirement", s)
-        raise ValueError("No requirements found", s)
-
-state_machine = {
-    #       =><
-    '<': '--T',
-    '<=': 'T-T',
-    '>': 'F+F',
-    '>=': 'T+F',
-    '==': 'T..',
-    '!=': 'F++',
-}
-
-
-def _get_mro(cls):
-    """Get an mro for a type or classic class"""
-    if not isinstance(cls,type):
-        class cls(cls,object): pass
-        return cls.__mro__[1:]
-    return cls.__mro__
-
-def _find_adapter(registry, ob):
-    """Return an adapter factory for `ob` from `registry`"""
-    for t in _get_mro(getattr(ob, '__class__', type(ob))):
-        if t in registry:
-            return registry[t]
-
-
-def ensure_directory(path):
-    """Ensure that the parent directory of `path` exists"""
-    dirname = os.path.dirname(path)
-    if not os.path.isdir(dirname):
-        os.makedirs(dirname)
-
-def split_sections(s):
-    """Split a string or iterable thereof into (section,content) pairs
-
-    Each ``section`` is a stripped version of the section header ("[section]")
-    and each ``content`` is a list of stripped lines excluding blank lines and
-    comment-only lines.  If there are any such lines before the first section
-    header, they're returned in a first ``section`` of ``None``.
-    """
-    section = None
-    content = []
-    for line in yield_lines(s):
-        if line.startswith("["):
-            if line.endswith("]"):
-                if section or content:
-                    yield section, content
-                section = line[1:-1].strip()
-                content = []
-            else:
-                raise ValueError("Invalid section heading", line)
-        else:
-            content.append(line)
-
-    # wrap up last segment
-    yield section, content
-
-def _mkstemp(*args,**kw):
-    from tempfile import mkstemp
-    old_open = os.open
-    try:
-        os.open = os_open   # temporarily bypass sandboxing
-        return mkstemp(*args,**kw)
-    finally:
-        os.open = old_open  # and then put it back
-
-
-# Set up global resource manager (deliberately not state-saved)
-_manager = ResourceManager()
-def _initialize(g):
-    for name in dir(_manager):
-        if not name.startswith('_'):
-            g[name] = getattr(_manager, name)
-_initialize(globals())
-
-# Prepare the master working set and make the ``require()`` API available
-working_set = WorkingSet._build_master()
-_declare_state('object', working_set=working_set)
-
-require = working_set.require
-iter_entry_points = working_set.iter_entry_points
-add_activation_listener = working_set.subscribe
-run_script = working_set.run_script
-run_main = run_script   # backward compatibility
-# Activate all distributions already on sys.path, and ensure that
-# all distributions added to the working set in the future (e.g. by
-# calling ``require()``) will get activated as well.
-add_activation_listener(lambda dist: dist.activate())
-working_set.entries=[]
-list(map(working_set.add_entry,sys.path)) # match order
diff -Nru python-setuptools-3.3/pytest.ini python-setuptools-20.1.1/pytest.ini
--- python-setuptools-3.3/pytest.ini	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/pytest.ini	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,3 @@
+[pytest]
+addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt --ignore scripts/upload-old-releases-as-zip.py
+norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern
diff -Nru python-setuptools-3.3/README.txt python-setuptools-20.1.1/README.txt
--- python-setuptools-3.3/README.txt	2014-03-08 13:37:44.000000000 +0000
+++ python-setuptools-20.1.1/README.txt	2016-02-07 14:25:06.000000000 +0000
@@ -5,6 +5,8 @@
 .. contents:: **Table of Contents**
 
 
+`Change History `_.
+
 -------------------------
 Installation Instructions
 -------------------------
@@ -21,32 +23,33 @@
 The link provided to ez_setup.py is a bookmark to bootstrap script for the
 latest known stable release.
 
-.. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
+.. _ez_setup.py: https://bootstrap.pypa.io/ez_setup.py
 
-Windows 8 (Powershell)
-======================
+Windows (Powershell 3 or later)
+===============================
 
 For best results, uninstall previous versions FIRST (see `Uninstalling`_).
 
-Using Windows 8 or later, it's possible to install with one simple Powershell
-command. Start up Powershell and paste this command::
+Using Windows 8 (which includes PowerShell 3) or earlier versions of Windows
+with PowerShell 3 installed, it's possible to install with one simple
+Powershell command. Start up Powershell and paste this command::
 
-    > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | python -
+    > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python -
 
 You must start the Powershell with Administrative privileges or you may choose
 to install a user-local installation::
 
-    > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | python - --user
+    > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - --user
 
 If you have Python 3.3 or later, you can use the ``py`` command to install to
 different Python versions. For example, to install to Python 3.3 if you have
 Python 2.7 installed::
 
-    > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | py -3 -
+    > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | py -3 -
 
 The recommended way to install setuptools on Windows is to download
-`ez_setup.py`_ and run it. The script will download the appropriate .egg
-file and install it for you.
+`ez_setup.py`_ and run it. The script will download the appropriate
+distribution file and install it for you.
 
 Once installation is complete, you will find an ``easy_install`` program in
 your Python ``Scripts`` subdirectory.  For simple invocation and best results,
@@ -55,11 +58,12 @@
 ``$env:APPDATA\Python\Scripts``.
 
 
-Windows 7 (or graphical install)
-================================
+Windows (simplified)
+====================
 
-For Windows 7 and earlier, download `ez_setup.py`_ using your favorite web
-browser or other technique and "run" that file.
+For Windows without PowerShell 3 or for installation without a command-line,
+download `ez_setup.py`_ using your preferred web browser or other technique
+and "run" that file.
 
 
 Unix (wget)
@@ -70,16 +74,28 @@
 Download `ez_setup.py`_ and run it using the target Python version. The script
 will download the appropriate version and install it for you::
 
-    > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python
+    > wget https://bootstrap.pypa.io/ez_setup.py -O - | python
 
 Note that you will may need to invoke the command with superuser privileges to
 install to the system Python::
 
-    > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | sudo python
+    > wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python
 
 Alternatively, Setuptools may be installed to a user-local path::
 
-    > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python - --user
+    > wget https://bootstrap.pypa.io/ez_setup.py -O - | python - --user
+
+Note that on some older systems (noted on Debian 6 and CentOS 5 installations),
+`wget` may refuse to download `ez_setup.py`, complaining that the certificate common name `*.c.ssl.fastly.net`
+does not match the host name `bootstrap.pypa.io`. In addition, the `ez_setup.py` script may then encounter similar problems using
+`wget` internally to download `setuptools-x.y.zip`, complaining that the certificate common name of `www.python.org` does not match the
+host name `pypi.python.org`. Those are known issues, related to a bug in the older versions of `wget`
+(see `Issue 59 `_). If you happen to encounter them,
+install Setuptools as follows::
+
+    > wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py
+    > python ez_setup.py --insecure
+
 
 Unix including Mac OS X (curl)
 ==============================
@@ -87,7 +103,7 @@
 If your system has curl installed, follow the ``wget`` instructions but
 replace ``wget`` with ``curl`` and ``-O`` with ``-o``. For example::
 
-    > curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -o - | python
+    > curl https://bootstrap.pypa.io/ez_setup.py -o - | python
 
 
 Advanced Installation
@@ -151,7 +167,6 @@
 * `The EasyInstall user's guide and reference manual`_
 * `The setuptools Developer's Guide`_
 * `The pkg_resources API reference`_
-* `Package Compatibility Notes`_ (user-maintained)
 * `The Internal Structure of Python Eggs`_
 
 Questions, comments, and bug reports should be directed to the `distutils-sig
@@ -162,7 +177,6 @@
 the `setuptools bug tracker`_.
 
 .. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/issues
-.. _Package Compatibility Notes: https://pythonhosted.org/setuptools/PackageNotes
 .. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html
 .. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html
 .. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html
@@ -209,3 +223,14 @@
   the Python Packaging Authority (PyPA) and the larger Python community.
 
 .. _files:
+
+
+---------------
+Code of Conduct
+---------------
+
+Everyone interacting in the setuptools project's codebases, issue trackers,
+chat rooms, and mailing lists is expected to follow the
+`PyPA Code of Conduct`_.
+
+.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/
diff -Nru python-setuptools-3.3/release.py python-setuptools-20.1.1/release.py
--- python-setuptools-3.3/release.py	2014-02-12 03:53:21.000000000 +0000
+++ python-setuptools-20.1.1/release.py	2016-02-07 14:25:06.000000000 +0000
@@ -3,28 +3,14 @@
 install jaraco.packaging and run 'python -m jaraco.packaging.release'
 """
 
-import re
 import os
-import subprocess
 
 import pkg_resources
 
 pkg_resources.require('jaraco.packaging>=2.0')
 pkg_resources.require('wheel')
 
-
-def before_upload():
-    _linkify('CHANGES.txt', 'CHANGES (links).txt')
-    BootstrapBookmark.add()
-
-
-def after_push():
-    os.remove('CHANGES (links).txt')
-    BootstrapBookmark.push()
-
-files_with_versions = (
-    'ez_setup.py', 'setuptools/version.py',
-)
+files_with_versions = 'setuptools/version.py',
 
 # bdist_wheel must be included or pip will break
 dist_commands = 'sdist', 'bdist_wheel'
@@ -32,60 +18,3 @@
 test_info = "Travis-CI tests: http://travis-ci.org/#!/jaraco/setuptools"
 
 os.environ["SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES"] = "1"
-
-link_patterns = [
-    r"(Issue )?#(?P\d+)",
-    r"Pull Request ?#(?P\d+)",
-    r"Distribute #(?P\d+)",
-    r"Buildout #(?P\d+)",
-    r"Old Setuptools #(?P\d+)",
-    r"Jython #(?P\d+)",
-    r"Python #(?P\d+)",
-]
-
-issue_urls = dict(
-    pull_request='https://bitbucket.org'
-        '/pypa/setuptools/pull-request/{pull_request}',
-    issue='https://bitbucket.org/pypa/setuptools/issue/{issue}',
-    distribute='https://bitbucket.org/tarek/distribute/issue/{distribute}',
-    buildout='https://github.com/buildout/buildout/issues/{buildout}',
-    old_setuptools='http://bugs.python.org/setuptools/issue{old_setuptools}',
-    jython='http://bugs.jython.org/issue{jython}',
-    python='http://bugs.python.org/issue{python}',
-)
-
-
-def _linkify(source, dest):
-    pattern = '|'.join(link_patterns)
-    with open(source) as source:
-        out = re.sub(pattern, replacer, source.read())
-    with open(dest, 'w') as dest:
-        dest.write(out)
-
-
-def replacer(match):
-    text = match.group(0)
-    match_dict = match.groupdict()
-    for key in match_dict:
-        if match_dict[key]:
-            url = issue_urls[key].format(**match_dict)
-            return "`{text} <{url}>`_".format(text=text, url=url)
-
-class BootstrapBookmark:
-    name = 'bootstrap'
-
-    @classmethod
-    def add(cls):
-        cmd = ['hg', 'bookmark', '-i', cls.name, '-f']
-        subprocess.Popen(cmd)
-
-    @classmethod
-    def push(cls):
-        """
-        Push the bootstrap bookmark
-        """
-        push_command = ['hg', 'push', '-B', cls.name]
-        # don't use check_call here because mercurial will return a non-zero
-        # code even if it succeeds at pushing the bookmark (because there are
-        # no changesets to be pushed). !dm mercurial
-        subprocess.call(push_command)
diff -Nru python-setuptools-3.3/setup.cfg python-setuptools-20.1.1/setup.cfg
--- python-setuptools-3.3/setup.cfg	2014-03-16 09:04:38.000000000 +0000
+++ python-setuptools-20.1.1/setup.cfg	2016-02-12 16:11:11.000000000 +0000
@@ -1,24 +1,25 @@
-[egg_info]
-tag_build = 
-tag_svn_revision = 0
-tag_date = 0
-
-[aliases]
-release = egg_info -RDb ''
-source = register sdist binary
-binary = bdist_egg upload --show-response
-
-[build_sphinx]
-source-dir = docs/
-build-dir = docs/build
-all_files = 1
-
-[upload_docs]
-upload-dir = docs/build/html
-
-[sdist]
-formats = gztar zip
-
-[wheel]
-universal = 1
-
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
+[aliases]
+release = egg_info -RDb ''
+source = register sdist binary
+binary = bdist_egg upload --show-response
+test = pytest
+
+[build_sphinx]
+source-dir = docs/
+build-dir = docs/build
+all_files = 1
+
+[upload_docs]
+upload-dir = docs/build/html
+
+[sdist]
+formats = gztar zip
+
+[wheel]
+universal = 1
+
diff -Nru python-setuptools-3.3/setup.py python-setuptools-20.1.1/setup.py
--- python-setuptools-3.3/setup.py	2014-03-15 12:37:21.000000000 +0000
+++ python-setuptools-20.1.1/setup.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,5 +1,8 @@
 #!/usr/bin/env python
-"""Distutils setup file, used to install or test 'setuptools'"""
+"""
+Distutils setup file, used to install or test 'setuptools'
+"""
+
 import io
 import os
 import sys
@@ -25,8 +28,6 @@
     exec(ver_file.read(), main_ns)
 
 import setuptools
-from setuptools.command.build_py import build_py as _build_py
-from setuptools.command.test import test as _test
 
 scripts = []
 
@@ -47,62 +48,27 @@
 
 console_scripts = list(_gen_console_scripts())
 
-
-# specific command that is used to generate windows .exe files
-class build_py(_build_py):
-    def build_package_data(self):
-        """Copy data files into build directory"""
-        for package, src_dir, build_dir, filenames in self.data_files:
-            for filename in filenames:
-                target = os.path.join(build_dir, filename)
-                self.mkpath(os.path.dirname(target))
-                srcfile = os.path.join(src_dir, filename)
-                outf, copied = self.copy_file(srcfile, target)
-                srcfile = os.path.abspath(srcfile)
-
-class test(_test):
-    """Specific test class to avoid rewriting the entry_points.txt"""
-    def run(self):
-        entry_points = os.path.join('setuptools.egg-info', 'entry_points.txt')
-
-        if not os.path.exists(entry_points):
-            _test.run(self)
-            return # even though _test.run will raise SystemExit
-
-        # save the content
-        with open(entry_points) as f:
-            ep_content = f.read()
-
-        # run the test
-        try:
-            _test.run(self)
-        finally:
-            # restore the file
-            with open(entry_points, 'w') as f:
-                f.write(ep_content)
-
-
 readme_file = io.open('README.txt', encoding='utf-8')
 
-# the release script adds hyperlinks to issues
-if os.path.exists('CHANGES (links).txt'):
-    changes_file = open('CHANGES (links).txt')
-else:
-    # but if the release script has not run, fall back to the source file
-    changes_file = open('CHANGES.txt')
 with readme_file:
-    with changes_file:
-        long_description = readme_file.read() + '\n' + changes_file.read()
+    long_description = readme_file.read()
 
-package_data = {'setuptools': ['site-patch.py']}
+package_data = {
+        'setuptools': ['script (dev).tmpl', 'script.tmpl', 'site-patch.py']}
 force_windows_specific_files = (
     os.environ.get("SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES")
     not in (None, "", "0")
 )
-if sys.platform == 'win32' or force_windows_specific_files:
+if (sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt')) \
+        or force_windows_specific_files:
     package_data.setdefault('setuptools', []).extend(['*.exe'])
     package_data.setdefault('setuptools.command', []).extend(['*.xml'])
 
+needs_pytest = set(['ptr', 'pytest', 'test']).intersection(sys.argv)
+pytest_runner = ['pytest-runner'] if needs_pytest else []
+needs_sphinx = set(['build_sphinx', 'upload_docs']).intersection(sys.argv)
+sphinx = ['sphinx', 'rst.linker'] if needs_sphinx else []
+
 setup_params = dict(
     name="setuptools",
     version=main_ns['__version__'],
@@ -110,21 +76,18 @@
                 "Python packages",
     author="Python Packaging Authority",
     author_email="distutils-sig@python.org",
-    license="PSF or ZPL",
-    long_description = long_description,
-    keywords = "CPAN PyPI distutils eggs package management",
-    url = "https://pypi.python.org/pypi/setuptools",
-    test_suite = 'setuptools.tests',
-    src_root = src_root,
-    packages = setuptools.find_packages(),
-    package_data = package_data,
+    long_description=long_description,
+    keywords="CPAN PyPI distutils eggs package management",
+    url="https://bitbucket.org/pypa/setuptools",
+    src_root=src_root,
+    packages=setuptools.find_packages(exclude=['*.tests']),
+    package_data=package_data,
 
-    py_modules = ['pkg_resources', 'easy_install'],
+    py_modules=['easy_install'],
 
-    zip_safe = True,
+    zip_safe=True,
 
-    cmdclass = {'test': test},
-    entry_points = {
+    entry_points={
         "distutils.commands": [
             "%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals()
             for cmd in SETUP_COMMANDS
@@ -135,6 +98,7 @@
             "extras_require         = setuptools.dist:check_extras",
             "install_requires       = setuptools.dist:check_requirements",
             "tests_require          = setuptools.dist:check_requirements",
+            "setup_requires         = setuptools.dist:check_requirements",
             "entry_points           = setuptools.dist:check_entry_points",
             "test_suite             = setuptools.dist:check_test_suite",
             "zip_safe               = setuptools.dist:assert_bool",
@@ -144,6 +108,7 @@
             "packages               = setuptools.dist:check_packages",
             "dependency_links       = setuptools.dist:assert_string_list",
             "test_loader            = setuptools.dist:check_importable",
+            "test_runner            = 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",
@@ -161,42 +126,42 @@
         ],
         "console_scripts": console_scripts,
 
-        "setuptools.file_finders":
-            ["svn_cvs = setuptools.command.sdist:_default_revctrl"],
-
         "setuptools.installation":
             ['eggsecutable = setuptools.command.easy_install:bootstrap'],
     },
 
 
-    classifiers = textwrap.dedent("""
+    classifiers=textwrap.dedent("""
         Development Status :: 5 - Production/Stable
         Intended Audience :: Developers
-        License :: OSI Approved :: Python Software Foundation License
-        License :: OSI Approved :: Zope Public License
+        License :: OSI Approved :: MIT License
         Operating System :: OS Independent
         Programming Language :: Python :: 2.6
         Programming Language :: Python :: 2.7
         Programming Language :: Python :: 3
-        Programming Language :: Python :: 3.1
-        Programming Language :: Python :: 3.2
         Programming Language :: Python :: 3.3
         Programming Language :: Python :: 3.4
+        Programming Language :: Python :: 3.5
         Topic :: Software Development :: Libraries :: Python Modules
         Topic :: System :: Archiving :: Packaging
         Topic :: System :: Systems Administration
         Topic :: Utilities
         """).strip().splitlines(),
-    extras_require = {
+    extras_require={
         "ssl:sys_platform=='win32'": "wincertstore==0.2",
-        "certs": "certifi==1.0.1",
+        "certs": "certifi==2015.11.20",
     },
-    dependency_links = [
-        'https://pypi.python.org/packages/source/c/certifi/certifi-1.0.1.tar.gz#md5=45f5cb94b8af9e1df0f9450a8f61b790',
+    dependency_links=[
+        'https://pypi.python.org/packages/source/c/certifi/certifi-2015.11.20.tar.gz#md5=25134646672c695c1ff1593c2dd75d08',
         'https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2',
     ],
-    scripts = [],
-    # tests_require = "setuptools[ssl]",
+    scripts=[],
+    tests_require=[
+        'setuptools[ssl]',
+        'pytest>=2.8',
+    ] + (['mock'] if sys.version_info[:2] < (3, 3) else []),
+    setup_requires=[
+    ] + sphinx + pytest_runner,
 )
 
 if __name__ == '__main__':
diff -Nru python-setuptools-3.3/setuptools/archive_util.py python-setuptools-20.1.1/setuptools/archive_util.py
--- python-setuptools-3.3/setuptools/archive_util.py	2014-02-12 03:53:21.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/archive_util.py	2016-02-07 14:25:06.000000000 +0000
@@ -6,42 +6,25 @@
     "UnrecognizedFormat", "extraction_drivers", "unpack_directory",
 ]
 
-import zipfile, tarfile, os, shutil, posixpath
-from pkg_resources import ensure_directory
+import zipfile
+import tarfile
+import os
+import shutil
+import posixpath
+import contextlib
+from pkg_resources import ensure_directory, ContextualZipFile
 from distutils.errors import DistutilsError
 
 class UnrecognizedFormat(DistutilsError):
     """Couldn't recognize the archive type"""
 
 def default_filter(src,dst):
-    """The default progress/filter callback; returns True for all files"""   
+    """The default progress/filter callback; returns True for all files"""
     return dst
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 def unpack_archive(filename, extract_dir, progress_filter=default_filter,
-    drivers=None
-):
+        drivers=None):
     """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
 
     `progress_filter` is a function taking two arguments: a source path
@@ -75,52 +58,33 @@
         )
 
 
-
-
-
-
-
 def unpack_directory(filename, extract_dir, progress_filter=default_filter):
     """"Unpack" a directory, using the same interface as for archives
 
     Raises ``UnrecognizedFormat`` if `filename` is not a directory
     """
     if not os.path.isdir(filename):
-        raise UnrecognizedFormat("%s is not a directory" % (filename,))
+        raise UnrecognizedFormat("%s is not a directory" % filename)
 
-    paths = {filename:('',extract_dir)}
+    paths = {
+        filename: ('', extract_dir),
+    }
     for base, dirs, files in os.walk(filename):
-        src,dst = paths[base]
+        src, dst = paths[base]
         for d in dirs:
-            paths[os.path.join(base,d)] = src+d+'/', os.path.join(dst,d)
+            paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d)
         for f in files:
-            name = src+f
-            target = os.path.join(dst,f)
-            target = progress_filter(src+f, target)
+            target = os.path.join(dst, f)
+            target = progress_filter(src + f, target)
             if not target:
-                continue    # skip non-files
+                # skip non-files
+                continue
             ensure_directory(target)
-            f = os.path.join(base,f)
+            f = os.path.join(base, f)
             shutil.copyfile(f, target)
             shutil.copystat(f, target)
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
     """Unpack zip `filename` to `extract_dir`
 
@@ -132,8 +96,7 @@
     if not zipfile.is_zipfile(filename):
         raise UnrecognizedFormat("%s is not a zip file" % (filename,))
 
-    z = zipfile.ZipFile(filename)
-    try:
+    with ContextualZipFile(filename) as z:
         for info in z.infolist():
             name = info.filename
 
@@ -152,17 +115,11 @@
                 # file
                 ensure_directory(target)
                 data = z.read(info.filename)
-                f = open(target,'wb')
-                try:
+                with open(target, 'wb') as f:
                     f.write(data)
-                finally:
-                    f.close()
-                    del data
             unix_attributes = info.external_attr >> 16
             if unix_attributes:
                 os.chmod(target, unix_attributes)
-    finally:
-        z.close()
 
 
 def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
@@ -178,19 +135,22 @@
         raise UnrecognizedFormat(
             "%s is not a compressed or uncompressed tar file" % (filename,)
         )
-    try:
-        tarobj.chown = lambda *args: None   # don't do any chowning!
+    with contextlib.closing(tarobj):
+        # don't do any chowning!
+        tarobj.chown = lambda *args: None
         for member in tarobj:
             name = member.name
             # don't extract absolute paths or ones with .. in them
             if not name.startswith('/') and '..' not in name.split('/'):
                 prelim_dst = os.path.join(extract_dir, *name.split('/'))
 
-                # resolve any links and to extract the link targets as normal files
+                # resolve any links and to extract the link targets as normal
+                # files
                 while member is not None and (member.islnk() or member.issym()):
                     linkpath = member.linkname
                     if member.issym():
-                        linkpath = posixpath.join(posixpath.dirname(member.name), linkpath)
+                        base = posixpath.dirname(member.name)
+                        linkpath = posixpath.join(base, linkpath)
                         linkpath = posixpath.normpath(linkpath)
                     member = tarobj._getmember(linkpath)
 
@@ -200,11 +160,11 @@
                         if final_dst.endswith(os.sep):
                             final_dst = final_dst[:-1]
                         try:
-                            tarobj._extract_member(member, final_dst)  # XXX Ugh
+                            # XXX Ugh
+                            tarobj._extract_member(member, final_dst)
                         except tarfile.ExtractError:
-                            pass    # chown/chmod/mkfifo/mknode/makedev failed
+                            # chown/chmod/mkfifo/mknode/makedev failed
+                            pass
         return True
-    finally:
-        tarobj.close()
 
 extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
diff -Nru python-setuptools-3.3/setuptools/command/alias.py python-setuptools-20.1.1/setuptools/command/alias.py
--- python-setuptools-3.3/setuptools/command/alias.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/alias.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,11 +1,15 @@
 from distutils.errors import DistutilsOptionError
 
+from setuptools.extern.six.moves import map
+
 from setuptools.command.setopt import edit_config, option_base, config_file
 
+
 def shquote(arg):
     """Quote an argument for later parsing by shlex.split()"""
     for c in '"', "'", "\\", "#":
-        if c in arg: return repr(arg)
+        if c in arg:
+            return repr(arg)
     if arg.split() != [arg]:
         return repr(arg)
     return arg
@@ -18,7 +22,7 @@
     command_consumes_arguments = True
 
     user_options = [
-        ('remove',  'r', 'remove (unset) the alias'),
+        ('remove', 'r', 'remove (unset) the alias'),
     ] + option_base.user_options
 
     boolean_options = option_base.boolean_options + ['remove']
@@ -46,7 +50,7 @@
                 print("setup.py alias", format_alias(alias, aliases))
             return
 
-        elif len(self.args)==1:
+        elif len(self.args) == 1:
             alias, = self.args
             if self.remove:
                 command = None
@@ -58,9 +62,9 @@
                 return
         else:
             alias = self.args[0]
-            command = ' '.join(map(shquote,self.args[1:]))
+            command = ' '.join(map(shquote, self.args[1:]))
 
-        edit_config(self.filename, {'aliases': {alias:command}}, self.dry_run)
+        edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run)
 
 
 def format_alias(name, aliases):
@@ -73,4 +77,4 @@
         source = ''
     else:
         source = '--filename=%r' % source
-    return source+name+' '+command
+    return source + name + ' ' + command
diff -Nru python-setuptools-3.3/setuptools/command/bdist_egg.py python-setuptools-20.1.1/setuptools/command/bdist_egg.py
--- python-setuptools-3.3/setuptools/command/bdist_egg.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/bdist_egg.py	2016-02-07 14:25:06.000000000 +0000
@@ -2,27 +2,34 @@
 
 Build .egg distributions"""
 
-# This module should be kept compatible with Python 2.3
-import sys, os, marshal
-from setuptools import Command
+from distutils.errors import DistutilsSetupError
 from distutils.dir_util import remove_tree, mkpath
+from distutils import log
+from types import CodeType
+import sys
+import os
+import marshal
+import textwrap
+
+from setuptools.extern import six
+
+from pkg_resources import get_build_platform, Distribution, ensure_directory
+from pkg_resources import EntryPoint
+from setuptools.extension import Library
+from setuptools import Command
+
 try:
     # Python 2.7 or >=3.2
     from sysconfig import get_path, get_python_version
+
     def _get_purelib():
         return get_path("purelib")
 except ImportError:
     from distutils.sysconfig import get_python_lib, get_python_version
+
     def _get_purelib():
         return get_python_lib(False)
 
-from distutils import log
-from distutils.errors import DistutilsSetupError
-from pkg_resources import get_build_platform, Distribution, ensure_directory
-from pkg_resources import EntryPoint
-from types import CodeType
-from setuptools.compat import basestring, next
-from setuptools.extension import Library
 
 def strip_module(filename):
     if '.' in filename:
@@ -31,66 +38,45 @@
         filename = filename[:-6]
     return filename
 
-def write_stub(resource, pyfile):
-    f = open(pyfile,'w')
-    f.write('\n'.join([
-        "def __bootstrap__():",
-        "   global __bootstrap__, __loader__, __file__",
-        "   import sys, pkg_resources, imp",
-        "   __file__ = pkg_resources.resource_filename(__name__,%r)"
-            % resource,
-        "   __loader__ = None; del __bootstrap__, __loader__",
-        "   imp.load_dynamic(__name__,__file__)",
-        "__bootstrap__()",
-        "" # terminal \n
-    ]))
-    f.close()
-
 
+def write_stub(resource, pyfile):
+    _stub_template = textwrap.dedent("""
+        def __bootstrap__():
+            global __bootstrap__, __loader__, __file__
+            import sys, pkg_resources, imp
+            __file__ = pkg_resources.resource_filename(__name__, %r)
+            __loader__ = None; del __bootstrap__, __loader__
+            imp.load_dynamic(__name__,__file__)
+        __bootstrap__()
+        """).lstrip()
+    with open(pyfile, 'w') as f:
+        f.write(_stub_template % resource)
 
 
 class bdist_egg(Command):
-
     description = "create an \"egg\" distribution"
 
     user_options = [
         ('bdist-dir=', 'b',
-            "temporary directory for creating the distribution"),
-        ('plat-name=', 'p',
-                     "platform name to embed in generated filenames "
-                     "(default: %s)" % get_build_platform()),
+         "temporary directory for creating the distribution"),
+        ('plat-name=', 'p', "platform name to embed in generated filenames "
+                            "(default: %s)" % get_build_platform()),
         ('exclude-source-files', None,
-                     "remove all .py files from the generated egg"),
+         "remove all .py files from the generated egg"),
         ('keep-temp', 'k',
-                     "keep the pseudo-installation tree around after " +
-                     "creating the distribution archive"),
+         "keep the pseudo-installation tree around after " +
+         "creating the distribution archive"),
         ('dist-dir=', 'd',
-                     "directory to put final built distributions in"),
+         "directory to put final built distributions in"),
         ('skip-build', None,
-                     "skip rebuilding everything (for testing/debugging)"),
+         "skip rebuilding everything (for testing/debugging)"),
     ]
 
     boolean_options = [
         'keep-temp', 'skip-build', 'exclude-source-files'
     ]
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-    def initialize_options (self):
+    def initialize_options(self):
         self.bdist_dir = None
         self.plat_name = None
         self.keep_temp = 0
@@ -99,7 +85,6 @@
         self.egg_output = None
         self.exclude_source_files = None
 
-
     def finalize_options(self):
         ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
         self.egg_info = ei_cmd.egg_info
@@ -111,7 +96,7 @@
         if self.plat_name is None:
             self.plat_name = get_build_platform()
 
-        self.set_undefined_options('bdist',('dist_dir', 'dist_dir'))
+        self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
 
         if self.egg_output is None:
 
@@ -122,32 +107,25 @@
                 self.distribution.has_ext_modules() and self.plat_name
             ).egg_name()
 
-            self.egg_output = os.path.join(self.dist_dir, basename+'.egg')
-
-
-
-
-
-
-
+            self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
 
     def do_install_data(self):
         # Hack for packages that install data to install's --install-lib
         self.get_finalized_command('install').install_lib = self.bdist_dir
 
         site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
-        old, self.distribution.data_files = self.distribution.data_files,[]
+        old, self.distribution.data_files = self.distribution.data_files, []
 
         for item in old:
-            if isinstance(item,tuple) and len(item)==2:
+            if isinstance(item, tuple) and len(item) == 2:
                 if os.path.isabs(item[0]):
                     realpath = os.path.realpath(item[0])
                     normalized = os.path.normcase(realpath)
-                    if normalized==site_packages or normalized.startswith(
-                        site_packages+os.sep
+                    if normalized == site_packages or normalized.startswith(
+                        site_packages + os.sep
                     ):
-                        item = realpath[len(site_packages)+1:], item[1]
-                    # XXX else: raise ???
+                        item = realpath[len(site_packages) + 1:], item[1]
+                        # XXX else: raise ???
             self.distribution.data_files.append(item)
 
         try:
@@ -156,22 +134,19 @@
         finally:
             self.distribution.data_files = old
 
-
     def get_outputs(self):
         return [self.egg_output]
 
-
-    def call_command(self,cmdname,**kw):
+    def call_command(self, cmdname, **kw):
         """Invoke reinitialized command `cmdname` with keyword args"""
         for dirname in INSTALL_DIRECTORY_ATTRS:
-            kw.setdefault(dirname,self.bdist_dir)
-        kw.setdefault('skip_build',self.skip_build)
+            kw.setdefault(dirname, self.bdist_dir)
+        kw.setdefault('skip_build', self.skip_build)
         kw.setdefault('dry_run', self.dry_run)
         cmd = self.reinitialize_command(cmdname, **kw)
         self.run_command(cmdname)
         return cmd
 
-
     def run(self):
         # Generate metadata first
         self.run_command("egg_info")
@@ -179,7 +154,8 @@
         # pull their data path from the install_lib command.
         log.info("installing library code to %s" % self.bdist_dir)
         instcmd = self.get_finalized_command('install')
-        old_root = instcmd.root; instcmd.root = None
+        old_root = instcmd.root
+        instcmd.root = None
         if self.distribution.has_c_libraries() and not self.skip_build:
             self.run_command('build_clib')
         cmd = self.call_command('install_lib', warn_dir=0)
@@ -188,15 +164,16 @@
         all_outputs, ext_outputs = self.get_ext_outputs()
         self.stubs = []
         to_compile = []
-        for (p,ext_name) in enumerate(ext_outputs):
-            filename,ext = os.path.splitext(ext_name)
-            pyfile = os.path.join(self.bdist_dir, strip_module(filename)+'.py')
+        for (p, ext_name) in enumerate(ext_outputs):
+            filename, ext = os.path.splitext(ext_name)
+            pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
+                                  '.py')
             self.stubs.append(pyfile)
             log.info("creating stub loader for %s" % ext_name)
             if not self.dry_run:
                 write_stub(os.path.basename(ext_name), pyfile)
             to_compile.append(pyfile)
-            ext_outputs[p] = ext_name.replace(os.sep,'/')
+            ext_outputs[p] = ext_name.replace(os.sep, '/')
 
         if to_compile:
             cmd.byte_compile(to_compile)
@@ -205,12 +182,13 @@
 
         # Make the EGG-INFO directory
         archive_root = self.bdist_dir
-        egg_info = os.path.join(archive_root,'EGG-INFO')
+        egg_info = os.path.join(archive_root, 'EGG-INFO')
         self.mkpath(egg_info)
         if self.distribution.scripts:
             script_dir = os.path.join(egg_info, 'scripts')
             log.info("installing scripts to %s" % script_dir)
-            self.call_command('install_scripts',install_dir=script_dir,no_ep=1)
+            self.call_command('install_scripts', install_dir=script_dir,
+                              no_ep=1)
 
         self.copy_metadata_to(egg_info)
         native_libs = os.path.join(egg_info, "native_libs.txt")
@@ -228,10 +206,10 @@
                 os.unlink(native_libs)
 
         write_safety_flag(
-            os.path.join(archive_root,'EGG-INFO'), self.zip_safe()
+            os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
         )
 
-        if os.path.exists(os.path.join(self.egg_info,'depends.txt')):
+        if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
             log.warn(
                 "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
                 "Use the install_requires/extras_require setup() args instead."
@@ -242,38 +220,33 @@
 
         # Make the archive
         make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
-                          dry_run=self.dry_run, mode=self.gen_header())
+                     dry_run=self.dry_run, mode=self.gen_header())
         if not self.keep_temp:
             remove_tree(self.bdist_dir, dry_run=self.dry_run)
 
         # Add to 'Distribution.dist_files' so that the "upload" command works
-        getattr(self.distribution,'dist_files',[]).append(
-            ('bdist_egg',get_python_version(),self.egg_output))
-
-
-
+        getattr(self.distribution, 'dist_files', []).append(
+            ('bdist_egg', get_python_version(), self.egg_output))
 
     def zap_pyfiles(self):
         log.info("Removing .py files from temporary directory")
-        for base,dirs,files in walk_egg(self.bdist_dir):
+        for base, dirs, files in walk_egg(self.bdist_dir):
             for name in files:
                 if name.endswith('.py'):
-                    path = os.path.join(base,name)
+                    path = os.path.join(base, name)
                     log.debug("Deleting %s", path)
                     os.unlink(path)
 
     def zip_safe(self):
-        safe = getattr(self.distribution,'zip_safe',None)
+        safe = getattr(self.distribution, 'zip_safe', None)
         if safe is not None:
             return safe
         log.warn("zip_safe flag not set; analyzing archive contents...")
         return analyze_egg(self.bdist_dir, self.stubs)
 
-
-
     def gen_header(self):
         epm = EntryPoint.parse_map(self.distribution.entry_points or '')
-        ep = epm.get('setuptools.installation',{}).get('eggsecutable')
+        ep = epm.get('setuptools.installation', {}).get('eggsecutable')
         if ep is None:
             return 'w'  # not an eggsecutable, do it the usual way.
 
@@ -301,7 +274,6 @@
             '  echo Please rename it back to %(basename)s and try again.\n'
             '  exec false\n'
             'fi\n'
-
         ) % locals()
 
         if not self.dry_run:
@@ -311,13 +283,12 @@
             f.close()
         return 'a'
 
-
     def copy_metadata_to(self, target_dir):
         "Copy metadata (egg info) to the target_dir"
         # normalize the path (so that a forward-slash in egg_info will
         # match using startswith below)
         norm_egg_info = os.path.normpath(self.egg_info)
-        prefix = os.path.join(norm_egg_info,'')
+        prefix = os.path.join(norm_egg_info, '')
         for path in self.ei_cmd.filelist.files:
             if path.startswith(prefix):
                 target = os.path.join(target_dir, path[len(prefix):])
@@ -330,23 +301,24 @@
         all_outputs = []
         ext_outputs = []
 
-        paths = {self.bdist_dir:''}
+        paths = {self.bdist_dir: ''}
         for base, dirs, files in os.walk(self.bdist_dir):
             for filename in files:
                 if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
-                    all_outputs.append(paths[base]+filename)
+                    all_outputs.append(paths[base] + filename)
             for filename in dirs:
-                paths[os.path.join(base,filename)] = paths[base]+filename+'/'
+                paths[os.path.join(base, filename)] = (paths[base] +
+                                                       filename + '/')
 
         if self.distribution.has_ext_modules():
             build_cmd = self.get_finalized_command('build_ext')
             for ext in build_cmd.extensions:
-                if isinstance(ext,Library):
+                if isinstance(ext, Library):
                     continue
                 fullname = build_cmd.get_ext_fullname(ext.name)
                 filename = build_cmd.get_ext_filename(fullname)
                 if not os.path.basename(filename).startswith('dl-'):
-                    if os.path.exists(os.path.join(self.bdist_dir,filename)):
+                    if os.path.exists(os.path.join(self.bdist_dir, filename)):
                         ext_outputs.append(filename)
 
         return all_outputs, ext_outputs
@@ -355,24 +327,24 @@
 NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
 
 
-
-
 def walk_egg(egg_dir):
     """Walk an unpacked egg's contents, skipping the metadata directory"""
     walker = os.walk(egg_dir)
-    base,dirs,files = next(walker)
+    base, dirs, files = next(walker)
     if 'EGG-INFO' in dirs:
         dirs.remove('EGG-INFO')
-    yield base,dirs,files
+    yield base, dirs, files
     for bdf in walker:
         yield bdf
 
+
 def analyze_egg(egg_dir, stubs):
     # check for existing flag in EGG-INFO
-    for flag,fn in safety_flags.items():
-        if os.path.exists(os.path.join(egg_dir,'EGG-INFO',fn)):
+    for flag, fn in safety_flags.items():
+        if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)):
             return flag
-    if not can_scan(): return False
+    if not can_scan():
+        return False
     safe = True
     for base, dirs, files in walk_egg(egg_dir):
         for name in files:
@@ -383,35 +355,42 @@
                 safe = scan_module(egg_dir, base, name, stubs) and safe
     return safe
 
+
 def write_safety_flag(egg_dir, safe):
     # Write or remove zip safety flag file(s)
-    for flag,fn in safety_flags.items():
+    for flag, fn in safety_flags.items():
         fn = os.path.join(egg_dir, fn)
         if os.path.exists(fn):
             if safe is None or bool(safe) != flag:
                 os.unlink(fn)
-        elif safe is not None and bool(safe)==flag:
-            f=open(fn,'wt'); f.write('\n'); f.close()
+        elif safe is not None and bool(safe) == flag:
+            f = open(fn, 'wt')
+            f.write('\n')
+            f.close()
+
 
 safety_flags = {
     True: 'zip-safe',
     False: 'not-zip-safe',
 }
 
+
 def scan_module(egg_dir, base, name, stubs):
     """Check whether module possibly uses unsafe-for-zipfile stuff"""
 
-    filename = os.path.join(base,name)
+    filename = os.path.join(base, name)
     if filename[:-1] in stubs:
-        return True     # Extension module
-    pkg = base[len(egg_dir)+1:].replace(os.sep,'.')
-    module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0]
+        return True  # Extension module
+    pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
+    module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
     if sys.version_info < (3, 3):
-        skip = 8   # skip magic & date
+        skip = 8  # skip magic & date
     else:
         skip = 12  # skip magic & date & file size
-    f = open(filename,'rb'); f.read(skip)
-    code = marshal.load(f); f.close()
+    f = open(filename, 'rb')
+    f.read(skip)
+    code = marshal.load(f)
+    f.close()
     safe = True
     symbols = dict.fromkeys(iter_symbols(code))
     for bad in ['__file__', '__path__']:
@@ -427,22 +406,21 @@
             if bad in symbols:
                 log.warn("%s: module MAY be using inspect.%s", module, bad)
                 safe = False
-    if '__name__' in symbols and '__main__' in symbols and '.' not in module:
-        if sys.version[:3]=="2.4":  # -m works w/zipfiles in 2.5
-            log.warn("%s: top-level module may be 'python -m' script", module)
-            safe = False
     return safe
 
+
 def iter_symbols(code):
     """Yield names and strings used by `code` and its nested code objects"""
-    for name in code.co_names: yield name
+    for name in code.co_names:
+        yield name
     for const in code.co_consts:
-        if isinstance(const,basestring):
+        if isinstance(const, six.string_types):
             yield const
-        elif isinstance(const,CodeType):
+        elif isinstance(const, CodeType):
             for name in iter_symbols(const):
                 yield name
 
+
 def can_scan():
     if not sys.platform.startswith('java') and sys.platform != 'cli':
         # CPython, PyPy, etc.
@@ -451,39 +429,6 @@
     log.warn("Please ask the author to include a 'zip_safe'"
              " setting (either True or False) in the package's setup.py")
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 # Attribute names of options for commands that might need to be convinced to
 # install to the egg build directory
 
@@ -491,9 +436,9 @@
     'install_lib', 'install_dir', 'install_data', 'install_base'
 ]
 
-def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
-    mode='w'
-):
+
+def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True,
+                 mode='w'):
     """Create a zip file from all the files under 'base_dir'.  The output
     zip file will be named 'base_dir' + ".zip".  Uses either the "zipfile"
     Python module (if available) or the InfoZIP "zip" utility (if installed
@@ -501,6 +446,7 @@
     raises DistutilsExecError.  Returns the name of the output zip file.
     """
     import zipfile
+
     mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
     log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
 
@@ -508,15 +454,12 @@
         for name in names:
             path = os.path.normpath(os.path.join(dirname, name))
             if os.path.isfile(path):
-                p = path[len(base_dir)+1:]
+                p = path[len(base_dir) + 1:]
                 if not dry_run:
                     z.write(path, p)
                 log.debug("adding '%s'" % p)
 
-    if compress is None:
-        compress = (sys.version>="2.4") # avoid 2.3 zipimport bug when 64 bits
-
-    compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)]
+    compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED
     if not dry_run:
         z = zipfile.ZipFile(zip_filename, mode, compression=compression)
         for dirname, dirs, files in os.walk(base_dir):
@@ -526,4 +469,3 @@
         for dirname, dirs, files in os.walk(base_dir):
             visit(None, dirname, files)
     return zip_filename
-#
diff -Nru python-setuptools-3.3/setuptools/command/bdist_rpm.py python-setuptools-20.1.1/setuptools/command/bdist_rpm.py
--- python-setuptools-3.3/setuptools/command/bdist_rpm.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/bdist_rpm.py	2016-01-30 17:43:56.000000000 +0000
@@ -1,51 +1,30 @@
-# This is just a kludge so that bdist_rpm doesn't guess wrong about the
-# distribution name and version, if the egg_info command is going to alter
-# them, another kludge to allow you to build old-style non-egg RPMs, and
-# finally, a kludge to track .rpm files for uploading when run on Python <2.5.
-
-from distutils.command.bdist_rpm import bdist_rpm as _bdist_rpm
-import sys, os
-
-class bdist_rpm(_bdist_rpm):
-
-    def initialize_options(self):
-        _bdist_rpm.initialize_options(self)
-        self.no_egg = None
-
-    if sys.version<"2.5":
-        # Track for uploading any .rpm file(s) moved to self.dist_dir
-        def move_file(self, src, dst, level=1):
-            _bdist_rpm.move_file(self, src, dst, level)
-            if dst==self.dist_dir and src.endswith('.rpm'):
-                getattr(self.distribution,'dist_files',[]).append(
-                    ('bdist_rpm',
-                    src.endswith('.src.rpm') and 'any' or sys.version[:3],
-                     os.path.join(dst, os.path.basename(src)))
-                )
-
-    def run(self):
-        self.run_command('egg_info')    # ensure distro name is up-to-date
-        _bdist_rpm.run(self)
-
-
-
-
-
-
-
-
+import distutils.command.bdist_rpm as orig
 
 
+class bdist_rpm(orig.bdist_rpm):
+    """
+    Override the default bdist_rpm behavior to do the following:
+
+    1. Run egg_info to ensure the name and version are properly calculated.
+    2. Always run 'install' using --single-version-externally-managed to
+       disable eggs in RPM distributions.
+    3. Replace dash with underscore in the version numbers for better RPM
+       compatibility.
+    """
 
+    def run(self):
+        # ensure distro name is up-to-date
+        self.run_command('egg_info')
 
+        orig.bdist_rpm.run(self)
 
     def _make_spec_file(self):
         version = self.distribution.get_version()
-        rpmversion = version.replace('-','_')
-        spec = _bdist_rpm._make_spec_file(self)
-        line23 = '%define version '+version
-        line24 = '%define version '+rpmversion
-        spec  = [
+        rpmversion = version.replace('-', '_')
+        spec = orig.bdist_rpm._make_spec_file(self)
+        line23 = '%define version ' + version
+        line24 = '%define version ' + rpmversion
+        spec = [
             line.replace(
                 "Source0: %{name}-%{version}.tar",
                 "Source0: %{name}-%{unmangled_version}.tar"
@@ -55,28 +34,10 @@
             ).replace(
                 "%setup",
                 "%setup -n %{name}-%{unmangled_version}"
-            ).replace(line23,line24)
+            ).replace(line23, line24)
             for line in spec
         ]
-        spec.insert(spec.index(line24)+1, "%define unmangled_version "+version)
+        insert_loc = spec.index(line24) + 1
+        unmangled_version = "%define unmangled_version " + version
+        spec.insert(insert_loc, unmangled_version)
         return spec
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru python-setuptools-3.3/setuptools/command/bdist_wininst.py python-setuptools-20.1.1/setuptools/command/bdist_wininst.py
--- python-setuptools-3.3/setuptools/command/bdist_wininst.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/bdist_wininst.py	2016-01-30 17:43:56.000000000 +0000
@@ -1,6 +1,7 @@
-from distutils.command.bdist_wininst import bdist_wininst as _bdist_wininst
+import distutils.command.bdist_wininst as orig
 
-class bdist_wininst(_bdist_wininst):
+
+class bdist_wininst(orig.bdist_wininst):
     def reinitialize_command(self, command, reinit_subcommands=0):
         """
         Supplement reinitialize_command to work around
@@ -15,6 +16,6 @@
     def run(self):
         self._is_running = True
         try:
-            _bdist_wininst.run(self)
+            orig.bdist_wininst.run(self)
         finally:
             self._is_running = False
diff -Nru python-setuptools-3.3/setuptools/command/build_ext.py python-setuptools-20.1.1/setuptools/command/build_ext.py
--- python-setuptools-3.3/setuptools/command/build_ext.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/build_ext.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,26 +1,30 @@
 from distutils.command.build_ext import build_ext as _du_build_ext
+from distutils.file_util import copy_file
+from distutils.ccompiler import new_compiler
+from distutils.sysconfig import customize_compiler
+from distutils.errors import DistutilsError
+from distutils import log
+import os
+import sys
+import itertools
+
+from setuptools.extension import Library
+
 try:
-    # Attempt to use Pyrex for building extensions, if available
-    from Pyrex.Distutils.build_ext import build_ext as _build_ext
+    # Attempt to use Cython for building extensions, if available
+    from Cython.Distutils.build_ext import build_ext as _build_ext
 except ImportError:
     _build_ext = _du_build_ext
 
-import os
-import sys
-from distutils.file_util import copy_file
-from setuptools.extension import Library
-from distutils.ccompiler import new_compiler
-from distutils.sysconfig import customize_compiler
 try:
     # Python 2.7 or >=3.2
     from sysconfig import _CONFIG_VARS
 except ImportError:
     from distutils.sysconfig import get_config_var
+
     get_config_var("LDSHARED")  # make sure _config_vars is initialized
     del get_config_var
     from distutils.sysconfig import _config_vars as _CONFIG_VARS
-from distutils import log
-from distutils.errors import DistutilsError
 
 have_rtld = False
 use_stubs = False
@@ -30,17 +34,13 @@
     use_stubs = True
 elif os.name != 'nt':
     try:
-        from dl import RTLD_NOW
-        have_rtld = True
-        use_stubs = True
+        import dl
+        use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW')
     except ImportError:
         pass
 
-def if_dl(s):
-    if have_rtld:
-        return s
-    return ''
 
+if_dl = lambda s: s if have_rtld else ''
 
 class build_ext(_build_ext):
     def run(self):
@@ -59,8 +59,9 @@
             modpath = fullname.split('.')
             package = '.'.join(modpath[:-1])
             package_dir = build_py.get_package_dir(package)
-            dest_filename = os.path.join(package_dir,os.path.basename(filename))
-            src_filename = os.path.join(self.build_lib,filename)
+            dest_filename = os.path.join(package_dir,
+                                         os.path.basename(filename))
+            src_filename = os.path.join(self.build_lib, filename)
 
             # Always copy, even if source is older than destination, to ensure
             # that the right extensions for the current Python/platform are
@@ -72,24 +73,16 @@
             if ext._needs_stub:
                 self.write_stub(package_dir or os.curdir, ext, True)
 
-    if _build_ext is not _du_build_ext and not hasattr(_build_ext,'pyrex_sources'):
-        # Workaround for problems using some Pyrex versions w/SWIG and/or 2.4
-        def swig_sources(self, sources, *otherargs):
-            # first do any Pyrex processing
-            sources = _build_ext.swig_sources(self, sources) or sources
-            # Then do any actual SWIG stuff on the remainder
-            return _du_build_ext.swig_sources(self, sources, *otherargs)
-
     def get_ext_filename(self, fullname):
-        filename = _build_ext.get_ext_filename(self,fullname)
+        filename = _build_ext.get_ext_filename(self, fullname)
         if fullname in self.ext_map:
             ext = self.ext_map[fullname]
-            if isinstance(ext,Library):
+            if isinstance(ext, Library):
                 fn, ext = os.path.splitext(filename)
-                return self.shlib_compiler.library_filename(fn,libtype)
+                return self.shlib_compiler.library_filename(fn, libtype)
             elif use_stubs and ext._links_to_dynamic:
-                d,fn = os.path.split(filename)
-                return os.path.join(d,'dl-'+fn)
+                d, fn = os.path.split(filename)
+                return os.path.join(d, 'dl-' + fn)
         return filename
 
     def initialize_options(self):
@@ -103,7 +96,7 @@
         self.extensions = self.extensions or []
         self.check_extensions_list(self.extensions)
         self.shlibs = [ext for ext in self.extensions
-            if isinstance(ext, Library)]
+                       if isinstance(ext, Library)]
         if self.shlibs:
             self.setup_shlib_compiler()
         for ext in self.extensions:
@@ -116,11 +109,12 @@
             # XXX what to do with conflicts?
             self.ext_map[fullname.split('.')[-1]] = ext
 
-            ltd = ext._links_to_dynamic = \
-                self.shlibs and self.links_to_dynamic(ext) or False
-            ext._needs_stub = ltd and use_stubs and not isinstance(ext,Library)
+            ltd = self.shlibs and self.links_to_dynamic(ext) or False
+            ns = ltd and use_stubs and not isinstance(ext, Library)
+            ext._links_to_dynamic = ltd
+            ext._needs_stub = ns
             filename = ext._file_name = self.get_ext_filename(fullname)
-            libdir = os.path.dirname(os.path.join(self.build_lib,filename))
+            libdir = os.path.dirname(os.path.join(self.build_lib, filename))
             if ltd and libdir not in ext.library_dirs:
                 ext.library_dirs.append(libdir)
             if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
@@ -134,7 +128,8 @@
             tmp = _CONFIG_VARS.copy()
             try:
                 # XXX Help!  I don't have any idea whether these are right...
-                _CONFIG_VARS['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup"
+                _CONFIG_VARS['LDSHARED'] = (
+                    "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
                 _CONFIG_VARS['CCSHARED'] = " -dynamiclib"
                 _CONFIG_VARS['SO'] = ".dylib"
                 customize_compiler(compiler)
@@ -148,7 +143,7 @@
             compiler.set_include_dirs(self.include_dirs)
         if self.define is not None:
             # 'define' option is a list of (name,value) tuples
-            for (name,value) in self.define:
+            for (name, value) in self.define:
                 compiler.define_macro(name, value)
         if self.undef is not None:
             for macro in self.undef:
@@ -166,20 +161,20 @@
         compiler.link_shared_object = link_shared_object.__get__(compiler)
 
     def get_export_symbols(self, ext):
-        if isinstance(ext,Library):
+        if isinstance(ext, Library):
             return ext.export_symbols
-        return _build_ext.get_export_symbols(self,ext)
+        return _build_ext.get_export_symbols(self, ext)
 
     def build_extension(self, ext):
+        ext._convert_pyx_sources_to_lang()
         _compiler = self.compiler
         try:
-            if isinstance(ext,Library):
+            if isinstance(ext, Library):
                 self.compiler = self.shlib_compiler
-            _build_ext.build_extension(self,ext)
+            _build_ext.build_extension(self, ext)
             if ext._needs_stub:
-                self.write_stub(
-                    self.get_finalized_command('build_py').build_lib, ext
-                )
+                cmd = self.get_finalized_command('build_py').build_lib
+                self.write_stub(cmd, ext)
         finally:
             self.compiler = _compiler
 
@@ -189,37 +184,46 @@
         # XXX as dynamic, and not just using a locally-found version or a
         # XXX static-compiled version
         libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
-        pkg = '.'.join(ext._full_name.split('.')[:-1]+[''])
-        for libname in ext.libraries:
-            if pkg+libname in libnames: return True
-        return False
+        pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
+        return any(pkg + libname in libnames for libname in ext.libraries)
 
     def get_outputs(self):
-        outputs = _build_ext.get_outputs(self)
-        optimize = self.get_finalized_command('build_py').optimize
-        for ext in self.extensions:
-            if ext._needs_stub:
-                base = os.path.join(self.build_lib, *ext._full_name.split('.'))
-                outputs.append(base+'.py')
-                outputs.append(base+'.pyc')
-                if optimize:
-                    outputs.append(base+'.pyo')
-        return outputs
+        return _build_ext.get_outputs(self) + self.__get_stubs_outputs()
+
+    def __get_stubs_outputs(self):
+        # assemble the base name for each extension that needs a stub
+        ns_ext_bases = (
+            os.path.join(self.build_lib, *ext._full_name.split('.'))
+            for ext in self.extensions
+            if ext._needs_stub
+        )
+        # pair each base with the extension
+        pairs = itertools.product(ns_ext_bases, self.__get_output_extensions())
+        return list(base + fnext for base, fnext in pairs)
+
+    def __get_output_extensions(self):
+        yield '.py'
+        yield '.pyc'
+        if self.get_finalized_command('build_py').optimize:
+            yield '.pyo'
 
     def write_stub(self, output_dir, ext, compile=False):
-        log.info("writing stub loader for %s to %s",ext._full_name, output_dir)
-        stub_file = os.path.join(output_dir, *ext._full_name.split('.'))+'.py'
+        log.info("writing stub loader for %s to %s", ext._full_name,
+                 output_dir)
+        stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +
+                     '.py')
         if compile and os.path.exists(stub_file):
-            raise DistutilsError(stub_file+" already exists! Please delete.")
+            raise DistutilsError(stub_file + " already exists! Please delete.")
         if not self.dry_run:
-            f = open(stub_file,'w')
+            f = open(stub_file, 'w')
             f.write(
                 '\n'.join([
                     "def __bootstrap__():",
                     "   global __bootstrap__, __file__, __loader__",
-                    "   import sys, os, pkg_resources, imp"+if_dl(", dl"),
-                    "   __file__ = pkg_resources.resource_filename(__name__,%r)"
-                        % os.path.basename(ext._file_name),
+                    "   import sys, os, pkg_resources, imp" + if_dl(", dl"),
+                    "   __file__ = pkg_resources.resource_filename"
+                    "(__name__,%r)"
+                    % os.path.basename(ext._file_name),
                     "   del __bootstrap__",
                     "   if '__loader__' in globals():",
                     "       del __loader__",
@@ -233,12 +237,13 @@
                     if_dl("     sys.setdlopenflags(old_flags)"),
                     "     os.chdir(old_dir)",
                     "__bootstrap__()",
-                    "" # terminal \n
+                    ""  # terminal \n
                 ])
             )
             f.close()
         if compile:
             from distutils.util import byte_compile
+
             byte_compile([stub_file], optimize=0,
                          force=True, dry_run=self.dry_run)
             optimize = self.get_finalized_command('install_lib').optimize
@@ -249,13 +254,14 @@
                 os.unlink(stub_file)
 
 
-if use_stubs or os.name=='nt':
+if use_stubs or os.name == 'nt':
     # Build shared libraries
     #
-    def link_shared_object(self, objects, output_libname, output_dir=None,
-            libraries=None, library_dirs=None, runtime_library_dirs=None,
-            export_symbols=None, debug=0, extra_preargs=None,
-            extra_postargs=None, build_temp=None, target_lang=None):
+    def link_shared_object(
+            self, objects, output_libname, output_dir=None, libraries=None,
+            library_dirs=None, runtime_library_dirs=None, export_symbols=None,
+            debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
+            target_lang=None):
         self.link(
             self.SHARED_LIBRARY, objects, output_libname,
             output_dir, libraries, library_dirs, runtime_library_dirs,
@@ -266,18 +272,19 @@
     # Build static libraries everywhere else
     libtype = 'static'
 
-    def link_shared_object(self, objects, output_libname, output_dir=None,
-            libraries=None, library_dirs=None, runtime_library_dirs=None,
-            export_symbols=None, debug=0, extra_preargs=None,
-            extra_postargs=None, build_temp=None, target_lang=None):
+    def link_shared_object(
+            self, objects, output_libname, output_dir=None, libraries=None,
+            library_dirs=None, runtime_library_dirs=None, export_symbols=None,
+            debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
+            target_lang=None):
         # XXX we need to either disallow these attrs on Library instances,
-        #     or warn/abort here if set, or something...
-        #libraries=None, library_dirs=None, runtime_library_dirs=None,
-        #export_symbols=None, extra_preargs=None, extra_postargs=None,
-        #build_temp=None
+        # or warn/abort here if set, or something...
+        # libraries=None, library_dirs=None, runtime_library_dirs=None,
+        # export_symbols=None, extra_preargs=None, extra_postargs=None,
+        # build_temp=None
 
-        assert output_dir is None   # distutils build_ext doesn't pass this
-        output_dir,filename = os.path.split(output_libname)
+        assert output_dir is None  # distutils build_ext doesn't pass this
+        output_dir, filename = os.path.split(output_libname)
         basename, ext = os.path.splitext(filename)
         if self.library_filename("x").startswith('lib'):
             # strip 'lib' prefix; this is kludgy if some platform uses
diff -Nru python-setuptools-3.3/setuptools/command/build_py.py python-setuptools-20.1.1/setuptools/command/build_py.py
--- python-setuptools-3.3/setuptools/command/build_py.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/build_py.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,10 +1,15 @@
+from glob import glob
+from distutils.util import convert_path
+import distutils.command.build_py as orig
 import os
-import sys
 import fnmatch
 import textwrap
-from distutils.command.build_py import build_py as _build_py
-from distutils.util import convert_path
-from glob import glob
+import io
+import distutils.errors
+import collections
+import itertools
+
+from setuptools.extern.six.moves import map
 
 try:
     from setuptools.lib2to3_ex import Mixin2to3
@@ -13,7 +18,8 @@
         def run_2to3(self, files, doctests=True):
             "do nothing"
 
-class build_py(_build_py, Mixin2to3):
+
+class build_py(orig.build_py, Mixin2to3):
     """Enhanced 'build_py' command that includes data files with packages
 
     The data files are specified via a 'package_data' argument to 'setup()'.
@@ -22,11 +28,14 @@
     Also, this version of the 'build_py' command allows you to specify both
     'py_modules' and 'packages' in the same setup operation.
     """
+
     def finalize_options(self):
-        _build_py.finalize_options(self)
+        orig.build_py.finalize_options(self)
         self.package_data = self.distribution.package_data
-        self.exclude_package_data = self.distribution.exclude_package_data or {}
-        if 'data_files' in self.__dict__: del self.__dict__['data_files']
+        self.exclude_package_data = (self.distribution.exclude_package_data or
+                                     {})
+        if 'data_files' in self.__dict__:
+            del self.__dict__['data_files']
         self.__updated_files = []
         self.__doctests_2to3 = []
 
@@ -48,16 +57,18 @@
 
         # Only compile actual .py files, using our base class' idea of what our
         # output files are.
-        self.byte_compile(_build_py.get_outputs(self, include_bytecode=0))
+        self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
 
     def __getattr__(self, attr):
-        if attr=='data_files':  # lazily compute data files
-            self.data_files = files = self._get_data_files()
-            return files
-        return _build_py.__getattr__(self,attr)
+        "lazily compute data files"
+        if attr == 'data_files':
+            self.data_files = self._get_data_files()
+            return self.data_files
+        return orig.build_py.__getattr__(self, attr)
 
     def build_module(self, module, module_file, package):
-        outfile, copied = _build_py.build_module(self, module, module_file, package)
+        outfile, copied = orig.build_py.build_module(self, module, module_file,
+                                                     package)
         if copied:
             self.__updated_files.append(outfile)
         return outfile, copied
@@ -65,23 +76,21 @@
     def _get_data_files(self):
         """Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
         self.analyze_manifest()
-        data = []
-        for package in self.packages or ():
-            # Locate package source directory
-            src_dir = self.get_package_dir(package)
-
-            # Compute package build directory
-            build_dir = os.path.join(*([self.build_lib] + package.split('.')))
+        return list(map(self._get_pkg_data_files, self.packages or ()))
 
-            # Length of path to strip from found files
-            plen = len(src_dir)+1
-
-            # Strip directory from globbed filenames
-            filenames = [
-                file[plen:] for file in self.find_data_files(package, src_dir)
-                ]
-            data.append((package, src_dir, build_dir, filenames))
-        return data
+    def _get_pkg_data_files(self, package):
+        # Locate package source directory
+        src_dir = self.get_package_dir(package)
+
+        # Compute package build directory
+        build_dir = os.path.join(*([self.build_lib] + package.split('.')))
+
+        # Strip directory from globbed filenames
+        filenames = [
+            os.path.relpath(file, src_dir)
+            for file in self.find_data_files(package, src_dir)
+        ]
+        return package, src_dir, build_dir, filenames
 
     def find_data_files(self, package, src_dir):
         """Return filenames for package's data files in 'src_dir'"""
@@ -102,7 +111,8 @@
                 srcfile = os.path.join(src_dir, filename)
                 outf, copied = self.copy_file(srcfile, target)
                 srcfile = os.path.abspath(srcfile)
-                if copied and srcfile in self.distribution.convert_2to3_doctests:
+                if (copied and
+                        srcfile in self.distribution.convert_2to3_doctests):
                     self.__doctests_2to3.append(outf)
 
     def analyze_manifest(self):
@@ -117,34 +127,20 @@
         self.run_command('egg_info')
         ei_cmd = self.get_finalized_command('egg_info')
         for path in ei_cmd.filelist.files:
-            d,f = os.path.split(assert_relative(path))
+            d, f = os.path.split(assert_relative(path))
             prev = None
             oldf = f
-            while d and d!=prev and d not in src_dirs:
+            while d and d != prev and d not in src_dirs:
                 prev = d
                 d, df = os.path.split(d)
                 f = os.path.join(df, f)
             if d in src_dirs:
-                if path.endswith('.py') and f==oldf:
-                    continue    # it's a module, not data
-                mf.setdefault(src_dirs[d],[]).append(path)
-
-    def get_data_files(self): pass  # kludge 2.4 for lazy computation
-
-    if sys.version<"2.4":    # Python 2.4 already has this code
-        def get_outputs(self, include_bytecode=1):
-            """Return complete list of files copied to the build directory
-
-            This includes both '.py' files and data files, as well as '.pyc'
-            and '.pyo' files if 'include_bytecode' is true.  (This method is
-            needed for the 'install_lib' command to do its job properly, and to
-            generate a correct installation manifest.)
-            """
-            return _build_py.get_outputs(self, include_bytecode) + [
-                os.path.join(build_dir, filename)
-                for package, src_dir, build_dir,filenames in self.data_files
-                for filename in filenames
-                ]
+                if path.endswith('.py') and f == oldf:
+                    continue  # it's a module, not data
+                mf.setdefault(src_dirs[d], []).append(path)
+
+    def get_data_files(self):
+        pass  # Lazily compute data files in _get_data_files() function.
 
     def check_package(self, package, package_dir):
         """Check namespace packages' __init__ for declare_namespace"""
@@ -153,56 +149,60 @@
         except KeyError:
             pass
 
-        init_py = _build_py.check_package(self, package, package_dir)
+        init_py = orig.build_py.check_package(self, package, package_dir)
         self.packages_checked[package] = init_py
 
         if not init_py or not self.distribution.namespace_packages:
             return init_py
 
         for pkg in self.distribution.namespace_packages:
-            if pkg==package or pkg.startswith(package+'.'):
+            if pkg == package or pkg.startswith(package + '.'):
                 break
         else:
             return init_py
 
-        f = open(init_py,'rbU')
-        if 'declare_namespace'.encode() not in f.read():
-            from distutils.errors import DistutilsError
-            raise DistutilsError(
-                "Namespace package problem: %s is a namespace package, but its\n"
-                "__init__.py does not call declare_namespace()! Please fix it.\n"
-                '(See the setuptools manual under "Namespace Packages" for '
-                "details.)\n" % (package,)
+        with io.open(init_py, 'rb') as f:
+            contents = f.read()
+        if b'declare_namespace' not in contents:
+            raise distutils.errors.DistutilsError(
+                "Namespace package problem: %s is a namespace package, but "
+                "its\n__init__.py does not call declare_namespace()! Please "
+                'fix it.\n(See the setuptools manual under '
+                '"Namespace Packages" for details.)\n"' % (package,)
             )
-        f.close()
         return init_py
 
     def initialize_options(self):
-        self.packages_checked={}
-        _build_py.initialize_options(self)
+        self.packages_checked = {}
+        orig.build_py.initialize_options(self)
 
     def get_package_dir(self, package):
-        res = _build_py.get_package_dir(self, package)
+        res = orig.build_py.get_package_dir(self, package)
         if self.distribution.src_root is not None:
             return os.path.join(self.distribution.src_root, res)
         return res
 
     def exclude_data_files(self, package, src_dir, files):
         """Filter filenames for package's data files in 'src_dir'"""
-        globs = (self.exclude_package_data.get('', [])
-                 + self.exclude_package_data.get(package, []))
-        bad = []
-        for pattern in globs:
-            bad.extend(
-                fnmatch.filter(
-                    files, os.path.join(src_dir, convert_path(pattern))
-                )
+        globs = (
+            self.exclude_package_data.get('', [])
+            + self.exclude_package_data.get(package, [])
+        )
+        bad = set(
+            item
+            for pattern in globs
+            for item in fnmatch.filter(
+                files,
+                os.path.join(src_dir, convert_path(pattern)),
             )
-        bad = dict.fromkeys(bad)
-        seen = {}
+        )
+        seen = collections.defaultdict(itertools.count)
         return [
-            f for f in files if f not in bad
-                and f not in seen and seen.setdefault(f,1)  # ditch dupes
+            fn
+            for fn in files
+            if fn not in bad
+            # ditch dupes
+            and not next(seen[fn])
         ]
 
 
@@ -210,6 +210,7 @@
     if not os.path.isabs(path):
         return path
     from distutils.errors import DistutilsSetupError
+
     msg = textwrap.dedent("""
         Error: setup script specifies an absolute path:
 
diff -Nru python-setuptools-3.3/setuptools/command/develop.py python-setuptools-20.1.1/setuptools/command/develop.py
--- python-setuptools-3.3/setuptools/command/develop.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/develop.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,9 +1,16 @@
-from setuptools.command.easy_install import easy_install
-from distutils.util import convert_path, subst_vars
-from pkg_resources import Distribution, PathMetadata, normalize_path
+from distutils.util import convert_path
 from distutils import log
 from distutils.errors import DistutilsError, DistutilsOptionError
-import os, sys, setuptools, glob
+import os
+import glob
+import io
+
+from setuptools.extern import six
+
+from pkg_resources import Distribution, PathMetadata, normalize_path
+from setuptools.command.easy_install import easy_install
+import setuptools
+
 
 class develop(easy_install):
     """Set up package for development"""
@@ -32,59 +39,56 @@
         self.egg_path = None
         easy_install.initialize_options(self)
         self.setup_path = None
-        self.always_copy_from = '.'   # always copy eggs installed in curdir
-
-
+        self.always_copy_from = '.'  # always copy eggs installed in curdir
 
     def finalize_options(self):
         ei = self.get_finalized_command("egg_info")
         if ei.broken_egg_info:
-            raise DistutilsError(
-            "Please rename %r to %r before using 'develop'"
-            % (ei.egg_info, ei.broken_egg_info)
-            )
+            template = "Please rename %r to %r before using 'develop'"
+            args = ei.egg_info, ei.broken_egg_info
+            raise DistutilsError(template % args)
         self.args = [ei.egg_name]
 
-
-
-
         easy_install.finalize_options(self)
         self.expand_basedirs()
         self.expand_dirs()
         # pick up setup-dir .egg files only: no .egg-info
         self.package_index.scan(glob.glob('*.egg'))
 
-        self.egg_link = os.path.join(self.install_dir, ei.egg_name+'.egg-link')
+        egg_link_fn = ei.egg_name + '.egg-link'
+        self.egg_link = os.path.join(self.install_dir, egg_link_fn)
         self.egg_base = ei.egg_base
         if self.egg_path is None:
             self.egg_path = os.path.abspath(ei.egg_base)
 
         target = normalize_path(self.egg_base)
-        if normalize_path(os.path.join(self.install_dir, self.egg_path)) != target:
+        egg_path = normalize_path(os.path.join(self.install_dir,
+                                               self.egg_path))
+        if egg_path != target:
             raise DistutilsOptionError(
                 "--egg-path must be a relative path from the install"
-                " directory to "+target
-        )
+                " directory to " + target
+            )
 
         # Make a distribution for the package's source
         self.dist = Distribution(
             target,
             PathMetadata(target, os.path.abspath(ei.egg_info)),
-            project_name = ei.egg_name
+            project_name=ei.egg_name
         )
 
-        p = self.egg_base.replace(os.sep,'/')
-        if p!= os.curdir:
-            p = '../' * (p.count('/')+1)
+        p = self.egg_base.replace(os.sep, '/')
+        if p != os.curdir:
+            p = '../' * (p.count('/') + 1)
         self.setup_path = p
         p = normalize_path(os.path.join(self.install_dir, self.egg_path, p))
-        if  p != normalize_path(os.curdir):
+        if p != normalize_path(os.curdir):
             raise DistutilsOptionError(
                 "Can't get a consistent path to setup script from"
                 " installation directory", p, normalize_path(os.curdir))
 
     def install_for_development(self):
-        if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
+        if six.PY3 and getattr(self.distribution, 'use_2to3', False):
             # If we run 2to3 we can not do this inplace:
 
             # Ensure metadata is up-to-date
@@ -99,12 +103,13 @@
 
             self.reinitialize_command('build_ext', inplace=0)
             self.run_command('build_ext')
-            
+
             # Fixup egg-link and easy-install.pth
             ei_cmd = self.get_finalized_command("egg_info")
             self.egg_path = build_path
             self.dist.location = build_path
-            self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info)    # XXX
+            # XXX
+            self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info)
         else:
             # Without 2to3 inplace works fine:
             self.run_command('egg_info')
@@ -112,7 +117,7 @@
             # Build extensions in-place
             self.reinitialize_command('build_ext', inplace=1)
             self.run_command('build_ext')
-        
+
         self.install_site_py()  # ensure that target dir is site-safe
         if setuptools.bootstrap_install_from:
             self.easy_install(setuptools.bootstrap_install_from)
@@ -121,21 +126,20 @@
         # create an .egg-link in the installation dir, pointing to our egg
         log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
         if not self.dry_run:
-            f = open(self.egg_link,"w")
-            f.write(self.egg_path + "\n" + self.setup_path)
-            f.close()
+            with open(self.egg_link, "w") as f:
+                f.write(self.egg_path + "\n" + self.setup_path)
         # postprocess the installed distro, fixing up .pth, installing scripts,
         # and handling requirements
         self.process_distribution(None, self.dist, not self.no_deps)
 
-
     def uninstall_link(self):
         if os.path.exists(self.egg_link):
             log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
             egg_link_file = open(self.egg_link)
             contents = [line.rstrip() for line in egg_link_file]
             egg_link_file.close()
-            if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
+            if contents not in ([self.egg_path],
+                                [self.egg_path, self.setup_path]):
                 log.warn("Link points to %s: uninstall aborted", contents)
                 return
             if not self.dry_run:
@@ -149,7 +153,7 @@
     def install_egg_scripts(self, dist):
         if dist is not self.dist:
             # Installing a dependency, so fall back to normal behavior
-            return easy_install.install_egg_scripts(self,dist)
+            return easy_install.install_egg_scripts(self, dist)
 
         # create wrapper scripts in the script dir, pointing to dist.scripts
 
@@ -160,8 +164,33 @@
         for script_name in self.distribution.scripts or []:
             script_path = os.path.abspath(convert_path(script_name))
             script_name = os.path.basename(script_path)
-            f = open(script_path,'rU')
-            script_text = f.read()
-            f.close()
+            with io.open(script_path) as strm:
+                script_text = strm.read()
             self.install_script(dist, script_name, script_text, script_path)
 
+    def install_wrapper_scripts(self, dist):
+        dist = VersionlessRequirement(dist)
+        return easy_install.install_wrapper_scripts(self, dist)
+
+
+class VersionlessRequirement(object):
+    """
+    Adapt a pkg_resources.Distribution to simply return the project
+    name as the 'requirement' so that scripts will work across
+    multiple versions.
+
+    >>> dist = Distribution(project_name='foo', version='1.0')
+    >>> str(dist.as_requirement())
+    'foo==1.0'
+    >>> adapted_dist = VersionlessRequirement(dist)
+    >>> str(adapted_dist.as_requirement())
+    'foo'
+    """
+    def __init__(self, dist):
+        self.__dist = dist
+
+    def __getattr__(self, name):
+        return getattr(self.__dist, name)
+
+    def as_requirement(self):
+        return self.project_name
diff -Nru python-setuptools-3.3/setuptools/command/easy_install.py python-setuptools-20.1.1/setuptools/command/easy_install.py
--- python-setuptools-3.3/setuptools/command/easy_install.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/easy_install.py	2016-02-08 20:07:52.000000000 +0000
@@ -12,6 +12,15 @@
 
 """
 
+from glob import glob
+from distutils.util import get_platform
+from distutils.util import convert_path, subst_vars
+from distutils.errors import DistutilsArgError, DistutilsOptionError, \
+    DistutilsError, DistutilsPlatformError
+from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
+from distutils import log, dir_util
+from distutils.command.build_scripts import first_line_re
+from distutils.spawn import find_executable
 import sys
 import os
 import zipimport
@@ -26,44 +35,44 @@
 import warnings
 import site
 import struct
-from glob import glob
-from distutils import log, dir_util
+import contextlib
+import subprocess
+import shlex
+import io
 
-import pkg_resources
-from setuptools import Command, _dont_write_bytecode
+from setuptools.extern import six
+from setuptools.extern.six.moves import configparser, map
+
+from setuptools import Command
 from setuptools.sandbox import run_setup
 from setuptools.py31compat import get_path, get_config_vars
-
-from distutils.util import get_platform
-from distutils.util import convert_path, subst_vars
-from distutils.errors import DistutilsArgError, DistutilsOptionError, \
-    DistutilsError, DistutilsPlatformError
-from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
 from setuptools.command import setopt
 from setuptools.archive_util import unpack_archive
 from setuptools.package_index import PackageIndex
 from setuptools.package_index import URL_SCHEME
 from setuptools.command import bdist_egg, egg_info
-from setuptools.compat import (iteritems, maxsize, basestring, unicode,
-                               reraise)
 from pkg_resources import (
     yield_lines, normalize_path, resource_string, ensure_directory,
     get_distribution, find_distributions, Environment, Requirement,
     Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
     VersionConflict, DEVELOP_DIST,
 )
+import pkg_resources
+
+# Turn on PEP440Warnings
+warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
 
-sys_executable = os.environ.get('__PYVENV_LAUNCHER__',
-    os.path.normpath(sys.executable))
 
 __all__ = [
     'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
     'main', 'get_exe_prefixes',
 ]
 
+
 def is_64bit():
     return struct.calcsize("P") == 8
 
+
 def samefile(p1, p2):
     both_exist = os.path.exists(p1) and os.path.exists(p2)
     use_samefile = hasattr(os.path, 'samefile') and both_exist
@@ -73,18 +82,21 @@
     norm_p2 = os.path.normpath(os.path.normcase(p2))
     return norm_p1 == norm_p2
 
-if sys.version_info <= (3,):
+
+if six.PY2:
     def _to_ascii(s):
         return s
+
     def isascii(s):
         try:
-            unicode(s, 'ascii')
+            six.text_type(s, 'ascii')
             return True
         except UnicodeError:
             return False
 else:
     def _to_ascii(s):
         return s.encode('ascii')
+
     def isascii(s):
         try:
             s.encode('ascii')
@@ -92,6 +104,7 @@
         except UnicodeError:
             return False
 
+
 class easy_install(Command):
     """Manage a download/build/install process"""
     description = "Find/get/install Python packages"
@@ -109,22 +122,22 @@
         ("index-url=", "i", "base URL of Python Package Index"),
         ("find-links=", "f", "additional URL(s) to search for packages"),
         ("build-directory=", "b",
-            "download/extract/build in DIR; keep the results"),
+         "download/extract/build in DIR; keep the results"),
         ('optimize=', 'O',
-            "also compile with optimization: -O1 for \"python -O\", "
-            "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
+         "also compile with optimization: -O1 for \"python -O\", "
+         "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
         ('record=', None,
-            "filename in which to record list of installed files"),
+         "filename in which to record list of installed files"),
         ('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
-        ('site-dirs=','S',"list of directories where .pth files work"),
+        ('site-dirs=', 'S', "list of directories where .pth files work"),
         ('editable', 'e', "Install specified packages in editable form"),
         ('no-deps', 'N', "don't install dependencies"),
         ('allow-hosts=', 'H', "pattern(s) that hostnames must match"),
         ('local-snapshots-ok', 'l',
-            "allow building eggs from local checkouts"),
+         "allow building eggs from local checkouts"),
         ('version', None, "print version information and exit"),
         ('no-find-links', None,
-            "Don't load find-links defined in packages being installed")
+         "Don't load find-links defined in packages being installed")
     ]
     boolean_options = [
         'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
@@ -141,12 +154,9 @@
     create_index = PackageIndex
 
     def initialize_options(self):
-        if site.ENABLE_USER_SITE:
-            whereami = os.path.abspath(__file__)
-            self.user = whereami.startswith(site.USER_SITE)
-        else:
-            self.user = 0
-
+        # the --user option seems to be an opt-in one,
+        # so the default should be False.
+        self.user = 0
         self.zip_ok = self.local_snapshots_ok = None
         self.install_dir = self.script_dir = self.exclude_scripts = None
         self.index_url = None
@@ -158,10 +168,10 @@
         self.editable = self.no_deps = self.allow_hosts = None
         self.root = self.prefix = self.no_report = None
         self.version = None
-        self.install_purelib = None     # for pure module distributions
-        self.install_platlib = None     # non-pure (dists w/ extensions)
-        self.install_headers = None     # for C/C++ headers
-        self.install_lib = None         # set to either purelib or platlib
+        self.install_purelib = None  # for pure module distributions
+        self.install_platlib = None  # non-pure (dists w/ extensions)
+        self.install_headers = None  # for C/C++ headers
+        self.install_lib = None  # set to either purelib or platlib
         self.install_scripts = None
         self.install_data = None
         self.install_base = None
@@ -192,19 +202,34 @@
         )
 
     def delete_blockers(self, blockers):
-        for filename in blockers:
-            if os.path.exists(filename) or os.path.islink(filename):
-                log.info("Deleting %s", filename)
-                if not self.dry_run:
-                    if os.path.isdir(filename) and not os.path.islink(filename):
-                        rmtree(filename)
-                    else:
-                        os.unlink(filename)
+        extant_blockers = (
+            filename for filename in blockers
+            if os.path.exists(filename) or os.path.islink(filename)
+        )
+        list(map(self._delete_path, extant_blockers))
+
+    def _delete_path(self, path):
+        log.info("Deleting %s", path)
+        if self.dry_run:
+            return
+
+        is_tree = os.path.isdir(path) and not os.path.islink(path)
+        remover = rmtree if is_tree else os.unlink
+        remover(path)
+
+    @staticmethod
+    def _render_version():
+        """
+        Render the Setuptools version and installation details, then exit.
+        """
+        ver = sys.version[:3]
+        dist = get_distribution('setuptools')
+        tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})'
+        print(tmpl.format(**locals()))
+        raise SystemExit()
 
     def finalize_options(self):
-        if self.version:
-            print('setuptools %s' % get_distribution('setuptools').version)
-            sys.exit()
+        self.version and self._render_version()
 
         py_version = sys.version.split()[0]
         prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix')
@@ -228,23 +253,13 @@
             self.config_vars['userbase'] = self.install_userbase
             self.config_vars['usersite'] = self.install_usersite
 
-        # fix the install_dir if "--user" was used
-        #XXX: duplicate of the code in the setup command
-        if self.user and site.ENABLE_USER_SITE:
-            self.create_home_path()
-            if self.install_userbase is None:
-                raise DistutilsPlatformError(
-                    "User base directory is not specified")
-            self.install_base = self.install_platbase = self.install_userbase
-            if os.name == 'posix':
-                self.select_scheme("unix_user")
-            else:
-                self.select_scheme(os.name + "_user")
+        self._fix_install_dir_for_user_site()
 
         self.expand_basedirs()
         self.expand_dirs()
 
-        self._expand('install_dir','script_dir','build_directory','site_dirs')
+        self._expand('install_dir', 'script_dir', 'build_directory',
+                     'site_dirs')
         # If a non-default installation directory was specified, default the
         # script directory to match it.
         if self.script_dir is None:
@@ -256,12 +271,12 @@
         # Let install_dir get set by install_lib command, which in turn
         # gets its info from the install command, and takes into account
         # --prefix and --home and all that other crud.
-        self.set_undefined_options('install_lib',
-            ('install_dir','install_dir')
+        self.set_undefined_options(
+            'install_lib', ('install_dir', 'install_dir')
         )
         # Likewise, set default script_dir from 'install_scripts.install_dir'
-        self.set_undefined_options('install_scripts',
-            ('install_dir', 'script_dir')
+        self.set_undefined_options(
+            'install_scripts', ('install_dir', 'script_dir')
         )
 
         if self.user and self.install_purelib:
@@ -275,18 +290,20 @@
         self.all_site_dirs = get_site_dirs()
         if self.site_dirs is not None:
             site_dirs = [
-                os.path.expanduser(s.strip()) for s in self.site_dirs.split(',')
+                os.path.expanduser(s.strip()) for s in
+                self.site_dirs.split(',')
             ]
             for d in site_dirs:
                 if not os.path.isdir(d):
                     log.warn("%s (in --site-dirs) does not exist", d)
                 elif normalize_path(d) not in normpath:
                     raise DistutilsOptionError(
-                        d+" (in --site-dirs) is not on sys.path"
+                        d + " (in --site-dirs) is not on sys.path"
                     )
                 else:
                     self.all_site_dirs.append(normalize_path(d))
-        if not self.editable: self.check_site_dir()
+        if not self.editable:
+            self.check_site_dir()
         self.index_url = self.index_url or "https://pypi.python.org/simple"
         self.shadow_path = self.all_site_dirs[:]
         for path_item in self.install_dir, normalize_path(self.script_dir):
@@ -299,24 +316,25 @@
             hosts = ['*']
         if self.package_index is None:
             self.package_index = self.create_index(
-                self.index_url, search_path = self.shadow_path, hosts=hosts,
+                self.index_url, search_path=self.shadow_path, hosts=hosts,
             )
-        self.local_index = Environment(self.shadow_path+sys.path)
+        self.local_index = Environment(self.shadow_path + sys.path)
 
         if self.find_links is not None:
-            if isinstance(self.find_links, basestring):
+            if isinstance(self.find_links, six.string_types):
                 self.find_links = self.find_links.split()
         else:
             self.find_links = []
         if self.local_snapshots_ok:
-            self.package_index.scan_egg_links(self.shadow_path+sys.path)
+            self.package_index.scan_egg_links(self.shadow_path + sys.path)
         if not self.no_find_links:
             self.package_index.add_find_links(self.find_links)
-        self.set_undefined_options('install_lib', ('optimize','optimize'))
-        if not isinstance(self.optimize,int):
+        self.set_undefined_options('install_lib', ('optimize', 'optimize'))
+        if not isinstance(self.optimize, int):
             try:
                 self.optimize = int(self.optimize)
-                if not (0 <= self.optimize <= 2): raise ValueError
+                if not (0 <= self.optimize <= 2):
+                    raise ValueError
             except ValueError:
                 raise DistutilsOptionError("--optimize must be 0, 1, or 2")
 
@@ -330,6 +348,21 @@
 
         self.outputs = []
 
+    def _fix_install_dir_for_user_site(self):
+        """
+        Fix the install_dir if "--user" was used.
+        """
+        if not self.user or not site.ENABLE_USER_SITE:
+            return
+
+        self.create_home_path()
+        if self.install_userbase is None:
+            msg = "User base directory is not specified"
+            raise DistutilsPlatformError(msg)
+        self.install_base = self.install_platbase = self.install_userbase
+        scheme_name = os.name.replace('posix', 'unix') + '_user'
+        self.select_scheme(scheme_name)
+
     def _expand_attrs(self, attrs):
         for attr in attrs:
             val = getattr(self, attr)
@@ -348,7 +381,7 @@
         """Calls `os.path.expanduser` on install dirs."""
         self._expand_attrs(['install_purelib', 'install_platlib',
                             'install_lib', 'install_headers',
-                            'install_scripts', 'install_data',])
+                            'install_scripts', 'install_data', ])
 
     def run(self):
         if self.verbose != self.distribution.verbose:
@@ -358,11 +391,12 @@
                 self.easy_install(spec, not self.no_deps)
             if self.record:
                 outputs = self.outputs
-                if self.root:               # strip any package prefix
+                if self.root:  # strip any package prefix
                     root_len = len(self.root)
                     for counter in range(len(outputs)):
                         outputs[counter] = outputs[counter][root_len:]
                 from distutils import file_util
+
                 self.execute(
                     file_util.write_file, (self.record, outputs),
                     "writing list of installed files to '%s'" %
@@ -380,7 +414,7 @@
         try:
             pid = os.getpid()
         except:
-            pid = random.randint(0, maxsize)
+            pid = random.randint(0, sys.maxsize)
         return os.path.join(self.install_dir, "test-easy-install-%s" % pid)
 
     def warn_deprecated_options(self):
@@ -390,7 +424,7 @@
         """Verify that self.install_dir is .pth-capable dir, if needed"""
 
         instdir = normalize_path(self.install_dir)
-        pth_file = os.path.join(instdir,'easy-install.pth')
+        pth_file = os.path.join(instdir, 'easy-install.pth')
 
         # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
         is_site_dir = instdir in self.all_site_dirs
@@ -400,13 +434,14 @@
             is_site_dir = self.check_pth_processing()
         else:
             # make sure we can write to target dir
-            testfile = self.pseudo_tempname()+'.write-test'
+            testfile = self.pseudo_tempname() + '.write-test'
             test_exists = os.path.exists(testfile)
             try:
-                if test_exists: os.unlink(testfile)
-                open(testfile,'w').close()
+                if test_exists:
+                    os.unlink(testfile)
+                open(testfile, 'w').close()
                 os.unlink(testfile)
-            except (OSError,IOError):
+            except (OSError, IOError):
                 self.cant_write_to_target()
 
         if not is_site_dir and not self.multi_version:
@@ -419,84 +454,94 @@
         else:
             self.pth_file = None
 
-        PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep)
-        if instdir not in map(normalize_path, [_f for _f in PYTHONPATH if _f]):
+        PYTHONPATH = os.environ.get('PYTHONPATH', '').split(os.pathsep)
+        if instdir not in map(normalize_path, filter(None, PYTHONPATH)):
             # only PYTHONPATH dirs need a site.py, so pretend it's there
             self.sitepy_installed = True
         elif self.multi_version and not os.path.exists(pth_file):
-            self.sitepy_installed = True    # don't need site.py in this case
-            self.pth_file = None            # and don't create a .pth file
+            self.sitepy_installed = True  # don't need site.py in this case
+            self.pth_file = None  # and don't create a .pth file
         self.install_dir = instdir
 
-    def cant_write_to_target(self):
-        template = """can't create or remove files in install directory
+    __cant_write_msg = textwrap.dedent("""
+        can't create or remove files in install directory
 
-The following error occurred while trying to add or remove files in the
-installation directory:
+        The following error occurred while trying to add or remove files in the
+        installation directory:
 
-    %s
+            %s
 
-The installation directory you specified (via --install-dir, --prefix, or
-the distutils default setting) was:
+        The installation directory you specified (via --install-dir, --prefix, or
+        the distutils default setting) was:
 
-    %s
-"""
-        msg = template % (sys.exc_info()[1], self.install_dir,)
+            %s
+        """).lstrip()
 
-        if not os.path.exists(self.install_dir):
-            msg += """
-This directory does not currently exist.  Please create it and try again, or
-choose a different installation directory (using the -d or --install-dir
-option).
-"""
-        else:
-            msg += """
-Perhaps your account does not have write access to this directory?  If the
-installation directory is a system-owned directory, you may need to sign in
-as the administrator or "root" account.  If you do not have administrative
-access to this machine, you may wish to choose a different installation
-directory, preferably one that is listed in your PYTHONPATH environment
-variable.
+    __not_exists_id = textwrap.dedent("""
+        This directory does not currently exist.  Please create it and try again, or
+        choose a different installation directory (using the -d or --install-dir
+        option).
+        """).lstrip()
 
-For information on other options, you may wish to consult the
-documentation at:
+    __access_msg = textwrap.dedent("""
+        Perhaps your account does not have write access to this directory?  If the
+        installation directory is a system-owned directory, you may need to sign in
+        as the administrator or "root" account.  If you do not have administrative
+        access to this machine, you may wish to choose a different installation
+        directory, preferably one that is listed in your PYTHONPATH environment
+        variable.
 
-  https://pythonhosted.org/setuptools/easy_install.html
+        For information on other options, you may wish to consult the
+        documentation at:
 
-Please make the appropriate changes for your system and try again.
-"""
+          https://pythonhosted.org/setuptools/easy_install.html
+
+        Please make the appropriate changes for your system and try again.
+        """).lstrip()
+
+    def cant_write_to_target(self):
+        msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,)
+
+        if not os.path.exists(self.install_dir):
+            msg += '\n' + self.__not_exists_id
+        else:
+            msg += '\n' + self.__access_msg
         raise DistutilsError(msg)
 
     def check_pth_processing(self):
         """Empirically verify whether .pth files are supported in inst. dir"""
         instdir = self.install_dir
         log.info("Checking .pth file support in %s", instdir)
-        pth_file = self.pseudo_tempname()+".pth"
-        ok_file = pth_file+'.ok'
+        pth_file = self.pseudo_tempname() + ".pth"
+        ok_file = pth_file + '.ok'
         ok_exists = os.path.exists(ok_file)
         try:
-            if ok_exists: os.unlink(ok_file)
+            if ok_exists:
+                os.unlink(ok_file)
             dirname = os.path.dirname(ok_file)
             if not os.path.exists(dirname):
                 os.makedirs(dirname)
-            f = open(pth_file,'w')
-        except (OSError,IOError):
+            f = open(pth_file, 'w')
+        except (OSError, IOError):
             self.cant_write_to_target()
         else:
             try:
-                f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,))
+                f.write("import os; f = open(%r, 'w'); f.write('OK'); "
+                        "f.close()\n" % (ok_file,))
                 f.close()
-                f=None
+                f = None
                 executable = sys.executable
-                if os.name=='nt':
-                    dirname,basename = os.path.split(executable)
-                    alt = os.path.join(dirname,'pythonw.exe')
-                    if basename.lower()=='python.exe' and os.path.exists(alt):
+                if os.name == 'nt':
+                    dirname, basename = os.path.split(executable)
+                    alt = os.path.join(dirname, 'pythonw.exe')
+                    if (basename.lower() == 'python.exe' and
+                            os.path.exists(alt)):
                         # use pythonw.exe to avoid opening a console window
                         executable = alt
 
                 from distutils.spawn import spawn
-                spawn([executable,'-E','-c','pass'],0)
+
+                spawn([executable, '-E', '-c', 'pass'], 0)
 
                 if os.path.exists(ok_file):
                     log.info(
@@ -525,7 +570,7 @@
                     continue
                 self.install_script(
                     dist, script_name,
-                    dist.get_metadata('scripts/'+script_name)
+                    dist.get_metadata('scripts/' + script_name)
                 )
         self.install_wrapper_scripts(dist)
 
@@ -533,7 +578,7 @@
         if os.path.isdir(path):
             for base, dirs, files in os.walk(path):
                 for filename in files:
-                    self.outputs.append(os.path.join(base,filename))
+                    self.outputs.append(os.path.join(base, filename))
         else:
             self.outputs.append(path)
 
@@ -545,7 +590,7 @@
                 % (spec,)
             )
 
-    def check_editable(self,spec):
+    def check_editable(self, spec):
         if not self.editable:
             return
 
@@ -558,15 +603,17 @@
     def easy_install(self, spec, deps=False):
         tmpdir = tempfile.mkdtemp(prefix="easy_install-")
         download = None
-        if not self.editable: self.install_site_py()
+        if not self.editable:
+            self.install_site_py()
 
         try:
-            if not isinstance(spec,Requirement):
+            if not isinstance(spec, Requirement):
                 if URL_SCHEME(spec):
                     # It's a url, download it to tmpdir and process
                     self.not_editable(spec)
                     download = self.package_index.download(spec, tmpdir)
-                    return self.install_item(None, download, tmpdir, deps, True)
+                    return self.install_item(None, download, tmpdir, deps,
+                                             True)
 
                 elif os.path.exists(spec):
                     # Existing file or directory, just process it directly
@@ -577,15 +624,15 @@
 
             self.check_editable(spec)
             dist = self.package_index.fetch_distribution(
-                spec, tmpdir, self.upgrade, self.editable, not self.always_copy,
-                self.local_index
+                spec, tmpdir, self.upgrade, self.editable,
+                not self.always_copy, self.local_index
             )
             if dist is None:
                 msg = "Could not find suitable distribution for %r" % spec
                 if self.always_copy:
-                    msg+=" (--always-copy skips system and development eggs)"
+                    msg += " (--always-copy skips system and development eggs)"
                 raise DistutilsError(msg)
-            elif dist.precedence==DEVELOP_DIST:
+            elif dist.precedence == DEVELOP_DIST:
                 # .egg-info dists don't need installing, just process deps
                 self.process_distribution(spec, dist, deps, "Using")
                 return dist
@@ -612,10 +659,10 @@
             # at this point, we know it's a local .egg, we just don't know if
             # it's already installed.
             for dist in self.local_index[spec.project_name]:
-                if dist.location==download:
+                if dist.location == download:
                     break
             else:
-                install_needed = True   # it's not in the local index
+                install_needed = True  # it's not in the local index
 
         log.info("Processing %s", os.path.basename(download))
 
@@ -644,6 +691,8 @@
     def process_distribution(self, requirement, dist, deps=True, *info):
         self.update_pth(dist)
         self.package_index.add(dist)
+        if dist in self.local_index[dist.key]:
+            self.local_index.remove(dist)
         self.local_index.add(dist)
         self.install_egg_scripts(dist)
         self.installed_projects[dist.key] = dist
@@ -670,17 +719,10 @@
             distros = WorkingSet([]).resolve(
                 [requirement], self.local_index, self.easy_install
             )
-        except DistributionNotFound:
-            e = sys.exc_info()[1]
-            raise DistutilsError(
-                "Could not find required distribution %s" % e.args
-            )
-        except VersionConflict:
-            e = sys.exc_info()[1]
-            raise DistutilsError(
-                "Installed distribution %s conflicts with requirement %s"
-                % e.args
-            )
+        except DistributionNotFound as e:
+            raise DistutilsError(str(e))
+        except VersionConflict as e:
+            raise DistutilsError(e.report())
         if self.always_copy or self.always_copy_from:
             # Force all the relevant distros to be copied or activated
             for dist in distros:
@@ -700,17 +742,18 @@
     def maybe_move(self, spec, dist_filename, setup_base):
         dst = os.path.join(self.build_directory, spec.key)
         if os.path.exists(dst):
-            msg = "%r already exists in %s; build directory %s will not be kept"
+            msg = ("%r already exists in %s; build directory %s will not be "
+                   "kept")
             log.warn(msg, spec.key, self.build_directory, setup_base)
             return setup_base
         if os.path.isdir(dist_filename):
             setup_base = dist_filename
         else:
-            if os.path.dirname(dist_filename)==setup_base:
-                os.unlink(dist_filename)   # get it out of the tmp dir
+            if os.path.dirname(dist_filename) == setup_base:
+                os.unlink(dist_filename)  # get it out of the tmp dir
             contents = os.listdir(setup_base)
-            if len(contents)==1:
-                dist_filename = os.path.join(setup_base,contents[0])
+            if len(contents) == 1:
+                dist_filename = os.path.join(setup_base, contents[0])
                 if os.path.isdir(dist_filename):
                     # if the only thing there is a directory, move it instead
                     setup_base = dist_filename
@@ -719,43 +762,41 @@
         return dst
 
     def install_wrapper_scripts(self, dist):
-        if not self.exclude_scripts:
-            for args in get_script_args(dist):
-                self.write_script(*args)
+        if self.exclude_scripts:
+            return
+        for args in ScriptWriter.best().get_args(dist):
+            self.write_script(*args)
 
     def install_script(self, dist, script_name, script_text, dev_path=None):
         """Generate a legacy script wrapper and install it"""
         spec = str(dist.as_requirement())
         is_script = is_python_script(script_text, script_name)
 
-        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:
-            # See https://bitbucket.org/pypa/setuptools/issue/134 for info
-            #  on script file naming and downstream issues with SVR4
-            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())
+            body = self._load_template(dev_path) % locals()
+            script_text = ScriptWriter.get_header(script_text) + body
         self.write_script(script_name, _to_ascii(script_text), 'b')
 
+    @staticmethod
+    def _load_template(dev_path):
+        """
+        There are a couple of template scripts in the package. This
+        function loads one of them and prepares it for use.
+        """
+        # See https://bitbucket.org/pypa/setuptools/issue/134 for info
+        # on script file naming and downstream issues with SVR4
+        name = 'script.tmpl'
+        if dev_path:
+            name = name.replace('.tmpl', ' (dev).tmpl')
+
+        raw_bytes = resource_string('setuptools', name)
+        return raw_bytes.decode('utf-8')
+
     def write_script(self, script_name, contents, mode="t", blockers=()):
         """Write an executable file to the scripts directory"""
-        self.delete_blockers(   # clean up old .py/.pyw w/o a script
-            [os.path.join(self.script_dir,x) for x in blockers])
+        self.delete_blockers(  # clean up old .py/.pyw w/o a script
+            [os.path.join(self.script_dir, x) for x in blockers]
+        )
         log.info("Installing %s script to %s", script_name, self.script_dir)
         target = os.path.join(self.script_dir, script_name)
         self.add_output(target)
@@ -765,10 +806,9 @@
             ensure_directory(target)
             if os.path.exists(target):
                 os.unlink(target)
-            f = open(target,"w"+mode)
-            f.write(contents)
-            f.close()
-            chmod(target, 0x1FF-mask) # 0777
+            with open(target, "w" + mode) as f:
+                f.write(contents)
+            chmod(target, 0o777 - mask)
 
     def install_eggs(self, spec, dist_filename, tmpdir):
         # .egg dirs or files are already built, so just return them
@@ -784,7 +824,7 @@
         elif os.path.isdir(dist_filename):
             setup_base = os.path.abspath(dist_filename)
 
-        if (setup_base.startswith(tmpdir)   # something we downloaded
+        if (setup_base.startswith(tmpdir)  # something we downloaded
                 and self.build_directory and spec is not None):
             setup_base = self.maybe_move(spec, dist_filename, setup_base)
 
@@ -795,11 +835,13 @@
             setups = glob(os.path.join(setup_base, '*', 'setup.py'))
             if not setups:
                 raise DistutilsError(
-                    "Couldn't find a setup script in %s" % os.path.abspath(dist_filename)
+                    "Couldn't find a setup script in %s" %
+                    os.path.abspath(dist_filename)
                 )
-            if len(setups)>1:
+            if len(setups) > 1:
                 raise DistutilsError(
-                    "Multiple setup scripts in %s" % os.path.abspath(dist_filename)
+                    "Multiple setup scripts in %s" %
+                    os.path.abspath(dist_filename)
                 )
             setup_script = setups[0]
 
@@ -812,13 +854,15 @@
 
     def egg_distribution(self, egg_path):
         if os.path.isdir(egg_path):
-            metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO'))
+            metadata = PathMetadata(egg_path, os.path.join(egg_path,
+                                                           'EGG-INFO'))
         else:
             metadata = EggMetadata(zipimport.zipimporter(egg_path))
-        return Distribution.from_filename(egg_path,metadata=metadata)
+        return Distribution.from_filename(egg_path, metadata=metadata)
 
     def install_egg(self, egg_path, tmpdir):
-        destination = os.path.join(self.install_dir,os.path.basename(egg_path))
+        destination = os.path.join(self.install_dir,
+                                   os.path.basename(egg_path))
         destination = os.path.abspath(destination)
         if not self.dry_run:
             ensure_directory(destination)
@@ -828,24 +872,33 @@
             if os.path.isdir(destination) and not os.path.islink(destination):
                 dir_util.remove_tree(destination, dry_run=self.dry_run)
             elif os.path.exists(destination):
-                self.execute(os.unlink,(destination,),"Removing "+destination)
-            uncache_zipdir(destination)
-            if os.path.isdir(egg_path):
-                if egg_path.startswith(tmpdir):
-                    f,m = shutil.move, "Moving"
+                self.execute(os.unlink, (destination,), "Removing " +
+                             destination)
+            try:
+                new_dist_is_zipped = False
+                if os.path.isdir(egg_path):
+                    if egg_path.startswith(tmpdir):
+                        f, m = shutil.move, "Moving"
+                    else:
+                        f, m = shutil.copytree, "Copying"
+                elif self.should_unzip(dist):
+                    self.mkpath(destination)
+                    f, m = self.unpack_and_compile, "Extracting"
                 else:
-                    f,m = shutil.copytree, "Copying"
-            elif self.should_unzip(dist):
-                self.mkpath(destination)
-                f,m = self.unpack_and_compile, "Extracting"
-            elif egg_path.startswith(tmpdir):
-                f,m = shutil.move, "Moving"
-            else:
-                f,m = shutil.copy2, "Copying"
-
-            self.execute(f, (egg_path, destination),
-                (m+" %s to %s") %
-                (os.path.basename(egg_path),os.path.dirname(destination)))
+                    new_dist_is_zipped = True
+                    if egg_path.startswith(tmpdir):
+                        f, m = shutil.move, "Moving"
+                    else:
+                        f, m = shutil.copy2, "Copying"
+                self.execute(f, (egg_path, destination),
+                             (m + " %s to %s") %
+                             (os.path.basename(egg_path),
+                              os.path.dirname(destination)))
+                update_dist_caches(destination,
+                                   fix_zipimporter_caches=new_dist_is_zipped)
+            except:
+                update_dist_caches(destination, fix_zipimporter_caches=False)
+                raise
 
         self.add_output(destination)
         return self.egg_distribution(destination)
@@ -860,30 +913,33 @@
         # Create a dummy distribution object until we build the real distro
         dist = Distribution(
             None,
-            project_name=cfg.get('metadata','name'),
-            version=cfg.get('metadata','version'), platform=get_platform(),
+            project_name=cfg.get('metadata', 'name'),
+            version=cfg.get('metadata', 'version'), platform=get_platform(),
         )
 
         # Convert the .exe to an unpacked egg
-        egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg')
+        egg_path = dist.location = os.path.join(tmpdir, dist.egg_name() +
+                                                '.egg')
         egg_tmp = egg_path + '.tmp'
         _egg_info = os.path.join(egg_tmp, 'EGG-INFO')
         pkg_inf = os.path.join(_egg_info, 'PKG-INFO')
-        ensure_directory(pkg_inf)   # make sure EGG-INFO dir exists
-        dist._provider = PathMetadata(egg_tmp, _egg_info)    # XXX
+        ensure_directory(pkg_inf)  # make sure EGG-INFO dir exists
+        dist._provider = PathMetadata(egg_tmp, _egg_info)  # XXX
         self.exe_to_egg(dist_filename, egg_tmp)
 
         # Write EGG-INFO/PKG-INFO
         if not os.path.exists(pkg_inf):
-            f = open(pkg_inf,'w')
+            f = open(pkg_inf, 'w')
             f.write('Metadata-Version: 1.0\n')
-            for k,v in cfg.items('metadata'):
+            for k, v in cfg.items('metadata'):
                 if k != 'target_version':
-                    f.write('%s: %s\n' % (k.replace('_','-').title(), v))
+                    f.write('%s: %s\n' % (k.replace('_', '-').title(), v))
             f.close()
-        script_dir = os.path.join(_egg_info,'scripts')
-        self.delete_blockers(   # delete entry-point scripts to avoid duping
-            [os.path.join(script_dir,args[0]) for args in get_script_args(dist)]
+        script_dir = os.path.join(_egg_info, 'scripts')
+        # delete entry-point scripts to avoid duping
+        self.delete_blockers(
+            [os.path.join(script_dir, args[0]) for args in
+             ScriptWriter.get_args(dist)]
         )
         # Build .egg file from tmpdir
         bdist_egg.make_zipfile(
@@ -899,11 +955,12 @@
         to_compile = []
         native_libs = []
         top_level = {}
-        def process(src,dst):
+
+        def process(src, dst):
             s = src.lower()
-            for old,new in prefixes:
+            for old, new in prefixes:
                 if s.startswith(old):
-                    src = new+src[len(old):]
+                    src = new + src[len(old):]
                     parts = src.split('/')
                     dst = os.path.join(egg_tmp, *parts)
                     dl = dst.lower()
@@ -911,97 +968,104 @@
                         parts[-1] = bdist_egg.strip_module(parts[-1])
                         top_level[os.path.splitext(parts[0])[0]] = 1
                         native_libs.append(src)
-                    elif dl.endswith('.py') and old!='SCRIPTS/':
+                    elif dl.endswith('.py') and old != 'SCRIPTS/':
                         top_level[os.path.splitext(parts[0])[0]] = 1
                         to_compile.append(dst)
                     return dst
             if not src.endswith('.pth'):
                 log.warn("WARNING: can't process %s", src)
             return None
+
         # extract, tracking .pyd/.dll->native_libs and .py -> to_compile
         unpack_archive(dist_filename, egg_tmp, process)
         stubs = []
         for res in native_libs:
-            if res.lower().endswith('.pyd'):    # create stubs for .pyd's
+            if res.lower().endswith('.pyd'):  # create stubs for .pyd's
                 parts = res.split('/')
                 resource = parts[-1]
-                parts[-1] = bdist_egg.strip_module(parts[-1])+'.py'
+                parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py'
                 pyfile = os.path.join(egg_tmp, *parts)
                 to_compile.append(pyfile)
                 stubs.append(pyfile)
                 bdist_egg.write_stub(resource, pyfile)
-        self.byte_compile(to_compile)   # compile .py's
-        bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'),
+        self.byte_compile(to_compile)  # compile .py's
+        bdist_egg.write_safety_flag(
+            os.path.join(egg_tmp, 'EGG-INFO'),
             bdist_egg.analyze_egg(egg_tmp, stubs))  # write zip-safety flag
 
-        for name in 'top_level','native_libs':
+        for name in 'top_level', 'native_libs':
             if locals()[name]:
-                txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt')
+                txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt')
                 if not os.path.exists(txt):
-                    f = open(txt,'w')
-                    f.write('\n'.join(locals()[name])+'\n')
+                    f = open(txt, 'w')
+                    f.write('\n'.join(locals()[name]) + '\n')
                     f.close()
 
+    __mv_warning = textwrap.dedent("""
+        Because this distribution was installed --multi-version, before you can
+        import modules from this package in an application, you will need to
+        'import pkg_resources' and then use a 'require()' call similar to one of
+        these examples, in order to select the desired version:
+
+            pkg_resources.require("%(name)s")  # latest installed version
+            pkg_resources.require("%(name)s==%(version)s")  # this exact version
+            pkg_resources.require("%(name)s>=%(version)s")  # this version or higher
+        """).lstrip()
+
+    __id_warning = textwrap.dedent("""
+        Note also that the installation directory must be on sys.path at runtime for
+        this to work.  (e.g. by being the application's script directory, by being on
+        PYTHONPATH, or by being added to sys.path by your code.)
+        """)
+
     def installation_report(self, req, dist, what="Installed"):
         """Helpful installation message for display to package users"""
         msg = "\n%(what)s %(eggloc)s%(extras)s"
         if self.multi_version and not self.no_report:
-            msg += """
+            msg += '\n' + self.__mv_warning
+            if self.install_dir not in map(normalize_path, sys.path):
+                msg += '\n' + self.__id_warning
 
-Because this distribution was installed --multi-version, before you can
-import modules from this package in an application, you will need to
-'import pkg_resources' and then use a 'require()' call similar to one of
-these examples, in order to select the desired version:
-
-    pkg_resources.require("%(name)s")  # latest installed version
-    pkg_resources.require("%(name)s==%(version)s")  # this exact version
-    pkg_resources.require("%(name)s>=%(version)s")  # this version or higher
-"""
-            if self.install_dir not in map(normalize_path,sys.path):
-                msg += """
-
-Note also that the installation directory must be on sys.path at runtime for
-this to work.  (e.g. by being the application's script directory, by being on
-PYTHONPATH, or by being added to sys.path by your code.)
-"""
         eggloc = dist.location
         name = dist.project_name
         version = dist.version
-        extras = '' # TODO: self.report_extras(req, dist)
+        extras = ''  # TODO: self.report_extras(req, dist)
         return msg % locals()
 
-    def report_editable(self, spec, setup_script):
-        dirname = os.path.dirname(setup_script)
-        python = sys.executable
-        return """\nExtracted editable version of %(spec)s to %(dirname)s
+    __editable_msg = textwrap.dedent("""
+        Extracted editable version of %(spec)s to %(dirname)s
 
-If it uses setuptools in its setup script, you can activate it in
-"development" mode by going to that directory and running::
+        If it uses setuptools in its setup script, you can activate it in
+        "development" mode by going to that directory and running::
 
-    %(python)s setup.py develop
+            %(python)s setup.py develop
 
-See the setuptools documentation for the "develop" command for more info.
-""" % locals()
+        See the setuptools documentation for the "develop" command for more info.
+        """).lstrip()
+
+    def report_editable(self, spec, setup_script):
+        dirname = os.path.dirname(setup_script)
+        python = sys.executable
+        return '\n' + self.__editable_msg % locals()
 
     def run_setup(self, setup_script, setup_base, args):
         sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg)
         sys.modules.setdefault('distutils.command.egg_info', egg_info)
 
         args = list(args)
-        if self.verbose>2:
+        if self.verbose > 2:
             v = 'v' * (self.verbose - 1)
-            args.insert(0,'-'+v)
-        elif self.verbose<2:
-            args.insert(0,'-q')
+            args.insert(0, '-' + v)
+        elif self.verbose < 2:
+            args.insert(0, '-q')
         if self.dry_run:
-            args.insert(0,'-n')
+            args.insert(0, '-n')
         log.info(
-            "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args)
+            "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args)
         )
         try:
             run_setup(setup_script, args)
-        except SystemExit:
-            v = sys.exc_info()[1]
+        except SystemExit as v:
             raise DistutilsError("Setup script exited with %s" % (v.args[0],))
 
     def build_and_install(self, setup_script, setup_base):
@@ -1022,11 +1086,11 @@
                     eggs.append(self.install_egg(dist.location, setup_base))
             if not eggs and not self.dry_run:
                 log.warn("No eggs found in %s (setup script problem?)",
-                    dist_dir)
+                         dist_dir)
             return eggs
         finally:
             rmtree(dist_dir)
-            log.set_verbosity(self.verbose) # restore our log verbosity
+            log.set_verbosity(self.verbose)  # restore our log verbosity
 
     def _set_fetcher_options(self, base):
         """
@@ -1036,7 +1100,7 @@
         are available to that command as well.
         """
         # find the fetch options from easy_install and write them out
-        #  to the setup.cfg file.
+        # to the setup.cfg file.
         ei_opts = self.distribution.get_option_dict('easy_install').copy()
         fetch_directives = (
             'find_links', 'site_dirs', 'index_url', 'optimize',
@@ -1044,7 +1108,8 @@
         )
         fetch_options = {}
         for key, val in ei_opts.items():
-            if key not in fetch_directives: continue
+            if key not in fetch_directives:
+                continue
             fetch_options[key.replace('_', '-')] = val[1]
         # create a settings dictionary suitable for `edit_config`
         settings = dict(easy_install=fetch_options)
@@ -1055,7 +1120,7 @@
         if self.pth_file is None:
             return
 
-        for d in self.pth_file[dist.key]:    # drop old entries
+        for d in self.pth_file[dist.key]:  # drop old entries
             if self.multi_version or d.location != dist.location:
                 log.info("Removing %s from easy-install.pth file", d)
                 self.pth_file.remove(d)
@@ -1070,7 +1135,7 @@
                 )
             else:
                 log.info("Adding %s to easy-install.pth file", dist)
-                self.pth_file.add(dist) # add new entry
+                self.pth_file.add(dist)  # add new entry
                 if dist.location not in self.shadow_path:
                     self.shadow_path.append(dist.location)
 
@@ -1078,19 +1143,20 @@
 
             self.pth_file.save()
 
-            if dist.key=='setuptools':
+            if dist.key == 'setuptools':
                 # Ensure that setuptools itself never becomes unavailable!
                 # XXX should this check for latest version?
-                filename = os.path.join(self.install_dir,'setuptools.pth')
-                if os.path.islink(filename): os.unlink(filename)
+                filename = os.path.join(self.install_dir, 'setuptools.pth')
+                if os.path.islink(filename):
+                    os.unlink(filename)
                 f = open(filename, 'wt')
-                f.write(self.pth_file.make_relative(dist.location)+'\n')
+                f.write(self.pth_file.make_relative(dist.location) + '\n')
                 f.close()
 
     def unpack_progress(self, src, dst):
         # Progress filter for unpacking
         log.debug("Unpacking %s to %s", src, dst)
-        return dst     # only unpack-and-compile skips files for dry run
+        return dst  # only unpack-and-compile skips files for dry run
 
     def unpack_and_compile(self, egg_path, destination):
         to_compile = []
@@ -1101,22 +1167,23 @@
                 to_compile.append(dst)
             elif dst.endswith('.dll') or dst.endswith('.so'):
                 to_chmod.append(dst)
-            self.unpack_progress(src,dst)
+            self.unpack_progress(src, dst)
             return not self.dry_run and dst or None
 
         unpack_archive(egg_path, destination, pf)
         self.byte_compile(to_compile)
         if not self.dry_run:
             for f in to_chmod:
-                mode = ((os.stat(f)[stat.ST_MODE]) | 0x16D) & 0xFED  # 0555, 07755
+                mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755
                 chmod(f, mode)
 
     def byte_compile(self, to_compile):
-        if _dont_write_bytecode:
+        if sys.dont_write_bytecode:
             self.warn('byte-compiling is disabled, skipping.')
             return
 
         from distutils.util import byte_compile
+
         try:
             # try to make the byte compile messages quieter
             log.set_verbosity(self.verbose - 1)
@@ -1128,38 +1195,41 @@
                     dry_run=self.dry_run
                 )
         finally:
-            log.set_verbosity(self.verbose)     # restore original verbosity
+            log.set_verbosity(self.verbose)  # restore original verbosity
 
-    def no_default_version_msg(self):
-        template = """bad install directory or PYTHONPATH
+    __no_default_msg = textwrap.dedent("""
+        bad install directory or PYTHONPATH
 
-You are attempting to install a package to a directory that is not
-on PYTHONPATH and which Python does not read ".pth" files from.  The
-installation directory you specified (via --install-dir, --prefix, or
-the distutils default setting) was:
+        You are attempting to install a package to a directory that is not
+        on PYTHONPATH and which Python does not read ".pth" files from.  The
+        installation directory you specified (via --install-dir, --prefix, or
+        the distutils default setting) was:
 
-    %s
+            %s
 
-and your PYTHONPATH environment variable currently contains:
+        and your PYTHONPATH environment variable currently contains:
 
-    %r
+            %r
 
-Here are some of your options for correcting the problem:
+        Here are some of your options for correcting the problem:
 
-* You can choose a different installation directory, i.e., one that is
-  on PYTHONPATH or supports .pth files
+        * You can choose a different installation directory, i.e., one that is
+          on PYTHONPATH or supports .pth files
 
-* You can add the installation directory to the PYTHONPATH environment
-  variable.  (It must then also be on PYTHONPATH whenever you run
-  Python and want to use the package(s) you are installing.)
+        * You can add the installation directory to the PYTHONPATH environment
+          variable.  (It must then also be on PYTHONPATH whenever you run
+          Python and want to use the package(s) you are installing.)
 
-* You can set up the installation directory to support ".pth" files by
-  using one of the approaches described here:
+        * You can set up the installation directory to support ".pth" files by
+          using one of the approaches described here:
 
-  https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
+          https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
 
-Please make the appropriate changes for your system and try again."""
-        return template % (self.install_dir, os.environ.get('PYTHONPATH',''))
+        Please make the appropriate changes for your system and try again.""").lstrip()
+
+    def no_default_version_msg(self):
+        template = self.__no_default_msg
+        return template % (self.install_dir, os.environ.get('PYTHONPATH', ''))
 
     def install_site_py(self):
         """Make sure there's a site.py in the target dir, if needed"""
@@ -1173,10 +1243,10 @@
 
         if os.path.exists(sitepy):
             log.debug("Checking existing site.py in %s", self.install_dir)
-            f = open(sitepy,'rb')
+            f = open(sitepy, 'rb')
             current = f.read()
             # we want str, not bytes
-            if sys.version_info >= (3,):
+            if six.PY3:
                 current = current.decode()
 
             f.close()
@@ -1190,7 +1260,7 @@
             log.info("Creating %s", sitepy)
             if not self.dry_run:
                 ensure_directory(sitepy)
-                f = open(sitepy,'wb')
+                f = open(sitepy, 'wb')
                 f.write(source)
                 f.close()
             self.byte_compile([sitepy])
@@ -1202,21 +1272,21 @@
         if not self.user:
             return
         home = convert_path(os.path.expanduser("~"))
-        for name, path in iteritems(self.config_vars):
+        for name, path in six.iteritems(self.config_vars):
             if path.startswith(home) and not os.path.isdir(path):
-                self.debug_print("os.makedirs('%s', 0700)" % path)
-                os.makedirs(path, 0x1C0)    # 0700
+                self.debug_print("os.makedirs('%s', 0o700)" % path)
+                os.makedirs(path, 0o700)
 
     INSTALL_SCHEMES = dict(
-        posix = dict(
-            install_dir = '$base/lib/python$py_version_short/site-packages',
-            script_dir = '$base/bin',
+        posix=dict(
+            install_dir='$base/lib/python$py_version_short/site-packages',
+            script_dir='$base/bin',
         ),
     )
 
     DEFAULT_SCHEME = dict(
-        install_dir = '$base/Lib/site-packages',
-        script_dir = '$base/Scripts',
+        install_dir='$base/Lib/site-packages',
+        script_dir='$base/Scripts',
     )
 
     def _expand(self, *attrs):
@@ -1226,12 +1296,13 @@
             # Set default install_dir/scripts from --prefix
             config_vars = config_vars.copy()
             config_vars['base'] = self.prefix
-            scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME)
-            for attr,val in scheme.items():
-                if getattr(self,attr,None) is None:
-                    setattr(self,attr,val)
+            scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME)
+            for attr, val in scheme.items():
+                if getattr(self, attr, None) is None:
+                    setattr(self, attr, val)
 
         from distutils.util import subst_vars
+
         for attr in attrs:
             val = getattr(self, attr)
             if val is not None:
@@ -1240,6 +1311,7 @@
                     val = os.path.expanduser(val)
                 setattr(self, attr, val)
 
+
 def get_site_dirs():
     # return a list of 'site' dirs
     sitedirs = [_f for _f in os.environ.get('PYTHONPATH',
@@ -1253,10 +1325,10 @@
                 sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
             elif os.sep == '/':
                 sitedirs.extend([os.path.join(prefix,
-                                         "lib",
-                                         "python" + sys.version[:3],
-                                         "site-packages"),
-                            os.path.join(prefix, "lib", "site-python")])
+                                              "lib",
+                                              "python" + sys.version[:3],
+                                              "site-packages"),
+                                 os.path.join(prefix, "lib", "site-python")])
             else:
                 sitedirs.extend(
                     [prefix, os.path.join(prefix, "lib", "site-packages")]
@@ -1276,7 +1348,8 @@
                                          'site-packages'))
     lib_paths = get_path('purelib'), get_path('platlib')
     for site_lib in lib_paths:
-        if site_lib not in sitedirs: sitedirs.append(site_lib)
+        if site_lib not in sitedirs:
+            sitedirs.append(site_lib)
 
     if site.ENABLE_USER_SITE:
         sitedirs.append(site.USER_SITE)
@@ -1307,12 +1380,12 @@
             if not name.endswith('.pth'):
                 # We only care about the .pth files
                 continue
-            if name in ('easy-install.pth','setuptools.pth'):
+            if name in ('easy-install.pth', 'setuptools.pth'):
                 # Ignore .pth files that we control
                 continue
 
             # Read the .pth file
-            f = open(os.path.join(dirname,name))
+            f = open(os.path.join(dirname, name))
             lines = list(yield_lines(f))
             f.close()
 
@@ -1330,9 +1403,9 @@
 def extract_wininst_cfg(dist_filename):
     """Extract configuration data from a bdist_wininst .exe
 
-    Returns a ConfigParser.RawConfigParser, or None
+    Returns a configparser.RawConfigParser, or None
     """
-    f = open(dist_filename,'rb')
+    f = open(dist_filename, 'rb')
     try:
         endrec = zipfile._EndRecData(f)
         if endrec is None:
@@ -1341,30 +1414,24 @@
         prepended = (endrec[9] - endrec[5]) - endrec[6]
         if prepended < 12:  # no wininst data here
             return None
-        f.seek(prepended-12)
+        f.seek(prepended - 12)
 
-        from setuptools.compat import StringIO, ConfigParser
-        import struct
-        tag, cfglen, bmlen = struct.unpack("= (2,6):
-                null_byte = bytes([0])
-            else:
-                null_byte = chr(0)
-            config = part.split(null_byte, 1)[0]
+            # Read up to the first null byte.
+            config = part.split(b'\0', 1)[0]
             # Now the config is in bytes, but for RawConfigParser, it should
             #  be text, so decode it.
             config = config.decode(sys.getfilesystemencoding())
-            cfg.readfp(StringIO(config))
-        except ConfigParser.Error:
+            cfg.readfp(six.StringIO(config))
+        except configparser.Error:
             return None
         if not cfg.has_section('metadata') or not cfg.has_section('Setup'):
             return None
@@ -1388,25 +1455,25 @@
         for info in z.infolist():
             name = info.filename
             parts = name.split('/')
-            if len(parts)==3 and parts[2]=='PKG-INFO':
+            if len(parts) == 3 and parts[2] == 'PKG-INFO':
                 if parts[1].endswith('.egg-info'):
-                    prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/'))
+                    prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/'))
                     break
             if len(parts) != 2 or not name.endswith('.pth'):
                 continue
             if name.endswith('-nspkg.pth'):
                 continue
-            if parts[0].upper() in ('PURELIB','PLATLIB'):
+            if parts[0].upper() in ('PURELIB', 'PLATLIB'):
                 contents = z.read(name)
-                if sys.version_info >= (3,):
+                if six.PY3:
                     contents = contents.decode()
                 for pth in yield_lines(contents):
-                    pth = pth.strip().replace('\\','/')
+                    pth = pth.strip().replace('\\', '/')
                     if not pth.startswith('import'):
-                        prefixes.append((('%s/%s/' % (parts[0],pth)), ''))
+                        prefixes.append((('%s/%s/' % (parts[0], pth)), ''))
     finally:
         z.close()
-    prefixes = [(x.lower(),y) for x, y in prefixes]
+    prefixes = [(x.lower(), y) for x, y in prefixes]
     prefixes.sort()
     prefixes.reverse()
     return prefixes
@@ -1420,6 +1487,7 @@
             "Not a URL, existing file, or requirement spec: %r" % (spec,)
         )
 
+
 class PthDistributions(Environment):
     """A .pth file with Distribution paths in it"""
 
@@ -1439,7 +1507,7 @@
         saw_import = False
         seen = dict.fromkeys(self.sitedirs)
         if os.path.isfile(self.filename):
-            f = open(self.filename,'rt')
+            f = open(self.filename, 'rt')
             for line in f:
                 if line.startswith('import'):
                     saw_import = True
@@ -1451,17 +1519,17 @@
                 # skip non-existent paths, in case somebody deleted a package
                 # manually, and duplicate paths as well
                 path = self.paths[-1] = normalize_path(
-                    os.path.join(self.basedir,path)
+                    os.path.join(self.basedir, path)
                 )
                 if not os.path.exists(path) or path in seen:
-                    self.paths.pop()    # skip it
-                    self.dirty = True   # we cleaned up, so we're dirty now :)
+                    self.paths.pop()  # skip it
+                    self.dirty = True  # we cleaned up, so we're dirty now :)
                     continue
                 seen[path] = 1
             f.close()
 
         if self.paths and not saw_import:
-            self.dirty = True   # ensure anything we touch has import wrappers
+            self.dirty = True  # ensure anything we touch has import wrappers
         while self.paths and not self.paths[-1].strip():
             self.paths.pop()
 
@@ -1470,23 +1538,16 @@
         if not self.dirty:
             return
 
-        data = '\n'.join(map(self.make_relative,self.paths))
-        if data:
+        rel_paths = list(map(self.make_relative, self.paths))
+        if rel_paths:
             log.debug("Saving %s", self.filename)
-            data = (
-                "import sys; sys.__plen = len(sys.path)\n"
-                "%s\n"
-                "import sys; new=sys.path[sys.__plen:];"
-                " del sys.path[sys.__plen:];"
-                " p=getattr(sys,'__egginsert',0); sys.path[p:p]=new;"
-                " sys.__egginsert = p+len(new)\n"
-            ) % data
+            lines = self._wrap_lines(rel_paths)
+            data = '\n'.join(lines) + '\n'
 
             if os.path.islink(self.filename):
                 os.unlink(self.filename)
-            f = open(self.filename,'wt')
-            f.write(data)
-            f.close()
+            with open(self.filename, 'wt') as f:
+                f.write(data)
 
         elif os.path.exists(self.filename):
             log.debug("Deleting empty %s", self.filename)
@@ -1494,12 +1555,20 @@
 
         self.dirty = False
 
+    @staticmethod
+    def _wrap_lines(lines):
+        return lines
+
     def add(self, dist):
         """Add `dist` to the distribution map"""
-        if (dist.location not in self.paths and (
+        new_path = (
+            dist.location not in self.paths and (
                 dist.location not in self.sitedirs or
-                dist.location == os.getcwd() # account for '.' being in PYTHONPATH
-                )):
+                # account for '.' being in PYTHONPATH
+                dist.location == os.getcwd()
+            )
+        )
+        if new_path:
             self.paths.append(dist.location)
             self.dirty = True
         Environment.add(self, dist)
@@ -1511,13 +1580,13 @@
             self.dirty = True
         Environment.remove(self, dist)
 
-    def make_relative(self,path):
+    def make_relative(self, path):
         npath, last = os.path.split(normalize_path(path))
         baselen = len(self.basedir)
         parts = [last]
-        sep = os.altsep=='/' and '/' or os.sep
-        while len(npath)>=baselen:
-            if npath==self.basedir:
+        sep = os.altsep == '/' and '/' or os.sep
+        while len(npath) >= baselen:
+            if npath == self.basedir:
                 parts.append(os.curdir)
                 parts.reverse()
                 return sep.join(parts)
@@ -1526,59 +1595,231 @@
         else:
             return path
 
-def get_script_header(script_text, executable=sys_executable, wininst=False):
-    """Create a #! line, getting options (if any) from script_text"""
-    from distutils.command.build_scripts import first_line_re
+
+class RewritePthDistributions(PthDistributions):
+
+    @classmethod
+    def _wrap_lines(cls, lines):
+        yield cls.prelude
+        for line in lines:
+            yield line
+        yield cls.postlude
+
+    _inline = lambda text: textwrap.dedent(text).strip().replace('\n', '; ')
+    prelude = _inline("""
+        import sys
+        sys.__plen = len(sys.path)
+        """)
+    postlude = _inline("""
+        import sys
+        new = sys.path[sys.__plen:]
+        del sys.path[sys.__plen:]
+        p = getattr(sys, '__egginsert', 0)
+        sys.path[p:p] = new
+        sys.__egginsert = p + len(new)
+        """)
+
+
+if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'rewrite') == 'rewrite':
+    PthDistributions = RewritePthDistributions
+
+
+def _first_line_re():
+    """
+    Return a regular expression based on first_line_re suitable for matching
+    strings.
+    """
+    if isinstance(first_line_re.pattern, str):
+        return first_line_re
 
     # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern.
-    if not isinstance(first_line_re.pattern, str):
-        first_line_re = re.compile(first_line_re.pattern.decode())
+    return re.compile(first_line_re.pattern.decode())
 
-    first = (script_text+'\n').splitlines()[0]
-    match = first_line_re.match(first)
-    options = ''
-    if match:
-        options = match.group(1) or ''
-        if options: options = ' '+options
-    if wininst:
-        executable = "python.exe"
-    else:
-        executable = nt_quote_arg(executable)
-    hdr = "#!%(executable)s%(options)s\n" % locals()
-    if not isascii(hdr):
-        # Non-ascii path to sys.executable, use -x to prevent warnings
-        if options:
-            if options.strip().startswith('-'):
-                options = ' -x'+options.strip()[1:]
-            # else: punt, we can't do it, let the warning happen anyway
-        else:
-            options = ' -x'
-    executable = fix_jython_executable(executable, options)
-    hdr = "#!%(executable)s%(options)s\n" % locals()
-    return hdr
 
 def auto_chmod(func, arg, exc):
-    if func is os.remove and os.name=='nt':
+    if func is os.remove and os.name == 'nt':
         chmod(arg, stat.S_IWRITE)
         return func(arg)
     et, ev, _ = sys.exc_info()
-    reraise(et, (ev[0], ev[1] + (" %s %s" % (func,arg))))
+    six.reraise(et, (ev[0], ev[1] + (" %s %s" % (func, arg))))
+
+
+def update_dist_caches(dist_path, fix_zipimporter_caches):
+    """
+    Fix any globally cached `dist_path` related data
 
-def uncache_zipdir(path):
-    """Ensure that the importer caches dont have stale info for `path`"""
-    from zipimport import _zip_directory_cache as zdc
-    _uncache(path, zdc)
-    _uncache(path, sys.path_importer_cache)
-
-def _uncache(path, cache):
-    if path in cache:
-        del cache[path]
+    `dist_path` should be a path of a newly installed egg distribution (zipped
+    or unzipped).
+
+    sys.path_importer_cache contains finder objects that have been cached when
+    importing data from the original distribution. Any such finders need to be
+    cleared since the replacement distribution might be packaged differently,
+    e.g. a zipped egg distribution might get replaced with an unzipped egg
+    folder or vice versa. Having the old finders cached may then cause Python
+    to attempt loading modules from the replacement distribution using an
+    incorrect loader.
+
+    zipimport.zipimporter objects are Python loaders charged with importing
+    data packaged inside zip archives. If stale loaders referencing the
+    original distribution, are left behind, they can fail to load modules from
+    the replacement distribution. E.g. if an old zipimport.zipimporter instance
+    is used to load data from a new zipped egg archive, it may cause the
+    operation to attempt to locate the requested data in the wrong location -
+    one indicated by the original distribution's zip archive directory
+    information. Such an operation may then fail outright, e.g. report having
+    read a 'bad local file header', or even worse, it may fail silently &
+    return invalid data.
+
+    zipimport._zip_directory_cache contains cached zip archive directory
+    information for all existing zipimport.zipimporter instances and all such
+    instances connected to the same archive share the same cached directory
+    information.
+
+    If asked, and the underlying Python implementation allows it, we can fix
+    all existing zipimport.zipimporter instances instead of having to track
+    them down and remove them one by one, by updating their shared cached zip
+    archive directory information. This, of course, assumes that the
+    replacement distribution is packaged as a zipped egg.
+
+    If not asked to fix existing zipimport.zipimporter instances, we still do
+    our best to clear any remaining zipimport.zipimporter related cached data
+    that might somehow later get used when attempting to load data from the new
+    distribution and thus cause such load operations to fail. Note that when
+    tracking down such remaining stale data, we can not catch every conceivable
+    usage from here, and we clear only those that we know of and have found to
+    cause problems if left alive. Any remaining caches should be updated by
+    whomever is in charge of maintaining them, i.e. they should be ready to
+    handle us replacing their zip archives with new distributions at runtime.
+
+    """
+    # There are several other known sources of stale zipimport.zipimporter
+    # instances that we do not clear here, but might if ever given a reason to
+    # do so:
+    # * Global setuptools pkg_resources.working_set (a.k.a. 'master working
+    # set') may contain distributions which may in turn contain their
+    #   zipimport.zipimporter loaders.
+    # * Several zipimport.zipimporter loaders held by local variables further
+    #   up the function call stack when running the setuptools installation.
+    # * Already loaded modules may have their __loader__ attribute set to the
+    #   exact loader instance used when importing them. Python 3.4 docs state
+    #   that this information is intended mostly for introspection and so is
+    #   not expected to cause us problems.
+    normalized_path = normalize_path(dist_path)
+    _uncache(normalized_path, sys.path_importer_cache)
+    if fix_zipimporter_caches:
+        _replace_zip_directory_cache_data(normalized_path)
     else:
-        path = normalize_path(path)
-        for p in cache:
-            if normalize_path(p)==path:
-                del cache[p]
-                return
+        # Here, even though we do not want to fix existing and now stale
+        # zipimporter cache information, we still want to remove it. Related to
+        # Python's zip archive directory information cache, we clear each of
+        # its stale entries in two phases:
+        #   1. Clear the entry so attempting to access zip archive information
+        #      via any existing stale zipimport.zipimporter instances fails.
+        #   2. Remove the entry from the cache so any newly constructed
+        #      zipimport.zipimporter instances do not end up using old stale
+        #      zip archive directory information.
+        # This whole stale data removal step does not seem strictly necessary,
+        # but has been left in because it was done before we started replacing
+        # the zip archive directory information cache content if possible, and
+        # there are no relevant unit tests that we can depend on to tell us if
+        # this is really needed.
+        _remove_and_clear_zip_directory_cache_data(normalized_path)
+
+
+def _collect_zipimporter_cache_entries(normalized_path, cache):
+    """
+    Return zipimporter cache entry keys related to a given normalized path.
+
+    Alternative path spellings (e.g. those using different character case or
+    those using alternative path separators) related to the same path are
+    included. Any sub-path entries are included as well, i.e. those
+    corresponding to zip archives embedded in other zip archives.
+
+    """
+    result = []
+    prefix_len = len(normalized_path)
+    for p in cache:
+        np = normalize_path(p)
+        if (np.startswith(normalized_path) and
+                np[prefix_len:prefix_len + 1] in (os.sep, '')):
+            result.append(p)
+    return result
+
+
+def _update_zipimporter_cache(normalized_path, cache, updater=None):
+    """
+    Update zipimporter cache data for a given normalized path.
+
+    Any sub-path entries are processed as well, i.e. those corresponding to zip
+    archives embedded in other zip archives.
+
+    Given updater is a callable taking a cache entry key and the original entry
+    (after already removing the entry from the cache), and expected to update
+    the entry and possibly return a new one to be inserted in its place.
+    Returning None indicates that the entry should not be replaced with a new
+    one. If no updater is given, the cache entries are simply removed without
+    any additional processing, the same as if the updater simply returned None.
+
+    """
+    for p in _collect_zipimporter_cache_entries(normalized_path, cache):
+        # N.B. pypy's custom zipimport._zip_directory_cache implementation does
+        # not support the complete dict interface:
+        # * Does not support item assignment, thus not allowing this function
+        #    to be used only for removing existing cache entries.
+        #  * Does not support the dict.pop() method, forcing us to use the
+        #    get/del patterns instead. For more detailed information see the
+        #    following links:
+        #      https://bitbucket.org/pypa/setuptools/issue/202/more-robust-zipimporter-cache-invalidation#comment-10495960
+        #      https://bitbucket.org/pypy/pypy/src/dd07756a34a41f674c0cacfbc8ae1d4cc9ea2ae4/pypy/module/zipimport/interp_zipimport.py#cl-99
+        old_entry = cache[p]
+        del cache[p]
+        new_entry = updater and updater(p, old_entry)
+        if new_entry is not None:
+            cache[p] = new_entry
+
+
+def _uncache(normalized_path, cache):
+    _update_zipimporter_cache(normalized_path, cache)
+
+
+def _remove_and_clear_zip_directory_cache_data(normalized_path):
+    def clear_and_remove_cached_zip_archive_directory_data(path, old_entry):
+        old_entry.clear()
+
+    _update_zipimporter_cache(
+        normalized_path, zipimport._zip_directory_cache,
+        updater=clear_and_remove_cached_zip_archive_directory_data)
+
+# PyPy Python implementation does not allow directly writing to the
+# zipimport._zip_directory_cache and so prevents us from attempting to correct
+# its content. The best we can do there is clear the problematic cache content
+# and have PyPy repopulate it as needed. The downside is that if there are any
+# stale zipimport.zipimporter instances laying around, attempting to use them
+# will fail due to not having its zip archive directory information available
+# instead of being automatically corrected to use the new correct zip archive
+# directory information.
+if '__pypy__' in sys.builtin_module_names:
+    _replace_zip_directory_cache_data = \
+        _remove_and_clear_zip_directory_cache_data
+else:
+    def _replace_zip_directory_cache_data(normalized_path):
+        def replace_cached_zip_archive_directory_data(path, old_entry):
+            # N.B. In theory, we could load the zip directory information just
+            # once for all updated path spellings, and then copy it locally and
+            # update its contained path strings to contain the correct
+            # spelling, but that seems like a way too invasive move (this cache
+            # structure is not officially documented anywhere and could in
+            # theory change with new Python releases) for no significant
+            # benefit.
+            old_entry.clear()
+            zipimport.zipimporter(path)
+            old_entry.update(zipimport._zip_directory_cache[path])
+            return old_entry
+
+        _update_zipimporter_cache(
+            normalized_path, zipimport._zip_directory_cache,
+            updater=replace_cached_zip_archive_directory_data)
+
 
 def is_python(text, filename=''):
     "Is this string a valid Python script?"
@@ -1589,94 +1830,131 @@
     else:
         return True
 
+
 def is_sh(executable):
     """Determine if the specified executable is a .sh (contains a #! line)"""
     try:
-        fp = open(executable)
-        magic = fp.read(2)
-        fp.close()
-    except (OSError,IOError): return executable
+        with io.open(executable, encoding='latin-1') as fp:
+            magic = fp.read(2)
+    except (OSError, IOError):
+        return executable
     return magic == '#!'
 
+
 def nt_quote_arg(arg):
     """Quote a command line argument according to Windows parsing rules"""
+    return subprocess.list2cmdline([arg])
 
-    result = []
-    needquote = False
-    nb = 0
-
-    needquote = (" " in arg) or ("\t" in arg)
-    if needquote:
-        result.append('"')
-
-    for c in arg:
-        if c == '\\':
-            nb += 1
-        elif c == '"':
-            # double preceding backslashes, then add a \"
-            result.append('\\' * (nb*2) + '\\"')
-            nb = 0
-        else:
-            if nb:
-                result.append('\\' * nb)
-                nb = 0
-            result.append(c)
-
-    if nb:
-        result.append('\\' * nb)
-
-    if needquote:
-        result.append('\\' * nb)    # double the trailing backslashes
-        result.append('"')
-
-    return ''.join(result)
 
 def is_python_script(script_text, filename):
     """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
     """
     if filename.endswith('.py') or filename.endswith('.pyw'):
-        return True     # extension says it's Python
+        return True  # extension says it's Python
     if is_python(script_text, filename):
-        return True     # it's syntactically valid Python
+        return True  # it's syntactically valid Python
     if script_text.startswith('#!'):
         # It begins with a '#!' line, so check if 'python' is in it somewhere
         return 'python' in script_text.splitlines()[0].lower()
 
-    return False    # Not any Python I can recognize
+    return False  # Not any Python I can recognize
+
 
 try:
     from os import chmod as _chmod
 except ImportError:
     # Jython compatibility
-    def _chmod(*args): pass
+    def _chmod(*args):
+        pass
+
 
 def chmod(path, mode):
     log.debug("changing mode of %s to %o", path, mode)
     try:
         _chmod(path, mode)
-    except os.error:
-        e = sys.exc_info()[1]
+    except os.error as e:
         log.debug("chmod failed: %s", e)
 
-def fix_jython_executable(executable, options):
-    if sys.platform.startswith('java') and is_sh(executable):
-        # Workaround for Jython is not needed on Linux systems.
-        import java
-        if java.lang.System.getProperty("os.name") == "Linux":
-            return executable
-
-        # Workaround Jython's sys.executable being a .sh (an invalid
-        # shebang line interpreter)
-        if options:
-            # Can't apply the workaround, leave it broken
-            log.warn(
-                "WARNING: Unable to adapt shebang line for Jython,"
-                " the following script is NOT executable\n"
-                "         see http://bugs.jython.org/issue1112 for"
-                " more information.")
-        else:
-            return '/usr/bin/env %s' % executable
-    return executable
+
+class CommandSpec(list):
+    """
+    A command spec for a #! header, specified as a list of arguments akin to
+    those passed to Popen.
+    """
+
+    options = []
+    split_args = dict()
+
+    @classmethod
+    def best(cls):
+        """
+        Choose the best CommandSpec class based on environmental conditions.
+        """
+        return cls
+
+    @classmethod
+    def _sys_executable(cls):
+        _default = os.path.normpath(sys.executable)
+        return os.environ.get('__PYVENV_LAUNCHER__', _default)
+
+    @classmethod
+    def from_param(cls, param):
+        """
+        Construct a CommandSpec from a parameter to build_scripts, which may
+        be None.
+        """
+        if isinstance(param, cls):
+            return param
+        if isinstance(param, list):
+            return cls(param)
+        if param is None:
+            return cls.from_environment()
+        # otherwise, assume it's a string.
+        return cls.from_string(param)
+
+    @classmethod
+    def from_environment(cls):
+        return cls([cls._sys_executable()])
+
+    @classmethod
+    def from_string(cls, string):
+        """
+        Construct a command spec from a simple string representing a command
+        line parseable by shlex.split.
+        """
+        items = shlex.split(string, **cls.split_args)
+        return cls(items)
+
+    def install_options(self, script_text):
+        self.options = shlex.split(self._extract_options(script_text))
+        cmdline = subprocess.list2cmdline(self)
+        if not isascii(cmdline):
+            self.options[:0] = ['-x']
+
+    @staticmethod
+    def _extract_options(orig_script):
+        """
+        Extract any options from the first line of the script.
+        """
+        first = (orig_script + '\n').splitlines()[0]
+        match = _first_line_re().match(first)
+        options = match.group(1) or '' if match else ''
+        return options.strip()
+
+    def as_header(self):
+        return self._render(self + list(self.options))
+
+    @staticmethod
+    def _render(items):
+        cmdline = subprocess.list2cmdline(items)
+        return '#!' + cmdline + '\n'
+
+# For pbr compat; will be removed in a future version.
+sys_executable = CommandSpec._sys_executable()
+
+
+class WindowsCommandSpec(CommandSpec):
+    split_args = dict(posix=False)
 
 
 class ScriptWriter(object):
@@ -1697,39 +1975,95 @@
             )
     """).lstrip()
 
+    command_spec_class = CommandSpec
+
+    @classmethod
+    def get_script_args(cls, dist, executable=None, wininst=False):
+        # for backward compatibility
+        warnings.warn("Use get_args", DeprecationWarning)
+        writer = (WindowsScriptWriter if wininst else ScriptWriter).best()
+        header = cls.get_script_header("", executable, wininst)
+        return writer.get_args(dist, header)
+
     @classmethod
-    def get_script_args(cls, dist, executable=sys_executable, wininst=False):
+    def get_script_header(cls, script_text, executable=None, wininst=False):
+        # for backward compatibility
+        warnings.warn("Use get_header", DeprecationWarning)
+        if wininst:
+            executable = "python.exe"
+        cmd = cls.command_spec_class.best().from_param(executable)
+        cmd.install_options(script_text)
+        return cmd.as_header()
+
+    @classmethod
+    def get_args(cls, dist, header=None):
         """
-        Yield write_script() argument tuples for a distribution's entrypoints
+        Yield write_script() argument tuples for a distribution's
+        console_scripts and gui_scripts entry points.
         """
-        gen_class = cls.get_writer(wininst)
+        if header is None:
+            header = cls.get_header()
         spec = str(dist.as_requirement())
-        header = get_script_header("", executable, wininst)
         for type_ in 'console', 'gui':
             group = type_ + '_scripts'
             for name, ep in dist.get_entry_map(group).items():
-                script_text = gen_class.template % locals()
-                for res in gen_class._get_script_args(type_, name, header,
-                        script_text):
+                cls._ensure_safe_name(name)
+                script_text = cls.template % locals()
+                args = cls._get_script_args(type_, name, header, script_text)
+                for res in args:
                     yield res
 
+    @staticmethod
+    def _ensure_safe_name(name):
+        """
+        Prevent paths in *_scripts entry point names.
+        """
+        has_path_sep = re.search(r'[\\/]', name)
+        if has_path_sep:
+            raise ValueError("Path separators not allowed in script names")
+
     @classmethod
     def get_writer(cls, force_windows):
-        if force_windows or sys.platform=='win32':
-            return WindowsScriptWriter.get_writer()
-        return cls
+        # for backward compatibility
+        warnings.warn("Use best", DeprecationWarning)
+        return WindowsScriptWriter.best() if force_windows else cls.best()
+
+    @classmethod
+    def best(cls):
+        """
+        Select the best ScriptWriter for this environment.
+        """
+        if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'):
+            return WindowsScriptWriter.best()
+        else:
+            return cls
 
     @classmethod
     def _get_script_args(cls, type_, name, header, script_text):
         # Simply write the stub with no extension.
-        yield (name, header+script_text)
+        yield (name, header + script_text)
+
+    @classmethod
+    def get_header(cls, script_text="", executable=None):
+        """Create a #! line, getting options (if any) from script_text"""
+        cmd = cls.command_spec_class.best().from_param(executable)
+        cmd.install_options(script_text)
+        return cmd.as_header()
 
 
 class WindowsScriptWriter(ScriptWriter):
+    command_spec_class = WindowsCommandSpec
+
     @classmethod
     def get_writer(cls):
+        # for backward compatibility
+        warnings.warn("Use best", DeprecationWarning)
+        return cls.best()
+
+    @classmethod
+    def best(cls):
         """
-        Get a script writer suitable for Windows
+        Select the best ScriptWriter suitable for Windows
         """
         writer_lookup = dict(
             executable=WindowsExecutableLauncherWriter,
@@ -1745,15 +2079,15 @@
         ext = dict(console='.pya', gui='.pyw')[type_]
         if ext not in os.environ['PATHEXT'].lower().split(';'):
             warnings.warn("%s not listed in PATHEXT; scripts will not be "
-                "recognized as executables." % ext, UserWarning)
+                          "recognized as executables." % ext, UserWarning)
         old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe']
         old.remove(ext)
         header = cls._adjust_header(type_, header)
-        blockers = [name+x for x in old]
-        yield name+ext, header+script_text, 't', blockers
+        blockers = [name + x for x in old]
+        yield name + ext, header + script_text, 't', blockers
 
-    @staticmethod
-    def _adjust_header(type_, orig_header):
+    @classmethod
+    def _adjust_header(cls, type_, orig_header):
         """
         Make sure 'pythonw' is used for gui and and 'python' is used for
         console (regardless of what sys.executable is).
@@ -1764,11 +2098,19 @@
             pattern, repl = repl, pattern
         pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE)
         new_header = pattern_ob.sub(string=orig_header, repl=repl)
+        return new_header if cls._use_header(new_header) else orig_header
+
+    @staticmethod
+    def _use_header(new_header):
+        """
+        Should _adjust_header use the replaced header?
+
+        On non-windows systems, always use. On
+        Windows systems, only use the replaced header if it resolves
+        to an executable on the system.
+        """
         clean_header = new_header[2:-1].strip('"')
-        if sys.platform == 'win32' and not os.path.exists(clean_header):
-            # the adjusted version doesn't exist, so return the original
-            return orig_header
-        return new_header
+        return sys.platform != 'win32' or find_executable(clean_header)
 
 
 class WindowsExecutableLauncherWriter(WindowsScriptWriter):
@@ -1777,32 +2119,35 @@
         """
         For Windows, add a .py extension and an .exe launcher
         """
-        if type_=='gui':
+        if type_ == 'gui':
             launcher_type = 'gui'
             ext = '-script.pyw'
             old = ['.pyw']
         else:
             launcher_type = 'cli'
             ext = '-script.py'
-            old = ['.py','.pyc','.pyo']
+            old = ['.py', '.pyc', '.pyo']
         hdr = cls._adjust_header(type_, header)
-        blockers = [name+x for x in old]
-        yield (name+ext, hdr+script_text, 't', blockers)
+        blockers = [name + x for x in old]
+        yield (name + ext, hdr + script_text, 't', blockers)
         yield (
-            name+'.exe', get_win_launcher(launcher_type),
-            'b' # write in binary mode
+            name + '.exe', get_win_launcher(launcher_type),
+            'b'  # write in binary mode
         )
         if not is_64bit():
             # install a manifest for the launcher to prevent Windows
-            #  from detecting it as an installer (which it will for
+            # from detecting it as an installer (which it will for
             #  launchers like easy_install.exe). Consider only
             #  adding a manifest for launchers detected as installers.
             #  See Distribute #143 for details.
             m_name = name + '.exe.manifest'
             yield (m_name, load_launcher_manifest(name), 't')
 
+
 # for backward-compatibility
 get_script_args = ScriptWriter.get_script_args
+get_script_header = ScriptWriter.get_script_header
+
 
 def get_win_launcher(type):
     """
@@ -1813,7 +2158,7 @@
     Returns the executable as a byte string.
     """
     launcher_fn = '%s.exe' % type
-    if platform.machine().lower()=='arm':
+    if platform.machine().lower() == 'arm':
         launcher_fn = launcher_fn.replace(".", "-arm.")
     if is_64bit():
         launcher_fn = launcher_fn.replace(".", "-64.")
@@ -1821,13 +2166,15 @@
         launcher_fn = launcher_fn.replace(".", "-32.")
     return resource_string('setuptools', launcher_fn)
 
+
 def load_launcher_manifest(name):
     manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml')
-    if sys.version_info[0] < 3:
+    if six.PY2:
         return manifest % vars()
     else:
         return manifest.decode('utf-8') % vars()
 
+
 def rmtree(path, ignore_errors=False, onerror=auto_chmod):
     """Recursively delete a directory tree.
 
@@ -1863,55 +2210,61 @@
     except os.error:
         onerror(os.rmdir, path, sys.exc_info())
 
+
 def current_umask():
-    tmp = os.umask(0x12)    # 022
+    tmp = os.umask(0o022)
     os.umask(tmp)
     return tmp
 
+
 def bootstrap():
     # This function is called when setuptools*.egg is run using /bin/sh
     import setuptools
+
     argv0 = os.path.dirname(setuptools.__path__[0])
     sys.argv[0] = argv0
     sys.argv.append(argv0)
     main()
 
+
 def main(argv=None, **kw):
     from setuptools import setup
     from setuptools.dist import Distribution
-    import distutils.core
-
-    USAGE = """\
-usage: %(script)s [options] requirement_or_url ...
-   or: %(script)s --help
-"""
-
-    def gen_usage(script_name):
-        return USAGE % dict(
-            script=os.path.basename(script_name),
-        )
-
-    def with_ei_usage(f):
-        old_gen_usage = distutils.core.gen_usage
-        try:
-            distutils.core.gen_usage = gen_usage
-            return f()
-        finally:
-            distutils.core.gen_usage = old_gen_usage
 
     class DistributionWithoutHelpCommands(Distribution):
         common_usage = ""
 
-        def _show_help(self,*args,**kw):
-            with_ei_usage(lambda: Distribution._show_help(self,*args,**kw))
+        def _show_help(self, *args, **kw):
+            with _patch_usage():
+                Distribution._show_help(self, *args, **kw)
 
     if argv is None:
         argv = sys.argv[1:]
 
-    with_ei_usage(lambda:
+    with _patch_usage():
         setup(
-            script_args = ['-q','easy_install', '-v']+argv,
-            script_name = sys.argv[0] or 'easy_install',
+            script_args=['-q', 'easy_install', '-v'] + argv,
+            script_name=sys.argv[0] or 'easy_install',
             distclass=DistributionWithoutHelpCommands, **kw
         )
-    )
+
+
+@contextlib.contextmanager
+def _patch_usage():
+    import distutils.core
+    USAGE = textwrap.dedent("""
+        usage: %(script)s [options] requirement_or_url ...
+           or: %(script)s --help
+        """).lstrip()
+
+    def gen_usage(script_name):
+        return USAGE % dict(
+            script=os.path.basename(script_name),
+        )
+
+    saved = distutils.core.gen_usage
+    distutils.core.gen_usage = gen_usage
+    try:
+        yield
+    finally:
+        distutils.core.gen_usage = saved
diff -Nru python-setuptools-3.3/setuptools/command/egg_info.py python-setuptools-20.1.1/setuptools/command/egg_info.py
--- python-setuptools-3.3/setuptools/command/egg_info.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/egg_info.py	2016-02-07 14:25:06.000000000 +0000
@@ -2,21 +2,37 @@
 
 Create a distribution's .egg-info directory and contents"""
 
+from distutils.filelist import FileList as _FileList
+from distutils.util import convert_path
+from distutils import log
+import distutils.errors
+import distutils.filelist
 import os
 import re
 import sys
+import io
+import warnings
+import time
+
+from setuptools.extern import six
+from setuptools.extern.six.moves import map
 
 from setuptools import Command
-import distutils.errors
-from distutils import log
 from setuptools.command.sdist import sdist
-from setuptools.compat import basestring
-from setuptools import svn_utils
-from distutils.util import convert_path
-from distutils.filelist import FileList as _FileList
-from pkg_resources import (parse_requirements, safe_name, parse_version,
-    safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
 from setuptools.command.sdist import walk_revctrl
+from setuptools.command.setopt import edit_config
+from setuptools.command import bdist_egg
+from pkg_resources import (
+    parse_requirements, safe_name, parse_version,
+    safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
+import setuptools.unicode_utils as unicode_utils
+
+from pkg_resources.extern import packaging
+
+try:
+    from setuptools_svn import svn_utils
+except ImportError:
+    pass
 
 
 class egg_info(Command):
@@ -26,11 +42,11 @@
         ('egg-base=', 'e', "directory containing .egg-info directories"
                            " (default: top of the source tree)"),
         ('tag-svn-revision', 'r',
-            "Add subversion revision ID to version number"),
+         "Add subversion revision ID to version number"),
         ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
         ('tag-build=', 'b', "Specify explicit tag to add to version number"),
         ('no-svn-revision', 'R',
-            "Don't add subversion revision ID [default]"),
+         "Don't add subversion revision ID [default]"),
         ('no-date', 'D', "Don't include date stamp [default]"),
     ]
 
@@ -50,7 +66,6 @@
         self.vtags = None
 
     def save_version_info(self, filename):
-        from setuptools.command.setopt import edit_config
         values = dict(
             egg_info=dict(
                 tag_svn_revision=0,
@@ -65,25 +80,32 @@
         self.vtags = self.tags()
         self.egg_version = self.tagged_version()
 
+        parsed_version = parse_version(self.egg_version)
+
         try:
+            is_version = isinstance(parsed_version, packaging.version.Version)
+            spec = (
+                "%s==%s" if is_version else "%s===%s"
+            )
             list(
-                parse_requirements('%s==%s' % (self.egg_name,self.egg_version))
+                parse_requirements(spec % (self.egg_name, self.egg_version))
             )
         except ValueError:
             raise distutils.errors.DistutilsOptionError(
                 "Invalid distribution name or version syntax: %s-%s" %
-                (self.egg_name,self.egg_version)
+                (self.egg_name, self.egg_version)
             )
 
         if self.egg_base is None:
             dirs = self.distribution.package_dir
-            self.egg_base = (dirs or {}).get('',os.curdir)
+            self.egg_base = (dirs or {}).get('', os.curdir)
 
         self.ensure_dirname('egg_base')
-        self.egg_info = to_filename(self.egg_name)+'.egg-info'
+        self.egg_info = to_filename(self.egg_name) + '.egg-info'
         if self.egg_base != os.curdir:
             self.egg_info = os.path.join(self.egg_base, self.egg_info)
-        if '-' in self.egg_name: self.check_broken_egg_info()
+        if '-' in self.egg_name:
+            self.check_broken_egg_info()
 
         # Set package version for the benefit of dumber commands
         # (e.g. sdist, bdist_wininst, etc.)
@@ -95,7 +117,7 @@
         # to the version info
         #
         pd = self.distribution._patched_dist
-        if pd is not None and pd.key==self.egg_name.lower():
+        if pd is not None and pd.key == self.egg_name.lower():
             pd._version = self.egg_version
             pd._parsed_version = parse_version(self.egg_version)
             self.distribution._patched_dist = None
@@ -127,7 +149,7 @@
         to the file.
         """
         log.info("writing %s to %s", what, filename)
-        if sys.version_info >= (3,):
+        if six.PY3:
             data = data.encode("utf-8")
         if not self.dry_run:
             f = open(filename, 'wb')
@@ -152,8 +174,9 @@
         self.mkpath(self.egg_info)
         installer = self.distribution.fetch_build_egg
         for ep in iter_entry_points('egg_info.writers'):
-            writer = ep.load(installer=installer)
-            writer(self, ep.name, os.path.join(self.egg_info,ep.name))
+            ep.require(installer=installer)
+            writer = ep.resolve()
+            writer(self, ep.name, os.path.join(self.egg_info, ep.name))
 
         # Get rid of native_libs.txt if it was put there by older bdist_egg
         nl = os.path.join(self.egg_info, "native_libs.txt")
@@ -165,68 +188,92 @@
     def tags(self):
         version = ''
         if self.tag_build:
-            version+=self.tag_build
-        if self.tag_svn_revision and (
-            os.path.exists('.svn') or os.path.exists('PKG-INFO')
-        ):  version += '-r%s' % self.get_svn_revision()
+            version += self.tag_build
+        if self.tag_svn_revision:
+            version += '-r%s' % self.get_svn_revision()
         if self.tag_date:
-            import time
             version += time.strftime("-%Y%m%d")
         return version
 
     @staticmethod
     def get_svn_revision():
+        if 'svn_utils' not in globals():
+            return "0"
         return str(svn_utils.SvnInfo.load(os.curdir).get_revision())
 
     def find_sources(self):
         """Generate SOURCES.txt manifest file"""
-        manifest_filename = os.path.join(self.egg_info,"SOURCES.txt")
+        manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
         mm = manifest_maker(self.distribution)
         mm.manifest = manifest_filename
         mm.run()
         self.filelist = mm.filelist
 
     def check_broken_egg_info(self):
-        bei = self.egg_name+'.egg-info'
+        bei = self.egg_name + '.egg-info'
         if self.egg_base != os.curdir:
             bei = os.path.join(self.egg_base, bei)
         if os.path.exists(bei):
             log.warn(
-                "-"*78+'\n'
+                "-" * 78 + '\n'
                 "Note: Your current .egg-info directory has a '-' in its name;"
                 '\nthis will not work correctly with "setup.py develop".\n\n'
-                'Please rename %s to %s to correct this problem.\n'+'-'*78,
+                'Please rename %s to %s to correct this problem.\n' + '-' * 78,
                 bei, self.egg_info
             )
             self.broken_egg_info = self.egg_info
-            self.egg_info = bei     # make it work for now
+            self.egg_info = bei  # make it work for now
+
 
 class FileList(_FileList):
     """File list that accepts only existing, platform-independent paths"""
 
     def append(self, item):
-        if item.endswith('\r'):     # Fix older sdists built on Windows
+        if item.endswith('\r'):  # Fix older sdists built on Windows
             item = item[:-1]
         path = convert_path(item)
 
-        if sys.version_info >= (3,):
-            try:
-                if os.path.exists(path) or os.path.exists(path.encode('utf-8')):
-                    self.files.append(path)
-            except UnicodeEncodeError:
-                # Accept UTF-8 filenames even if LANG=C
-                if os.path.exists(path.encode('utf-8')):
-                    self.files.append(path)
-                else:
-                    log.warn("'%s' not %s encodable -- skipping", path,
-                        sys.getfilesystemencoding())
-        else:
-            if os.path.exists(path):
-                self.files.append(path)
+        if self._safe_path(path):
+            self.files.append(path)
 
+    def extend(self, paths):
+        self.files.extend(filter(self._safe_path, paths))
 
-class manifest_maker(sdist):
+    def _repair(self):
+        """
+        Replace self.files with only safe paths
+
+        Because some owners of FileList manipulate the underlying
+        ``files`` attribute directly, this method must be called to
+        repair those paths.
+        """
+        self.files = list(filter(self._safe_path, self.files))
+
+    def _safe_path(self, path):
+        enc_warn = "'%s' not %s encodable -- skipping"
+
+        # To avoid accidental trans-codings errors, first to unicode
+        u_path = unicode_utils.filesys_decode(path)
+        if u_path is None:
+            log.warn("'%s' in unexpected encoding -- skipping" % path)
+            return False
+
+        # Must ensure utf-8 encodability
+        utf8_path = unicode_utils.try_encode(u_path, "utf-8")
+        if utf8_path is None:
+            log.warn(enc_warn, path, 'utf-8')
+            return False
+
+        try:
+            # accept is either way checks out
+            if os.path.exists(u_path) or os.path.exists(utf8_path):
+                return True
+        # this will catch any encode errors decoding u_path
+        except UnicodeEncodeError:
+            log.warn(enc_warn, path, sys.getfilesystemencoding())
 
+
+class manifest_maker(sdist):
     template = "MANIFEST.in"
 
     def initialize_options(self):
@@ -241,7 +288,7 @@
     def run(self):
         self.filelist = FileList()
         if not os.path.exists(self.manifest):
-            self.write_manifest()   # it must exist so it'll get in the list
+            self.write_manifest()  # it must exist so it'll get in the list
         self.filelist.findall()
         self.add_defaults()
         if os.path.exists(self.template):
@@ -251,30 +298,23 @@
         self.filelist.remove_duplicates()
         self.write_manifest()
 
+    def _manifest_normalize(self, path):
+        path = unicode_utils.filesys_decode(path)
+        return path.replace(os.sep, '/')
+
     def write_manifest(self):
-        """Write the file list in 'self.filelist' (presumably as filled in
-        by 'add_defaults()' and 'read_template()') to the manifest file
+        """
+        Write the file list in 'self.filelist' to the manifest file
         named by 'self.manifest'.
         """
-        # The manifest must be UTF-8 encodable. See #303.
-        if sys.version_info >= (3,):
-            files = []
-            for file in self.filelist.files:
-                try:
-                    file.encode("utf-8")
-                except UnicodeEncodeError:
-                    log.warn("'%s' not UTF-8 encodable -- skipping" % file)
-                else:
-                    files.append(file)
-            self.filelist.files = files
-
-        files = self.filelist.files
-        if os.sep!='/':
-            files = [f.replace(os.sep,'/') for f in files]
-        self.execute(write_file, (self.manifest, files),
-                     "writing manifest file '%s'" % self.manifest)
+        self.filelist._repair()
+
+        # Now _repairs should encodability, but not unicode
+        files = [self._manifest_normalize(f) for f in self.filelist.files]
+        msg = "writing manifest file '%s'" % self.manifest
+        self.execute(write_file, (self.manifest, files), msg)
 
-    def warn(self, msg):    # suppress missing-file warnings from sdist
+    def warn(self, msg):  # suppress missing-file warnings from sdist
         if not msg.startswith("standard file not found:"):
             sdist.warn(self, msg)
 
@@ -288,15 +328,41 @@
         elif os.path.exists(self.manifest):
             self.read_manifest()
         ei_cmd = self.get_finalized_command('egg_info')
+        self._add_egg_info(cmd=ei_cmd)
         self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
 
+    def _add_egg_info(self, cmd):
+        """
+        Add paths for egg-info files for an external egg-base.
+
+        The egg-info files are written to egg-base. If egg-base is
+        outside the current working directory, this method
+        searchs the egg-base directory for files to include
+        in the manifest. Uses distutils.filelist.findall (which is
+        really the version monkeypatched in by setuptools/__init__.py)
+        to perform the search.
+
+        Since findall records relative paths, prefix the returned
+        paths with cmd.egg_base, so add_default's include_pattern call
+        (which is looking for the absolute cmd.egg_info) will match
+        them.
+        """
+        if cmd.egg_base == os.curdir:
+            # egg-info files were already added by something else
+            return
+
+        discovered = distutils.filelist.findall(cmd.egg_base)
+        resolved = (os.path.join(cmd.egg_base, path) for path in discovered)
+        self.filelist.allfiles.extend(resolved)
+
     def prune_file_list(self):
         build = self.get_finalized_command('build')
         base_dir = self.distribution.get_fullname()
         self.filelist.exclude_pattern(None, prefix=build.build_base)
         self.filelist.exclude_pattern(None, prefix=base_dir)
         sep = re.escape(os.sep)
-        self.filelist.exclude_pattern(sep+r'(RCS|CVS|\.svn)'+sep, is_regex=1)
+        self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
+                                      is_regex=1)
 
 
 def write_file(filename, contents):
@@ -304,11 +370,13 @@
     sequence of strings without line terminators) to it.
     """
     contents = "\n".join(contents)
-    if sys.version_info >= (3,):
-        contents = contents.encode("utf-8")
-    f = open(filename, "wb")        # always write POSIX-style manifest
-    f.write(contents)
-    f.close()
+
+    # assuming the contents has been vetted for utf-8 encoding
+    contents = contents.encode("utf-8")
+
+    with open(filename, "wb") as f:  # always write POSIX-style manifest
+        f.write(contents)
+
 
 def write_pkg_info(cmd, basename, filename):
     log.info("writing %s", filename)
@@ -323,10 +391,11 @@
         finally:
             metadata.name, metadata.version = oldname, oldver
 
-        safe = getattr(cmd.distribution,'zip_safe',None)
-        from setuptools.command import bdist_egg
+        safe = getattr(cmd.distribution, 'zip_safe', None)
+
         bdist_egg.write_safety_flag(cmd.egg_info, safe)
 
+
 def warn_depends_obsolete(cmd, basename, filename):
     if os.path.exists(filename):
         log.warn(
@@ -335,58 +404,79 @@
         )
 
 
+def _write_requirements(stream, reqs):
+    lines = yield_lines(reqs or ())
+    append_cr = lambda line: line + '\n'
+    lines = map(append_cr, lines)
+    stream.writelines(lines)
+
+
 def write_requirements(cmd, basename, filename):
     dist = cmd.distribution
-    data = ['\n'.join(yield_lines(dist.install_requires or ()))]
-    for extra,reqs in (dist.extras_require or {}).items():
-        data.append('\n\n[%s]\n%s' % (extra, '\n'.join(yield_lines(reqs))))
-    cmd.write_or_delete_file("requirements", filename, ''.join(data))
+    data = six.StringIO()
+    _write_requirements(data, dist.install_requires)
+    extras_require = dist.extras_require or {}
+    for extra in sorted(extras_require):
+        data.write('\n[{extra}]\n'.format(**vars()))
+        _write_requirements(data, extras_require[extra])
+    cmd.write_or_delete_file("requirements", filename, data.getvalue())
+
+
+def write_setup_requirements(cmd, basename, filename):
+    data = StringIO()
+    _write_requirements(data, cmd.distribution.setup_requires)
+    cmd.write_or_delete_file("setup-requirements", filename, data.getvalue())
+
 
 def write_toplevel_names(cmd, basename, filename):
     pkgs = dict.fromkeys(
         [
-            k.split('.',1)[0]
+            k.split('.', 1)[0]
             for k in cmd.distribution.iter_distribution_names()
         ]
     )
-    cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n')
+    cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n')
 
 
 def overwrite_arg(cmd, basename, filename):
     write_arg(cmd, basename, filename, True)
 
+
 def write_arg(cmd, basename, filename, force=False):
     argname = os.path.splitext(basename)[0]
     value = getattr(cmd.distribution, argname, None)
     if value is not None:
-        value = '\n'.join(value)+'\n'
+        value = '\n'.join(value) + '\n'
     cmd.write_or_delete_file(argname, filename, value, force)
 
+
 def write_entries(cmd, basename, filename):
     ep = cmd.distribution.entry_points
 
-    if isinstance(ep,basestring) or ep is None:
+    if isinstance(ep, six.string_types) or ep is None:
         data = ep
     elif ep is not None:
         data = []
-        for section, contents in ep.items():
-            if not isinstance(contents,basestring):
+        for section, contents in sorted(ep.items()):
+            if not isinstance(contents, six.string_types):
                 contents = EntryPoint.parse_group(section, contents)
-                contents = '\n'.join(map(str,contents.values()))
-            data.append('[%s]\n%s\n\n' % (section,contents))
+                contents = '\n'.join(sorted(map(str, contents.values())))
+            data.append('[%s]\n%s\n\n' % (section, contents))
         data = ''.join(data)
 
     cmd.write_or_delete_file('entry points', filename, data, True)
 
+
 def get_pkg_info_revision():
-    # See if we can get a -r### off of PKG-INFO, in case this is an sdist of
-    # a subversion revision
-    #
+    """
+    Get a -r### off of PKG-INFO Version in case this is an sdist of
+    a subversion revision.
+    """
+    warnings.warn("get_pkg_info_revision is deprecated.", DeprecationWarning)
     if os.path.exists('PKG-INFO'):
-        f = open('PKG-INFO','rU')
-        for line in f:
-            match = re.match(r"Version:.*-r(\d+)\s*$", line)
-            if match:
-                return int(match.group(1))
-        f.close()
+        with io.open('PKG-INFO') as f:
+            for line in f:
+                match = re.match(r"Version:.*-r(\d+)\s*$", line)
+                if match:
+                    return int(match.group(1))
     return 0
diff -Nru python-setuptools-3.3/setuptools/command/__init__.py python-setuptools-20.1.1/setuptools/command/__init__.py
--- python-setuptools-3.3/setuptools/command/__init__.py	2014-02-12 03:53:21.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/__init__.py	2016-02-12 04:34:08.000000000 +0000
@@ -2,13 +2,14 @@
     'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop',
     'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts',
     'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts',
-    'register', 'bdist_wininst', 'upload_docs',
+    'register', 'bdist_wininst', 'upload_docs', 'upload',
 ]
 
-from setuptools.command import install_scripts
+from distutils.command.bdist import bdist
 import sys
 
-from distutils.command.bdist import bdist
+from setuptools.command import install_scripts
+
 
 if 'egg' not in bdist.format_commands:
     bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
diff -Nru python-setuptools-3.3/setuptools/command/install_egg_info.py python-setuptools-20.1.1/setuptools/command/install_egg_info.py
--- python-setuptools-3.3/setuptools/command/install_egg_info.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/install_egg_info.py	2016-02-07 14:36:03.000000000 +0000
@@ -1,7 +1,12 @@
+from distutils import log, dir_util
+import os
+
+from setuptools.extern.six.moves import map
+
 from setuptools import Command
 from setuptools.archive_util import unpack_archive
-from distutils import log, dir_util
-import os, pkg_resources
+import pkg_resources
+
 
 class install_egg_info(Command):
     """Install an .egg-info directory for the package"""
@@ -16,26 +21,26 @@
         self.install_dir = None
 
     def finalize_options(self):
-        self.set_undefined_options('install_lib',('install_dir','install_dir'))
+        self.set_undefined_options('install_lib',
+                                   ('install_dir', 'install_dir'))
         ei_cmd = self.get_finalized_command("egg_info")
         basename = pkg_resources.Distribution(
             None, None, ei_cmd.egg_name, ei_cmd.egg_version
-        ).egg_name()+'.egg-info'
+        ).egg_name() + '.egg-info'
         self.source = ei_cmd.egg_info
         self.target = os.path.join(self.install_dir, basename)
-        self.outputs = [self.target]
+        self.outputs = []
 
     def run(self):
         self.run_command('egg_info')
-        target = self.target
         if os.path.isdir(self.target) and not os.path.islink(self.target):
             dir_util.remove_tree(self.target, dry_run=self.dry_run)
         elif os.path.exists(self.target):
-            self.execute(os.unlink,(self.target,),"Removing "+self.target)
+            self.execute(os.unlink, (self.target,), "Removing " + self.target)
         if not self.dry_run:
             pkg_resources.ensure_directory(self.target)
-        self.execute(self.copytree, (),
-            "Copying %s to %s" % (self.source, self.target)
+        self.execute(
+            self.copytree, (), "Copying %s to %s" % (self.source, self.target)
         )
         self.install_namespaces()
 
@@ -44,82 +49,70 @@
 
     def copytree(self):
         # Copy the .egg-info tree to site-packages
-        def skimmer(src,dst):
+        def skimmer(src, dst):
             # filter out source-control directories; note that 'src' is always
             # a '/'-separated path, regardless of platform.  'dst' is a
             # platform-specific path.
-            for skip in '.svn/','CVS/':
-                if src.startswith(skip) or '/'+skip in src:
+            for skip in '.svn/', 'CVS/':
+                if src.startswith(skip) or '/' + skip in src:
                     return None
             self.outputs.append(dst)
             log.debug("Copying %s to %s", src, dst)
             return dst
-        unpack_archive(self.source, self.target, skimmer)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 
+        unpack_archive(self.source, self.target, skimmer)
 
     def install_namespaces(self):
         nsp = self._get_all_ns_packages()
-        if not nsp: return
-        filename,ext = os.path.splitext(self.target)
-        filename += '-nspkg.pth'; self.outputs.append(filename)
-        log.info("Installing %s",filename)
-        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:
-                    trailer = (
-                        "; m and setattr(sys.modules[%r], %r, m)\n"
-                        % ('.'.join(pth[:-1]), pth[-1])
-                    )
-                f.write(
-                    "import sys,types,os; "
-                    "p = os.path.join(sys._getframe(1).f_locals['sitedir'], "
-                        "*%(pth)r); "
-                    "ie = os.path.exists(os.path.join(p,'__init__.py')); "
-                    "m = not ie and "
-                        "sys.modules.setdefault(%(pkg)r,types.ModuleType(%(pkg)r)); "
-                    "mp = (m or []) and m.__dict__.setdefault('__path__',[]); "
-                    "(p not in mp) and mp.append(p)%(trailer)s"
-                    % locals()
-                )
-            f.close()
+        if not nsp:
+            return
+        filename, ext = os.path.splitext(self.target)
+        filename += '-nspkg.pth'
+        self.outputs.append(filename)
+        log.info("Installing %s", filename)
+        lines = map(self._gen_nspkg_line, nsp)
+
+        if self.dry_run:
+            # always generate the lines, even in dry run
+            list(lines)
+            return
+
+        with open(filename, 'wt') as f:
+            f.writelines(lines)
+
+    _nspkg_tmpl = (
+        "import sys, types, os",
+        "p = os.path.join(sys._getframe(1).f_locals['sitedir'], *%(pth)r)",
+        "ie = os.path.exists(os.path.join(p,'__init__.py'))",
+        "m = not ie and "
+            "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
+        "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
+        "(p not in mp) and mp.append(p)",
+    )
+    "lines for the namespace installer"
+
+    _nspkg_tmpl_multi = (
+        'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
+    )
+    "additional line(s) when a parent package is indicated"
+
+    @classmethod
+    def _gen_nspkg_line(cls, pkg):
+        # ensure pkg is not a unicode string under Python 2.7
+        pkg = str(pkg)
+        pth = tuple(pkg.split('.'))
+        tmpl_lines = cls._nspkg_tmpl
+        parent, sep, child = pkg.rpartition('.')
+        if parent:
+            tmpl_lines += cls._nspkg_tmpl_multi
+        return ';'.join(tmpl_lines) % locals() + '\n'
 
     def _get_all_ns_packages(self):
-        nsp = {}
+        """Return sorted list of all package namespaces"""
+        nsp = set()
         for pkg in self.distribution.namespace_packages or []:
             pkg = pkg.split('.')
             while pkg:
-                nsp['.'.join(pkg)] = 1
+                nsp.add('.'.join(pkg))
                 pkg.pop()
-        nsp=list(nsp)
-        nsp.sort()  # set up shorter names first
-        return nsp
-
-
+        return sorted(nsp)
diff -Nru python-setuptools-3.3/setuptools/command/install_lib.py python-setuptools-20.1.1/setuptools/command/install_lib.py
--- python-setuptools-3.3/setuptools/command/install_lib.py	2014-03-15 12:37:21.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/install_lib.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,7 +1,9 @@
-from distutils.command.install_lib import install_lib as _install_lib
 import os
+import imp
+from itertools import product, starmap
+import distutils.command.install_lib as orig
 
-class install_lib(_install_lib):
+class install_lib(orig.install_lib):
     """Don't add compiled flags to filenames of non-Python files"""
 
     def run(self):
@@ -12,29 +14,83 @@
             self.byte_compile(outfiles)
 
     def get_exclusions(self):
-        exclude = {}
-        nsp = self.distribution.namespace_packages
-        svem = (nsp and self.get_finalized_command('install')
-            .single_version_externally_managed)
-        if svem:
-            for pkg in nsp:
-                parts = pkg.split('.')
-                while parts:
-                    pkgdir = os.path.join(self.install_dir, *parts)
-                    for f in '__init__.py', '__init__.pyc', '__init__.pyo':
-                        exclude[os.path.join(pkgdir,f)] = 1
-                    parts.pop()
-        return exclude
+        """
+        Return a collections.Sized collections.Container of paths to be
+        excluded for single_version_externally_managed installations.
+        """
+        all_packages = (
+            pkg
+            for ns_pkg in self._get_SVEM_NSPs()
+            for pkg in self._all_packages(ns_pkg)
+        )
+
+        excl_specs = product(all_packages, self._gen_exclusion_paths())
+        return set(starmap(self._exclude_pkg_path, excl_specs))
+
+    def _exclude_pkg_path(self, pkg, exclusion_path):
+        """
+        Given a package name and exclusion path within that package,
+        compute the full exclusion path.
+        """
+        parts = pkg.split('.') + [exclusion_path]
+        return os.path.join(self.install_dir, *parts)
+
+    @staticmethod
+    def _all_packages(pkg_name):
+        """
+        >>> list(install_lib._all_packages('foo.bar.baz'))
+        ['foo.bar.baz', 'foo.bar', 'foo']
+        """
+        while pkg_name:
+            yield pkg_name
+            pkg_name, sep, child = pkg_name.rpartition('.')
+
+    def _get_SVEM_NSPs(self):
+        """
+        Get namespace packages (list) but only for
+        single_version_externally_managed installations and empty otherwise.
+        """
+        # TODO: is it necessary to short-circuit here? i.e. what's the cost
+        # if get_finalized_command is called even when namespace_packages is
+        # False?
+        if not self.distribution.namespace_packages:
+            return []
+
+        install_cmd = self.get_finalized_command('install')
+        svem = install_cmd.single_version_externally_managed
+
+        return self.distribution.namespace_packages if svem else []
+
+    @staticmethod
+    def _gen_exclusion_paths():
+        """
+        Generate file paths to be excluded for namespace packages (bytecode
+        cache files).
+        """
+        # always exclude the package module itself
+        yield '__init__.py'
+
+        yield '__init__.pyc'
+        yield '__init__.pyo'
+
+        if not hasattr(imp, 'get_tag'):
+            return
+
+        base = os.path.join('__pycache__', '__init__.' + imp.get_tag())
+        yield base + '.pyc'
+        yield base + '.pyo'
+        yield base + '.opt-1.pyc'
+        yield base + '.opt-2.pyc'
 
     def copy_tree(
-        self, infile, outfile,
-        preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
+            self, infile, outfile,
+            preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
     ):
         assert preserve_mode and preserve_times and not preserve_symlinks
         exclude = self.get_exclusions()
 
         if not exclude:
-            return _install_lib.copy_tree(self, infile, outfile)
+            return orig.install_lib.copy_tree(self, infile, outfile)
 
         # Exclude namespace package __init__.py* files from the output
 
@@ -45,7 +101,8 @@
 
         def pf(src, dst):
             if dst in exclude:
-                log.warn("Skipping installation of %s (namespace package)",dst)
+                log.warn("Skipping installation of %s (namespace package)",
+                         dst)
                 return False
 
             log.info("copying %s -> %s", src, os.path.dirname(dst))
@@ -56,7 +113,7 @@
         return outfiles
 
     def get_outputs(self):
-        outputs = _install_lib.get_outputs(self)
+        outputs = orig.install_lib.get_outputs(self)
         exclude = self.get_exclusions()
         if exclude:
             return [f for f in outputs if f not in exclude]
diff -Nru python-setuptools-3.3/setuptools/command/install.py python-setuptools-20.1.1/setuptools/command/install.py
--- python-setuptools-3.3/setuptools/command/install.py	2014-03-15 12:37:21.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/install.py	2016-01-30 17:43:56.000000000 +0000
@@ -1,18 +1,26 @@
-import setuptools
-import sys
-import glob
-from distutils.command.install import install as _install
 from distutils.errors import DistutilsArgError
+import inspect
+import glob
+import warnings
+import platform
+import distutils.command.install as orig
+
+import setuptools
 
-class install(_install):
+# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for
+# now. See https://bitbucket.org/pypa/setuptools/issue/199/
+_install = orig.install
+
+
+class install(orig.install):
     """Use easy_install to install the package, w/dependencies"""
 
-    user_options = _install.user_options + [
+    user_options = orig.install.user_options + [
         ('old-and-unmanageable', None, "Try not to use this!"),
         ('single-version-externally-managed', None,
-            "used by system package builders to create 'flat' eggs"),
+         "used by system package builders to create 'flat' eggs"),
     ]
-    boolean_options = _install.boolean_options + [
+    boolean_options = orig.install.boolean_options + [
         'old-and-unmanageable', 'single-version-externally-managed',
     ]
     new_commands = [
@@ -22,12 +30,12 @@
     _nc = dict(new_commands)
 
     def initialize_options(self):
-        _install.initialize_options(self)
+        orig.install.initialize_options(self)
         self.old_and_unmanageable = None
         self.single_version_externally_managed = None
 
     def finalize_options(self):
-        _install.finalize_options(self)
+        orig.install.finalize_options(self)
         if self.root:
             self.single_version_externally_managed = True
         elif self.single_version_externally_managed:
@@ -40,7 +48,7 @@
     def handle_extra_path(self):
         if self.root or self.single_version_externally_managed:
             # explicit backward-compatibility mode, allow extra_path to work
-            return _install.handle_extra_path(self)
+            return orig.install.handle_extra_path(self)
 
         # Ignore extra_path when installing an egg (or being run by another
         # command without --root or --single-version-externally-managed
@@ -50,28 +58,41 @@
     def run(self):
         # Explicit request for old-style install?  Just do it
         if self.old_and_unmanageable or self.single_version_externally_managed:
-            return _install.run(self)
+            return orig.install.run(self)
 
-        # Attempt to detect whether we were called from setup() or by another
-        # command.  If we were called by setup(), our caller will be the
-        # 'run_command' method in 'distutils.dist', and *its* caller will be
-        # the 'run_commands' method.  If we were called any other way, our
-        # immediate caller *might* be 'run_command', but it won't have been
-        # called by 'run_commands'.  This is slightly kludgy, but seems to
-        # work.
-        #
-        caller = sys._getframe(2)
-        caller_module = caller.f_globals.get('__name__','')
-        caller_name = caller.f_code.co_name
-
-        if caller_module != 'distutils.dist' or caller_name!='run_commands':
-            # We weren't called from the command line or setup(), so we
-            # should run in backward-compatibility mode to support bdist_*
-            # commands.
-            _install.run(self)
+        if not self._called_from_setup(inspect.currentframe()):
+            # Run in backward-compatibility mode to support bdist_* commands.
+            orig.install.run(self)
         else:
             self.do_egg_install()
 
+    @staticmethod
+    def _called_from_setup(run_frame):
+        """
+        Attempt to detect whether run() was called from setup() or by another
+        command.  If called by setup(), the parent caller will be the
+        'run_command' method in 'distutils.dist', and *its* caller will be
+        the 'run_commands' method.  If called any other way, the
+        immediate caller *might* be 'run_command', but it won't have been
+        called by 'run_commands'. Return True in that case or if a call stack
+        is unavailable. Return False otherwise.
+        """
+        if run_frame is None:
+            msg = "Call stack not available. bdist_* commands may fail."
+            warnings.warn(msg)
+            if platform.python_implementation() == 'IronPython':
+                msg = "For best results, pass -X:Frames to enable call stack."
+                warnings.warn(msg)
+            return True
+        res = inspect.getouterframes(run_frame)[2]
+        caller, = res[:1]
+        info = inspect.getframeinfo(caller)
+        caller_module = caller.f_globals.get('__name__', '')
+        return (
+            caller_module == 'distutils.dist'
+            and info.function == 'run_commands'
+        )
+
     def do_egg_install(self):
 
         easy_install = self.distribution.get_command_class('easy_install')
@@ -96,7 +117,9 @@
         cmd.run()
         setuptools.bootstrap_install_from = None
 
+
 # XXX Python 3.1 doesn't see _nc if this is inside the class
-install.sub_commands = [
-        cmd for cmd in _install.sub_commands if cmd[0] not in install._nc
-    ] + install.new_commands
+install.sub_commands = (
+    [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] +
+    install.new_commands
+)
diff -Nru python-setuptools-3.3/setuptools/command/install_scripts.py python-setuptools-20.1.1/setuptools/command/install_scripts.py
--- python-setuptools-3.3/setuptools/command/install_scripts.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/install_scripts.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,23 +1,23 @@
-from distutils.command.install_scripts import install_scripts \
-     as _install_scripts
-from pkg_resources import Distribution, PathMetadata, ensure_directory
-import os
 from distutils import log
+import distutils.command.install_scripts as orig
+import os
+
+from pkg_resources import Distribution, PathMetadata, ensure_directory
+
 
-class install_scripts(_install_scripts):
+class install_scripts(orig.install_scripts):
     """Do normal script install, plus any egg_info wrapper scripts"""
 
     def initialize_options(self):
-        _install_scripts.initialize_options(self)
+        orig.install_scripts.initialize_options(self)
         self.no_ep = False
 
     def run(self):
-        from setuptools.command.easy_install import get_script_args
-        from setuptools.command.easy_install import sys_executable
+        import setuptools.command.easy_install as ei
 
         self.run_command("egg_info")
         if self.distribution.scripts:
-            _install_scripts.run(self)  # run first to set up self.outfiles
+            orig.install_scripts.run(self)  # run first to set up self.outfiles
         else:
             self.outfiles = []
         if self.no_ep:
@@ -30,16 +30,23 @@
             ei_cmd.egg_name, ei_cmd.egg_version,
         )
         bs_cmd = self.get_finalized_command('build_scripts')
-        executable = getattr(bs_cmd,'executable',sys_executable)
-        is_wininst = getattr(
-            self.get_finalized_command("bdist_wininst"), '_is_running', False
-        )
-        for args in get_script_args(dist, executable, is_wininst):
+        exec_param = getattr(bs_cmd, 'executable', None)
+        bw_cmd = self.get_finalized_command("bdist_wininst")
+        is_wininst = getattr(bw_cmd, '_is_running', False)
+        writer = ei.ScriptWriter
+        if is_wininst:
+            exec_param = "python.exe"
+            writer = ei.WindowsScriptWriter
+        # resolve the writer to the environment
+        writer = writer.best()
+        cmd = writer.command_spec_class.best().from_param(exec_param)
+        for args in writer.get_args(dist, cmd.as_header()):
             self.write_script(*args)
 
     def write_script(self, script_name, contents, mode="t", *ignored):
         """Write an executable file to the scripts directory"""
         from setuptools.command.easy_install import chmod, current_umask
+
         log.info("Installing %s script to %s", script_name, self.install_dir)
         target = os.path.join(self.install_dir, script_name)
         self.outfiles.append(target)
@@ -47,7 +54,7 @@
         mask = current_umask()
         if not self.dry_run:
             ensure_directory(target)
-            f = open(target,"w"+mode)
+            f = open(target, "w" + mode)
             f.write(contents)
             f.close()
-            chmod(target, 0x1FF-mask)  # 0777
+            chmod(target, 0o777 - mask)
diff -Nru python-setuptools-3.3/setuptools/command/launcher manifest.xml python-setuptools-20.1.1/setuptools/command/launcher manifest.xml
--- python-setuptools-3.3/setuptools/command/launcher manifest.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/launcher manifest.xml	2016-01-30 17:43:56.000000000 +0000
@@ -1,15 +1,15 @@
 
 
-
+    
     
     
-    
-        
-            
-        
-    
+        
+            
+                
+            
+        
     
 
diff -Nru python-setuptools-3.3/setuptools/command/register.py python-setuptools-20.1.1/setuptools/command/register.py
--- python-setuptools-3.3/setuptools/command/register.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/register.py	2016-01-30 17:43:56.000000000 +0000
@@ -1,10 +1,10 @@
-from distutils.command.register import register as _register
+import distutils.command.register as orig
 
-class register(_register):
-    __doc__ = _register.__doc__
+
+class register(orig.register):
+    __doc__ = orig.register.__doc__
 
     def run(self):
         # Make sure that we are using valid current name/version info
         self.run_command('egg_info')
-        _register.run(self)
-
+        orig.register.run(self)
diff -Nru python-setuptools-3.3/setuptools/command/rotate.py python-setuptools-20.1.1/setuptools/command/rotate.py
--- python-setuptools-3.3/setuptools/command/rotate.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/rotate.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,18 +1,21 @@
-import os
-from setuptools import Command
-from setuptools.compat import basestring
 from distutils.util import convert_path
 from distutils import log
 from distutils.errors import DistutilsOptionError
+import os
+
+from setuptools.extern import six
+
+from setuptools import Command
+
 
 class rotate(Command):
     """Delete older distributions"""
 
     description = "delete older distributions, keeping N newest files"
     user_options = [
-        ('match=',    'm', "patterns to match (required)"),
+        ('match=', 'm', "patterns to match (required)"),
         ('dist-dir=', 'd', "directory where the distributions are"),
-        ('keep=',     'k', "number of matching distributions to keep"),
+        ('keep=', 'k', "number of matching distributions to keep"),
     ]
 
     boolean_options = []
@@ -34,25 +37,26 @@
             self.keep = int(self.keep)
         except ValueError:
             raise DistutilsOptionError("--keep must be an integer")
-        if isinstance(self.match, basestring):
+        if isinstance(self.match, six.string_types):
             self.match = [
                 convert_path(p.strip()) for p in self.match.split(',')
             ]
-        self.set_undefined_options('bdist',('dist_dir', 'dist_dir'))
+        self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
 
     def run(self):
         self.run_command("egg_info")
         from glob import glob
+
         for pattern in self.match:
-            pattern = self.distribution.get_name()+'*'+pattern
-            files = glob(os.path.join(self.dist_dir,pattern))
-            files = [(os.path.getmtime(f),f) for f in files]
+            pattern = self.distribution.get_name() + '*' + pattern
+            files = glob(os.path.join(self.dist_dir, pattern))
+            files = [(os.path.getmtime(f), f) for f in files]
             files.sort()
             files.reverse()
 
             log.info("%d file(s) matching %s", len(files), pattern)
             files = files[self.keep:]
-            for (t,f) in files:
+            for (t, f) in files:
                 log.info("Deleting %s", f)
                 if not self.dry_run:
                     os.unlink(f)
diff -Nru python-setuptools-3.3/setuptools/command/saveopts.py python-setuptools-20.1.1/setuptools/command/saveopts.py
--- python-setuptools-3.3/setuptools/command/saveopts.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/saveopts.py	2016-01-30 17:43:56.000000000 +0000
@@ -1,7 +1,6 @@
-import distutils, os
-from setuptools import Command
 from setuptools.command.setopt import edit_config, option_base
 
+
 class saveopts(option_base):
     """Save command-line options to a file"""
 
@@ -13,12 +12,11 @@
 
         for cmd in dist.command_options:
 
-            if cmd=='saveopts':
-                continue    # don't save our own options!
+            if cmd == 'saveopts':
+                continue  # don't save our own options!
 
-            for opt,(src,val) in dist.get_option_dict(cmd).items():
-                if src=="command line":
-                    settings.setdefault(cmd,{})[opt] = val
+            for opt, (src, val) in dist.get_option_dict(cmd).items():
+                if src == "command line":
+                    settings.setdefault(cmd, {})[opt] = val
 
         edit_config(self.filename, settings, self.dry_run)
-
diff -Nru python-setuptools-3.3/setuptools/command/sdist.py python-setuptools-20.1.1/setuptools/command/sdist.py
--- python-setuptools-3.3/setuptools/command/sdist.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/sdist.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,16 +1,19 @@
+from glob import glob
+from distutils import log
+import distutils.command.sdist as orig
 import os
-import re
 import sys
-from glob import glob
+import io
+
+from setuptools.extern import six
+
+from setuptools.utils import cs_path_exists
 
 import pkg_resources
-from distutils.command.sdist import sdist as _sdist
-from distutils.util import convert_path
-from distutils import log
-from setuptools import svn_utils
 
-READMES = ('README', 'README.rst', 'README.txt')
+READMES = 'README', 'README.rst', 'README.txt'
 
+_default_revctrl = list
 
 def walk_revctrl(dirname=''):
     """Find all files under revision control"""
@@ -19,60 +22,7 @@
             yield item
 
 
-#TODO will need test case
-class re_finder(object):
-    """
-    Finder that locates files based on entries in a file matched by a
-    regular expression.
-    """
-
-    def __init__(self, path, pattern, postproc=lambda x: x):
-        self.pattern = pattern
-        self.postproc = postproc
-        self.entries_path = convert_path(path)
-
-    def _finder(self, dirname, filename):
-        f = open(filename,'rU')
-        try:
-            data = f.read()
-        finally:
-            f.close()
-        for match in self.pattern.finditer(data):
-            path = match.group(1)
-            # postproc was formerly used when the svn finder
-            # was an re_finder for calling unescape
-            path = self.postproc(path)
-            yield svn_utils.joinpath(dirname, path)
-
-    def find(self, dirname=''):
-        path = svn_utils.joinpath(dirname, self.entries_path)
-
-        if not os.path.isfile(path):
-            # entries file doesn't exist
-            return
-        for path in self._finder(dirname,path):
-            if os.path.isfile(path):
-                yield path
-            elif os.path.isdir(path):
-                for item in self.find(path):
-                    yield item
-    __call__ = find
-
-
-def _default_revctrl(dirname=''):
-    'Primary svn_cvs entry point'
-    for finder in finders:
-        for item in finder(dirname):
-            yield item
-
-
-finders = [
-    re_finder('CVS/Entries', re.compile(r"^\w?/([^/]+)/", re.M)),
-    svn_utils.svn_finder,
-]
-
-
-class sdist(_sdist):
+class sdist(orig.sdist):
     """Smart sdist that finds anything supported by revision control"""
 
     user_options = [
@@ -84,7 +34,7 @@
         ('dist-dir=', 'd',
          "directory to put the source distribution archive(s) in "
          "[default: dist]"),
-        ]
+    ]
 
     negative_opt = {}
 
@@ -92,7 +42,7 @@
         self.run_command('egg_info')
         ei_cmd = self.get_finalized_command('egg_info')
         self.filelist = ei_cmd.filelist
-        self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt'))
+        self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
         self.check_readme()
 
         # Run sub commands
@@ -102,12 +52,13 @@
         # Call check_metadata only if no 'check' command
         # (distutils <= 2.6)
         import distutils.command
+
         if 'check' not in distutils.command.__all__:
             self.check_metadata()
 
         self.make_distribution()
 
-        dist_files = getattr(self.distribution,'dist_files',[])
+        dist_files = getattr(self.distribution, 'dist_files', [])
         for file in self.archive_files:
             data = ('sdist', '', file)
             if data not in dist_files:
@@ -119,17 +70,19 @@
         # Doing so prevents an error when easy_install attempts to delete the
         #  file.
         try:
-            _sdist.read_template(self)
+            orig.sdist.read_template(self)
         except:
-            sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
+            _, _, tb = sys.exc_info()
+            tb.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.
     has_leaky_handle = (
-        sys.version_info < (2,7,2)
-        or (3,0) <= sys.version_info < (3,1,4)
-        or (3,2) <= sys.version_info < (3,2,1)
+        sys.version_info < (2, 7, 2)
+        or (3, 0) <= sys.version_info < (3, 1, 4)
+        or (3, 2) <= sys.version_info < (3, 2, 1)
     )
     if has_leaky_handle:
         read_template = __read_template_hack
@@ -142,7 +95,7 @@
                 alts = fn
                 got_it = 0
                 for fn in alts:
-                    if os.path.exists(fn):
+                    if cs_path_exists(fn):
                         got_it = 1
                         self.filelist.append(fn)
                         break
@@ -151,14 +104,14 @@
                     self.warn("standard file not found: should have one of " +
                               ', '.join(alts))
             else:
-                if os.path.exists(fn):
+                if cs_path_exists(fn):
                     self.filelist.append(fn)
                 else:
                     self.warn("standard file '%s' not found" % fn)
 
         optional = ['test/test*.py', 'setup.cfg']
         for pattern in optional:
-            files = list(filter(os.path.isfile, glob(pattern)))
+            files = list(filter(cs_path_exists, glob(pattern)))
             if files:
                 self.filelist.extend(files)
 
@@ -193,15 +146,16 @@
                 return
         else:
             self.warn(
-                "standard file not found: should have one of " +', '.join(READMES)
+                "standard file not found: should have one of " +
+                ', '.join(READMES)
             )
 
     def make_release_tree(self, base_dir, files):
-        _sdist.make_release_tree(self, base_dir, files)
+        orig.sdist.make_release_tree(self, base_dir, files)
 
         # Save any egg_info command line options used to create this sdist
         dest = os.path.join(base_dir, 'setup.cfg')
-        if hasattr(os,'link') and os.path.exists(dest):
+        if hasattr(os, 'link') and os.path.exists(dest):
             # unlink and re-copy, since it might be hard-linked, and
             # we don't want to change the source version
             os.unlink(dest)
@@ -214,12 +168,10 @@
         if not os.path.isfile(self.manifest):
             return False
 
-        fp = open(self.manifest, 'rbU')
-        try:
+        with io.open(self.manifest, 'rb') as fp:
             first_line = fp.readline()
-        finally:
-            fp.close()
-        return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode()
+        return (first_line !=
+                '# file GENERATED by distutils, do NOT edit\n'.encode())
 
     def read_manifest(self):
         """Read the manifest file (named by 'self.manifest') and use it to
@@ -230,7 +182,7 @@
         manifest = open(self.manifest, 'rbU')
         for line in manifest:
             # The manifest must contain UTF-8. See #303.
-            if sys.version_info >= (3,):
+            if six.PY3:
                 try:
                     line = line.decode('UTF-8')
                 except UnicodeDecodeError:
diff -Nru python-setuptools-3.3/setuptools/command/setopt.py python-setuptools-20.1.1/setuptools/command/setopt.py
--- python-setuptools-3.3/setuptools/command/setopt.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/setopt.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,9 +1,13 @@
-import os
-import distutils
-from setuptools import Command
 from distutils.util import convert_path
 from distutils import log
 from distutils.errors import DistutilsOptionError
+import distutils
+import os
+
+from setuptools.extern.six.moves import configparser
+
+from setuptools import Command
+
 
 __all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
 
@@ -13,19 +17,20 @@
 
     `kind` must be one of "local", "global", or "user"
     """
-    if kind=='local':
+    if kind == 'local':
         return 'setup.cfg'
-    if kind=='global':
+    if kind == 'global':
         return os.path.join(
-            os.path.dirname(distutils.__file__),'distutils.cfg'
+            os.path.dirname(distutils.__file__), 'distutils.cfg'
         )
-    if kind=='user':
-        dot = os.name=='posix' and '.' or ''
+    if kind == 'user':
+        dot = os.name == 'posix' and '.' or ''
         return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
     raise ValueError(
         "config_file() type must be 'local', 'global', or 'user'", kind
     )
 
+
 def edit_config(filename, settings, dry_run=False):
     """Edit a configuration file to include `settings`
 
@@ -34,9 +39,8 @@
     while a dictionary lists settings to be changed or deleted in that section.
     A setting of ``None`` means to delete that setting.
     """
-    from setuptools.compat import ConfigParser
     log.debug("Reading configuration from %s", filename)
-    opts = ConfigParser.RawConfigParser()
+    opts = configparser.RawConfigParser()
     opts.read([filename])
     for section, options in settings.items():
         if options is None:
@@ -46,39 +50,40 @@
             if not opts.has_section(section):
                 log.debug("Adding new section [%s] to %s", section, filename)
                 opts.add_section(section)
-            for option,value in options.items():
+            for option, value in options.items():
                 if value is None:
                     log.debug(
                         "Deleting %s.%s from %s",
                         section, option, filename
                     )
-                    opts.remove_option(section,option)
+                    opts.remove_option(section, option)
                     if not opts.options(section):
                         log.info("Deleting empty [%s] section from %s",
-                            section, filename)
+                                 section, filename)
                         opts.remove_section(section)
                 else:
                     log.debug(
                         "Setting %s.%s to %r in %s",
                         section, option, value, filename
                     )
-                    opts.set(section,option,value)
+                    opts.set(section, option, value)
 
     log.info("Writing %s", filename)
     if not dry_run:
         with open(filename, 'w') as f:
             opts.write(f)
 
+
 class option_base(Command):
     """Abstract base class for commands that mess with config files"""
 
     user_options = [
         ('global-config', 'g',
-            "save options to the site-wide distutils.cfg file"),
+         "save options to the site-wide distutils.cfg file"),
         ('user-config', 'u',
-            "save options to the current user's pydistutils.cfg file"),
+         "save options to the current user's pydistutils.cfg file"),
         ('filename=', 'f',
-            "configuration file to use (default=setup.cfg)"),
+         "configuration file to use (default=setup.cfg)"),
     ]
 
     boolean_options = [
@@ -100,7 +105,7 @@
             filenames.append(self.filename)
         if not filenames:
             filenames.append(config_file('local'))
-        if len(filenames)>1:
+        if len(filenames) > 1:
             raise DistutilsOptionError(
                 "Must specify only one configuration file option",
                 filenames
@@ -115,9 +120,9 @@
 
     user_options = [
         ('command=', 'c', 'command to set an option for'),
-        ('option=',  'o',  'option to set'),
-        ('set-value=',   's', 'value of the option'),
-        ('remove',   'r', 'remove (unset) the value'),
+        ('option=', 'o', 'option to set'),
+        ('set-value=', 's', 'value of the option'),
+        ('remove', 'r', 'remove (unset) the value'),
     ] + option_base.user_options
 
     boolean_options = option_base.boolean_options + ['remove']
@@ -139,7 +144,7 @@
     def run(self):
         edit_config(
             self.filename, {
-                self.command: {self.option.replace('-','_'):self.set_value}
+                self.command: {self.option.replace('-', '_'): self.set_value}
             },
             self.dry_run
         )
diff -Nru python-setuptools-3.3/setuptools/command/test.py python-setuptools-20.1.1/setuptools/command/test.py
--- python-setuptools-3.3/setuptools/command/test.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/test.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,14 +1,19 @@
-from setuptools import Command
 from distutils.errors import DistutilsOptionError
-import sys
-from pkg_resources import (resource_listdir, resource_exists,
-    normalize_path, working_set, _namespace_packages, add_activation_listener,
-    require, EntryPoint)
 from unittest import TestLoader
+import sys
+
+from setuptools.extern import six
+from setuptools.extern.six.moves import map
+
+from pkg_resources import (resource_listdir, resource_exists, normalize_path,
+                           working_set, _namespace_packages,
+                           add_activation_listener, require, EntryPoint)
+from setuptools import Command
+from setuptools.py31compat import unittest_main
 
-class ScanningLoader(TestLoader):
 
-    def loadTestsFromModule(self, module):
+class ScanningLoader(TestLoader):
+    def loadTestsFromModule(self, module, pattern=None):
         """Return a suite of all tests cases contained in the given module
 
         If the module is a package, load tests from all the modules in it.
@@ -16,71 +21,90 @@
         the return value to the tests.
         """
         tests = []
-        if module.__name__!='setuptools.tests.doctest':  # ugh
-            tests.append(TestLoader.loadTestsFromModule(self,module))
+        tests.append(TestLoader.loadTestsFromModule(self, module))
 
         if hasattr(module, "additional_tests"):
             tests.append(module.additional_tests())
 
         if hasattr(module, '__path__'):
             for file in resource_listdir(module.__name__, ''):
-                if file.endswith('.py') and file!='__init__.py':
-                    submodule = module.__name__+'.'+file[:-3]
+                if file.endswith('.py') and file != '__init__.py':
+                    submodule = module.__name__ + '.' + file[:-3]
                 else:
-                    if resource_exists(
-                        module.__name__, file+'/__init__.py'
-                    ):
-                        submodule = module.__name__+'.'+file
+                    if resource_exists(module.__name__, file + '/__init__.py'):
+                        submodule = module.__name__ + '.' + file
                     else:
                         continue
                 tests.append(self.loadTestsFromName(submodule))
 
-        if len(tests)!=1:
+        if len(tests) != 1:
             return self.suiteClass(tests)
         else:
-            return tests[0] # don't create a nested suite for only one return
+            return tests[0]  # don't create a nested suite for only one return
 
 
-class test(Command):
+# adapted from jaraco.classes.properties:NonDataProperty
+class NonDataProperty(object):
+    def __init__(self, fget):
+        self.fget = fget
+
+    def __get__(self, obj, objtype=None):
+        if obj is None:
+            return self
+        return self.fget(obj)
 
+
+class test(Command):
     """Command to run unit tests after in-place build"""
 
     description = "run unit tests after in-place build"
 
     user_options = [
-        ('test-module=','m', "Run 'test_suite' in specified module"),
-        ('test-suite=','s',
-            "Test suite to run (e.g. 'some_module.test_suite')"),
+        ('test-module=', 'm', "Run 'test_suite' in specified module"),
+        ('test-suite=', 's',
+         "Test suite to run (e.g. 'some_module.test_suite')"),
+        ('test-runner=', 'r', "Test runner to use"),
     ]
 
     def initialize_options(self):
         self.test_suite = None
         self.test_module = None
         self.test_loader = None
+        self.test_runner = None
 
     def finalize_options(self):
 
+        if self.test_suite and self.test_module:
+            msg = "You may specify a module or a suite, but not both"
+            raise DistutilsOptionError(msg)
+
         if self.test_suite is None:
             if self.test_module is None:
                 self.test_suite = self.distribution.test_suite
             else:
-                self.test_suite = self.test_module+".test_suite"
-        elif self.test_module:
-            raise DistutilsOptionError(
-                "You may specify a module or a suite, but not both"
-            )
-
-        self.test_args = [self.test_suite]
+                self.test_suite = self.test_module + ".test_suite"
 
-        if self.verbose:
-            self.test_args.insert(0,'--verbose')
         if self.test_loader is None:
-            self.test_loader = getattr(self.distribution,'test_loader',None)
+            self.test_loader = getattr(self.distribution, 'test_loader', None)
         if self.test_loader is None:
             self.test_loader = "setuptools.command.test:ScanningLoader"
+        if self.test_runner is None:
+            self.test_runner = getattr(self.distribution, 'test_runner', None)
+
+    @NonDataProperty
+    def test_args(self):
+        return list(self._test_args())
+
+    def _test_args(self):
+        if self.verbose:
+            yield '--verbose'
+        if self.test_suite:
+            yield self.test_suite
 
     def with_project_on_sys_path(self, func):
-        if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
+        with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
+
+        if with_2to3:
             # If we run 2to3 we can not do this inplace:
 
             # Ensure metadata is up-to-date
@@ -122,26 +146,24 @@
 
     def run(self):
         if self.distribution.install_requires:
-            self.distribution.fetch_build_eggs(self.distribution.install_requires)
+            self.distribution.fetch_build_eggs(
+                self.distribution.install_requires)
         if self.distribution.tests_require:
             self.distribution.fetch_build_eggs(self.distribution.tests_require)
 
-        if self.test_suite:
-            cmd = ' '.join(self.test_args)
-            if self.dry_run:
-                self.announce('skipping "unittest %s" (dry run)' % cmd)
-            else:
-                self.announce('running "unittest %s"' % cmd)
-                self.with_project_on_sys_path(self.run_tests)
+        cmd = ' '.join(self._argv)
+        if self.dry_run:
+            self.announce('skipping "%s" (dry run)' % cmd)
+        else:
+            self.announce('running "%s"' % cmd)
+            self.with_project_on_sys_path(self.run_tests)
 
     def run_tests(self):
-        import unittest
-
         # Purge modules under test from sys.modules. The test loader will
         # re-import them from the build location. Required when 2to3 is used
         # with namespace packages.
-        if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
-            module = self.test_args[-1].split('.')[0]
+        if six.PY3 and getattr(self.distribution, 'use_2to3', False):
+            module = self.test_suite.split('.')[0]
             if module in _namespace_packages:
                 del_modules = []
                 if module in sys.modules:
@@ -152,10 +174,23 @@
                         del_modules.append(name)
                 list(map(sys.modules.__delitem__, del_modules))
 
-        loader_ep = EntryPoint.parse("x="+self.test_loader)
-        loader_class = loader_ep.load(require=False)
-        cks = loader_class()
-        unittest.main(
-            None, None, [unittest.__file__]+self.test_args,
-            testLoader = cks
+        unittest_main(
+            None, None, self._argv,
+            testLoader=self._resolve_as_ep(self.test_loader),
+            testRunner=self._resolve_as_ep(self.test_runner),
         )
+
+    @property
+    def _argv(self):
+        return ['unittest'] + self.test_args
+
+    @staticmethod
+    def _resolve_as_ep(val):
+        """
+        Load the indicated attribute value, called, as a as if it were
+        specified as an entry point.
+        """
+        if val is None:
+            return
+        parsed = EntryPoint.parse("x=" + val)
+        return parsed.resolve()()
diff -Nru python-setuptools-3.3/setuptools/command/upload_docs.py python-setuptools-20.1.1/setuptools/command/upload_docs.py
--- python-setuptools-3.3/setuptools/command/upload_docs.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/upload_docs.py	2016-02-12 16:08:14.000000000 +0000
@@ -5,35 +5,34 @@
 PyPI's pythonhosted.org).
 """
 
+from base64 import standard_b64encode
+from distutils import log
+from distutils.errors import DistutilsOptionError
 import os
 import socket
 import zipfile
 import tempfile
-import sys
 import shutil
 
-from base64 import standard_b64encode
-from pkg_resources import iter_entry_points
+from setuptools.extern import six
+from setuptools.extern.six.moves import http_client, urllib
 
-from distutils import log
-from distutils.errors import DistutilsOptionError
-from distutils.command.upload import upload
+from pkg_resources import iter_entry_points
+from .upload import upload
 
-from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
 
-errors = 'surrogateescape' if PY3 else 'strict'
+errors = 'surrogateescape' if six.PY3 else 'strict'
 
 
 # This is not just a replacement for byte literals
 # but works as a general purpose encoder
 def b(s, encoding='utf-8'):
-    if isinstance(s, unicode):
+    if isinstance(s, six.text_type):
         return s.encode(encoding, errors)
     return s
 
 
 class upload_docs(upload):
-
     description = 'Upload documentation to PyPI'
 
     user_options = [
@@ -42,7 +41,7 @@
         ('show-response', None,
          'display full response text from server'),
         ('upload-dir=', None, 'directory to upload'),
-        ]
+    ]
     boolean_options = upload.boolean_options
 
     def has_sphinx(self):
@@ -115,7 +114,7 @@
         # set up the authentication
         credentials = b(self.username + ':' + self.password)
         credentials = standard_b64encode(credentials)
-        if PY3:
+        if six.PY3:
             credentials = credentials.decode('ascii')
         auth = "Basic " + credentials
 
@@ -124,7 +123,7 @@
         sep_boundary = b('\n--') + b(boundary)
         end_boundary = sep_boundary + b('--')
         body = []
-        for key, values in iteritems(data):
+        for key, values in six.iteritems(data):
             title = '\nContent-Disposition: form-data; name="%s"' % key
             # handle multiple entries for the same name
             if not isinstance(values, list):
@@ -152,14 +151,14 @@
         # We can't use urllib2 since we need to send the Basic
         # auth right with the first request
         schema, netloc, url, params, query, fragments = \
-            urlparse(self.repository)
+            urllib.parse.urlparse(self.repository)
         assert not params and not query and not fragments
         if schema == 'http':
-            conn = httplib.HTTPConnection(netloc)
+            conn = http_client.HTTPConnection(netloc)
         elif schema == 'https':
-            conn = httplib.HTTPSConnection(netloc)
+            conn = http_client.HTTPSConnection(netloc)
         else:
-            raise AssertionError("unsupported schema "+schema)
+            raise AssertionError("unsupported schema " + schema)
 
         data = ''
         try:
@@ -171,8 +170,7 @@
             conn.putheader('Authorization', auth)
             conn.endheaders()
             conn.send(body)
-        except socket.error:
-            e = sys.exc_info()[1]
+        except socket.error as e:
             self.announce(str(e), log.ERROR)
             return
 
@@ -190,4 +188,4 @@
             self.announce('Upload failed (%s): %s' % (r.status, r.reason),
                           log.ERROR)
         if self.show_response:
-            print('-'*75, r.read(), '-'*75)
+            print('-' * 75, r.read(), '-' * 75)
diff -Nru python-setuptools-3.3/setuptools/command/upload.py python-setuptools-20.1.1/setuptools/command/upload.py
--- python-setuptools-3.3/setuptools/command/upload.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/command/upload.py	2016-02-12 12:49:14.000000000 +0000
@@ -0,0 +1,23 @@
+from distutils.command import upload as orig
+
+
+class upload(orig.upload):
+    """
+    Override default upload behavior to look up password
+    in the keyring if available.
+    """
+
+    def finalize_options(self):
+        orig.upload.finalize_options(self)
+        self.password or self._load_password_from_keyring()
+
+    def _load_password_from_keyring(self):
+        """
+        Attempt to load password from keyring. Suppress Exceptions.
+        """
+        try:
+            keyring = __import__('keyring')
+            self.password = keyring.get_password(self.repository,
+                self.username)
+        except Exception:
+            pass
diff -Nru python-setuptools-3.3/setuptools/compat.py python-setuptools-20.1.1/setuptools/compat.py
--- python-setuptools-3.3/setuptools/compat.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/compat.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,83 +0,0 @@
-import sys
-import itertools
-
-if sys.version_info[0] < 3:
-    PY3 = False
-
-    basestring = basestring
-    import __builtin__ as builtins
-    import ConfigParser
-    from StringIO import StringIO
-    BytesIO = StringIO
-    execfile = execfile
-    func_code = lambda o: o.func_code
-    func_globals = lambda o: o.func_globals
-    im_func = lambda o: o.im_func
-    from htmlentitydefs import name2codepoint
-    import httplib
-    from BaseHTTPServer import HTTPServer
-    from SimpleHTTPServer import SimpleHTTPRequestHandler
-    from BaseHTTPServer import BaseHTTPRequestHandler
-    iteritems = lambda o: o.iteritems()
-    long_type = long
-    maxsize = sys.maxint
-    next = lambda o: o.next()
-    numeric_types = (int, long, float)
-    unichr = unichr
-    unicode = unicode
-    bytes = str
-    from urllib import url2pathname, splittag, pathname2url
-    import urllib2
-    from urllib2 import urlopen, HTTPError, URLError, unquote, splituser
-    from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit
-    filterfalse = itertools.ifilterfalse
-
-    exec("""def reraise(tp, value, tb=None):
-    raise tp, value, tb""")
-else:
-    PY3 = True
-
-    basestring = str
-    import builtins
-    import configparser as ConfigParser
-    from io import StringIO, BytesIO
-    func_code = lambda o: o.__code__
-    func_globals = lambda o: o.__globals__
-    im_func = lambda o: o.__func__
-    from html.entities import name2codepoint
-    import http.client as httplib
-    from http.server import HTTPServer, SimpleHTTPRequestHandler
-    from http.server import BaseHTTPRequestHandler
-    iteritems = lambda o: o.items()
-    long_type = int
-    maxsize = sys.maxsize
-    next = next
-    numeric_types = (int, float)
-    unichr = chr
-    unicode = str
-    bytes = bytes
-    from urllib.error import HTTPError, URLError
-    import urllib.request as urllib2
-    from urllib.request import urlopen, url2pathname, pathname2url
-    from urllib.parse import (
-        urlparse, urlunparse, unquote, splituser, urljoin, urlsplit,
-        urlunsplit, splittag,
-    )
-    filterfalse = itertools.filterfalse
-
-    def execfile(fn, globs=None, locs=None):
-        if globs is None:
-            globs = globals()
-        if locs is None:
-            locs = globs
-        f = open(fn, 'rb')
-        try:
-            source = f.read()
-        finally:
-            f.close()
-        exec(compile(source, fn, 'exec'), globs, locs)
-
-    def reraise(tp, value, tb=None):
-        if value.__traceback__ is not tb:
-            raise value.with_traceback(tb)
-        raise value
diff -Nru python-setuptools-3.3/setuptools/depends.py python-setuptools-20.1.1/setuptools/depends.py
--- python-setuptools-3.3/setuptools/depends.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/depends.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,7 +1,10 @@
-from __future__ import generators
-import sys, imp, marshal
+import sys
+import imp
+import marshal
 from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
-from distutils.version import StrictVersion, LooseVersion
+from distutils.version import StrictVersion
+
+from setuptools.extern import six
 
 __all__ = [
     'Require', 'find_module', 'get_module_constant', 'extract_constant'
@@ -10,9 +13,8 @@
 class Require:
     """A prerequisite to building or installing a distribution"""
 
-    def __init__(self,name,requested_version,module,homepage='',
-        attribute=None,format=None
-    ):
+    def __init__(self, name, requested_version, module, homepage='',
+            attribute=None, format=None):
 
         if format is None and requested_version is not None:
             format = StrictVersion
@@ -25,20 +27,17 @@
         self.__dict__.update(locals())
         del self.self
 
-
     def full_name(self):
         """Return full package/distribution name, w/version"""
         if self.requested_version is not None:
             return '%s-%s' % (self.name,self.requested_version)
         return self.name
 
-
-    def version_ok(self,version):
+    def version_ok(self, version):
         """Is 'version' sufficiently up-to-date?"""
         return self.attribute is None or self.format is None or \
             str(version) != "unknown" and version >= self.requested_version
 
-
     def get_version(self, paths=None, default="unknown"):
 
         """Get version number of installed module, 'None', or 'default'
@@ -59,20 +58,18 @@
             except ImportError:
                 return None
 
-        v = get_module_constant(self.module,self.attribute,default,paths)
+        v = get_module_constant(self.module, self.attribute, default, paths)
 
         if v is not None and v is not default and self.format is not None:
             return self.format(v)
 
         return v
 
-
-    def is_present(self,paths=None):
+    def is_present(self, paths=None):
         """Return true if dependency is present on 'paths'"""
         return self.get_version(paths) is not None
 
-
-    def is_current(self,paths=None):
+    def is_current(self, paths=None):
         """Return true if dependency is present and up-to-date on 'paths'"""
         version = self.get_version(paths)
         if version is None:
@@ -103,6 +100,7 @@
             ptr += 3
 
             if op==EXTENDED_ARG:
+                long_type = six.integer_types[-1]
                 extended_arg = arg * long_type(65536)
                 continue
 
@@ -113,14 +111,6 @@
         yield op,arg
 
 
-
-
-
-
-
-
-
-
 def find_module(module, paths=None):
     """Just like 'imp.find_module()', but with package support"""
 
@@ -140,28 +130,6 @@
     return info
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 def get_module_constant(module, symbol, default=-1, paths=None):
 
     """Find 'module' by searching 'paths', and extract 'symbol'
@@ -171,7 +139,7 @@
     constant.  Otherwise, return 'default'."""
 
     try:
-        f, path, (suffix,mode,kind) = find_module(module,paths)
+        f, path, (suffix, mode, kind) = find_module(module, paths)
     except ImportError:
         # Module doesn't exist
         return None
@@ -187,23 +155,17 @@
         else:
             # Not something we can parse; we'll have to import it.  :(
             if module not in sys.modules:
-                imp.load_module(module,f,path,(suffix,mode,kind))
-            return getattr(sys.modules[module],symbol,None)
+                imp.load_module(module, f, path, (suffix, mode, kind))
+            return getattr(sys.modules[module], symbol, None)
 
     finally:
         if f:
             f.close()
 
-    return extract_constant(code,symbol,default)
+    return extract_constant(code, symbol, default)
 
 
-
-
-
-
-
-
-def extract_constant(code,symbol,default=-1):
+def extract_constant(code, symbol, default=-1):
     """Extract the constant value of 'symbol' from 'code'
 
     If the name 'symbol' is bound to a constant value by the Python code
@@ -236,11 +198,20 @@
             return const
         else:
             const = default
-            
-if sys.platform.startswith('java') or sys.platform == 'cli':
-    # XXX it'd be better to test assertions about bytecode instead...
-    del extract_constant, get_module_constant
-    __all__.remove('extract_constant')
-    __all__.remove('get_module_constant')
 
 
+def _update_globals():
+    """
+    Patch the globals to remove the objects not available on some platforms.
+
+    XXX it'd be better to test assertions about bytecode instead.
+    """
+
+    if not sys.platform.startswith('java') and sys.platform != 'cli':
+        return
+    incompatible = 'extract_constant', 'get_module_constant'
+    for name in incompatible:
+        del globals()[name]
+        __all__.remove(name)
+
+_update_globals()
diff -Nru python-setuptools-3.3/setuptools/dist.py python-setuptools-20.1.1/setuptools/dist.py
--- python-setuptools-3.3/setuptools/dist.py	2014-03-08 14:22:24.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/dist.py	2016-02-12 04:13:01.000000000 +0000
@@ -4,17 +4,24 @@
 import os
 import sys
 import warnings
+import numbers
 import distutils.log
 import distutils.core
 import distutils.cmd
+import distutils.dist
 from distutils.core import Distribution as _Distribution
 from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
     DistutilsSetupError)
 
+from setuptools.extern import six
+from setuptools.extern.six.moves import map
+from pkg_resources.extern import packaging
+
 from setuptools.depends import Require
-from setuptools.compat import numeric_types, basestring
+from setuptools import windows_support
 import pkg_resources
 
+
 def _get_unpatched(cls):
     """Protect against re-patching the distutils if reloaded
 
@@ -31,6 +38,27 @@
 
 _Distribution = _get_unpatched(_Distribution)
 
+def _patch_distribution_metadata_write_pkg_info():
+    """
+    Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
+    encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
+    correct this undesirable behavior.
+    """
+    environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
+    if not environment_local:
+        return
+
+    # from Python 3.4
+    def write_pkg_info(self, base_dir):
+        """Write the PKG-INFO file into the release tree.
+        """
+        with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
+                  encoding='UTF-8') as pkg_info:
+            self.write_pkg_file(pkg_info)
+
+    distutils.dist.DistributionMetadata.write_pkg_info = write_pkg_info
+_patch_distribution_metadata_write_pkg_info()
+
 sequence = tuple, list
 
 def check_importable(dist, attr, value):
@@ -88,28 +116,30 @@
 def assert_bool(dist, attr, value):
     """Verify that value is True, False, 0, or 1"""
     if bool(value) != value:
-        raise DistutilsSetupError(
-            "%r must be a boolean value (got %r)" % (attr,value)
-        )
+        tmpl = "{attr!r} must be a boolean value (got {value!r})"
+        raise DistutilsSetupError(tmpl.format(attr=attr, value=value))
+
+
 def check_requirements(dist, attr, value):
     """Verify that install_requires is a valid requirements list"""
     try:
         list(pkg_resources.parse_requirements(value))
-    except (TypeError,ValueError):
-        raise DistutilsSetupError(
-            "%r must be a string or list of strings "
-            "containing valid project/version requirement specifiers" % (attr,)
+    except (TypeError, ValueError) as error:
+        tmpl = (
+            "{attr!r} must be a string or list of strings "
+            "containing valid project/version requirement specifiers; {error}"
         )
+        raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
+
 def check_entry_points(dist, attr, value):
     """Verify that entry_points map is parseable"""
     try:
         pkg_resources.EntryPoint.parse_map(value)
-    except ValueError:
-        e = sys.exc_info()[1]
+    except ValueError as e:
         raise DistutilsSetupError(e)
 
 def check_test_suite(dist, attr, value):
-    if not isinstance(value,basestring):
+    if not isinstance(value, six.string_types):
         raise DistutilsSetupError("test_suite must be a string")
 
 def check_package_data(dist, attr, value):
@@ -131,7 +161,7 @@
     for pkgname in value:
         if not re.match(r'\w+(\.\w+)*', pkgname):
             distutils.log.warn(
-                "WARNING: %r not a valid package name; please use only"
+                "WARNING: %r not a valid package name; please use only "
                 ".-separated package names in setup.py", pkgname
             )
 
@@ -236,15 +266,34 @@
             self.dependency_links = attrs.pop('dependency_links', [])
             assert_string_list(self,'dependency_links',self.dependency_links)
         if attrs and 'setup_requires' in attrs:
-            self.fetch_build_eggs(attrs.pop('setup_requires'))
+            self.fetch_build_eggs(attrs['setup_requires'])
         for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
-            if not hasattr(self,ep.name):
-                setattr(self,ep.name,None)
+            vars(self).setdefault(ep.name, None)
         _Distribution.__init__(self,attrs)
-        if isinstance(self.metadata.version, numeric_types):
+        if isinstance(self.metadata.version, numbers.Number):
             # Some people apparently take "version number" too literally :)
             self.metadata.version = str(self.metadata.version)
 
+        if self.metadata.version is not None:
+            try:
+                ver = packaging.version.Version(self.metadata.version)
+                normalized_version = str(ver)
+                if self.metadata.version != normalized_version:
+                    warnings.warn(
+                        "Normalizing '%s' to '%s'" % (
+                            self.metadata.version,
+                            normalized_version,
+                        )
+                    )
+                    self.metadata.version = normalized_version
+            except (packaging.version.InvalidVersion, TypeError):
+                warnings.warn(
+                    "The version specified (%r) is an invalid version, this "
+                    "may not work as expected with newer versions of "
+                    "setuptools, pip, and PyPI. Please see PEP 440 for more "
+                    "details." % self.metadata.version
+                )
+
     def parse_command_line(self):
         """Process features after parsing command line options"""
         result = _Distribution.parse_command_line(self)
@@ -258,12 +307,13 @@
 
     def fetch_build_eggs(self, requires):
         """Resolve pre-setup requirements"""
-        from pkg_resources import working_set, parse_requirements
-        for dist in working_set.resolve(
-            parse_requirements(requires), installer=self.fetch_build_egg,
-            replace_conflicting=True
-        ):
-            working_set.add(dist, replace=True)
+        resolved_dists = pkg_resources.working_set.resolve(
+            pkg_resources.parse_requirements(requires),
+            installer=self.fetch_build_egg,
+            replace_conflicting=True,
+        )
+        for dist in resolved_dists:
+            pkg_resources.working_set.add(dist, replace=True)
 
     def finalize_options(self):
         _Distribution.finalize_options(self)
@@ -281,6 +331,21 @@
         else:
             self.convert_2to3_doctests = []
 
+    def get_egg_cache_dir(self):
+        egg_cache_dir = os.path.join(os.curdir, '.eggs')
+        if not os.path.exists(egg_cache_dir):
+            os.mkdir(egg_cache_dir)
+            windows_support.hide_file(egg_cache_dir)
+            readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
+            with open(readme_txt_filename, 'w') as f:
+                f.write('This directory contains eggs that were downloaded '
+                        'by setuptools to build, test, and run plug-ins.\n\n')
+                f.write('This directory caches those eggs to prevent '
+                        'repeated downloads.\n\n')
+                f.write('However, it is safe to delete this directory.\n\n')
+
+        return egg_cache_dir
+
     def fetch_build_egg(self, req):
         """Fetch an egg needed for building"""
 
@@ -304,8 +369,9 @@
                 if 'find_links' in opts:
                     links = opts['find_links'][1].split() + links
                 opts['find_links'] = ('setup', links)
+            install_dir = self.get_egg_cache_dir()
             cmd = easy_install(
-                dist, args=["x"], install_dir=os.curdir, exclude_scripts=True,
+                dist, args=["x"], install_dir=install_dir, exclude_scripts=True,
                 always_copy=False, build_directory=None, editable=False,
                 upgrade=False, multi_version=True, no_report=True, user=False
             )
@@ -369,10 +435,19 @@
     def print_commands(self):
         for ep in pkg_resources.iter_entry_points('distutils.commands'):
             if ep.name not in self.cmdclass:
-                cmdclass = ep.load(False) # don't require extras, we're not running
+                # don't require extras as the commands won't be invoked
+                cmdclass = ep.resolve()
                 self.cmdclass[ep.name] = cmdclass
         return _Distribution.print_commands(self)
 
+    def get_command_list(self):
+        for ep in pkg_resources.iter_entry_points('distutils.commands'):
+            if ep.name not in self.cmdclass:
+                # don't require extras as the commands won't be invoked
+                cmdclass = ep.resolve()
+                self.cmdclass[ep.name] = cmdclass
+        return _Distribution.get_command_list(self)
+
     def _set_feature(self,name,status):
         """Set feature's inclusion status"""
         setattr(self,self._feature_attrname(name),status)
@@ -608,7 +683,7 @@
         """
         import sys
 
-        if sys.version_info < (3,) or self.help_commands:
+        if six.PY2 or self.help_commands:
             return _Distribution.handle_display_options(self, option_order)
 
         # Stdout may be StringIO (e.g. in tests)
@@ -751,7 +826,7 @@
 
         if not self.available:
             raise DistutilsPlatformError(
-                self.description+" is required,"
+                self.description+" is required, "
                 "but is not available on this platform"
             )
 
diff -Nru python-setuptools-3.3/setuptools/extension.py python-setuptools-20.1.1/setuptools/extension.py
--- python-setuptools-3.3/setuptools/extension.py	2014-03-15 12:37:21.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/extension.py	2016-02-07 14:25:06.000000000 +0000
@@ -2,41 +2,45 @@
 import re
 import functools
 import distutils.core
+import distutils.errors
 import distutils.extension
 
-from setuptools.dist import _get_unpatched
+from setuptools.extern.six.moves import map
+
+from .dist import _get_unpatched
+from . import msvc9_support
 
 _Extension = _get_unpatched(distutils.core.Extension)
 
-def have_pyrex():
+msvc9_support.patch_for_specialized_compiler()
+
+def _have_cython():
     """
-    Return True if Cython or Pyrex can be imported.
+    Return True if Cython 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
+    cython_impl = 'Cython.Distutils.build_ext',
+    try:
+        # from (cython_impl) import build_ext
+        __import__(cython_impl, fromlist=['build_ext']).build_ext
+        return True
+    except Exception:
+        pass
     return False
 
+# for compatibility
+have_pyrex = _have_cython
+
 
 class Extension(_Extension):
     """Extension that uses '.c' files in place of '.pyx' files"""
 
-    def __init__(self, *args, **kw):
-        _Extension.__init__(self, *args, **kw)
-        self._convert_pyx_sources_to_lang()
-
     def _convert_pyx_sources_to_lang(self):
         """
         Replace sources with .pyx extensions to sources with the target
         language extension. This mechanism allows language authors to supply
         pre-converted sources but to prefer the .pyx sources.
         """
-        if have_pyrex():
+        if _have_cython():
             # the build has Cython, so allow it to compile the .pyx files
             return
         lang = self.language or ''
diff -Nru python-setuptools-3.3/setuptools/extern/__init__.py python-setuptools-20.1.1/setuptools/extern/__init__.py
--- python-setuptools-3.3/setuptools/extern/__init__.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/extern/__init__.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,5 @@
+from pkg_resources.extern import VendorImporter
+
+
+names = 'six',
+VendorImporter(__name__, names, 'pkg_resources._vendor').install()
diff -Nru python-setuptools-3.3/setuptools/__init__.py python-setuptools-20.1.1/setuptools/__init__.py
--- python-setuptools-3.3/setuptools/__init__.py	2014-03-16 08:02:09.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/__init__.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,13 +1,15 @@
 """Extensions to the 'distutils' for large or complex distributions"""
 
 import os
-import sys
+import functools
 import distutils.core
 import distutils.filelist
 from distutils.core import Command as _Command
 from distutils.util import convert_path
 from fnmatch import fnmatchcase
 
+from setuptools.extern.six.moves import filterfalse, map
+
 import setuptools.version
 from setuptools.extension import Extension
 from setuptools.dist import Distribution, Feature, _get_unpatched
@@ -28,45 +30,90 @@
 # Standard package names for fixer packages
 lib2to3_fixer_packages = ['lib2to3.fixes']
 
-def find_packages(where='.', exclude=(), include=()):
-    """Return a list all Python packages found within directory 'where'
 
-    'where' should be supplied as a "cross-platform" (i.e. URL-style) path; it
-    will be converted to the appropriate local path syntax.  'exclude' is a
-    sequence of package names to exclude; '*' can be used as a wildcard in the
-    names, such that 'foo.*' will exclude all subpackages of 'foo' (but not
-    'foo' itself).
-
-    'include' is a sequence of package names to include.  If it's specified,
-    only the named packages will be included.  If it's not specified, all found
-    packages will be included.  'include' can contain shell style wildcard
-    patterns just like 'exclude'.
+class PackageFinder(object):
+    @classmethod
+    def find(cls, where='.', exclude=(), include=('*',)):
+        """Return a list all Python packages found within directory 'where'
+
+        'where' should be supplied as a "cross-platform" (i.e. URL-style)
+        path; it will be converted to the appropriate local path syntax.
+        'exclude' is a sequence of package names to exclude; '*' can be used
+        as a wildcard in the names, such that 'foo.*' will exclude all
+        subpackages of 'foo' (but not 'foo' itself).
+
+        'include' is a sequence of package names to include.  If it's
+        specified, only the named packages will be included.  If it's not
+        specified, all found packages will be included.  'include' can contain
+        shell style wildcard patterns just like 'exclude'.
+
+        The list of included packages is built up first and then any
+        explicitly excluded packages are removed from it.
+        """
+        out = cls._find_packages_iter(convert_path(where))
+        out = cls.require_parents(out)
+        includes = cls._build_filter(*include)
+        excludes = cls._build_filter('ez_setup', '*__pycache__', *exclude)
+        out = filter(includes, out)
+        out = filterfalse(excludes, out)
+        return list(out)
+
+    @staticmethod
+    def require_parents(packages):
+        """
+        Exclude any apparent package that apparently doesn't include its
+        parent.
+
+        For example, exclude 'foo.bar' if 'foo' is not present.
+        """
+        found = []
+        for pkg in packages:
+            base, sep, child = pkg.rpartition('.')
+            if base and base not in found:
+                continue
+            found.append(pkg)
+            yield pkg
+
+    @staticmethod
+    def _candidate_dirs(base_path):
+        """
+        Return all dirs in base_path that might be packages.
+        """
+        has_dot = lambda name: '.' in name
+        for root, dirs, files in os.walk(base_path, followlinks=True):
+            # Exclude directories that contain a period, as they cannot be
+            #  packages. Mutate the list to avoid traversal.
+            dirs[:] = filterfalse(has_dot, dirs)
+            for dir in dirs:
+                yield os.path.relpath(os.path.join(root, dir), base_path)
+
+    @classmethod
+    def _find_packages_iter(cls, base_path):
+        candidates = cls._candidate_dirs(base_path)
+        return (
+            path.replace(os.path.sep, '.')
+            for path in candidates
+            if cls._looks_like_package(os.path.join(base_path, path))
+        )
+
+    @staticmethod
+    def _looks_like_package(path):
+        return os.path.isfile(os.path.join(path, '__init__.py'))
+
+    @staticmethod
+    def _build_filter(*patterns):
+        """
+        Given a list of patterns, return a callable that will be true only if
+        the input matches one of the patterns.
+        """
+        return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
+
+class PEP420PackageFinder(PackageFinder):
+    @staticmethod
+    def _looks_like_package(path):
+        return True
 
-    The list of included packages is built up first and then any explicitly
-    excluded packages are removed from it.
-    """
-    out = []
-    stack=[(convert_path(where), '')]
-    include = list(include)
-    exclude = list(exclude) + ['ez_setup', '*__pycache__']
-    while stack:
-        where,prefix = stack.pop(0)
-        for name in os.listdir(where):
-            fn = os.path.join(where,name)
-            looks_like_package = (
-                '.' not in name
-                and os.path.isdir(fn)
-                and os.path.isfile(os.path.join(fn, '__init__.py'))
-            )
-            if looks_like_package:
-                pkg_name = prefix + name
-                if (not include or
-                        any(fnmatchcase(pkg_name, pat) for pat in include)):
-                    out.append(pkg_name)
-                    stack.append((fn, pkg_name + '.'))
-    for pat in exclude:
-        out = [item for item in out if not fnmatchcase(item,pat)]
-    return out
+find_packages = PackageFinder.find
 
 setup = distutils.core.setup
 
@@ -78,34 +125,45 @@
     command_consumes_arguments = False
 
     def __init__(self, dist, **kw):
-        # Add support for keyword arguments
-        _Command.__init__(self,dist)
-        for k,v in kw.items():
-            setattr(self,k,v)
+        """
+        Construct the command for dist, updating
+        vars(self) with any keyword parameters.
+        """
+        _Command.__init__(self, dist)
+        vars(self).update(kw)
 
     def reinitialize_command(self, command, reinit_subcommands=0, **kw):
         cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
-        for k,v in kw.items():
-            setattr(cmd,k,v)    # update command with keywords
+        vars(cmd).update(kw)
         return cmd
 
-distutils.core.Command = Command    # we can't patch distutils.cmd, alas
+# we can't patch distutils.cmd, alas
+distutils.core.Command = Command
+
+
+def _find_all_simple(path):
+    """
+    Find all files under 'path'
+    """
+    results = (
+        os.path.join(base, file)
+        for base, dirs, files in os.walk(path, followlinks=True)
+        for file in files
+    )
+    return filter(os.path.isfile, results)
+
 
-def findall(dir = os.curdir):
-    """Find all files under 'dir' and return the list of full filenames
-    (relative to 'dir').
+def findall(dir=os.curdir):
+    """
+    Find all files under 'dir' and return the list of full filenames.
+    Unless dir is '.', return full filenames with dir prepended.
     """
-    all_files = []
-    for base, dirs, files in os.walk(dir):
-        if base==os.curdir or base.startswith(os.curdir+os.sep):
-            base = base[2:]
-        if base:
-            files = [os.path.join(base, f) for f in files]
-        all_files.extend(filter(os.path.isfile, files))
-    return all_files
-
-distutils.filelist.findall = findall    # fix findall bug in distutils.
-
-# sys.dont_write_bytecode was introduced in Python 2.6.
-_dont_write_bytecode = getattr(sys, 'dont_write_bytecode',
-    bool(os.environ.get("PYTHONDONTWRITEBYTECODE")))
+    files = _find_all_simple(dir)
+    if dir == os.curdir:
+        make_rel = functools.partial(os.path.relpath, start=dir)
+        files = map(make_rel, files)
+    return list(files)
+
+
+# fix findall bug in distutils (http://bugs.python.org/issue12885)
+distutils.filelist.findall = findall
diff -Nru python-setuptools-3.3/setuptools/launch.py python-setuptools-20.1.1/setuptools/launch.py
--- python-setuptools-3.3/setuptools/launch.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/launch.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,35 @@
+"""
+Launch the Python script on the command line after
+setuptools is bootstrapped via import.
+"""
+
+# Note that setuptools gets imported implicitly by the
+# invocation of this script using python -m setuptools.launch
+
+import tokenize
+import sys
+
+
+def run():
+	"""
+	Run the script in sys.argv[1] as if it had
+	been invoked naturally.
+	"""
+	__builtins__
+	script_name = sys.argv[1]
+	namespace = dict(
+		__file__ = script_name,
+		__name__ = '__main__',
+		__doc__ = None,
+	)
+	sys.argv[:] = sys.argv[1:]
+
+	open_ = getattr(tokenize, 'open', open)
+	script = open_(script_name).read()
+	norm_script = script.replace('\\r\\n', '\\n')
+	code = compile(norm_script, script_name, 'exec')
+	exec(code, namespace)
+
+
+if __name__ == '__main__':
+	run()
diff -Nru python-setuptools-3.3/setuptools/msvc9_support.py python-setuptools-20.1.1/setuptools/msvc9_support.py
--- python-setuptools-3.3/setuptools/msvc9_support.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/msvc9_support.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,63 @@
+try:
+    import distutils.msvc9compiler
+except ImportError:
+    pass
+
+unpatched = dict()
+
+def patch_for_specialized_compiler():
+    """
+    Patch functions in distutils.msvc9compiler to use the standalone compiler
+    build for Python (Windows only). Fall back to original behavior when the
+    standalone compiler is not available.
+    """
+    if 'distutils' not in globals():
+        # The module isn't available to be patched
+        return
+
+    if unpatched:
+        # Already patched
+        return
+
+    unpatched.update(vars(distutils.msvc9compiler))
+
+    distutils.msvc9compiler.find_vcvarsall = find_vcvarsall
+    distutils.msvc9compiler.query_vcvarsall = query_vcvarsall
+
+def find_vcvarsall(version):
+    Reg = distutils.msvc9compiler.Reg
+    VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
+    key = VC_BASE % ('', version)
+    try:
+        # Per-user installs register the compiler path here
+        productdir = Reg.get_value(key, "installdir")
+    except KeyError:
+        try:
+            # All-user installs on a 64-bit system register here
+            key = VC_BASE % ('Wow6432Node\\', version)
+            productdir = Reg.get_value(key, "installdir")
+        except KeyError:
+            productdir = None
+
+    if productdir:
+        import os
+        vcvarsall = os.path.join(productdir, "vcvarsall.bat")
+        if os.path.isfile(vcvarsall):
+            return vcvarsall
+
+    return unpatched['find_vcvarsall'](version)
+
+def query_vcvarsall(version, *args, **kwargs):
+    try:
+        return unpatched['query_vcvarsall'](version, *args, **kwargs)
+    except distutils.errors.DistutilsPlatformError as exc:
+        if exc and "vcvarsall.bat" in exc.args[0]:
+            message = 'Microsoft Visual C++ %0.1f is required (%s).' % (version, exc.args[0])
+            if int(version) == 9:
+                # This redirection link is maintained by Microsoft.
+                # Contact vspython@microsoft.com if it needs updating.
+                raise distutils.errors.DistutilsPlatformError(
+                    message + ' Get it from http://aka.ms/vcpython27'
+                )
+            raise distutils.errors.DistutilsPlatformError(message)
+        raise
diff -Nru python-setuptools-3.3/setuptools/package_index.py python-setuptools-20.1.1/setuptools/package_index.py
--- python-setuptools-3.3/setuptools/package_index.py	2014-03-15 02:26:36.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/package_index.py	2016-02-07 14:25:06.000000000 +0000
@@ -6,8 +6,17 @@
 import socket
 import base64
 import hashlib
+import itertools
 from functools import wraps
 
+try:
+    from urllib.parse import splituser
+except ImportError:
+    from urllib2 import splituser
+
+from setuptools.extern import six
+from setuptools.extern.six.moves import urllib, http_client, configparser, map
+
 from pkg_resources import (
     CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST,
     require, Environment, find_distributions, safe_name, safe_version,
@@ -16,12 +25,6 @@
 from setuptools import ssl_support
 from distutils import log
 from distutils.errors import DistutilsError
-from setuptools.compat import (urllib2, httplib, StringIO, HTTPError,
-                               urlparse, urlunparse, unquote, splituser,
-                               url2pathname, name2codepoint,
-                               unichr, urljoin, urlsplit, urlunsplit,
-                               ConfigParser)
-from setuptools.compat import filterfalse
 from fnmatch import translate
 from setuptools.py26compat import strip_fragment
 from setuptools.py27compat import get_all_headers
@@ -68,10 +71,11 @@
 
 
 def egg_info_for_url(url):
-    scheme, server, path, parameters, query, fragment = urlparse(url)
-    base = unquote(path.split('/')[-1])
+    parts = urllib.parse.urlparse(url)
+    scheme, server, path, parameters, query, fragment = parts
+    base = urllib.parse.unquote(path.split('/')[-1])
     if server=='sourceforge.net' and base=='download':    # XXX Yuck
-        base = unquote(path.split('/')[-2])
+        base = urllib.parse.unquote(path.split('/')[-2])
     if '#' in base: base, fragment = base.split('#',1)
     return base,fragment
 
@@ -138,10 +142,9 @@
     # versions in distribution archive names (sdist and bdist).
 
     parts = basename.split('-')
-    if not py_version:
-        for i,p in enumerate(parts[2:]):
-            if len(p)==5 and p.startswith('py2.'):
-                return # It's a bdist_dumb, not an sdist -- bail out
+    if not py_version and any(re.match('py\d\.\d$', p) for p in parts[2:]):
+        # it is a bdist_dumb, not an sdist -- bail out
+        return
 
     for p in range(1,len(parts)+1):
         yield Distribution(
@@ -158,7 +161,7 @@
     seen = set()
     seen_add = seen.add
     if key is None:
-        for element in filterfalse(seen.__contains__, iterable):
+        for element in six.moves.filterfalse(seen.__contains__, iterable):
             seen_add(element)
             yield element
     else:
@@ -190,14 +193,14 @@
         rels = set(map(str.strip, rel.lower().split(',')))
         if 'homepage' in rels or 'download' in rels:
             for match in HREF.finditer(tag):
-                yield urljoin(url, htmldecode(match.group(1)))
+                yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
 
     for tag in ("Home Page", "Download URL"):
         pos = page.find(tag)
         if pos!=-1:
             match = HREF.search(page,pos)
             if match:
-                yield urljoin(url, htmldecode(match.group(1)))
+                yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
 
 user_agent = "Python-urllib/%s setuptools/%s" % (
     sys.version[:3], require('setuptools')[0].version
@@ -240,7 +243,7 @@
     @classmethod
     def from_url(cls, url):
         "Construct a (possibly null) ContentChecker from a URL"
-        fragment = urlparse(url)[-1]
+        fragment = urllib.parse.urlparse(url)[-1]
         if not fragment:
             return ContentChecker()
         match = cls.pattern.search(fragment)
@@ -275,7 +278,7 @@
         self.to_scan = []
         if verify_ssl and ssl_support.is_available and (ca_bundle or ssl_support.find_ca_bundle()):
             self.opener = ssl_support.opener_for(ca_bundle)
-        else: self.opener = urllib2.urlopen
+        else: self.opener = urllib.request.urlopen
 
     def process_url(self, url, retrieve=False):
         """Evaluate a URL as a possible download, and maybe retrieve it"""
@@ -312,7 +315,7 @@
         base = f.url     # handle redirects
         page = f.read()
         if not isinstance(page, str): # We are in Python 3 and got bytes. We want str.
-            if isinstance(f, HTTPError):
+            if isinstance(f, urllib.error.HTTPError):
                 # Errors have no charset, assume latin1:
                 charset = 'latin-1'
             else:
@@ -320,7 +323,7 @@
             page = page.decode(charset, "ignore")
         f.close()
         for match in HREF.finditer(page):
-            link = urljoin(base, htmldecode(match.group(1)))
+            link = urllib.parse.urljoin(base, htmldecode(match.group(1)))
             self.process_url(link)
         if url.startswith(self.index_url) and getattr(f,'code',None)!=404:
             page = self.process_index(url, page)
@@ -343,7 +346,7 @@
 
     def url_ok(self, url, fatal=False):
         s = URL_SCHEME(url)
-        if (s and s.group(1).lower()=='file') or self.allows(urlparse(url)[1]):
+        if (s and s.group(1).lower()=='file') or self.allows(urllib.parse.urlparse(url)[1]):
             return True
         msg = ("\nNote: Bypassing %s (disallowed host; see "
             "http://bit.ly/1dg9ijs for details).\n")
@@ -353,20 +356,30 @@
             self.warn(msg, url)
 
     def scan_egg_links(self, search_path):
-        for item in search_path:
-            if os.path.isdir(item):
-                for entry in os.listdir(item):
-                    if entry.endswith('.egg-link'):
-                        self.scan_egg_link(item, entry)
+        dirs = filter(os.path.isdir, search_path)
+        egg_links = (
+            (path, entry)
+            for path in dirs
+            for entry in os.listdir(path)
+            if entry.endswith('.egg-link')
+        )
+        list(itertools.starmap(self.scan_egg_link, egg_links))
 
     def scan_egg_link(self, path, entry):
-        lines = [_f for _f in map(str.strip,
-                                  open(os.path.join(path, entry))) if _f]
-        if len(lines)==2:
-            for dist in find_distributions(os.path.join(path, lines[0])):
-                dist.location = os.path.join(path, *lines)
-                dist.precedence = SOURCE_DIST
-                self.add(dist)
+        with open(os.path.join(path, entry)) as raw_lines:
+            # filter non-empty lines
+            lines = list(filter(None, map(str.strip, raw_lines)))
+
+        if len(lines) != 2:
+            # format is not recognized; punt
+            return
+
+        egg_path, setup_path = lines
+
+        for dist in find_distributions(os.path.join(path, egg_path)):
+            dist.location = os.path.join(path, *lines)
+            dist.precedence = SOURCE_DIST
+            self.add(dist)
 
     def process_index(self,url,page):
         """Process the contents of a PyPI page"""
@@ -374,7 +387,7 @@
             # Process a URL to see if it's for a package page
             if link.startswith(self.index_url):
                 parts = list(map(
-                    unquote, link[len(self.index_url):].split('/')
+                    urllib.parse.unquote, link[len(self.index_url):].split('/')
                 ))
                 if len(parts)==2 and '#' not in parts[1]:
                     # it's a package page, sanitize and index it
@@ -387,7 +400,7 @@
         # process an index page into the package-page index
         for match in HREF.finditer(page):
             try:
-                scan(urljoin(url, htmldecode(match.group(1))))
+                scan(urllib.parse.urljoin(url, htmldecode(match.group(1))))
             except ValueError:
                 pass
 
@@ -632,16 +645,15 @@
                     shutil.copy2(filename, dst)
                     filename=dst
 
-            file = open(os.path.join(tmpdir, 'setup.py'), 'w')
-            file.write(
-                "from setuptools import setup\n"
-                "setup(name=%r, version=%r, py_modules=[%r])\n"
-                % (
-                    dists[0].project_name, dists[0].version,
-                    os.path.splitext(basename)[0]
+            with open(os.path.join(tmpdir, 'setup.py'), 'w') as file:
+                file.write(
+                    "from setuptools import setup\n"
+                    "setup(name=%r, version=%r, py_modules=[%r])\n"
+                    % (
+                        dists[0].project_name, dists[0].version,
+                        os.path.splitext(basename)[0]
+                    )
                 )
-            )
-            file.close()
             return filename
 
         elif match:
@@ -660,11 +672,11 @@
     def _download_to(self, url, filename):
         self.info("Downloading %s", url)
         # Download the file
-        fp, tfp, info = None, None, None
+        fp, info = None, None
         try:
             checker = HashChecker.from_url(url)
             fp = self.open_url(strip_fragment(url))
-            if isinstance(fp, HTTPError):
+            if isinstance(fp, urllib.error.HTTPError):
                 raise DistutilsError(
                     "Can't download %s: %s %s" % (url, fp.code,fp.msg)
                 )
@@ -677,21 +689,20 @@
                 sizes = get_all_headers(headers, 'Content-Length')
                 size = max(map(int, sizes))
                 self.reporthook(url, filename, blocknum, bs, size)
-            tfp = open(filename,'wb')
-            while True:
-                block = fp.read(bs)
-                if block:
-                    checker.feed(block)
-                    tfp.write(block)
-                    blocknum += 1
-                    self.reporthook(url, filename, blocknum, bs, size)
-                else:
-                    break
-            self.check_hash(checker, filename, tfp)
+            with open(filename,'wb') as tfp:
+                while True:
+                    block = fp.read(bs)
+                    if block:
+                        checker.feed(block)
+                        tfp.write(block)
+                        blocknum += 1
+                        self.reporthook(url, filename, blocknum, bs, size)
+                    else:
+                        break
+                self.check_hash(checker, filename, tfp)
             return headers
         finally:
             if fp: fp.close()
-            if tfp: tfp.close()
 
     def reporthook(self, url, filename, blocknum, blksize, size):
         pass    # no-op
@@ -701,25 +712,21 @@
             return local_open(url)
         try:
             return open_with_auth(url, self.opener)
-        except (ValueError, httplib.InvalidURL):
-            v = sys.exc_info()[1]
+        except (ValueError, http_client.InvalidURL) as v:
             msg = ' '.join([str(arg) for arg in v.args])
             if warning:
                 self.warn(warning, msg)
             else:
                 raise DistutilsError('%s %s' % (url, msg))
-        except urllib2.HTTPError:
-            v = sys.exc_info()[1]
+        except urllib.error.HTTPError as v:
             return v
-        except urllib2.URLError:
-            v = sys.exc_info()[1]
+        except urllib.error.URLError as v:
             if warning:
                 self.warn(warning, v.reason)
             else:
                 raise DistutilsError("Download error for %s: %s"
                                      % (url, v.reason))
-        except httplib.BadStatusLine:
-            v = sys.exc_info()[1]
+        except http_client.BadStatusLine as v:
             if warning:
                 self.warn(warning, v.line)
             else:
@@ -728,8 +735,7 @@
                     'down, %s' %
                     (url, v.line)
                 )
-        except httplib.HTTPException:
-            v = sys.exc_info()[1]
+        except http_client.HTTPException as v:
             if warning:
                 self.warn(warning, v)
             else:
@@ -760,7 +766,7 @@
         elif scheme.startswith('hg+'):
             return self._download_hg(url, filename)
         elif scheme=='file':
-            return url2pathname(urlparse(url)[2])
+            return urllib.request.url2pathname(urllib.parse.urlparse(url)[2])
         else:
             self.url_ok(url, True)   # raises error if not allowed
             return self._attempt_download(url, filename)
@@ -794,7 +800,7 @@
         url = url.split('#',1)[0]   # remove any fragment for svn's sake
         creds = ''
         if url.lower().startswith('svn:') and '@' in url:
-            scheme, netloc, path, p, q, f = urlparse(url)
+            scheme, netloc, path, p, q, f = urllib.parse.urlparse(url)
             if not netloc and path.startswith('//') and '/' in path[2:]:
                 netloc, path = path[2:].split('/',1)
                 auth, host = splituser(netloc)
@@ -805,14 +811,15 @@
                     else:
                         creds = " --username="+auth
                     netloc = host
-                    url = urlunparse((scheme, netloc, url, p, q, f))
+                    parts = scheme, netloc, url, p, q, f
+                    url = urllib.parse.urlunparse(parts)
         self.info("Doing subversion checkout from %s to %s", url, filename)
         os.system("svn checkout%s -q %s %s" % (creds, url, filename))
         return filename
 
     @staticmethod
     def _vcs_split_rev_from_url(url, pop_prefix=False):
-        scheme, netloc, path, query, frag = urlsplit(url)
+        scheme, netloc, path, query, frag = urllib.parse.urlsplit(url)
 
         scheme = scheme.split('+', 1)[-1]
 
@@ -824,7 +831,7 @@
             path, rev = path.rsplit('@', 1)
 
         # Also, discard fragment
-        url = urlunsplit((scheme, netloc, path, query, ''))
+        url = urllib.parse.urlunsplit((scheme, netloc, path, query, ''))
 
         return url, rev
 
@@ -876,7 +883,7 @@
 def uchr(c):
     if not isinstance(c, int):
         return c
-    if c>255: return unichr(c)
+    if c>255: return six.unichr(c)
     return chr(c)
 
 def decode_entity(match):
@@ -886,7 +893,7 @@
     elif what.startswith('#'):
         what = int(what[1:])
     else:
-        what = name2codepoint.get(what, match.group(0))
+        what = six.moves.html_entities.name2codepoint.get(what, match.group(0))
     return uchr(what)
 
 def htmldecode(text):
@@ -917,7 +924,7 @@
     >>> chr(10) in str(_encode_auth(long_auth))
     False
     """
-    auth_s = unquote(auth)
+    auth_s = urllib.parse.unquote(auth)
     # convert to bytes
     auth_bytes = auth_s.encode()
     # use the legacy interface for Python 2.3 support
@@ -942,14 +949,14 @@
     def __str__(self):
         return '%(username)s:%(password)s' % vars(self)
 
-class PyPIConfig(ConfigParser.ConfigParser):
+class PyPIConfig(configparser.RawConfigParser):
 
     def __init__(self):
         """
         Load from ~/.pypirc
         """
         defaults = dict.fromkeys(['username', 'password', 'repository'], '')
-        ConfigParser.ConfigParser.__init__(self, defaults)
+        configparser.RawConfigParser.__init__(self, defaults)
 
         rc = os.path.join(os.path.expanduser('~'), '.pypirc')
         if os.path.exists(rc):
@@ -981,15 +988,15 @@
                 return cred
 
 
-def open_with_auth(url, opener=urllib2.urlopen):
+def open_with_auth(url, opener=urllib.request.urlopen):
     """Open a urllib2 request, handling HTTP authentication"""
 
-    scheme, netloc, path, params, query, frag = urlparse(url)
+    scheme, netloc, path, params, query, frag = urllib.parse.urlparse(url)
 
     # Double scheme does not raise on Mac OS X as revealed by a
     # failing test. We would expect "nonnumeric port". Refs #20.
     if netloc.endswith(':'):
-        raise httplib.InvalidURL("nonnumeric port: ''")
+        raise http_client.InvalidURL("nonnumeric port: ''")
 
     if scheme in ('http', 'https'):
         auth, host = splituser(netloc)
@@ -1005,11 +1012,12 @@
 
     if auth:
         auth = "Basic " + _encode_auth(auth)
-        new_url = urlunparse((scheme,host,path,params,query,frag))
-        request = urllib2.Request(new_url)
+        parts = scheme, host, path, params, query, frag
+        new_url = urllib.parse.urlunparse(parts)
+        request = urllib.request.Request(new_url)
         request.add_header("Authorization", auth)
     else:
-        request = urllib2.Request(url)
+        request = urllib.request.Request(url)
 
     request.add_header('User-Agent', user_agent)
     fp = opener(request)
@@ -1017,9 +1025,10 @@
     if auth:
         # Put authentication info back into request URL if same host,
         # so that links found on the page will work
-        s2, h2, path2, param2, query2, frag2 = urlparse(fp.url)
+        s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url)
         if s2==scheme and h2==host:
-            fp.url = urlunparse((s2,netloc,path2,param2,query2,frag2))
+            parts = s2, netloc, path2, param2, query2, frag2
+            fp.url = urllib.parse.urlunparse(parts)
 
     return fp
 
@@ -1032,27 +1041,29 @@
 
 def local_open(url):
     """Read a local path, with special support for directories"""
-    scheme, server, path, param, query, frag = urlparse(url)
-    filename = url2pathname(path)
+    scheme, server, path, param, query, frag = urllib.parse.urlparse(url)
+    filename = urllib.request.url2pathname(path)
     if os.path.isfile(filename):
-        return urllib2.urlopen(url)
+        return urllib.request.urlopen(url)
     elif path.endswith('/') and os.path.isdir(filename):
         files = []
         for f in os.listdir(filename):
-            if f=='index.html':
-                fp = open(os.path.join(filename,f),'r')
-                body = fp.read()
-                fp.close()
+            filepath = os.path.join(filename, f)
+            if f == 'index.html':
+                with open(filepath, 'r') as fp:
+                    body = fp.read()
                 break
-            elif os.path.isdir(os.path.join(filename,f)):
-                f+='/'
-            files.append("%s" % (f,f))
+            elif os.path.isdir(filepath):
+                f += '/'
+            files.append('{name}'.format(name=f))
         else:
-            body = ("%s" % url) + \
-                "%s" % '\n'.join(files)
+            tmpl = ("{url}"
+                "{files}")
+            body = tmpl.format(url=url, files='\n'.join(files))
         status, message = 200, "OK"
     else:
         status, message, body = 404, "Path not found", "Not found"
 
     headers = {'content-type': 'text/html'}
-    return HTTPError(url, status, message, headers, StringIO(body))
+    body_stream = six.StringIO(body)
+    return urllib.error.HTTPError(url, status, message, headers, body_stream)
diff -Nru python-setuptools-3.3/setuptools/py26compat.py python-setuptools-20.1.1/setuptools/py26compat.py
--- python-setuptools-3.3/setuptools/py26compat.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/py26compat.py	2016-02-07 14:25:06.000000000 +0000
@@ -4,7 +4,10 @@
 
 import sys
 
-from setuptools.compat import splittag
+try:
+	from urllib.parse import splittag
+except ImportError:
+	from urllib import splittag
 
 def strip_fragment(url):
 	"""
diff -Nru python-setuptools-3.3/setuptools/py31compat.py python-setuptools-20.1.1/setuptools/py31compat.py
--- python-setuptools-3.3/setuptools/py31compat.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/py31compat.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,3 +1,6 @@
+import sys
+import unittest
+
 __all__ = ['get_config_vars', 'get_path']
 
 try:
@@ -17,7 +20,7 @@
     import shutil
     import tempfile
     class TemporaryDirectory(object):
-        """"
+        """
         Very simple temporary directory context manager.
         Will try to delete afterward, but will also ignore OS and similar
         errors on deletion.
@@ -35,3 +38,15 @@
             except OSError: #removal errors are not the only possible
                 pass
             self.name = None
+
+
+unittest_main = unittest.main
+
+_PY31 = (3, 1) <= sys.version_info[:2] < (3, 2)
+if _PY31:
+    # on Python 3.1, translate testRunner==None to TextTestRunner
+    # for compatibility with Python 2.6, 2.7, and 3.2+
+    def unittest_main(*args, **kwargs):
+        if 'testRunner' in kwargs and kwargs['testRunner'] is None:
+            kwargs['testRunner'] = unittest.TextTestRunner
+        return unittest.main(*args, **kwargs)
diff -Nru python-setuptools-3.3/setuptools/sandbox.py python-setuptools-20.1.1/setuptools/sandbox.py
--- python-setuptools-3.3/setuptools/sandbox.py	2014-03-15 02:26:36.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/sandbox.py	2016-02-07 14:25:06.000000000 +0000
@@ -5,10 +5,15 @@
 import functools
 import itertools
 import re
+import contextlib
+import pickle
+
+from setuptools.extern import six
+from setuptools.extern.six.moves import builtins, map
 
 import pkg_resources
 
-if os.name == "java":
+if sys.platform.startswith('java'):
     import org.python.modules.posix.PosixModule as _os
 else:
     _os = sys.modules[os.name]
@@ -20,58 +25,226 @@
 from distutils.errors import DistutilsError
 from pkg_resources import working_set
 
-from setuptools.compat import builtins, execfile
-
 __all__ = [
     "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
 ]
 
+def _execfile(filename, globals, locals=None):
+    """
+    Python 3 implementation of execfile.
+    """
+    mode = 'rb'
+    with open(filename, mode) as stream:
+        script = stream.read()
+    # compile() function in Python 2.6 and 3.1 requires LF line endings.
+    if sys.version_info[:2] < (2, 7) or sys.version_info[:2] >= (3, 0) and sys.version_info[:2] < (3, 2):
+        script = script.replace(b'\r\n', b'\n')
+        script = script.replace(b'\r', b'\n')
+    if locals is None:
+        locals = globals
+    code = compile(script, filename, 'exec')
+    exec(code, globals, locals)
+
+
+@contextlib.contextmanager
+def save_argv(repl=None):
+    saved = sys.argv[:]
+    if repl is not None:
+        sys.argv[:] = repl
+    try:
+        yield saved
+    finally:
+        sys.argv[:] = saved
+
+
+@contextlib.contextmanager
+def save_path():
+    saved = sys.path[:]
+    try:
+        yield saved
+    finally:
+        sys.path[:] = saved
+
+
+@contextlib.contextmanager
+def override_temp(replacement):
+    """
+    Monkey-patch tempfile.tempdir with replacement, ensuring it exists
+    """
+    if not os.path.isdir(replacement):
+        os.makedirs(replacement)
+
+    saved = tempfile.tempdir
+
+    tempfile.tempdir = replacement
+
+    try:
+        yield
+    finally:
+        tempfile.tempdir = saved
+
+
+@contextlib.contextmanager
+def pushd(target):
+    saved = os.getcwd()
+    os.chdir(target)
+    try:
+        yield saved
+    finally:
+        os.chdir(saved)
+
+
+class UnpickleableException(Exception):
+    """
+    An exception representing another Exception that could not be pickled.
+    """
+    @staticmethod
+    def dump(type, exc):
+        """
+        Always return a dumped (pickled) type and exc. If exc can't be pickled,
+        wrap it in UnpickleableException first.
+        """
+        try:
+            return pickle.dumps(type), pickle.dumps(exc)
+        except Exception:
+            # get UnpickleableException inside the sandbox
+            from setuptools.sandbox import UnpickleableException as cls
+            return cls.dump(cls, cls(repr(exc)))
+
+
+class ExceptionSaver:
+    """
+    A Context Manager that will save an exception, serialized, and restore it
+    later.
+    """
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, exc, tb):
+        if not exc:
+            return
+
+        # dump the exception
+        self._saved = UnpickleableException.dump(type, exc)
+        self._tb = tb
+
+        # suppress the exception
+        return True
+
+    def resume(self):
+        "restore and re-raise any exception"
+
+        if '_saved' not in vars(self):
+            return
+
+        type, exc = map(pickle.loads, self._saved)
+        six.reraise(type, exc, self._tb)
+
+
+@contextlib.contextmanager
+def save_modules():
+    """
+    Context in which imported modules are saved.
+
+    Translates exceptions internal to the context into the equivalent exception
+    outside the context.
+    """
+    saved = sys.modules.copy()
+    with ExceptionSaver() as saved_exc:
+        yield saved
+
+    sys.modules.update(saved)
+    # remove any modules imported since
+    del_modules = (
+        mod_name for mod_name in sys.modules
+        if mod_name not in saved
+        # exclude any encodings modules. See #285
+        and not mod_name.startswith('encodings.')
+    )
+    _clear_modules(del_modules)
+
+    saved_exc.resume()
+
+
+def _clear_modules(module_names):
+    for mod_name in list(module_names):
+        del sys.modules[mod_name]
+
+
+@contextlib.contextmanager
+def save_pkg_resources_state():
+    saved = pkg_resources.__getstate__()
+    try:
+        yield saved
+    finally:
+        pkg_resources.__setstate__(saved)
+
+
+@contextlib.contextmanager
+def setup_context(setup_dir):
+    temp_dir = os.path.join(setup_dir, 'temp')
+    with save_pkg_resources_state():
+        with save_modules():
+            hide_setuptools()
+            with save_path():
+                with save_argv():
+                    with override_temp(temp_dir):
+                        with pushd(setup_dir):
+                            # ensure setuptools commands are available
+                            __import__('setuptools')
+                            yield
+
+
+def _needs_hiding(mod_name):
+    """
+    >>> _needs_hiding('setuptools')
+    True
+    >>> _needs_hiding('pkg_resources')
+    True
+    >>> _needs_hiding('setuptools_plugin')
+    False
+    >>> _needs_hiding('setuptools.__init__')
+    True
+    >>> _needs_hiding('distutils')
+    True
+    >>> _needs_hiding('os')
+    False
+    >>> _needs_hiding('Cython')
+    True
+    """
+    pattern = re.compile('(setuptools|pkg_resources|distutils|Cython)(\.|$)')
+    return bool(pattern.match(mod_name))
+
+
+def hide_setuptools():
+    """
+    Remove references to setuptools' modules from sys.modules to allow the
+    invocation to import the most appropriate setuptools. This technique is
+    necessary to avoid issues such as #315 where setuptools upgrading itself
+    would fail to find a function declared in the metadata.
+    """
+    modules = filter(_needs_hiding, sys.modules)
+    _clear_modules(modules)
+
+
 def run_setup(setup_script, args):
     """Run a distutils setup script, sandboxed in its directory"""
-    old_dir = os.getcwd()
-    save_argv = sys.argv[:]
-    save_path = sys.path[:]
     setup_dir = os.path.abspath(os.path.dirname(setup_script))
-    temp_dir = os.path.join(setup_dir,'temp')
-    if not os.path.isdir(temp_dir): os.makedirs(temp_dir)
-    save_tmp = tempfile.tempdir
-    save_modules = sys.modules.copy()
-    pr_state = pkg_resources.__getstate__()
-    try:
-        tempfile.tempdir = temp_dir
-        os.chdir(setup_dir)
+    with setup_context(setup_dir):
         try:
             sys.argv[:] = [setup_script]+list(args)
             sys.path.insert(0, setup_dir)
             # reset to include setup dir, w/clean callback list
             working_set.__init__()
             working_set.callbacks.append(lambda dist:dist.activate())
-            DirectorySandbox(setup_dir).run(
-                lambda: execfile(
-                    "setup.py",
-                    {'__file__':setup_script, '__name__':'__main__'}
-                )
-            )
-        except SystemExit:
-            v = sys.exc_info()[1]
+            def runner():
+                ns = dict(__file__=setup_script, __name__='__main__')
+                _execfile(setup_script, ns)
+            DirectorySandbox(setup_dir).run(runner)
+        except SystemExit as v:
             if v.args and v.args[0]:
                 raise
             # Normal exit, just return
-    finally:
-        pkg_resources.__setstate__(pr_state)
-        sys.modules.update(save_modules)
-        # remove any modules imported within the sandbox
-        del_modules = [
-            mod_name for mod_name in sys.modules
-            if mod_name not in save_modules
-            # exclude any encodings modules. See #285
-            and not mod_name.startswith('encodings.')
-        ]
-        list(map(sys.modules.__delitem__, del_modules))
-        os.chdir(old_dir)
-        sys.path[:] = save_path
-        sys.argv[:] = save_argv
-        tempfile.tempdir = save_tmp
 
 
 class AbstractSandbox:
@@ -215,6 +388,7 @@
         AbstractSandbox.__init__(self)
 
     def _violation(self, operation, *args, **kw):
+        from setuptools.sandbox import SandboxViolation
         raise SandboxViolation(operation, args, kw)
 
     if _file:
@@ -268,7 +442,7 @@
             self._violation(operation, src, dst, *args, **kw)
         return (src,dst)
 
-    def open(self, file, flags, mode=0x1FF, *args, **kw):    # 0777
+    def open(self, file, flags, mode=0o777, *args, **kw):
         """Called for low-level os.open()"""
         if flags & WRITE_FLAGS and not self._ok(file):
             self._violation("os.open", file, flags, mode, *args, **kw)
diff -Nru python-setuptools-3.3/setuptools/script (dev).tmpl python-setuptools-20.1.1/setuptools/script (dev).tmpl
--- python-setuptools-3.3/setuptools/script (dev).tmpl	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/script (dev).tmpl	2016-01-30 17:43:56.000000000 +0000
@@ -0,0 +1,5 @@
+# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = %(spec)r
+__import__('pkg_resources').require(%(spec)r)
+__file__ = %(dev_path)r
+exec(compile(open(__file__).read(), __file__, 'exec'))
diff -Nru python-setuptools-3.3/setuptools/script template (dev).py python-setuptools-20.1.1/setuptools/script template (dev).py
--- python-setuptools-3.3/setuptools/script template (dev).py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/script template (dev).py	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = """%(spec)r"""
-import sys
-from pkg_resources import require
-require("""%(spec)r""")
-del require
-__file__ = """%(dev_path)r"""
-if sys.version_info < (3, 0):
-    execfile(__file__)
-else:
-    exec(compile(open(__file__).read(), __file__, 'exec'))
diff -Nru python-setuptools-3.3/setuptools/script template.py python-setuptools-20.1.1/setuptools/script template.py
--- python-setuptools-3.3/setuptools/script template.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/script template.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = """%(spec)r"""
-import pkg_resources
-pkg_resources.run_script("""%(spec)r""", """%(script_name)r""")
diff -Nru python-setuptools-3.3/setuptools/script.tmpl python-setuptools-20.1.1/setuptools/script.tmpl
--- python-setuptools-3.3/setuptools/script.tmpl	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/script.tmpl	2016-01-30 17:43:56.000000000 +0000
@@ -0,0 +1,3 @@
+# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = %(spec)r
+__import__('pkg_resources').run_script(%(spec)r, %(script_name)r)
diff -Nru python-setuptools-3.3/setuptools/ssl_support.py python-setuptools-20.1.1/setuptools/ssl_support.py
--- python-setuptools-3.3/setuptools/ssl_support.py	2014-03-15 02:26:36.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/ssl_support.py	2016-02-07 14:25:06.000000000 +0000
@@ -3,9 +3,10 @@
 import atexit
 import re
 
+from setuptools.extern.six.moves import urllib, http_client, map
+
 import pkg_resources
 from pkg_resources import ResolutionError, ExtractionError
-from setuptools.compat import urllib2
 
 try:
     import ssl
@@ -24,20 +25,15 @@
 /usr/local/share/certs/ca-root.crt
 /etc/ssl/cert.pem
 /System/Library/OpenSSL/certs/cert.pem
+/usr/local/share/certs/ca-root-nss.crt
 """.strip().split()
 
 
-HTTPSHandler = HTTPSConnection = object
-
-for what, where in (
-    ('HTTPSHandler', ['urllib2','urllib.request']),
-    ('HTTPSConnection', ['httplib', 'http.client']),
-):
-    for module in where:
-        try:
-            exec("from %s import %s" % (module, what))
-        except ImportError:
-            pass
+try:
+    HTTPSHandler = urllib.request.HTTPSHandler
+    HTTPSConnection = http_client.HTTPSConnection
+except AttributeError:
+    HTTPSHandler = HTTPSConnection = object
 
 is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection)
 
@@ -178,12 +174,19 @@
         if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None):
             self.sock = sock
             self._tunnel()
+            # http://bugs.python.org/issue7776: Python>=3.4.1 and >=2.7.7
+            # change self.host to mean the proxy server host when tunneling is
+            # being used. Adapt, since we are interested in the destination
+            # host for the match_hostname() comparison.
+            actual_host = self._tunnel_host
+        else:
+            actual_host = self.host
 
         self.sock = ssl.wrap_socket(
             sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle
         )
         try:
-            match_hostname(self.sock.getpeercert(), self.host)
+            match_hostname(self.sock.getpeercert(), actual_host)
         except CertificateError:
             self.sock.shutdown(socket.SHUT_RDWR)
             self.sock.close()
@@ -191,7 +194,7 @@
 
 def opener_for(ca_bundle=None):
     """Get a urlopen() replacement that uses ca_bundle for verification"""
-    return urllib2.build_opener(
+    return urllib.request.build_opener(
         VerifyingHTTPSHandler(ca_bundle or find_ca_bundle())
     ).open
 
@@ -216,6 +219,12 @@
             self.addcerts(certs)
             atexit.register(self.close)
 
+        def close(self):
+            try:
+                super(MyCertFile, self).close()
+            except OSError:
+                pass
+
     _wincerts = MyCertFile(stores=['CA', 'ROOT'])
     return _wincerts.name
 
diff -Nru python-setuptools-3.3/setuptools/svn_utils.py python-setuptools-20.1.1/setuptools/svn_utils.py
--- python-setuptools-3.3/setuptools/svn_utils.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/svn_utils.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,583 +0,0 @@
-import os
-import re
-import sys
-from distutils import log
-import xml.dom.pulldom
-import shlex
-import locale
-import codecs
-import unicodedata
-import warnings
-from setuptools.compat import unicode
-from setuptools.py31compat import TemporaryDirectory
-from xml.sax.saxutils import unescape
-
-try:
-    import urlparse
-except ImportError:
-    import urllib.parse as urlparse
-
-from subprocess import Popen as _Popen, PIPE as _PIPE
-
-#NOTE: Use of the command line options require SVN 1.3 or newer (December 2005)
-#      and SVN 1.3 hasn't been supported by the developers since mid 2008.
-
-#subprocess is called several times with shell=(sys.platform=='win32')
-#see the follow for more information:
-#       http://bugs.python.org/issue8557
-#       http://stackoverflow.com/questions/5658622/
-#              python-subprocess-popen-environment-path
-
-def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
-    #regarding the shell argument, see: http://bugs.python.org/issue8557
-    try:
-        proc = _Popen(args, stdout=stdout, stderr=stderr,
-                      shell=(sys.platform == 'win32'))
-
-        data = proc.communicate()[stream]
-    except OSError:
-        return 1, ''
-
-    #doubled checked and
-    data = decode_as_string(data, encoding)
-
-    #communciate calls wait()
-    return proc.returncode, data
-
-
-def _get_entry_schedule(entry):
-    schedule = entry.getElementsByTagName('schedule')[0]
-    return "".join([t.nodeValue
-                    for t in schedule.childNodes
-                    if t.nodeType == t.TEXT_NODE])
-
-
-def _get_target_property(target):
-    property_text = target.getElementsByTagName('property')[0]
-    return "".join([t.nodeValue
-                    for t in property_text.childNodes
-                    if t.nodeType == t.TEXT_NODE])
-
-
-def _get_xml_data(decoded_str):
-    if sys.version_info < (3, 0):
-        #old versions want an encoded string
-        data = decoded_str.encode('utf-8')
-    else:
-        data = decoded_str
-    return data
-
-
-def joinpath(prefix, *suffix):
-    if not prefix or prefix == '.':
-        return os.path.join(*suffix)
-    return os.path.join(prefix, *suffix)
-
-def determine_console_encoding():
-    try:
-        #try for the preferred encoding
-        encoding = locale.getpreferredencoding()
-
-        #see if the locale.getdefaultlocale returns null
-        #some versions of python\platforms return US-ASCII
-        #when it cannot determine an encoding
-        if not encoding or encoding == "US-ASCII":
-            encoding = locale.getdefaultlocale()[1]
-
-        if encoding:
-            codecs.lookup(encoding)  # make sure a lookup error is not made
-
-    except (locale.Error, LookupError):
-        encoding = None
-
-    is_osx = sys.platform == "darwin"
-    if not encoding:
-        return ["US-ASCII", "utf-8"][is_osx]
-    elif encoding.startswith("mac-") and is_osx:
-        #certain versions of python would return mac-roman as default
-        #OSX as a left over of earlier mac versions.
-        return "utf-8"
-    else:
-        return encoding
-
-_console_encoding = determine_console_encoding()
-
-def decode_as_string(text, encoding=None):
-    """
-    Decode the console or file output explicitly using getpreferredencoding.
-    The text paraemeter should be a encoded string, if not no decode occurs
-    If no encoding is given, getpreferredencoding is used.  If encoding is
-    specified, that is used instead.  This would be needed for SVN --xml
-    output.  Unicode is explicitly put in composed NFC form.
-
-    --xml should be UTF-8 (SVN Issue 2938) the discussion on the Subversion
-    DEV List from 2007 seems to indicate the same.
-    """
-    #text should be a byte string
-
-    if encoding is None:
-        encoding = _console_encoding
-
-    if not isinstance(text, unicode):
-        text = text.decode(encoding)
-
-    text = unicodedata.normalize('NFC', text)
-
-    return text
-
-
-def parse_dir_entries(decoded_str):
-    '''Parse the entries from a recursive info xml'''
-    doc = xml.dom.pulldom.parseString(_get_xml_data(decoded_str))
-    entries = list()
-
-    for event, node in doc:
-        if event == 'START_ELEMENT' and node.nodeName == 'entry':
-            doc.expandNode(node)
-            if not _get_entry_schedule(node).startswith('delete'):
-                entries.append((node.getAttribute('path'),
-                                node.getAttribute('kind')))
-
-    return entries[1:]  # do not want the root directory
-
-
-def parse_externals_xml(decoded_str, prefix=''):
-    '''Parse a propget svn:externals xml'''
-    prefix = os.path.normpath(prefix)
-    prefix = os.path.normcase(prefix)
-
-    doc = xml.dom.pulldom.parseString(_get_xml_data(decoded_str))
-    externals = list()
-
-    for event, node in doc:
-        if event == 'START_ELEMENT' and node.nodeName == 'target':
-            doc.expandNode(node)
-            path = os.path.normpath(node.getAttribute('path'))
-
-            if os.path.normcase(path).startswith(prefix):
-                path = path[len(prefix)+1:]
-
-            data = _get_target_property(node)
-            #data should be decoded already
-            for external in parse_external_prop(data):
-                externals.append(joinpath(path, external))
-
-    return externals  # do not want the root directory
-
-
-def parse_external_prop(lines):
-    """
-    Parse the value of a retrieved svn:externals entry.
-
-    possible token setups (with quotng and backscaping in laters versions)
-        URL[@#] EXT_FOLDERNAME
-        [-r#] URL EXT_FOLDERNAME
-        EXT_FOLDERNAME [-r#] URL
-    """
-    externals = []
-    for line in lines.splitlines():
-        line = line.lstrip()  # there might be a "\ "
-        if not line:
-            continue
-
-        if sys.version_info < (3, 0):
-            #shlex handles NULLs just fine and shlex in 2.7 tries to encode
-            #as ascii automatiically
-            line = line.encode('utf-8')
-        line = shlex.split(line)
-        if sys.version_info < (3, 0):
-            line = [x.decode('utf-8') for x in line]
-
-        #EXT_FOLDERNAME is either the first or last depending on where
-        #the URL falls
-        if urlparse.urlsplit(line[-1])[0]:
-            external = line[0]
-        else:
-            external = line[-1]
-
-        external = decode_as_string(external, encoding="utf-8")
-        externals.append(os.path.normpath(external))
-
-    return externals
-
-
-def parse_prop_file(filename, key):
-    found = False
-    f = open(filename, 'rt')
-    data = ''
-    try:
-        for line in iter(f.readline, ''):    # can't use direct iter!
-            parts = line.split()
-            if len(parts) == 2:
-                kind, length = parts
-                data = f.read(int(length))
-                if kind == 'K' and data == key:
-                    found = True
-                elif kind == 'V' and found:
-                    break
-    finally:
-        f.close()
-
-    return data
-
-
-class SvnInfo(object):
-    '''
-    Generic svn_info object.  No has little knowledge of how to extract
-    information.  Use cls.load to instatiate according svn version.
-
-    Paths are not filesystem encoded.
-    '''
-
-    @staticmethod
-    def get_svn_version():
-        # Temp config directory should be enough to check for repository
-        # This is needed because .svn always creates .subversion and 
-        # some operating systems do not handle dot directory correctly.
-        # Real queries in real svn repos with be concerned with it creation
-        with TemporaryDirectory() as tempdir:
-            code, data = _run_command(['svn', 
-                                       '--config-dir', tempdir,
-                                       '--version', 
-                                       '--quiet'])
-
-        if code == 0 and data:
-            return data.strip()
-        else:
-            return ''
-
-    #svnversion return values (previous implementations return max revision)
-    #   4123:4168     mixed revision working copy
-    #   4168M         modified working copy
-    #   4123S         switched working copy
-    #   4123:4168MS   mixed revision, modified, switched working copy
-    revision_re = re.compile(r'(?:([\-0-9]+):)?(\d+)([a-z]*)\s*$', re.I)
-
-    @classmethod
-    def load(cls, dirname=''):
-        normdir = os.path.normpath(dirname)
-
-        # Temp config directory should be enough to check for repository
-        # This is needed because .svn always creates .subversion and 
-        # some operating systems do not handle dot directory correctly.
-        # Real queries in real svn repos with be concerned with it creation
-        with TemporaryDirectory() as tempdir:
-            code, data = _run_command(['svn', 
-                                       '--config-dir', tempdir,
-                                       'info', normdir])
-
-        # Must check for some contents, as some use empty directories
-        # in testcases, however only enteries is needed also the info
-        # command above MUST have worked
-        svn_dir = os.path.join(normdir, '.svn')
-        is_svn_wd = (not code or
-                     os.path.isfile(os.path.join(svn_dir, 'entries')))
-
-        svn_version = tuple(cls.get_svn_version().split('.'))
-
-        try:
-            base_svn_version = tuple(int(x) for x in svn_version[:2])
-        except ValueError:
-            base_svn_version = tuple()
-
-        if not is_svn_wd:
-            #return an instance of this NO-OP class
-            return SvnInfo(dirname)
-
-        if code or not base_svn_version or base_svn_version < (1, 3):
-            warnings.warn(("No SVN 1.3+ command found: falling back "
-                           "on pre 1.7 .svn parsing"), DeprecationWarning)
-            return SvnFileInfo(dirname)
-
-        if base_svn_version < (1, 5):
-            return Svn13Info(dirname)
-
-        return Svn15Info(dirname)
-
-    def __init__(self, path=''):
-        self.path = path
-        self._entries = None
-        self._externals = None
-
-    def get_revision(self):
-        'Retrieve the directory revision informatino using svnversion'
-        code, data = _run_command(['svnversion', '-c', self.path])
-        if code:
-            log.warn("svnversion failed")
-            return 0
-
-        parsed = self.revision_re.match(data)
-        if parsed:
-            return int(parsed.group(2))
-        else:
-            return 0
-
-    @property
-    def entries(self):
-        if self._entries is None:
-            self._entries = self.get_entries()
-        return self._entries
-
-    @property
-    def externals(self):
-        if self._externals is None:
-            self._externals = self.get_externals()
-        return self._externals
-
-    def iter_externals(self):
-        '''
-        Iterate over the svn:external references in the repository path.
-        '''
-        for item in self.externals:
-            yield item
-
-    def iter_files(self):
-        '''
-        Iterate over the non-deleted file entries in the repository path
-        '''
-        for item, kind in self.entries:
-            if kind.lower() == 'file':
-                yield item
-
-    def iter_dirs(self, include_root=True):
-        '''
-        Iterate over the non-deleted file entries in the repository path
-        '''
-        if include_root:
-            yield self.path
-        for item, kind in self.entries:
-            if kind.lower() == 'dir':
-                yield item
-
-    def get_entries(self):
-        return []
-
-    def get_externals(self):
-        return []
-
-
-class Svn13Info(SvnInfo):
-    def get_entries(self):
-        code, data = _run_command(['svn', 'info', '-R', '--xml', self.path],
-                                  encoding="utf-8")
-
-        if code:
-            log.debug("svn info failed")
-            return []
-
-        return parse_dir_entries(data)
-
-    def get_externals(self):
-        #Previous to 1.5 --xml was not supported for svn propget and the -R
-        #output format breaks the shlex compatible semantics.
-        cmd = ['svn', 'propget', 'svn:externals']
-        result = []
-        for folder in self.iter_dirs():
-            code, lines = _run_command(cmd + [folder], encoding="utf-8")
-            if code != 0:
-                log.warn("svn propget failed")
-                return []
-            #lines should a str
-            for external in parse_external_prop(lines):
-                if folder:
-                    external = os.path.join(folder, external)
-                result.append(os.path.normpath(external))
-
-        return result
-
-
-class Svn15Info(Svn13Info):
-    def get_externals(self):
-        cmd = ['svn', 'propget', 'svn:externals', self.path, '-R', '--xml']
-        code, lines = _run_command(cmd, encoding="utf-8")
-        if code:
-            log.debug("svn propget failed")
-            return []
-        return parse_externals_xml(lines, prefix=os.path.abspath(self.path))
-
-
-class SvnFileInfo(SvnInfo):
-
-    def __init__(self, path=''):
-        super(SvnFileInfo, self).__init__(path)
-        self._directories = None
-        self._revision = None
-
-    def _walk_svn(self, base):
-        entry_file = joinpath(base, '.svn', 'entries')
-        if os.path.isfile(entry_file):
-            entries = SVNEntriesFile.load(base)
-            yield (base, False, entries.parse_revision())
-            for path in entries.get_undeleted_records():
-                path = decode_as_string(path)
-                path = joinpath(base, path)
-                if os.path.isfile(path):
-                    yield (path, True, None)
-                elif os.path.isdir(path):
-                    for item in self._walk_svn(path):
-                        yield item
-
-    def _build_entries(self):
-        entries = list()
-
-        rev = 0
-        for path, isfile, dir_rev in self._walk_svn(self.path):
-            if isfile:
-                entries.append((path, 'file'))
-            else:
-                entries.append((path, 'dir'))
-                rev = max(rev, dir_rev)
-
-        self._entries = entries
-        self._revision = rev
-
-    def get_entries(self):
-        if self._entries is None:
-            self._build_entries()
-        return self._entries
-
-    def get_revision(self):
-        if self._revision is None:
-            self._build_entries()
-        return self._revision
-
-    def get_externals(self):
-        prop_files = [['.svn', 'dir-prop-base'],
-                      ['.svn', 'dir-props']]
-        externals = []
-
-        for dirname in self.iter_dirs():
-            prop_file = None
-            for rel_parts in prop_files:
-                filename = joinpath(dirname, *rel_parts)
-                if os.path.isfile(filename):
-                    prop_file = filename
-
-            if prop_file is not None:
-                ext_prop = parse_prop_file(prop_file, 'svn:externals')
-                #ext_prop should be utf-8 coming from svn:externals
-                ext_prop = decode_as_string(ext_prop, encoding="utf-8")
-                externals.extend(parse_external_prop(ext_prop))
-
-        return externals
-
-
-def svn_finder(dirname=''):
-    #combined externals due to common interface
-    #combined externals and entries due to lack of dir_props in 1.7
-    info = SvnInfo.load(dirname)
-    for path in info.iter_files():
-        yield path
-
-    for path in info.iter_externals():
-        sub_info = SvnInfo.load(path)
-        for sub_path in sub_info.iter_files():
-            yield sub_path
-
-
-class SVNEntriesFile(object):
-    def __init__(self, data):
-        self.data = data
-
-    @classmethod
-    def load(class_, base):
-        filename = os.path.join(base, '.svn', 'entries')
-        f = open(filename)
-        try:
-            result = SVNEntriesFile.read(f)
-        finally:
-            f.close()
-        return result
-
-    @classmethod
-    def read(class_, fileobj):
-        data = fileobj.read()
-        is_xml = data.startswith(' revision_line_number
-                and section[revision_line_number])
-        ]
-        return rev_numbers
-
-    def get_undeleted_records(self):
-        undeleted = lambda s: s and s[0] and (len(s) < 6 or s[5] != 'delete')
-        result = [
-            section[0]
-            for section in self.get_sections()
-            if undeleted(section)
-        ]
-        return result
-
-
-class SVNEntriesFileXML(SVNEntriesFile):
-    def is_valid(self):
-        return True
-
-    def get_url(self):
-        "Get repository URL"
-        urlre = re.compile('url="([^"]+)"')
-        return urlre.search(self.data).group(1)
-
-    def parse_revision_numbers(self):
-        revre = re.compile(r'committed-rev="(\d+)"')
-        return [
-            int(m.group(1))
-            for m in revre.finditer(self.data)
-        ]
-
-    def get_undeleted_records(self):
-        entries_pattern = \
-            re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I)
-        results = [
-            unescape(match.group(1))
-            for match in entries_pattern.finditer(self.data)
-        ]
-        return results
-
-
-if __name__ == '__main__':
-    for name in svn_finder(sys.argv[1]):
-        print(name)
diff -Nru python-setuptools-3.3/setuptools/tests/contexts.py python-setuptools-20.1.1/setuptools/tests/contexts.py
--- python-setuptools-3.3/setuptools/tests/contexts.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/contexts.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,98 @@
+import tempfile
+import os
+import shutil
+import sys
+import contextlib
+import site
+
+from setuptools.extern import six
+import pkg_resources
+
+
+@contextlib.contextmanager
+def tempdir(cd=lambda dir:None, **kwargs):
+    temp_dir = tempfile.mkdtemp(**kwargs)
+    orig_dir = os.getcwd()
+    try:
+        cd(temp_dir)
+        yield temp_dir
+    finally:
+        cd(orig_dir)
+        shutil.rmtree(temp_dir)
+
+
+@contextlib.contextmanager
+def environment(**replacements):
+    """
+    In a context, patch the environment with replacements. Pass None values
+    to clear the values.
+    """
+    saved = dict(
+        (key, os.environ[key])
+        for key in replacements
+        if key in os.environ
+    )
+
+    # remove values that are null
+    remove = (key for (key, value) in replacements.items() if value is None)
+    for key in list(remove):
+        os.environ.pop(key, None)
+        replacements.pop(key)
+
+    os.environ.update(replacements)
+
+    try:
+        yield saved
+    finally:
+        for key in replacements:
+            os.environ.pop(key, None)
+        os.environ.update(saved)
+
+
+@contextlib.contextmanager
+def quiet():
+    """
+    Redirect stdout/stderr to StringIO objects to prevent console output from
+    distutils commands.
+    """
+
+    old_stdout = sys.stdout
+    old_stderr = sys.stderr
+    new_stdout = sys.stdout = six.StringIO()
+    new_stderr = sys.stderr = six.StringIO()
+    try:
+        yield new_stdout, new_stderr
+    finally:
+        new_stdout.seek(0)
+        new_stderr.seek(0)
+        sys.stdout = old_stdout
+        sys.stderr = old_stderr
+
+
+@contextlib.contextmanager
+def save_user_site_setting():
+    saved = site.ENABLE_USER_SITE
+    try:
+        yield saved
+    finally:
+        site.ENABLE_USER_SITE = saved
+
+
+@contextlib.contextmanager
+def save_pkg_resources_state():
+    pr_state = pkg_resources.__getstate__()
+    # also save sys.path
+    sys_path = sys.path[:]
+    try:
+        yield pr_state, sys_path
+    finally:
+        sys.path[:] = sys_path
+        pkg_resources.__setstate__(pr_state)
+
+
+@contextlib.contextmanager
+def suppress_exceptions(*excs):
+    try:
+        yield
+    except excs:
+        pass
diff -Nru python-setuptools-3.3/setuptools/tests/doctest.py python-setuptools-20.1.1/setuptools/tests/doctest.py
--- python-setuptools-3.3/setuptools/tests/doctest.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/doctest.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,2683 +0,0 @@
-# Module doctest.
-# Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org).
-# Major enhancements and refactoring by:
-#     Jim Fulton
-#     Edward Loper
-
-# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
-
-try:
-    basestring
-except NameError:
-    basestring = str
-
-try:
-    enumerate
-except NameError:
-    def enumerate(seq):
-        return zip(range(len(seq)),seq)
-
-r"""Module doctest -- a framework for running examples in docstrings.
-
-In simplest use, end each module M to be tested with:
-
-def _test():
-    import doctest
-    doctest.testmod()
-
-if __name__ == "__main__":
-    _test()
-
-Then running the module as a script will cause the examples in the
-docstrings to get executed and verified:
-
-python M.py
-
-This won't display anything unless an example fails, in which case the
-failing example(s) and the cause(s) of the failure(s) are printed to stdout
-(why not stderr? because stderr is a lame hack <0.2 wink>), and the final
-line of output is "Test failed.".
-
-Run it with the -v switch instead:
-
-python M.py -v
-
-and a detailed report of all examples tried is printed to stdout, along
-with assorted summaries at the end.
-
-You can force verbose mode by passing "verbose=True" to testmod, or prohibit
-it by passing "verbose=False".  In either of those cases, sys.argv is not
-examined by testmod.
-
-There are a variety of other ways to run doctests, including integration
-with the unittest framework, and support for running non-Python text
-files containing doctests.  There are also many ways to override parts
-of doctest's default behaviors.  See the Library Reference Manual for
-details.
-"""
-
-__docformat__ = 'reStructuredText en'
-
-__all__ = [
-    # 0, Option Flags
-    'register_optionflag',
-    'DONT_ACCEPT_TRUE_FOR_1',
-    'DONT_ACCEPT_BLANKLINE',
-    'NORMALIZE_WHITESPACE',
-    'ELLIPSIS',
-    'IGNORE_EXCEPTION_DETAIL',
-    'COMPARISON_FLAGS',
-    'REPORT_UDIFF',
-    'REPORT_CDIFF',
-    'REPORT_NDIFF',
-    'REPORT_ONLY_FIRST_FAILURE',
-    'REPORTING_FLAGS',
-    # 1. Utility Functions
-    'is_private',
-    # 2. Example & DocTest
-    'Example',
-    'DocTest',
-    # 3. Doctest Parser
-    'DocTestParser',
-    # 4. Doctest Finder
-    'DocTestFinder',
-    # 5. Doctest Runner
-    'DocTestRunner',
-    'OutputChecker',
-    'DocTestFailure',
-    'UnexpectedException',
-    'DebugRunner',
-    # 6. Test Functions
-    'testmod',
-    'testfile',
-    'run_docstring_examples',
-    # 7. Tester
-    'Tester',
-    # 8. Unittest Support
-    'DocTestSuite',
-    'DocFileSuite',
-    'set_unittest_reportflags',
-    # 9. Debugging Support
-    'script_from_examples',
-    'testsource',
-    'debug_src',
-    'debug',
-]
-
-import __future__
-
-import sys, traceback, inspect, linecache, os, re, types
-import unittest, difflib, pdb, tempfile
-import warnings
-from setuptools.compat import StringIO, execfile, func_code, im_func
-
-# Don't whine about the deprecated is_private function in this
-# module's tests.
-warnings.filterwarnings("ignore", "is_private", DeprecationWarning,
-                        __name__, 0)
-
-# There are 4 basic classes:
-#  - Example: a  pair, plus an intra-docstring line number.
-#  - DocTest: a collection of examples, parsed from a docstring, plus
-#    info about where the docstring came from (name, filename, lineno).
-#  - DocTestFinder: extracts DocTests from a given object's docstring and
-#    its contained objects' docstrings.
-#  - DocTestRunner: runs DocTest cases, and accumulates statistics.
-#
-# So the basic picture is:
-#
-#                             list of:
-# +------+                   +---------+                   +-------+
-# |object| --DocTestFinder-> | DocTest | --DocTestRunner-> |results|
-# +------+                   +---------+                   +-------+
-#                            | Example |
-#                            |   ...   |
-#                            | Example |
-#                            +---------+
-
-# Option constants.
-
-OPTIONFLAGS_BY_NAME = {}
-def register_optionflag(name):
-    flag = 1 << len(OPTIONFLAGS_BY_NAME)
-    OPTIONFLAGS_BY_NAME[name] = flag
-    return flag
-
-DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1')
-DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE')
-NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE')
-ELLIPSIS = register_optionflag('ELLIPSIS')
-IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL')
-
-COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 |
-                    DONT_ACCEPT_BLANKLINE |
-                    NORMALIZE_WHITESPACE |
-                    ELLIPSIS |
-                    IGNORE_EXCEPTION_DETAIL)
-
-REPORT_UDIFF = register_optionflag('REPORT_UDIFF')
-REPORT_CDIFF = register_optionflag('REPORT_CDIFF')
-REPORT_NDIFF = register_optionflag('REPORT_NDIFF')
-REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE')
-
-REPORTING_FLAGS = (REPORT_UDIFF |
-                   REPORT_CDIFF |
-                   REPORT_NDIFF |
-                   REPORT_ONLY_FIRST_FAILURE)
-
-# Special string markers for use in `want` strings:
-BLANKLINE_MARKER = ''
-ELLIPSIS_MARKER = '...'
-
-######################################################################
-## Table of Contents
-######################################################################
-#  1. Utility Functions
-#  2. Example & DocTest -- store test cases
-#  3. DocTest Parser -- extracts examples from strings
-#  4. DocTest Finder -- extracts test cases from objects
-#  5. DocTest Runner -- runs test cases
-#  6. Test Functions -- convenient wrappers for testing
-#  7. Tester Class -- for backwards compatibility
-#  8. Unittest Support
-#  9. Debugging Support
-# 10. Example Usage
-
-######################################################################
-## 1. Utility Functions
-######################################################################
-
-def is_private(prefix, base):
-    """prefix, base -> true iff name prefix + "." + base is "private".
-
-    Prefix may be an empty string, and base does not contain a period.
-    Prefix is ignored (although functions you write conforming to this
-    protocol may make use of it).
-    Return true iff base begins with an (at least one) underscore, but
-    does not both begin and end with (at least) two underscores.
-
-    >>> is_private("a.b", "my_func")
-    False
-    >>> is_private("____", "_my_func")
-    True
-    >>> is_private("someclass", "__init__")
-    False
-    >>> is_private("sometypo", "__init_")
-    True
-    >>> is_private("x.y.z", "_")
-    True
-    >>> is_private("_x.y.z", "__")
-    False
-    >>> is_private("", "")  # senseless but consistent
-    False
-    """
-    warnings.warn("is_private is deprecated; it wasn't useful; "
-                  "examine DocTestFinder.find() lists instead",
-                  DeprecationWarning, stacklevel=2)
-    return base[:1] == "_" and not base[:2] == "__" == base[-2:]
-
-def _extract_future_flags(globs):
-    """
-    Return the compiler-flags associated with the future features that
-    have been imported into the given namespace (globs).
-    """
-    flags = 0
-    for fname in __future__.all_feature_names:
-        feature = globs.get(fname, None)
-        if feature is getattr(__future__, fname):
-            flags |= feature.compiler_flag
-    return flags
-
-def _normalize_module(module, depth=2):
-    """
-    Return the module specified by `module`.  In particular:
-      - If `module` is a module, then return module.
-      - If `module` is a string, then import and return the
-        module with that name.
-      - If `module` is None, then return the calling module.
-        The calling module is assumed to be the module of
-        the stack frame at the given depth in the call stack.
-    """
-    if inspect.ismodule(module):
-        return module
-    elif isinstance(module, basestring):
-        return __import__(module, globals(), locals(), ["*"])
-    elif module is None:
-        return sys.modules[sys._getframe(depth).f_globals['__name__']]
-    else:
-        raise TypeError("Expected a module, string, or None")
-
-def _indent(s, indent=4):
-    """
-    Add the given number of space characters to the beginning every
-    non-blank line in `s`, and return the result.
-    """
-    # This regexp matches the start of non-blank lines:
-    return re.sub('(?m)^(?!$)', indent*' ', s)
-
-def _exception_traceback(exc_info):
-    """
-    Return a string containing a traceback message for the given
-    exc_info tuple (as returned by sys.exc_info()).
-    """
-    # Get a traceback message.
-    excout = StringIO()
-    exc_type, exc_val, exc_tb = exc_info
-    traceback.print_exception(exc_type, exc_val, exc_tb, file=excout)
-    return excout.getvalue()
-
-# Override some StringIO methods.
-class _SpoofOut(StringIO):
-    def getvalue(self):
-        result = StringIO.getvalue(self)
-        # If anything at all was written, make sure there's a trailing
-        # newline.  There's no way for the expected output to indicate
-        # that a trailing newline is missing.
-        if result and not result.endswith("\n"):
-            result += "\n"
-        # Prevent softspace from screwing up the next test case, in
-        # case they used print with a trailing comma in an example.
-        if hasattr(self, "softspace"):
-            del self.softspace
-        return result
-
-    def truncate(self,   size=None):
-        StringIO.truncate(self, size)
-        if hasattr(self, "softspace"):
-            del self.softspace
-
-# Worst-case linear-time ellipsis matching.
-def _ellipsis_match(want, got):
-    """
-    Essentially the only subtle case:
-    >>> _ellipsis_match('aa...aa', 'aaa')
-    False
-    """
-    if want.find(ELLIPSIS_MARKER)==-1:
-        return want == got
-
-    # Find "the real" strings.
-    ws = want.split(ELLIPSIS_MARKER)
-    assert len(ws) >= 2
-
-    # Deal with exact matches possibly needed at one or both ends.
-    startpos, endpos = 0, len(got)
-    w = ws[0]
-    if w:   # starts with exact match
-        if got.startswith(w):
-            startpos = len(w)
-            del ws[0]
-        else:
-            return False
-    w = ws[-1]
-    if w:   # ends with exact match
-        if got.endswith(w):
-            endpos -= len(w)
-            del ws[-1]
-        else:
-            return False
-
-    if startpos > endpos:
-        # Exact end matches required more characters than we have, as in
-        # _ellipsis_match('aa...aa', 'aaa')
-        return False
-
-    # For the rest, we only need to find the leftmost non-overlapping
-    # match for each piece.  If there's no overall match that way alone,
-    # there's no overall match period.
-    for w in ws:
-        # w may be '' at times, if there are consecutive ellipses, or
-        # due to an ellipsis at the start or end of `want`.  That's OK.
-        # Search for an empty string succeeds, and doesn't change startpos.
-        startpos = got.find(w, startpos, endpos)
-        if startpos < 0:
-            return False
-        startpos += len(w)
-
-    return True
-
-def _comment_line(line):
-    "Return a commented form of the given line"
-    line = line.rstrip()
-    if line:
-        return '# '+line
-    else:
-        return '#'
-
-class _OutputRedirectingPdb(pdb.Pdb):
-    """
-    A specialized version of the python debugger that redirects stdout
-    to a given stream when interacting with the user.  Stdout is *not*
-    redirected when traced code is executed.
-    """
-    def __init__(self, out):
-        self.__out = out
-        pdb.Pdb.__init__(self)
-
-    def trace_dispatch(self, *args):
-        # Redirect stdout to the given stream.
-        save_stdout = sys.stdout
-        sys.stdout = self.__out
-        # Call Pdb's trace dispatch method.
-        try:
-            return pdb.Pdb.trace_dispatch(self, *args)
-        finally:
-            sys.stdout = save_stdout
-
-# [XX] Normalize with respect to os.path.pardir?
-def _module_relative_path(module, path):
-    if not inspect.ismodule(module):
-        raise TypeError('Expected a module: %r' % module)
-    if path.startswith('/'):
-        raise ValueError('Module-relative files may not have absolute paths')
-
-    # Find the base directory for the path.
-    if hasattr(module, '__file__'):
-        # A normal module/package
-        basedir = os.path.split(module.__file__)[0]
-    elif module.__name__ == '__main__':
-        # An interactive session.
-        if len(sys.argv)>0 and sys.argv[0] != '':
-            basedir = os.path.split(sys.argv[0])[0]
-        else:
-            basedir = os.curdir
-    else:
-        # A module w/o __file__ (this includes builtins)
-        raise ValueError("Can't resolve paths relative to the module " +
-                         module + " (it has no __file__)")
-
-    # Combine the base directory and the path.
-    return os.path.join(basedir, *(path.split('/')))
-
-######################################################################
-## 2. Example & DocTest
-######################################################################
-## - An "example" is a  pair, where "source" is a
-##   fragment of source code, and "want" is the expected output for
-##   "source."  The Example class also includes information about
-##   where the example was extracted from.
-##
-## - A "doctest" is a collection of examples, typically extracted from
-##   a string (such as an object's docstring).  The DocTest class also
-##   includes information about where the string was extracted from.
-
-class Example:
-    """
-    A single doctest example, consisting of source code and expected
-    output.  `Example` defines the following attributes:
-
-      - source: A single Python statement, always ending with a newline.
-        The constructor adds a newline if needed.
-
-      - want: The expected output from running the source code (either
-        from stdout, or a traceback in case of exception).  `want` ends
-        with a newline unless it's empty, in which case it's an empty
-        string.  The constructor adds a newline if needed.
-
-      - exc_msg: The exception message generated by the example, if
-        the example is expected to generate an exception; or `None` if
-        it is not expected to generate an exception.  This exception
-        message is compared against the return value of
-        `traceback.format_exception_only()`.  `exc_msg` ends with a
-        newline unless it's `None`.  The constructor adds a newline
-        if needed.
-
-      - lineno: The line number within the DocTest string containing
-        this Example where the Example begins.  This line number is
-        zero-based, with respect to the beginning of the DocTest.
-
-      - indent: The example's indentation in the DocTest string.
-        I.e., the number of space characters that preceed the
-        example's first prompt.
-
-      - options: A dictionary mapping from option flags to True or
-        False, which is used to override default options for this
-        example.  Any option flags not contained in this dictionary
-        are left at their default value (as specified by the
-        DocTestRunner's optionflags).  By default, no options are set.
-    """
-    def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
-                 options=None):
-        # Normalize inputs.
-        if not source.endswith('\n'):
-            source += '\n'
-        if want and not want.endswith('\n'):
-            want += '\n'
-        if exc_msg is not None and not exc_msg.endswith('\n'):
-            exc_msg += '\n'
-        # Store properties.
-        self.source = source
-        self.want = want
-        self.lineno = lineno
-        self.indent = indent
-        if options is None: options = {}
-        self.options = options
-        self.exc_msg = exc_msg
-
-class DocTest:
-    """
-    A collection of doctest examples that should be run in a single
-    namespace.  Each `DocTest` defines the following attributes:
-
-      - examples: the list of examples.
-
-      - globs: The namespace (aka globals) that the examples should
-        be run in.
-
-      - name: A name identifying the DocTest (typically, the name of
-        the object whose docstring this DocTest was extracted from).
-
-      - filename: The name of the file that this DocTest was extracted
-        from, or `None` if the filename is unknown.
-
-      - lineno: The line number within filename where this DocTest
-        begins, or `None` if the line number is unavailable.  This
-        line number is zero-based, with respect to the beginning of
-        the file.
-
-      - docstring: The string that the examples were extracted from,
-        or `None` if the string is unavailable.
-    """
-    def __init__(self, examples, globs, name, filename, lineno, docstring):
-        """
-        Create a new DocTest containing the given examples.  The
-        DocTest's globals are initialized with a copy of `globs`.
-        """
-        assert not isinstance(examples, basestring), \
-               "DocTest no longer accepts str; use DocTestParser instead"
-        self.examples = examples
-        self.docstring = docstring
-        self.globs = globs.copy()
-        self.name = name
-        self.filename = filename
-        self.lineno = lineno
-
-    def __repr__(self):
-        if len(self.examples) == 0:
-            examples = 'no examples'
-        elif len(self.examples) == 1:
-            examples = '1 example'
-        else:
-            examples = '%d examples' % len(self.examples)
-        return ('' %
-                (self.name, self.filename, self.lineno, examples))
-
-
-    # This lets us sort tests by name:
-    def __cmp__(self, other):
-        if not isinstance(other, DocTest):
-            return -1
-        return cmp((self.name, self.filename, self.lineno, id(self)),
-                   (other.name, other.filename, other.lineno, id(other)))
-
-######################################################################
-## 3. DocTestParser
-######################################################################
-
-class DocTestParser:
-    """
-    A class used to parse strings containing doctest examples.
-    """
-    # This regular expression is used to find doctest examples in a
-    # string.  It defines three groups: `source` is the source code
-    # (including leading indentation and prompts); `indent` is the
-    # indentation of the first (PS1) line of the source code; and
-    # `want` is the expected output (including leading indentation).
-    _EXAMPLE_RE = re.compile(r'''
-        # Source consists of a PS1 line followed by zero or more PS2 lines.
-        (?P
-            (?:^(?P [ ]*) >>>    .*)    # PS1 line
-            (?:\n           [ ]*  \.\.\. .*)*)  # PS2 lines
-        \n?
-        # Want consists of any non-blank lines that do not start with PS1.
-        (?P (?:(?![ ]*$)    # Not a blank line
-                     (?![ ]*>>>)  # Not a line starting with PS1
-                     .*$\n?       # But any other line
-                  )*)
-        ''', re.MULTILINE | re.VERBOSE)
-
-    # A regular expression for handling `want` strings that contain
-    # expected exceptions.  It divides `want` into three pieces:
-    #    - the traceback header line (`hdr`)
-    #    - the traceback stack (`stack`)
-    #    - the exception message (`msg`), as generated by
-    #      traceback.format_exception_only()
-    # `msg` may have multiple lines.  We assume/require that the
-    # exception message is the first non-indented line starting with a word
-    # character following the traceback header line.
-    _EXCEPTION_RE = re.compile(r"""
-        # Grab the traceback header.  Different versions of Python have
-        # said different things on the first traceback line.
-        ^(?P Traceback\ \(
-            (?: most\ recent\ call\ last
-            |   innermost\ last
-            ) \) :
-        )
-        \s* $                # toss trailing whitespace on the header.
-        (?P .*?)      # don't blink: absorb stuff until...
-        ^ (?P \w+ .*)   #     a line *starts* with alphanum.
-        """, re.VERBOSE | re.MULTILINE | re.DOTALL)
-
-    # A callable returning a true value iff its argument is a blank line
-    # or contains a single comment.
-    _IS_BLANK_OR_COMMENT = re.compile(r'^[ ]*(#.*)?$').match
-
-    def parse(self, string, name=''):
-        """
-        Divide the given string into examples and intervening text,
-        and return them as a list of alternating Examples and strings.
-        Line numbers for the Examples are 0-based.  The optional
-        argument `name` is a name identifying this string, and is only
-        used for error messages.
-        """
-        string = string.expandtabs()
-        # If all lines begin with the same indentation, then strip it.
-        min_indent = self._min_indent(string)
-        if min_indent > 0:
-            string = '\n'.join([l[min_indent:] for l in string.split('\n')])
-
-        output = []
-        charno, lineno = 0, 0
-        # Find all doctest examples in the string:
-        for m in self._EXAMPLE_RE.finditer(string):
-            # Add the pre-example text to `output`.
-            output.append(string[charno:m.start()])
-            # Update lineno (lines before this example)
-            lineno += string.count('\n', charno, m.start())
-            # Extract info from the regexp match.
-            (source, options, want, exc_msg) = \
-                     self._parse_example(m, name, lineno)
-            # Create an Example, and add it to the list.
-            if not self._IS_BLANK_OR_COMMENT(source):
-                output.append( Example(source, want, exc_msg,
-                                    lineno=lineno,
-                                    indent=min_indent+len(m.group('indent')),
-                                    options=options) )
-            # Update lineno (lines inside this example)
-            lineno += string.count('\n', m.start(), m.end())
-            # Update charno.
-            charno = m.end()
-        # Add any remaining post-example text to `output`.
-        output.append(string[charno:])
-        return output
-
-    def get_doctest(self, string, globs, name, filename, lineno):
-        """
-        Extract all doctest examples from the given string, and
-        collect them into a `DocTest` object.
-
-        `globs`, `name`, `filename`, and `lineno` are attributes for
-        the new `DocTest` object.  See the documentation for `DocTest`
-        for more information.
-        """
-        return DocTest(self.get_examples(string, name), globs,
-                       name, filename, lineno, string)
-
-    def get_examples(self, string, name=''):
-        """
-        Extract all doctest examples from the given string, and return
-        them as a list of `Example` objects.  Line numbers are
-        0-based, because it's most common in doctests that nothing
-        interesting appears on the same line as opening triple-quote,
-        and so the first interesting line is called \"line 1\" then.
-
-        The optional argument `name` is a name identifying this
-        string, and is only used for error messages.
-        """
-        return [x for x in self.parse(string, name)
-                if isinstance(x, Example)]
-
-    def _parse_example(self, m, name, lineno):
-        """
-        Given a regular expression match from `_EXAMPLE_RE` (`m`),
-        return a pair `(source, want)`, where `source` is the matched
-        example's source code (with prompts and indentation stripped);
-        and `want` is the example's expected output (with indentation
-        stripped).
-
-        `name` is the string's name, and `lineno` is the line number
-        where the example starts; both are used for error messages.
-        """
-        # Get the example's indentation level.
-        indent = len(m.group('indent'))
-
-        # Divide source into lines; check that they're properly
-        # indented; and then strip their indentation & prompts.
-        source_lines = m.group('source').split('\n')
-        self._check_prompt_blank(source_lines, indent, name, lineno)
-        self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno)
-        source = '\n'.join([sl[indent+4:] for sl in source_lines])
-
-        # Divide want into lines; check that it's properly indented; and
-        # then strip the indentation.  Spaces before the last newline should
-        # be preserved, so plain rstrip() isn't good enough.
-        want = m.group('want')
-        want_lines = want.split('\n')
-        if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
-            del want_lines[-1]  # forget final newline & spaces after it
-        self._check_prefix(want_lines, ' '*indent, name,
-                           lineno + len(source_lines))
-        want = '\n'.join([wl[indent:] for wl in want_lines])
-
-        # If `want` contains a traceback message, then extract it.
-        m = self._EXCEPTION_RE.match(want)
-        if m:
-            exc_msg = m.group('msg')
-        else:
-            exc_msg = None
-
-        # Extract options from the source.
-        options = self._find_options(source, name, lineno)
-
-        return source, options, want, exc_msg
-
-    # This regular expression looks for option directives in the
-    # source code of an example.  Option directives are comments
-    # starting with "doctest:".  Warning: this may give false
-    # positives for string-literals that contain the string
-    # "#doctest:".  Eliminating these false positives would require
-    # actually parsing the string; but we limit them by ignoring any
-    # line containing "#doctest:" that is *followed* by a quote mark.
-    _OPTION_DIRECTIVE_RE = re.compile(r'#\s*doctest:\s*([^\n\'"]*)$',
-                                      re.MULTILINE)
-
-    def _find_options(self, source, name, lineno):
-        """
-        Return a dictionary containing option overrides extracted from
-        option directives in the given source string.
-
-        `name` is the string's name, and `lineno` is the line number
-        where the example starts; both are used for error messages.
-        """
-        options = {}
-        # (note: with the current regexp, this will match at most once:)
-        for m in self._OPTION_DIRECTIVE_RE.finditer(source):
-            option_strings = m.group(1).replace(',', ' ').split()
-            for option in option_strings:
-                if (option[0] not in '+-' or
-                    option[1:] not in OPTIONFLAGS_BY_NAME):
-                    raise ValueError('line %r of the doctest for %s '
-                                     'has an invalid option: %r' %
-                                     (lineno+1, name, option))
-                flag = OPTIONFLAGS_BY_NAME[option[1:]]
-                options[flag] = (option[0] == '+')
-        if options and self._IS_BLANK_OR_COMMENT(source):
-            raise ValueError('line %r of the doctest for %s has an option '
-                             'directive on a line with no example: %r' %
-                             (lineno, name, source))
-        return options
-
-    # This regular expression finds the indentation of every non-blank
-    # line in a string.
-    _INDENT_RE = re.compile('^([ ]*)(?=\S)', re.MULTILINE)
-
-    def _min_indent(self, s):
-        "Return the minimum indentation of any non-blank line in `s`"
-        indents = [len(indent) for indent in self._INDENT_RE.findall(s)]
-        if len(indents) > 0:
-            return min(indents)
-        else:
-            return 0
-
-    def _check_prompt_blank(self, lines, indent, name, lineno):
-        """
-        Given the lines of a source string (including prompts and
-        leading indentation), check to make sure that every prompt is
-        followed by a space character.  If any line is not followed by
-        a space character, then raise ValueError.
-        """
-        for i, line in enumerate(lines):
-            if len(line) >= indent+4 and line[indent+3] != ' ':
-                raise ValueError('line %r of the docstring for %s '
-                                 'lacks blank after %s: %r' %
-                                 (lineno+i+1, name,
-                                  line[indent:indent+3], line))
-
-    def _check_prefix(self, lines, prefix, name, lineno):
-        """
-        Check that every line in the given list starts with the given
-        prefix; if any line does not, then raise a ValueError.
-        """
-        for i, line in enumerate(lines):
-            if line and not line.startswith(prefix):
-                raise ValueError('line %r of the docstring for %s has '
-                                 'inconsistent leading whitespace: %r' %
-                                 (lineno+i+1, name, line))
-
-
-######################################################################
-## 4. DocTest Finder
-######################################################################
-
-class DocTestFinder:
-    """
-    A class used to extract the DocTests that are relevant to a given
-    object, from its docstring and the docstrings of its contained
-    objects.  Doctests can currently be extracted from the following
-    object types: modules, functions, classes, methods, staticmethods,
-    classmethods, and properties.
-    """
-
-    def __init__(self, verbose=False, parser=DocTestParser(),
-                 recurse=True, _namefilter=None, exclude_empty=True):
-        """
-        Create a new doctest finder.
-
-        The optional argument `parser` specifies a class or
-        function that should be used to create new DocTest objects (or
-        objects that implement the same interface as DocTest).  The
-        signature for this factory function should match the signature
-        of the DocTest constructor.
-
-        If the optional argument `recurse` is false, then `find` will
-        only examine the given object, and not any contained objects.
-
-        If the optional argument `exclude_empty` is false, then `find`
-        will include tests for objects with empty docstrings.
-        """
-        self._parser = parser
-        self._verbose = verbose
-        self._recurse = recurse
-        self._exclude_empty = exclude_empty
-        # _namefilter is undocumented, and exists only for temporary backward-
-        # compatibility support of testmod's deprecated isprivate mess.
-        self._namefilter = _namefilter
-
-    def find(self, obj, name=None, module=None, globs=None,
-             extraglobs=None):
-        """
-        Return a list of the DocTests that are defined by the given
-        object's docstring, or by any of its contained objects'
-        docstrings.
-
-        The optional parameter `module` is the module that contains
-        the given object.  If the module is not specified or is None, then
-        the test finder will attempt to automatically determine the
-        correct module.  The object's module is used:
-
-            - As a default namespace, if `globs` is not specified.
-            - To prevent the DocTestFinder from extracting DocTests
-              from objects that are imported from other modules.
-            - To find the name of the file containing the object.
-            - To help find the line number of the object within its
-              file.
-
-        Contained objects whose module does not match `module` are ignored.
-
-        If `module` is False, no attempt to find the module will be made.
-        This is obscure, of use mostly in tests:  if `module` is False, or
-        is None but cannot be found automatically, then all objects are
-        considered to belong to the (non-existent) module, so all contained
-        objects will (recursively) be searched for doctests.
-
-        The globals for each DocTest is formed by combining `globs`
-        and `extraglobs` (bindings in `extraglobs` override bindings
-        in `globs`).  A new copy of the globals dictionary is created
-        for each DocTest.  If `globs` is not specified, then it
-        defaults to the module's `__dict__`, if specified, or {}
-        otherwise.  If `extraglobs` is not specified, then it defaults
-        to {}.
-
-        """
-        # If name was not specified, then extract it from the object.
-        if name is None:
-            name = getattr(obj, '__name__', None)
-            if name is None:
-                raise ValueError("DocTestFinder.find: name must be given "
-                        "when obj.__name__ doesn't exist: %r" %
-                                 (type(obj),))
-
-        # Find the module that contains the given object (if obj is
-        # a module, then module=obj.).  Note: this may fail, in which
-        # case module will be None.
-        if module is False:
-            module = None
-        elif module is None:
-            module = inspect.getmodule(obj)
-
-        # Read the module's source code.  This is used by
-        # DocTestFinder._find_lineno to find the line number for a
-        # given object's docstring.
-        try:
-            file = inspect.getsourcefile(obj) or inspect.getfile(obj)
-            source_lines = linecache.getlines(file)
-            if not source_lines:
-                source_lines = None
-        except TypeError:
-            source_lines = None
-
-        # Initialize globals, and merge in extraglobs.
-        if globs is None:
-            if module is None:
-                globs = {}
-            else:
-                globs = module.__dict__.copy()
-        else:
-            globs = globs.copy()
-        if extraglobs is not None:
-            globs.update(extraglobs)
-
-        # Recursively expore `obj`, extracting DocTests.
-        tests = []
-        self._find(tests, obj, name, module, source_lines, globs, {})
-        return tests
-
-    def _filter(self, obj, prefix, base):
-        """
-        Return true if the given object should not be examined.
-        """
-        return (self._namefilter is not None and
-                self._namefilter(prefix, base))
-
-    def _from_module(self, module, object):
-        """
-        Return true if the given object is defined in the given
-        module.
-        """
-        if module is None:
-            return True
-        elif inspect.isfunction(object):
-            return module.__dict__ is func_globals(object)
-        elif inspect.isclass(object):
-            return module.__name__ == object.__module__
-        elif inspect.getmodule(object) is not None:
-            return module is inspect.getmodule(object)
-        elif hasattr(object, '__module__'):
-            return module.__name__ == object.__module__
-        elif isinstance(object, property):
-            return True # [XX] no way not be sure.
-        else:
-            raise ValueError("object must be a class or function")
-
-    def _find(self, tests, obj, name, module, source_lines, globs, seen):
-        """
-        Find tests for the given object and any contained objects, and
-        add them to `tests`.
-        """
-        if self._verbose:
-            print('Finding tests in %s' % name)
-
-        # If we've already processed this object, then ignore it.
-        if id(obj) in seen:
-            return
-        seen[id(obj)] = 1
-
-        # Find a test for this object, and add it to the list of tests.
-        test = self._get_test(obj, name, module, globs, source_lines)
-        if test is not None:
-            tests.append(test)
-
-        # Look for tests in a module's contained objects.
-        if inspect.ismodule(obj) and self._recurse:
-            for valname, val in obj.__dict__.items():
-                # Check if this contained object should be ignored.
-                if self._filter(val, name, valname):
-                    continue
-                valname = '%s.%s' % (name, valname)
-                # Recurse to functions & classes.
-                if ((inspect.isfunction(val) or inspect.isclass(val)) and
-                    self._from_module(module, val)):
-                    self._find(tests, val, valname, module, source_lines,
-                               globs, seen)
-
-        # Look for tests in a module's __test__ dictionary.
-        if inspect.ismodule(obj) and self._recurse:
-            for valname, val in getattr(obj, '__test__', {}).items():
-                if not isinstance(valname, basestring):
-                    raise ValueError("DocTestFinder.find: __test__ keys "
-                                     "must be strings: %r" %
-                                     (type(valname),))
-                if not (inspect.isfunction(val) or inspect.isclass(val) or
-                        inspect.ismethod(val) or inspect.ismodule(val) or
-                        isinstance(val, basestring)):
-                    raise ValueError("DocTestFinder.find: __test__ values "
-                                     "must be strings, functions, methods, "
-                                     "classes, or modules: %r" %
-                                     (type(val),))
-                valname = '%s.__test__.%s' % (name, valname)
-                self._find(tests, val, valname, module, source_lines,
-                           globs, seen)
-
-        # Look for tests in a class's contained objects.
-        if inspect.isclass(obj) and self._recurse:
-            for valname, val in obj.__dict__.items():
-                # Check if this contained object should be ignored.
-                if self._filter(val, name, valname):
-                    continue
-                # Special handling for staticmethod/classmethod.
-                if isinstance(val, staticmethod):
-                    val = getattr(obj, valname)
-                if isinstance(val, classmethod):
-                    val = im_func(getattr(obj, valname))
-
-                # Recurse to methods, properties, and nested classes.
-                if ((inspect.isfunction(val) or inspect.isclass(val) or
-                      isinstance(val, property)) and
-                      self._from_module(module, val)):
-                    valname = '%s.%s' % (name, valname)
-                    self._find(tests, val, valname, module, source_lines,
-                               globs, seen)
-
-    def _get_test(self, obj, name, module, globs, source_lines):
-        """
-        Return a DocTest for the given object, if it defines a docstring;
-        otherwise, return None.
-        """
-        # Extract the object's docstring.  If it doesn't have one,
-        # then return None (no test for this object).
-        if isinstance(obj, basestring):
-            docstring = obj
-        else:
-            try:
-                if obj.__doc__ is None:
-                    docstring = ''
-                else:
-                    docstring = obj.__doc__
-                    if not isinstance(docstring, basestring):
-                        docstring = str(docstring)
-            except (TypeError, AttributeError):
-                docstring = ''
-
-        # Find the docstring's location in the file.
-        lineno = self._find_lineno(obj, source_lines)
-
-        # Don't bother if the docstring is empty.
-        if self._exclude_empty and not docstring:
-            return None
-
-        # Return a DocTest for this object.
-        if module is None:
-            filename = None
-        else:
-            filename = getattr(module, '__file__', module.__name__)
-            if filename[-4:] in (".pyc", ".pyo"):
-                filename = filename[:-1]
-        return self._parser.get_doctest(docstring, globs, name,
-                                        filename, lineno)
-
-    def _find_lineno(self, obj, source_lines):
-        """
-        Return a line number of the given object's docstring.  Note:
-        this method assumes that the object has a docstring.
-        """
-        lineno = None
-
-        # Find the line number for modules.
-        if inspect.ismodule(obj):
-            lineno = 0
-
-        # Find the line number for classes.
-        # Note: this could be fooled if a class is defined multiple
-        # times in a single file.
-        if inspect.isclass(obj):
-            if source_lines is None:
-                return None
-            pat = re.compile(r'^\s*class\s*%s\b' %
-                             getattr(obj, '__name__', '-'))
-            for i, line in enumerate(source_lines):
-                if pat.match(line):
-                    lineno = i
-                    break
-
-        # Find the line number for functions & methods.
-        if inspect.ismethod(obj): obj = im_func(obj)
-        if inspect.isfunction(obj): obj = func_code(obj)
-        if inspect.istraceback(obj): obj = obj.tb_frame
-        if inspect.isframe(obj): obj = obj.f_code
-        if inspect.iscode(obj):
-            lineno = getattr(obj, 'co_firstlineno', None)-1
-
-        # Find the line number where the docstring starts.  Assume
-        # that it's the first line that begins with a quote mark.
-        # Note: this could be fooled by a multiline function
-        # signature, where a continuation line begins with a quote
-        # mark.
-        if lineno is not None:
-            if source_lines is None:
-                return lineno+1
-            pat = re.compile('(^|.*:)\s*\w*("|\')')
-            for lineno in range(lineno, len(source_lines)):
-                if pat.match(source_lines[lineno]):
-                    return lineno
-
-        # We couldn't find the line number.
-        return None
-
-######################################################################
-## 5. DocTest Runner
-######################################################################
-
-class DocTestRunner:
-    """
-    A class used to run DocTest test cases, and accumulate statistics.
-    The `run` method is used to process a single DocTest case.  It
-    returns a tuple `(f, t)`, where `t` is the number of test cases
-    tried, and `f` is the number of test cases that failed.
-
-        >>> tests = DocTestFinder().find(_TestClass)
-        >>> runner = DocTestRunner(verbose=False)
-        >>> for test in tests:
-        ...     print runner.run(test)
-        (0, 2)
-        (0, 1)
-        (0, 2)
-        (0, 2)
-
-    The `summarize` method prints a summary of all the test cases that
-    have been run by the runner, and returns an aggregated `(f, t)`
-    tuple:
-
-        >>> runner.summarize(verbose=1)
-        4 items passed all tests:
-           2 tests in _TestClass
-           2 tests in _TestClass.__init__
-           2 tests in _TestClass.get
-           1 tests in _TestClass.square
-        7 tests in 4 items.
-        7 passed and 0 failed.
-        Test passed.
-        (0, 7)
-
-    The aggregated number of tried examples and failed examples is
-    also available via the `tries` and `failures` attributes:
-
-        >>> runner.tries
-        7
-        >>> runner.failures
-        0
-
-    The comparison between expected outputs and actual outputs is done
-    by an `OutputChecker`.  This comparison may be customized with a
-    number of option flags; see the documentation for `testmod` for
-    more information.  If the option flags are insufficient, then the
-    comparison may also be customized by passing a subclass of
-    `OutputChecker` to the constructor.
-
-    The test runner's display output can be controlled in two ways.
-    First, an output function (`out) can be passed to
-    `TestRunner.run`; this function will be called with strings that
-    should be displayed.  It defaults to `sys.stdout.write`.  If
-    capturing the output is not sufficient, then the display output
-    can be also customized by subclassing DocTestRunner, and
-    overriding the methods `report_start`, `report_success`,
-    `report_unexpected_exception`, and `report_failure`.
-    """
-    # This divider string is used to separate failure messages, and to
-    # separate sections of the summary.
-    DIVIDER = "*" * 70
-
-    def __init__(self, checker=None, verbose=None, optionflags=0):
-        """
-        Create a new test runner.
-
-        Optional keyword arg `checker` is the `OutputChecker` that
-        should be used to compare the expected outputs and actual
-        outputs of doctest examples.
-
-        Optional keyword arg 'verbose' prints lots of stuff if true,
-        only failures if false; by default, it's true iff '-v' is in
-        sys.argv.
-
-        Optional argument `optionflags` can be used to control how the
-        test runner compares expected output to actual output, and how
-        it displays failures.  See the documentation for `testmod` for
-        more information.
-        """
-        self._checker = checker or OutputChecker()
-        if verbose is None:
-            verbose = '-v' in sys.argv
-        self._verbose = verbose
-        self.optionflags = optionflags
-        self.original_optionflags = optionflags
-
-        # Keep track of the examples we've run.
-        self.tries = 0
-        self.failures = 0
-        self._name2ft = {}
-
-        # Create a fake output target for capturing doctest output.
-        self._fakeout = _SpoofOut()
-
-    #/////////////////////////////////////////////////////////////////
-    # Reporting methods
-    #/////////////////////////////////////////////////////////////////
-
-    def report_start(self, out, test, example):
-        """
-        Report that the test runner is about to process the given
-        example.  (Only displays a message if verbose=True)
-        """
-        if self._verbose:
-            if example.want:
-                out('Trying:\n' + _indent(example.source) +
-                    'Expecting:\n' + _indent(example.want))
-            else:
-                out('Trying:\n' + _indent(example.source) +
-                    'Expecting nothing\n')
-
-    def report_success(self, out, test, example, got):
-        """
-        Report that the given example ran successfully.  (Only
-        displays a message if verbose=True)
-        """
-        if self._verbose:
-            out("ok\n")
-
-    def report_failure(self, out, test, example, got):
-        """
-        Report that the given example failed.
-        """
-        out(self._failure_header(test, example) +
-            self._checker.output_difference(example, got, self.optionflags))
-
-    def report_unexpected_exception(self, out, test, example, exc_info):
-        """
-        Report that the given example raised an unexpected exception.
-        """
-        out(self._failure_header(test, example) +
-            'Exception raised:\n' + _indent(_exception_traceback(exc_info)))
-
-    def _failure_header(self, test, example):
-        out = [self.DIVIDER]
-        if test.filename:
-            if test.lineno is not None and example.lineno is not None:
-                lineno = test.lineno + example.lineno + 1
-            else:
-                lineno = '?'
-            out.append('File "%s", line %s, in %s' %
-                       (test.filename, lineno, test.name))
-        else:
-            out.append('Line %s, in %s' % (example.lineno+1, test.name))
-        out.append('Failed example:')
-        source = example.source
-        out.append(_indent(source))
-        return '\n'.join(out)
-
-    #/////////////////////////////////////////////////////////////////
-    # DocTest Running
-    #/////////////////////////////////////////////////////////////////
-
-    def __run(self, test, compileflags, out):
-        """
-        Run the examples in `test`.  Write the outcome of each example
-        with one of the `DocTestRunner.report_*` methods, using the
-        writer function `out`.  `compileflags` is the set of compiler
-        flags that should be used to execute examples.  Return a tuple
-        `(f, t)`, where `t` is the number of examples tried, and `f`
-        is the number of examples that failed.  The examples are run
-        in the namespace `test.globs`.
-        """
-        # Keep track of the number of failures and tries.
-        failures = tries = 0
-
-        # Save the option flags (since option directives can be used
-        # to modify them).
-        original_optionflags = self.optionflags
-
-        SUCCESS, FAILURE, BOOM = range(3) # `outcome` state
-
-        check = self._checker.check_output
-
-        # Process each example.
-        for examplenum, example in enumerate(test.examples):
-
-            # If REPORT_ONLY_FIRST_FAILURE is set, then supress
-            # reporting after the first failure.
-            quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and
-                     failures > 0)
-
-            # Merge in the example's options.
-            self.optionflags = original_optionflags
-            if example.options:
-                for (optionflag, val) in example.options.items():
-                    if val:
-                        self.optionflags |= optionflag
-                    else:
-                        self.optionflags &= ~optionflag
-
-            # Record that we started this example.
-            tries += 1
-            if not quiet:
-                self.report_start(out, test, example)
-
-            # Use a special filename for compile(), so we can retrieve
-            # the source code during interactive debugging (see
-            # __patched_linecache_getlines).
-            filename = '' % (test.name, examplenum)
-
-            # Run the example in the given context (globs), and record
-            # any exception that gets raised.  (But don't intercept
-            # keyboard interrupts.)
-            try:
-                # Don't blink!  This is where the user's code gets run.
-                exec(compile(example.source, filename, "single",
-                              compileflags, 1), test.globs)
-                self.debugger.set_continue() # ==== Example Finished ====
-                exception = None
-            except KeyboardInterrupt:
-                raise
-            except:
-                exception = sys.exc_info()
-                self.debugger.set_continue() # ==== Example Finished ====
-
-            got = self._fakeout.getvalue()  # the actual output
-            self._fakeout.truncate(0)
-            outcome = FAILURE   # guilty until proved innocent or insane
-
-            # If the example executed without raising any exceptions,
-            # verify its output.
-            if exception is None:
-                if check(example.want, got, self.optionflags):
-                    outcome = SUCCESS
-
-            # The example raised an exception:  check if it was expected.
-            else:
-                exc_info = sys.exc_info()
-                exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
-                if not quiet:
-                    got += _exception_traceback(exc_info)
-
-                # If `example.exc_msg` is None, then we weren't expecting
-                # an exception.
-                if example.exc_msg is None:
-                    outcome = BOOM
-
-                # We expected an exception:  see whether it matches.
-                elif check(example.exc_msg, exc_msg, self.optionflags):
-                    outcome = SUCCESS
-
-                # Another chance if they didn't care about the detail.
-                elif self.optionflags & IGNORE_EXCEPTION_DETAIL:
-                    m1 = re.match(r'[^:]*:', example.exc_msg)
-                    m2 = re.match(r'[^:]*:', exc_msg)
-                    if m1 and m2 and check(m1.group(0), m2.group(0),
-                                           self.optionflags):
-                        outcome = SUCCESS
-
-            # Report the outcome.
-            if outcome is SUCCESS:
-                if not quiet:
-                    self.report_success(out, test, example, got)
-            elif outcome is FAILURE:
-                if not quiet:
-                    self.report_failure(out, test, example, got)
-                failures += 1
-            elif outcome is BOOM:
-                if not quiet:
-                    self.report_unexpected_exception(out, test, example,
-                                                     exc_info)
-                failures += 1
-            else:
-                assert False, ("unknown outcome", outcome)
-
-        # Restore the option flags (in case they were modified)
-        self.optionflags = original_optionflags
-
-        # Record and return the number of failures and tries.
-        self.__record_outcome(test, failures, tries)
-        return failures, tries
-
-    def __record_outcome(self, test, f, t):
-        """
-        Record the fact that the given DocTest (`test`) generated `f`
-        failures out of `t` tried examples.
-        """
-        f2, t2 = self._name2ft.get(test.name, (0,0))
-        self._name2ft[test.name] = (f+f2, t+t2)
-        self.failures += f
-        self.tries += t
-
-    __LINECACHE_FILENAME_RE = re.compile(r'[\w\.]+)'
-                                         r'\[(?P\d+)\]>$')
-    def __patched_linecache_getlines(self, filename, module_globals=None):
-        m = self.__LINECACHE_FILENAME_RE.match(filename)
-        if m and m.group('name') == self.test.name:
-            example = self.test.examples[int(m.group('examplenum'))]
-            return example.source.splitlines(True)
-        elif func_code(self.save_linecache_getlines).co_argcount > 1:
-            return self.save_linecache_getlines(filename, module_globals)
-        else:
-            return self.save_linecache_getlines(filename)
-
-    def run(self, test, compileflags=None, out=None, clear_globs=True):
-        """
-        Run the examples in `test`, and display the results using the
-        writer function `out`.
-
-        The examples are run in the namespace `test.globs`.  If
-        `clear_globs` is true (the default), then this namespace will
-        be cleared after the test runs, to help with garbage
-        collection.  If you would like to examine the namespace after
-        the test completes, then use `clear_globs=False`.
-
-        `compileflags` gives the set of flags that should be used by
-        the Python compiler when running the examples.  If not
-        specified, then it will default to the set of future-import
-        flags that apply to `globs`.
-
-        The output of each example is checked using
-        `DocTestRunner.check_output`, and the results are formatted by
-        the `DocTestRunner.report_*` methods.
-        """
-        self.test = test
-
-        if compileflags is None:
-            compileflags = _extract_future_flags(test.globs)
-
-        save_stdout = sys.stdout
-        if out is None:
-            out = save_stdout.write
-        sys.stdout = self._fakeout
-
-        # Patch pdb.set_trace to restore sys.stdout during interactive
-        # debugging (so it's not still redirected to self._fakeout).
-        # Note that the interactive output will go to *our*
-        # save_stdout, even if that's not the real sys.stdout; this
-        # allows us to write test cases for the set_trace behavior.
-        save_set_trace = pdb.set_trace
-        self.debugger = _OutputRedirectingPdb(save_stdout)
-        self.debugger.reset()
-        pdb.set_trace = self.debugger.set_trace
-
-        # Patch linecache.getlines, so we can see the example's source
-        # when we're inside the debugger.
-        self.save_linecache_getlines = linecache.getlines
-        linecache.getlines = self.__patched_linecache_getlines
-
-        try:
-            return self.__run(test, compileflags, out)
-        finally:
-            sys.stdout = save_stdout
-            pdb.set_trace = save_set_trace
-            linecache.getlines = self.save_linecache_getlines
-            if clear_globs:
-                test.globs.clear()
-
-    #/////////////////////////////////////////////////////////////////
-    # Summarization
-    #/////////////////////////////////////////////////////////////////
-    def summarize(self, verbose=None):
-        """
-        Print a summary of all the test cases that have been run by
-        this DocTestRunner, and return a tuple `(f, t)`, where `f` is
-        the total number of failed examples, and `t` is the total
-        number of tried examples.
-
-        The optional `verbose` argument controls how detailed the
-        summary is.  If the verbosity is not specified, then the
-        DocTestRunner's verbosity is used.
-        """
-        if verbose is None:
-            verbose = self._verbose
-        notests = []
-        passed = []
-        failed = []
-        totalt = totalf = 0
-        for x in self._name2ft.items():
-            name, (f, t) = x
-            assert f <= t
-            totalt += t
-            totalf += f
-            if t == 0:
-                notests.append(name)
-            elif f == 0:
-                passed.append( (name, t) )
-            else:
-                failed.append(x)
-        if verbose:
-            if notests:
-                print(len(notests), "items had no tests:")
-                notests.sort()
-                for thing in notests:
-                    print("   ", thing)
-            if passed:
-                print(len(passed), "items passed all tests:")
-                passed.sort()
-                for thing, count in passed:
-                    print(" %3d tests in %s" % (count, thing))
-        if failed:
-            print(self.DIVIDER)
-            print(len(failed), "items had failures:")
-            failed.sort()
-            for thing, (f, t) in failed:
-                print(" %3d of %3d in %s" % (f, t, thing))
-        if verbose:
-            print(totalt, "tests in", len(self._name2ft), "items.")
-            print(totalt - totalf, "passed and", totalf, "failed.")
-        if totalf:
-            print("***Test Failed***", totalf, "failures.")
-        elif verbose:
-            print("Test passed.")
-        return totalf, totalt
-
-    #/////////////////////////////////////////////////////////////////
-    # Backward compatibility cruft to maintain doctest.master.
-    #/////////////////////////////////////////////////////////////////
-    def merge(self, other):
-        d = self._name2ft
-        for name, (f, t) in other._name2ft.items():
-            if name in d:
-                print("*** DocTestRunner.merge: '" + name + "' in both" \
-                    " testers; summing outcomes.")
-                f2, t2 = d[name]
-                f = f + f2
-                t = t + t2
-            d[name] = f, t
-
-class OutputChecker:
-    """
-    A class used to check the whether the actual output from a doctest
-    example matches the expected output.  `OutputChecker` defines two
-    methods: `check_output`, which compares a given pair of outputs,
-    and returns true if they match; and `output_difference`, which
-    returns a string describing the differences between two outputs.
-    """
-    def check_output(self, want, got, optionflags):
-        """
-        Return True iff the actual output from an example (`got`)
-        matches the expected output (`want`).  These strings are
-        always considered to match if they are identical; but
-        depending on what option flags the test runner is using,
-        several non-exact match types are also possible.  See the
-        documentation for `TestRunner` for more information about
-        option flags.
-        """
-        # Handle the common case first, for efficiency:
-        # if they're string-identical, always return true.
-        if got == want:
-            return True
-
-        # The values True and False replaced 1 and 0 as the return
-        # value for boolean comparisons in Python 2.3.
-        if not (optionflags & DONT_ACCEPT_TRUE_FOR_1):
-            if (got,want) == ("True\n", "1\n"):
-                return True
-            if (got,want) == ("False\n", "0\n"):
-                return True
-
-        #  can be used as a special sequence to signify a
-        # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used.
-        if not (optionflags & DONT_ACCEPT_BLANKLINE):
-            # Replace  in want with a blank line.
-            want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER),
-                          '', want)
-            # If a line in got contains only spaces, then remove the
-            # spaces.
-            got = re.sub('(?m)^\s*?$', '', got)
-            if got == want:
-                return True
-
-        # This flag causes doctest to ignore any differences in the
-        # contents of whitespace strings.  Note that this can be used
-        # in conjunction with the ELLIPSIS flag.
-        if optionflags & NORMALIZE_WHITESPACE:
-            got = ' '.join(got.split())
-            want = ' '.join(want.split())
-            if got == want:
-                return True
-
-        # The ELLIPSIS flag says to let the sequence "..." in `want`
-        # match any substring in `got`.
-        if optionflags & ELLIPSIS:
-            if _ellipsis_match(want, got):
-                return True
-
-        # We didn't find any match; return false.
-        return False
-
-    # Should we do a fancy diff?
-    def _do_a_fancy_diff(self, want, got, optionflags):
-        # Not unless they asked for a fancy diff.
-        if not optionflags & (REPORT_UDIFF |
-                              REPORT_CDIFF |
-                              REPORT_NDIFF):
-            return False
-
-        # If expected output uses ellipsis, a meaningful fancy diff is
-        # too hard ... or maybe not.  In two real-life failures Tim saw,
-        # a diff was a major help anyway, so this is commented out.
-        # [todo] _ellipsis_match() knows which pieces do and don't match,
-        # and could be the basis for a kick-ass diff in this case.
-        ##if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want:
-        ##    return False
-
-        # ndiff does intraline difference marking, so can be useful even
-        # for 1-line differences.
-        if optionflags & REPORT_NDIFF:
-            return True
-
-        # The other diff types need at least a few lines to be helpful.
-        return want.count('\n') > 2 and got.count('\n') > 2
-
-    def output_difference(self, example, got, optionflags):
-        """
-        Return a string describing the differences between the
-        expected output for a given example (`example`) and the actual
-        output (`got`).  `optionflags` is the set of option flags used
-        to compare `want` and `got`.
-        """
-        want = example.want
-        # If s are being used, then replace blank lines
-        # with  in the actual output string.
-        if not (optionflags & DONT_ACCEPT_BLANKLINE):
-            got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got)
-
-        # Check if we should use diff.
-        if self._do_a_fancy_diff(want, got, optionflags):
-            # Split want & got into lines.
-            want_lines = want.splitlines(True)  # True == keep line ends
-            got_lines = got.splitlines(True)
-            # Use difflib to find their differences.
-            if optionflags & REPORT_UDIFF:
-                diff = difflib.unified_diff(want_lines, got_lines, n=2)
-                diff = list(diff)[2:] # strip the diff header
-                kind = 'unified diff with -expected +actual'
-            elif optionflags & REPORT_CDIFF:
-                diff = difflib.context_diff(want_lines, got_lines, n=2)
-                diff = list(diff)[2:] # strip the diff header
-                kind = 'context diff with expected followed by actual'
-            elif optionflags & REPORT_NDIFF:
-                engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
-                diff = list(engine.compare(want_lines, got_lines))
-                kind = 'ndiff with -expected +actual'
-            else:
-                assert 0, 'Bad diff option'
-            # Remove trailing whitespace on diff output.
-            diff = [line.rstrip() + '\n' for line in diff]
-            return 'Differences (%s):\n' % kind + _indent(''.join(diff))
-
-        # If we're not using diff, then simply list the expected
-        # output followed by the actual output.
-        if want and got:
-            return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got))
-        elif want:
-            return 'Expected:\n%sGot nothing\n' % _indent(want)
-        elif got:
-            return 'Expected nothing\nGot:\n%s' % _indent(got)
-        else:
-            return 'Expected nothing\nGot nothing\n'
-
-class DocTestFailure(Exception):
-    """A DocTest example has failed in debugging mode.
-
-    The exception instance has variables:
-
-    - test: the DocTest object being run
-
-    - excample: the Example object that failed
-
-    - got: the actual output
-    """
-    def __init__(self, test, example, got):
-        self.test = test
-        self.example = example
-        self.got = got
-
-    def __str__(self):
-        return str(self.test)
-
-class UnexpectedException(Exception):
-    """A DocTest example has encountered an unexpected exception
-
-    The exception instance has variables:
-
-    - test: the DocTest object being run
-
-    - excample: the Example object that failed
-
-    - exc_info: the exception info
-    """
-    def __init__(self, test, example, exc_info):
-        self.test = test
-        self.example = example
-        self.exc_info = exc_info
-
-    def __str__(self):
-        return str(self.test)
-
-class DebugRunner(DocTestRunner):
-    r"""Run doc tests but raise an exception as soon as there is a failure.
-
-       If an unexpected exception occurs, an UnexpectedException is raised.
-       It contains the test, the example, and the original exception:
-
-         >>> runner = DebugRunner(verbose=False)
-         >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42',
-         ...                                    {}, 'foo', 'foo.py', 0)
-         >>> try:
-         ...     runner.run(test)
-         ... except UnexpectedException, failure:
-         ...     pass
-
-         >>> failure.test is test
-         True
-
-         >>> failure.example.want
-         '42\n'
-
-         >>> exc_info = failure.exc_info
-         >>> raise exc_info[0], exc_info[1], exc_info[2]
-         Traceback (most recent call last):
-         ...
-         KeyError
-
-       We wrap the original exception to give the calling application
-       access to the test and example information.
-
-       If the output doesn't match, then a DocTestFailure is raised:
-
-         >>> test = DocTestParser().get_doctest('''
-         ...      >>> x = 1
-         ...      >>> x
-         ...      2
-         ...      ''', {}, 'foo', 'foo.py', 0)
-
-         >>> try:
-         ...    runner.run(test)
-         ... except DocTestFailure, failure:
-         ...    pass
-
-       DocTestFailure objects provide access to the test:
-
-         >>> failure.test is test
-         True
-
-       As well as to the example:
-
-         >>> failure.example.want
-         '2\n'
-
-       and the actual output:
-
-         >>> failure.got
-         '1\n'
-
-       If a failure or error occurs, the globals are left intact:
-
-         >>> del test.globs['__builtins__']
-         >>> test.globs
-         {'x': 1}
-
-         >>> test = DocTestParser().get_doctest('''
-         ...      >>> x = 2
-         ...      >>> raise KeyError
-         ...      ''', {}, 'foo', 'foo.py', 0)
-
-         >>> runner.run(test)
-         Traceback (most recent call last):
-         ...
-         UnexpectedException: 
-
-         >>> del test.globs['__builtins__']
-         >>> test.globs
-         {'x': 2}
-
-       But the globals are cleared if there is no error:
-
-         >>> test = DocTestParser().get_doctest('''
-         ...      >>> x = 2
-         ...      ''', {}, 'foo', 'foo.py', 0)
-
-         >>> runner.run(test)
-         (0, 1)
-
-         >>> test.globs
-         {}
-
-       """
-
-    def run(self, test, compileflags=None, out=None, clear_globs=True):
-        r = DocTestRunner.run(self, test, compileflags, out, False)
-        if clear_globs:
-            test.globs.clear()
-        return r
-
-    def report_unexpected_exception(self, out, test, example, exc_info):
-        raise UnexpectedException(test, example, exc_info)
-
-    def report_failure(self, out, test, example, got):
-        raise DocTestFailure(test, example, got)
-
-######################################################################
-## 6. Test Functions
-######################################################################
-# These should be backwards compatible.
-
-# For backward compatibility, a global instance of a DocTestRunner
-# class, updated by testmod.
-master = None
-
-def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
-            report=True, optionflags=0, extraglobs=None,
-            raise_on_error=False, exclude_empty=False):
-    """m=None, name=None, globs=None, verbose=None, isprivate=None,
-       report=True, optionflags=0, extraglobs=None, raise_on_error=False,
-       exclude_empty=False
-
-    Test examples in docstrings in functions and classes reachable
-    from module m (or the current module if m is not supplied), starting
-    with m.__doc__.  Unless isprivate is specified, private names
-    are not skipped.
-
-    Also test examples reachable from dict m.__test__ if it exists and is
-    not None.  m.__test__ maps names to functions, classes and strings;
-    function and class docstrings are tested even if the name is private;
-    strings are tested directly, as if they were docstrings.
-
-    Return (#failures, #tests).
-
-    See doctest.__doc__ for an overview.
-
-    Optional keyword arg "name" gives the name of the module; by default
-    use m.__name__.
-
-    Optional keyword arg "globs" gives a dict to be used as the globals
-    when executing examples; by default, use m.__dict__.  A copy of this
-    dict is actually used for each docstring, so that each docstring's
-    examples start with a clean slate.
-
-    Optional keyword arg "extraglobs" gives a dictionary that should be
-    merged into the globals that are used to execute examples.  By
-    default, no extra globals are used.  This is new in 2.4.
-
-    Optional keyword arg "verbose" prints lots of stuff if true, prints
-    only failures if false; by default, it's true iff "-v" is in sys.argv.
-
-    Optional keyword arg "report" prints a summary at the end when true,
-    else prints nothing at the end.  In verbose mode, the summary is
-    detailed, else very brief (in fact, empty if all tests passed).
-
-    Optional keyword arg "optionflags" or's together module constants,
-    and defaults to 0.  This is new in 2.3.  Possible values (see the
-    docs for details):
-
-        DONT_ACCEPT_TRUE_FOR_1
-        DONT_ACCEPT_BLANKLINE
-        NORMALIZE_WHITESPACE
-        ELLIPSIS
-        IGNORE_EXCEPTION_DETAIL
-        REPORT_UDIFF
-        REPORT_CDIFF
-        REPORT_NDIFF
-        REPORT_ONLY_FIRST_FAILURE
-
-    Optional keyword arg "raise_on_error" raises an exception on the
-    first unexpected exception or failure. This allows failures to be
-    post-mortem debugged.
-
-    Deprecated in Python 2.4:
-    Optional keyword arg "isprivate" specifies a function used to
-    determine whether a name is private.  The default function is
-    treat all functions as public.  Optionally, "isprivate" can be
-    set to doctest.is_private to skip over functions marked as private
-    using the underscore naming convention; see its docs for details.
-
-    Advanced tomfoolery:  testmod runs methods of a local instance of
-    class doctest.Tester, then merges the results into (or creates)
-    global Tester instance doctest.master.  Methods of doctest.master
-    can be called directly too, if you want to do something unusual.
-    Passing report=0 to testmod is especially useful then, to delay
-    displaying a summary.  Invoke doctest.master.summarize(verbose)
-    when you're done fiddling.
-    """
-    global master
-
-    if isprivate is not None:
-        warnings.warn("the isprivate argument is deprecated; "
-                      "examine DocTestFinder.find() lists instead",
-                      DeprecationWarning)
-
-    # If no module was given, then use __main__.
-    if m is None:
-        # DWA - m will still be None if this wasn't invoked from the command
-        # line, in which case the following TypeError is about as good an error
-        # as we should expect
-        m = sys.modules.get('__main__')
-
-    # Check that we were actually given a module.
-    if not inspect.ismodule(m):
-        raise TypeError("testmod: module required; %r" % (m,))
-
-    # If no name was given, then use the module's name.
-    if name is None:
-        name = m.__name__
-
-    # Find, parse, and run all tests in the given module.
-    finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty)
-
-    if raise_on_error:
-        runner = DebugRunner(verbose=verbose, optionflags=optionflags)
-    else:
-        runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
-
-    for test in finder.find(m, name, globs=globs, extraglobs=extraglobs):
-        runner.run(test)
-
-    if report:
-        runner.summarize()
-
-    if master is None:
-        master = runner
-    else:
-        master.merge(runner)
-
-    return runner.failures, runner.tries
-
-def testfile(filename, module_relative=True, name=None, package=None,
-             globs=None, verbose=None, report=True, optionflags=0,
-             extraglobs=None, raise_on_error=False, parser=DocTestParser()):
-    """
-    Test examples in the given file.  Return (#failures, #tests).
-
-    Optional keyword arg "module_relative" specifies how filenames
-    should be interpreted:
-
-      - If "module_relative" is True (the default), then "filename"
-         specifies a module-relative path.  By default, this path is
-         relative to the calling module's directory; but if the
-         "package" argument is specified, then it is relative to that
-         package.  To ensure os-independence, "filename" should use
-         "/" characters to separate path segments, and should not
-         be an absolute path (i.e., it may not begin with "/").
-
-      - If "module_relative" is False, then "filename" specifies an
-        os-specific path.  The path may be absolute or relative (to
-        the current working directory).
-
-    Optional keyword arg "name" gives the name of the test; by default
-    use the file's basename.
-
-    Optional keyword argument "package" is a Python package or the
-    name of a Python package whose directory should be used as the
-    base directory for a module relative filename.  If no package is
-    specified, then the calling module's directory is used as the base
-    directory for module relative filenames.  It is an error to
-    specify "package" if "module_relative" is False.
-
-    Optional keyword arg "globs" gives a dict to be used as the globals
-    when executing examples; by default, use {}.  A copy of this dict
-    is actually used for each docstring, so that each docstring's
-    examples start with a clean slate.
-
-    Optional keyword arg "extraglobs" gives a dictionary that should be
-    merged into the globals that are used to execute examples.  By
-    default, no extra globals are used.
-
-    Optional keyword arg "verbose" prints lots of stuff if true, prints
-    only failures if false; by default, it's true iff "-v" is in sys.argv.
-
-    Optional keyword arg "report" prints a summary at the end when true,
-    else prints nothing at the end.  In verbose mode, the summary is
-    detailed, else very brief (in fact, empty if all tests passed).
-
-    Optional keyword arg "optionflags" or's together module constants,
-    and defaults to 0.  Possible values (see the docs for details):
-
-        DONT_ACCEPT_TRUE_FOR_1
-        DONT_ACCEPT_BLANKLINE
-        NORMALIZE_WHITESPACE
-        ELLIPSIS
-        IGNORE_EXCEPTION_DETAIL
-        REPORT_UDIFF
-        REPORT_CDIFF
-        REPORT_NDIFF
-        REPORT_ONLY_FIRST_FAILURE
-
-    Optional keyword arg "raise_on_error" raises an exception on the
-    first unexpected exception or failure. This allows failures to be
-    post-mortem debugged.
-
-    Optional keyword arg "parser" specifies a DocTestParser (or
-    subclass) that should be used to extract tests from the files.
-
-    Advanced tomfoolery:  testmod runs methods of a local instance of
-    class doctest.Tester, then merges the results into (or creates)
-    global Tester instance doctest.master.  Methods of doctest.master
-    can be called directly too, if you want to do something unusual.
-    Passing report=0 to testmod is especially useful then, to delay
-    displaying a summary.  Invoke doctest.master.summarize(verbose)
-    when you're done fiddling.
-    """
-    global master
-
-    if package and not module_relative:
-        raise ValueError("Package may only be specified for module-"
-                         "relative paths.")
-
-    # Relativize the path
-    if module_relative:
-        package = _normalize_module(package)
-        filename = _module_relative_path(package, filename)
-
-    # If no name was given, then use the file's name.
-    if name is None:
-        name = os.path.basename(filename)
-
-    # Assemble the globals.
-    if globs is None:
-        globs = {}
-    else:
-        globs = globs.copy()
-    if extraglobs is not None:
-        globs.update(extraglobs)
-
-    if raise_on_error:
-        runner = DebugRunner(verbose=verbose, optionflags=optionflags)
-    else:
-        runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
-
-    # Read the file, convert it to a test, and run it.
-    f = open(filename)
-    s = f.read()
-    f.close()
-    test = parser.get_doctest(s, globs, name, filename, 0)
-    runner.run(test)
-
-    if report:
-        runner.summarize()
-
-    if master is None:
-        master = runner
-    else:
-        master.merge(runner)
-
-    return runner.failures, runner.tries
-
-def run_docstring_examples(f, globs, verbose=False, name="NoName",
-                           compileflags=None, optionflags=0):
-    """
-    Test examples in the given object's docstring (`f`), using `globs`
-    as globals.  Optional argument `name` is used in failure messages.
-    If the optional argument `verbose` is true, then generate output
-    even if there are no failures.
-
-    `compileflags` gives the set of flags that should be used by the
-    Python compiler when running the examples.  If not specified, then
-    it will default to the set of future-import flags that apply to
-    `globs`.
-
-    Optional keyword arg `optionflags` specifies options for the
-    testing and output.  See the documentation for `testmod` for more
-    information.
-    """
-    # Find, parse, and run all tests in the given module.
-    finder = DocTestFinder(verbose=verbose, recurse=False)
-    runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
-    for test in finder.find(f, name, globs=globs):
-        runner.run(test, compileflags=compileflags)
-
-######################################################################
-## 7. Tester
-######################################################################
-# This is provided only for backwards compatibility.  It's not
-# actually used in any way.
-
-class Tester:
-    def __init__(self, mod=None, globs=None, verbose=None,
-                 isprivate=None, optionflags=0):
-
-        warnings.warn("class Tester is deprecated; "
-                      "use class doctest.DocTestRunner instead",
-                      DeprecationWarning, stacklevel=2)
-        if mod is None and globs is None:
-            raise TypeError("Tester.__init__: must specify mod or globs")
-        if mod is not None and not inspect.ismodule(mod):
-            raise TypeError("Tester.__init__: mod must be a module; %r" %
-                            (mod,))
-        if globs is None:
-            globs = mod.__dict__
-        self.globs = globs
-
-        self.verbose = verbose
-        self.isprivate = isprivate
-        self.optionflags = optionflags
-        self.testfinder = DocTestFinder(_namefilter=isprivate)
-        self.testrunner = DocTestRunner(verbose=verbose,
-                                        optionflags=optionflags)
-
-    def runstring(self, s, name):
-        test = DocTestParser().get_doctest(s, self.globs, name, None, None)
-        if self.verbose:
-            print("Running string", name)
-        (f,t) = self.testrunner.run(test)
-        if self.verbose:
-            print(f, "of", t, "examples failed in string", name)
-        return (f,t)
-
-    def rundoc(self, object, name=None, module=None):
-        f = t = 0
-        tests = self.testfinder.find(object, name, module=module,
-                                     globs=self.globs)
-        for test in tests:
-            (f2, t2) = self.testrunner.run(test)
-            (f,t) = (f+f2, t+t2)
-        return (f,t)
-
-    def rundict(self, d, name, module=None):
-        import types
-        m = types.ModuleType(name)
-        m.__dict__.update(d)
-        if module is None:
-            module = False
-        return self.rundoc(m, name, module)
-
-    def run__test__(self, d, name):
-        import types
-        m = types.ModuleType(name)
-        m.__test__ = d
-        return self.rundoc(m, name)
-
-    def summarize(self, verbose=None):
-        return self.testrunner.summarize(verbose)
-
-    def merge(self, other):
-        self.testrunner.merge(other.testrunner)
-
-######################################################################
-## 8. Unittest Support
-######################################################################
-
-_unittest_reportflags = 0
-
-def set_unittest_reportflags(flags):
-    """Sets the unittest option flags.
-
-    The old flag is returned so that a runner could restore the old
-    value if it wished to:
-
-      >>> old = _unittest_reportflags
-      >>> set_unittest_reportflags(REPORT_NDIFF |
-      ...                          REPORT_ONLY_FIRST_FAILURE) == old
-      True
-
-      >>> import doctest
-      >>> doctest._unittest_reportflags == (REPORT_NDIFF |
-      ...                                   REPORT_ONLY_FIRST_FAILURE)
-      True
-
-    Only reporting flags can be set:
-
-      >>> set_unittest_reportflags(ELLIPSIS)
-      Traceback (most recent call last):
-      ...
-      ValueError: ('Only reporting flags allowed', 8)
-
-      >>> set_unittest_reportflags(old) == (REPORT_NDIFF |
-      ...                                   REPORT_ONLY_FIRST_FAILURE)
-      True
-    """
-    global _unittest_reportflags
-
-    if (flags & REPORTING_FLAGS) != flags:
-        raise ValueError("Only reporting flags allowed", flags)
-    old = _unittest_reportflags
-    _unittest_reportflags = flags
-    return old
-
-
-class DocTestCase(unittest.TestCase):
-
-    def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
-                 checker=None):
-
-        unittest.TestCase.__init__(self)
-        self._dt_optionflags = optionflags
-        self._dt_checker = checker
-        self._dt_test = test
-        self._dt_setUp = setUp
-        self._dt_tearDown = tearDown
-
-    def setUp(self):
-        test = self._dt_test
-
-        if self._dt_setUp is not None:
-            self._dt_setUp(test)
-
-    def tearDown(self):
-        test = self._dt_test
-
-        if self._dt_tearDown is not None:
-            self._dt_tearDown(test)
-
-        test.globs.clear()
-
-    def runTest(self):
-        test = self._dt_test
-        old = sys.stdout
-        new = StringIO()
-        optionflags = self._dt_optionflags
-
-        if not (optionflags & REPORTING_FLAGS):
-            # The option flags don't include any reporting flags,
-            # so add the default reporting flags
-            optionflags |= _unittest_reportflags
-
-        runner = DocTestRunner(optionflags=optionflags,
-                               checker=self._dt_checker, verbose=False)
-
-        try:
-            runner.DIVIDER = "-"*70
-            failures, tries = runner.run(
-                test, out=new.write, clear_globs=False)
-        finally:
-            sys.stdout = old
-
-        if failures:
-            raise self.failureException(self.format_failure(new.getvalue()))
-
-    def format_failure(self, err):
-        test = self._dt_test
-        if test.lineno is None:
-            lineno = 'unknown line number'
-        else:
-            lineno = '%s' % test.lineno
-        lname = '.'.join(test.name.split('.')[-1:])
-        return ('Failed doctest test for %s\n'
-                '  File "%s", line %s, in %s\n\n%s'
-                % (test.name, test.filename, lineno, lname, err)
-                )
-
-    def debug(self):
-        r"""Run the test case without results and without catching exceptions
-
-           The unit test framework includes a debug method on test cases
-           and test suites to support post-mortem debugging.  The test code
-           is run in such a way that errors are not caught.  This way a
-           caller can catch the errors and initiate post-mortem debugging.
-
-           The DocTestCase provides a debug method that raises
-           UnexpectedException errors if there is an unexepcted
-           exception:
-
-             >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42',
-             ...                {}, 'foo', 'foo.py', 0)
-             >>> case = DocTestCase(test)
-             >>> try:
-             ...     case.debug()
-             ... except UnexpectedException, failure:
-             ...     pass
-
-           The UnexpectedException contains the test, the example, and
-           the original exception:
-
-             >>> failure.test is test
-             True
-
-             >>> failure.example.want
-             '42\n'
-
-             >>> exc_info = failure.exc_info
-             >>> raise exc_info[0], exc_info[1], exc_info[2]
-             Traceback (most recent call last):
-             ...
-             KeyError
-
-           If the output doesn't match, then a DocTestFailure is raised:
-
-             >>> test = DocTestParser().get_doctest('''
-             ...      >>> x = 1
-             ...      >>> x
-             ...      2
-             ...      ''', {}, 'foo', 'foo.py', 0)
-             >>> case = DocTestCase(test)
-
-             >>> try:
-             ...    case.debug()
-             ... except DocTestFailure, failure:
-             ...    pass
-
-           DocTestFailure objects provide access to the test:
-
-             >>> failure.test is test
-             True
-
-           As well as to the example:
-
-             >>> failure.example.want
-             '2\n'
-
-           and the actual output:
-
-             >>> failure.got
-             '1\n'
-
-           """
-
-        self.setUp()
-        runner = DebugRunner(optionflags=self._dt_optionflags,
-                             checker=self._dt_checker, verbose=False)
-        runner.run(self._dt_test)
-        self.tearDown()
-
-    def id(self):
-        return self._dt_test.name
-
-    def __repr__(self):
-        name = self._dt_test.name.split('.')
-        return "%s (%s)" % (name[-1], '.'.join(name[:-1]))
-
-    __str__ = __repr__
-
-    def shortDescription(self):
-        return "Doctest: " + self._dt_test.name
-
-def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None,
-                 **options):
-    """
-    Convert doctest tests for a module to a unittest test suite.
-
-    This converts each documentation string in a module that
-    contains doctest tests to a unittest test case.  If any of the
-    tests in a doc string fail, then the test case fails.  An exception
-    is raised showing the name of the file containing the test and a
-    (sometimes approximate) line number.
-
-    The `module` argument provides the module to be tested.  The argument
-    can be either a module or a module name.
-
-    If no argument is given, the calling module is used.
-
-    A number of options may be provided as keyword arguments:
-
-    setUp
-      A set-up function.  This is called before running the
-      tests in each file. The setUp function will be passed a DocTest
-      object.  The setUp function can access the test globals as the
-      globs attribute of the test passed.
-
-    tearDown
-      A tear-down function.  This is called after running the
-      tests in each file.  The tearDown function will be passed a DocTest
-      object.  The tearDown function can access the test globals as the
-      globs attribute of the test passed.
-
-    globs
-      A dictionary containing initial global variables for the tests.
-
-    optionflags
-       A set of doctest option flags expressed as an integer.
-    """
-
-    if test_finder is None:
-        test_finder = DocTestFinder()
-
-    module = _normalize_module(module)
-    tests = test_finder.find(module, globs=globs, extraglobs=extraglobs)
-    if globs is None:
-        globs = module.__dict__
-    if not tests:
-        # Why do we want to do this? Because it reveals a bug that might
-        # otherwise be hidden.
-        raise ValueError(module, "has no tests")
-
-    tests.sort()
-    suite = unittest.TestSuite()
-    for test in tests:
-        if len(test.examples) == 0:
-            continue
-        if not test.filename:
-            filename = module.__file__
-            if filename[-4:] in (".pyc", ".pyo"):
-                filename = filename[:-1]
-            test.filename = filename
-        suite.addTest(DocTestCase(test, **options))
-
-    return suite
-
-class DocFileCase(DocTestCase):
-
-    def id(self):
-        return '_'.join(self._dt_test.name.split('.'))
-
-    def __repr__(self):
-        return self._dt_test.filename
-    __str__ = __repr__
-
-    def format_failure(self, err):
-        return ('Failed doctest test for %s\n  File "%s", line 0\n\n%s'
-                % (self._dt_test.name, self._dt_test.filename, err)
-                )
-
-def DocFileTest(path, module_relative=True, package=None,
-                globs=None, parser=DocTestParser(), **options):
-    if globs is None:
-        globs = {}
-
-    if package and not module_relative:
-        raise ValueError("Package may only be specified for module-"
-                         "relative paths.")
-
-    # Relativize the path.
-    if module_relative:
-        package = _normalize_module(package)
-        path = _module_relative_path(package, path)
-
-    # Find the file and read it.
-    name = os.path.basename(path)
-    f = open(path)
-    doc = f.read()
-    f.close()
-
-    # Convert it to a test, and wrap it in a DocFileCase.
-    test = parser.get_doctest(doc, globs, name, path, 0)
-    return DocFileCase(test, **options)
-
-def DocFileSuite(*paths, **kw):
-    """A unittest suite for one or more doctest files.
-
-    The path to each doctest file is given as a string; the
-    interpretation of that string depends on the keyword argument
-    "module_relative".
-
-    A number of options may be provided as keyword arguments:
-
-    module_relative
-      If "module_relative" is True, then the given file paths are
-      interpreted as os-independent module-relative paths.  By
-      default, these paths are relative to the calling module's
-      directory; but if the "package" argument is specified, then
-      they are relative to that package.  To ensure os-independence,
-      "filename" should use "/" characters to separate path
-      segments, and may not be an absolute path (i.e., it may not
-      begin with "/").
-
-      If "module_relative" is False, then the given file paths are
-      interpreted as os-specific paths.  These paths may be absolute
-      or relative (to the current working directory).
-
-    package
-      A Python package or the name of a Python package whose directory
-      should be used as the base directory for module relative paths.
-      If "package" is not specified, then the calling module's
-      directory is used as the base directory for module relative
-      filenames.  It is an error to specify "package" if
-      "module_relative" is False.
-
-    setUp
-      A set-up function.  This is called before running the
-      tests in each file. The setUp function will be passed a DocTest
-      object.  The setUp function can access the test globals as the
-      globs attribute of the test passed.
-
-    tearDown
-      A tear-down function.  This is called after running the
-      tests in each file.  The tearDown function will be passed a DocTest
-      object.  The tearDown function can access the test globals as the
-      globs attribute of the test passed.
-
-    globs
-      A dictionary containing initial global variables for the tests.
-
-    optionflags
-      A set of doctest option flags expressed as an integer.
-
-    parser
-      A DocTestParser (or subclass) that should be used to extract
-      tests from the files.
-    """
-    suite = unittest.TestSuite()
-
-    # We do this here so that _normalize_module is called at the right
-    # level.  If it were called in DocFileTest, then this function
-    # would be the caller and we might guess the package incorrectly.
-    if kw.get('module_relative', True):
-        kw['package'] = _normalize_module(kw.get('package'))
-
-    for path in paths:
-        suite.addTest(DocFileTest(path, **kw))
-
-    return suite
-
-######################################################################
-## 9. Debugging Support
-######################################################################
-
-def script_from_examples(s):
-    r"""Extract script from text with examples.
-
-       Converts text with examples to a Python script.  Example input is
-       converted to regular code.  Example output and all other words
-       are converted to comments:
-
-       >>> text = '''
-       ...       Here are examples of simple math.
-       ...
-       ...           Python has super accurate integer addition
-       ...
-       ...           >>> 2 + 2
-       ...           5
-       ...
-       ...           And very friendly error messages:
-       ...
-       ...           >>> 1/0
-       ...           To Infinity
-       ...           And
-       ...           Beyond
-       ...
-       ...           You can use logic if you want:
-       ...
-       ...           >>> if 0:
-       ...           ...    blah
-       ...           ...    blah
-       ...           ...
-       ...
-       ...           Ho hum
-       ...           '''
-
-       >>> print script_from_examples(text)
-       # Here are examples of simple math.
-       #
-       #     Python has super accurate integer addition
-       #
-       2 + 2
-       # Expected:
-       ## 5
-       #
-       #     And very friendly error messages:
-       #
-       1/0
-       # Expected:
-       ## To Infinity
-       ## And
-       ## Beyond
-       #
-       #     You can use logic if you want:
-       #
-       if 0:
-          blah
-          blah
-       #
-       #     Ho hum
-       """
-    output = []
-    for piece in DocTestParser().parse(s):
-        if isinstance(piece, Example):
-            # Add the example's source code (strip trailing NL)
-            output.append(piece.source[:-1])
-            # Add the expected output:
-            want = piece.want
-            if want:
-                output.append('# Expected:')
-                output += ['## '+l for l in want.split('\n')[:-1]]
-        else:
-            # Add non-example text.
-            output += [_comment_line(l)
-                       for l in piece.split('\n')[:-1]]
-
-    # Trim junk on both ends.
-    while output and output[-1] == '#':
-        output.pop()
-    while output and output[0] == '#':
-        output.pop(0)
-    # Combine the output, and return it.
-    return '\n'.join(output)
-
-def testsource(module, name):
-    """Extract the test sources from a doctest docstring as a script.
-
-    Provide the module (or dotted name of the module) containing the
-    test to be debugged and the name (within the module) of the object
-    with the doc string with tests to be debugged.
-    """
-    module = _normalize_module(module)
-    tests = DocTestFinder().find(module)
-    test = [t for t in tests if t.name == name]
-    if not test:
-        raise ValueError(name, "not found in tests")
-    test = test[0]
-    testsrc = script_from_examples(test.docstring)
-    return testsrc
-
-def debug_src(src, pm=False, globs=None):
-    """Debug a single doctest docstring, in argument `src`'"""
-    testsrc = script_from_examples(src)
-    debug_script(testsrc, pm, globs)
-
-def debug_script(src, pm=False, globs=None):
-    "Debug a test script.  `src` is the script, as a string."
-    import pdb
-
-    # Note that tempfile.NameTemporaryFile() cannot be used.  As the
-    # docs say, a file so created cannot be opened by name a second time
-    # on modern Windows boxes, and execfile() needs to open it.
-    srcfilename = tempfile.mktemp(".py", "doctestdebug")
-    f = open(srcfilename, 'w')
-    f.write(src)
-    f.close()
-
-    try:
-        if globs:
-            globs = globs.copy()
-        else:
-            globs = {}
-
-        if pm:
-            try:
-                execfile(srcfilename, globs, globs)
-            except:
-                print(sys.exc_info()[1])
-                pdb.post_mortem(sys.exc_info()[2])
-        else:
-            # Note that %r is vital here.  '%s' instead can, e.g., cause
-            # backslashes to get treated as metacharacters on Windows.
-            pdb.run("execfile(%r)" % srcfilename, globs, globs)
-
-    finally:
-        os.remove(srcfilename)
-
-def debug(module, name, pm=False):
-    """Debug a single doctest docstring.
-
-    Provide the module (or dotted name of the module) containing the
-    test to be debugged and the name (within the module) of the object
-    with the docstring with tests to be debugged.
-    """
-    module = _normalize_module(module)
-    testsrc = testsource(module, name)
-    debug_script(testsrc, pm, module.__dict__)
-
-######################################################################
-## 10. Example Usage
-######################################################################
-class _TestClass:
-    """
-    A pointless class, for sanity-checking of docstring testing.
-
-    Methods:
-        square()
-        get()
-
-    >>> _TestClass(13).get() + _TestClass(-12).get()
-    1
-    >>> hex(_TestClass(13).square().get())
-    '0xa9'
-    """
-
-    def __init__(self, val):
-        """val -> _TestClass object with associated value val.
-
-        >>> t = _TestClass(123)
-        >>> print t.get()
-        123
-        """
-
-        self.val = val
-
-    def square(self):
-        """square() -> square TestClass's associated value
-
-        >>> _TestClass(13).square().get()
-        169
-        """
-
-        self.val = self.val ** 2
-        return self
-
-    def get(self):
-        """get() -> return TestClass's associated value.
-
-        >>> x = _TestClass(-42)
-        >>> print x.get()
-        -42
-        """
-
-        return self.val
-
-__test__ = {"_TestClass": _TestClass,
-            "string": r"""
-                      Example of a string object, searched as-is.
-                      >>> x = 1; y = 2
-                      >>> x + y, x * y
-                      (3, 2)
-                      """,
-
-            "bool-int equivalence": r"""
-                                    In 2.2, boolean expressions displayed
-                                    0 or 1.  By default, we still accept
-                                    them.  This can be disabled by passing
-                                    DONT_ACCEPT_TRUE_FOR_1 to the new
-                                    optionflags argument.
-                                    >>> 4 == 4
-                                    1
-                                    >>> 4 == 4
-                                    True
-                                    >>> 4 > 4
-                                    0
-                                    >>> 4 > 4
-                                    False
-                                    """,
-
-            "blank lines": r"""
-                Blank lines can be marked with :
-                    >>> print 'foo\n\nbar\n'
-                    foo
-                    
-                    bar
-                    
-            """,
-
-            "ellipsis": r"""
-                If the ellipsis flag is used, then '...' can be used to
-                elide substrings in the desired output:
-                    >>> print range(1000) #doctest: +ELLIPSIS
-                    [0, 1, 2, ..., 999]
-            """,
-
-            "whitespace normalization": r"""
-                If the whitespace normalization flag is used, then
-                differences in whitespace are ignored.
-                    >>> print range(30) #doctest: +NORMALIZE_WHITESPACE
-                    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-                     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
-                     27, 28, 29]
-            """,
-           }
-
-def _test():
-    r = unittest.TextTestRunner()
-    r.run(DocTestSuite())
-
-if __name__ == "__main__":
-    _test()
-
diff -Nru python-setuptools-3.3/setuptools/tests/entries-v10 python-setuptools-20.1.1/setuptools/tests/entries-v10
--- python-setuptools-3.3/setuptools/tests/entries-v10	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/entries-v10	1970-01-01 00:00:00.000000000 +0000
@@ -1,615 +0,0 @@
-10
-
-dir
-89001
-http://svn.python.org/projects/sandbox/branches/setuptools-0.6
-http://svn.python.org/projects
-
-
-
-2013-06-03T17:26:03.052972Z
-89000
-phillip.eby
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-6015fed2-1504-0410-9fe1-9d1591cc4771
-
-api_tests.txt
-file
-
-
-
-
-2013-06-19T13:20:47.948712Z
-dec366372ca14fbeaeb26f492bcf5725
-2013-05-15T22:04:59.389374Z
-88997
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-12312
-
-setuptools.egg-info
-dir
-
-README.txt
-file
-
-
-
-
-2013-06-19T13:20:47.948712Z
-26f0dd5d095522ba3ad999b6b6777b92
-2011-05-31T20:10:56.416725Z
-88846
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-7615
-
-easy_install.py
-file
-
-
-
-
-2013-06-19T13:20:47.948712Z
-97b52fe7253bf4683f9f626f015eb72e
-2006-09-20T20:48:18.716070Z
-51935
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-126
-
-setuptools
-dir
-
-launcher.c
-file
-
-
-
-
-2013-06-19T13:20:47.924700Z
-e5a8e77de9022688b80f77fc6d742fee
-2009-10-19T21:03:29.785400Z
-75544
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-7476
-
-ez_setup.py
-file
-
-
-
-
-2013-06-19T13:20:47.924700Z
-17e8ec5e08faccfcb08b5f8d5167ca14
-2011-01-20T18:50:00.815420Z
-88124
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-8350
-
-version
-file
-
-
-
-
-2013-06-19T13:20:47.924700Z
-e456da09e0c9e224a56302f8316b6dbf
-2007-01-09T19:21:05.921317Z
-53317
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-1143
-
-setup.py
-file
-
-
-
-
-2013-06-19T13:20:47.924700Z
-d4e5b3c16bd61bfef6c0bb9377a3a3ea
-2013-05-15T22:04:59.389374Z
-88997
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-5228
-
-release.sh
-file
-
-
-
-
-2013-06-19T13:20:47.932704Z
-b1fd4054a1c107ff0f27baacd97be94c
-2009-10-28T17:12:45.227140Z
-75925
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-1044
-
-pkg_resources.txt
-file
-
-
-
-
-2013-06-19T13:20:47.928702Z
-f497e7c92a4de207cbd9ab1943f93388
-2009-10-12T20:00:02.336146Z
-75385
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-94518
-
-site.py
-file
-
-
-
-
-2013-06-19T13:20:47.932704Z
-ebaac6fb6525f77ca950d22e6f8315df
-2006-03-11T00:39:09.666740Z
-42965
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-2362
-
-version.dat
-file
-
-
-
-
-2013-06-19T13:20:47.932704Z
-8e14ecea32b9874cd7d29277494554c0
-2009-10-28T17:12:45.227140Z
-75925
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-80
-
-virtual-python.py
-file
-
-
-
-
-2013-06-19T13:20:47.932704Z
-aa857add3b5563238f0a904187f5ded9
-2005-10-17T02:26:39.000000Z
-41262
-pje
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-3898
-
-setup.cfg
-file
-
-
-
-
-2013-06-19T13:20:47.932704Z
-eda883e744fce83f8107ad8dc8303536
-2006-09-21T22:26:48.050256Z
-51965
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-296
-
-setuptools.txt
-file
-
-
-
-
-2013-06-19T13:20:47.940708Z
-11926256f06046b196eaf814772504e7
-2013-05-15T22:04:59.389374Z
-88997
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-149832
-
-pkg_resources.py
-file
-
-
-
-
-2013-06-19T13:20:47.940708Z
-b63a30f5f0f0225a788c2c0e3430b3cf
-2013-05-15T22:04:59.389374Z
-88997
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-90397
-
-tests
-dir
-
-wikiup.cfg
-file
-
-
-
-
-2013-06-19T13:20:47.944710Z
-34ad845a5e0a0b46458557fa910bf429
-2008-08-21T17:23:50.797633Z
-65935
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-136
-
-EasyInstall.txt
-file
-
-
-
-
-2013-06-19T13:20:47.944710Z
-e97387c517f70fc18a377e42d19d64d4
-2013-05-15T22:04:59.389374Z
-88997
-phillip.eby
-has-props
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-82495
-
diff -Nru python-setuptools-3.3/setuptools/tests/environment.py python-setuptools-20.1.1/setuptools/tests/environment.py
--- python-setuptools-3.3/setuptools/tests/environment.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/environment.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,119 +1,10 @@
 import os
-import zipfile
 import sys
-import tempfile
-import unittest
-import shutil
-import stat
 import unicodedata
 
 from subprocess import Popen as _Popen, PIPE as _PIPE
 
 
-def _extract(self, member, path=None, pwd=None):
-    """for zipfile py2.5 borrowed from cpython"""
-    if not isinstance(member, zipfile.ZipInfo):
-        member = self.getinfo(member)
-
-    if path is None:
-        path = os.getcwd()
-
-    return _extract_member(self, member, path, pwd)
-
-
-def _extract_from_zip(self, name, dest_path):
-    dest_file = open(dest_path, 'wb')
-    try:
-        dest_file.write(self.read(name))
-    finally:
-        dest_file.close()
-
-
-def _extract_member(self, member, targetpath, pwd):
-    """for zipfile py2.5 borrowed from cpython"""
-    # build the destination pathname, replacing
-    # forward slashes to platform specific separators.
-    # Strip trailing path separator, unless it represents the root.
-    if (targetpath[-1:] in (os.path.sep, os.path.altsep)
-            and len(os.path.splitdrive(targetpath)[1]) > 1):
-        targetpath = targetpath[:-1]
-
-    # don't include leading "/" from file name if present
-    if member.filename[0] == '/':
-        targetpath = os.path.join(targetpath, member.filename[1:])
-    else:
-        targetpath = os.path.join(targetpath, member.filename)
-
-    targetpath = os.path.normpath(targetpath)
-
-    # Create all upper directories if necessary.
-    upperdirs = os.path.dirname(targetpath)
-    if upperdirs and not os.path.exists(upperdirs):
-        os.makedirs(upperdirs)
-
-    if member.filename[-1] == '/':
-        if not os.path.isdir(targetpath):
-            os.mkdir(targetpath)
-        return targetpath
-
-    _extract_from_zip(self, member.filename, targetpath)
-
-    return targetpath
-
-
-def _remove_dir(target):
-
-    #on windows this seems to a problem
-    for dir_path, dirs, files in os.walk(target):
-        os.chmod(dir_path, stat.S_IWRITE)
-        for filename in files:
-            os.chmod(os.path.join(dir_path, filename), stat.S_IWRITE)
-    shutil.rmtree(target)
-
-
-class ZippedEnvironment(unittest.TestCase):
-
-    datafile = None
-    dataname = None
-    old_cwd = None
-
-    def setUp(self):
-        if self.datafile is None or self.dataname is None:
-            return
-
-        if not os.path.isfile(self.datafile):
-            self.old_cwd = None
-            return
-
-        self.old_cwd = os.getcwd()
-
-        self.temp_dir = tempfile.mkdtemp()
-        zip_file, source, target = [None, None, None]
-        try:
-            zip_file = zipfile.ZipFile(self.datafile)
-            for files in zip_file.namelist():
-                _extract(zip_file, files, self.temp_dir)
-        finally:
-            if zip_file:
-                zip_file.close()
-            del zip_file
-
-        os.chdir(os.path.join(self.temp_dir, self.dataname))
-
-    def tearDown(self):
-        #Assume setUp was never completed
-        if self.dataname is None or self.datafile is None:
-            return
-
-        try:
-            if self.old_cwd:
-                os.chdir(self.old_cwd)
-                _remove_dir(self.temp_dir)
-        except OSError:
-            #sigh?
-            pass
-
-
 def _which_dirs(cmd):
     result = set()
     for path in os.environ.get('PATH', '').split(os.pathsep):
@@ -147,10 +38,13 @@
 
     cmd = [sys.executable, "setup.py"] + list(cmd)
 
-    #regarding the shell argument, see: http://bugs.python.org/issue8557
+    # http://bugs.python.org/issue8557
+    shell = sys.platform == 'win32'
+
     try:
-        proc = _Popen(cmd, stdout=_PIPE, stderr=_PIPE,
-                      shell=(sys.platform == 'win32'), env=env)
+        proc = _Popen(
+            cmd, stdout=_PIPE, stderr=_PIPE, shell=shell, env=env,
+        )
 
         data = proc.communicate()[data_stream]
     except OSError:
@@ -158,7 +52,8 @@
 
     #decode the console string if needed
     if hasattr(data,  "decode"):
-        data = data.decode()  # should use the preffered encoding
+        # use the default encoding
+        data = data.decode()
         data = unicodedata.normalize('NFC', data)
 
     #communciate calls wait()
diff -Nru python-setuptools-3.3/setuptools/tests/files.py python-setuptools-20.1.1/setuptools/tests/files.py
--- python-setuptools-3.3/setuptools/tests/files.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/files.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,32 @@
+import os
+
+
+def build_files(file_defs, prefix=""):
+    """
+    Build a set of files/directories, as described by the file_defs dictionary.
+
+    Each key/value pair in the dictionary is interpreted as a filename/contents
+    pair. If the contents value is a dictionary, a directory is created, and the
+    dictionary interpreted as the files within it, recursively.
+
+    For example:
+
+    {"README.txt": "A README file",
+     "foo": {
+        "__init__.py": "",
+        "bar": {
+            "__init__.py": "",
+        },
+        "baz.py": "# Some code",
+     }
+    }
+    """
+    for name, contents in file_defs.items():
+        full_name = os.path.join(prefix, name)
+        if isinstance(contents, dict):
+            if not os.path.exists(full_name):
+                os.makedirs(full_name)
+            build_files(contents, prefix=full_name)
+        else:
+            with open(full_name, 'w') as f:
+                f.write(contents)
diff -Nru python-setuptools-3.3/setuptools/tests/fixtures.py python-setuptools-20.1.1/setuptools/tests/fixtures.py
--- python-setuptools-3.3/setuptools/tests/fixtures.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/fixtures.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,27 @@
+try:
+    from unittest import mock
+except ImportError:
+    import mock
+import pytest
+
+from . import contexts
+
+
+@pytest.yield_fixture
+def user_override():
+    """
+    Override site.USER_BASE and site.USER_SITE with temporary directories in
+    a context.
+    """
+    with contexts.tempdir() as user_base:
+        with mock.patch('site.USER_BASE', user_base):
+            with contexts.tempdir() as user_site:
+                with mock.patch('site.USER_SITE', user_site):
+                    with contexts.save_user_site_setting():
+                        yield
+
+
+@pytest.yield_fixture
+def tmpdir_cwd(tmpdir):
+    with tmpdir.as_cwd() as orig:
+        yield orig
diff -Nru python-setuptools-3.3/setuptools/tests/__init__.py python-setuptools-20.1.1/setuptools/tests/__init__.py
--- python-setuptools-3.3/setuptools/tests/__init__.py	2014-03-08 14:22:24.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/__init__.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,33 +1,25 @@
 """Tests for the 'setuptools' package"""
 import sys
 import os
-import unittest
-from setuptools.tests import doctest
 import distutils.core
 import distutils.cmd
 from distutils.errors import DistutilsOptionError, DistutilsPlatformError
 from distutils.errors import DistutilsSetupError
 from distutils.core import Extension
 from distutils.version import LooseVersion
-from setuptools.compat import func_code
 
-from setuptools.compat import func_code
+from setuptools.extern import six
+import pytest
+
 import setuptools.dist
 import setuptools.depends as dep
 from setuptools import Feature
 from setuptools.depends import Require
 
-def additional_tests():
-    import doctest, unittest
-    suite = unittest.TestSuite((
-        doctest.DocFileSuite(
-            os.path.join('tests', 'api_tests.txt'),
-            optionflags=doctest.ELLIPSIS, package='pkg_resources',
-            ),
-        ))
-    if sys.platform == 'win32':
-        suite.addTest(doctest.DocFileSuite('win_script_wrapper.txt'))
-    return suite
+c_type = os.environ.get("LC_CTYPE", os.environ.get("LC_ALL"))
+is_ascii = c_type in ("C", "POSIX")
+fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale")
+
 
 def makeSetup(**args):
     """Return distribution from 'setup(**args)', without executing commands"""
@@ -43,7 +35,12 @@
         distutils.core._setup_stop_after = None
 
 
-class DependsTests(unittest.TestCase):
+needs_bytecode = pytest.mark.skipif(
+    not hasattr(dep, 'get_module_constant'),
+    reason="bytecode support not available",
+)
+
+class TestDepends:
 
     def testExtractConst(self):
         if not hasattr(dep, 'extract_constant'):
@@ -55,87 +52,78 @@
             x = "test"
             y = z
 
-        fc = func_code(f1)
+        fc = six.get_function_code(f1)
+
         # unrecognized name
-        self.assertEqual(dep.extract_constant(fc,'q', -1), None)
+        assert dep.extract_constant(fc,'q', -1) is None
 
         # constant assigned
-        self.assertEqual(dep.extract_constant(fc,'x', -1), "test")
+        dep.extract_constant(fc,'x', -1) == "test"
 
         # expression assigned
-        self.assertEqual(dep.extract_constant(fc,'y', -1), -1)
+        dep.extract_constant(fc,'y', -1) == -1
 
         # recognized name, not assigned
-        self.assertEqual(dep.extract_constant(fc,'z', -1), None)
+        dep.extract_constant(fc,'z', -1) is None
 
     def testFindModule(self):
-        self.assertRaises(ImportError, dep.find_module, 'no-such.-thing')
-        self.assertRaises(ImportError, dep.find_module, 'setuptools.non-existent')
+        with pytest.raises(ImportError):
+            dep.find_module('no-such.-thing')
+        with pytest.raises(ImportError):
+            dep.find_module('setuptools.non-existent')
         f,p,i = dep.find_module('setuptools.tests')
         f.close()
 
+    @needs_bytecode
     def testModuleExtract(self):
-        if not hasattr(dep, 'get_module_constant'):
-            # skip on non-bytecode platforms
-            return
-
         from email import __version__
-        self.assertEqual(
-            dep.get_module_constant('email','__version__'), __version__
-        )
-        self.assertEqual(
-            dep.get_module_constant('sys','version'), sys.version
-        )
-        self.assertEqual(
-            dep.get_module_constant('setuptools.tests','__doc__'),__doc__
-        )
+        assert dep.get_module_constant('email','__version__') == __version__
+        assert dep.get_module_constant('sys','version') == sys.version
+        assert dep.get_module_constant('setuptools.tests','__doc__') == __doc__
 
+    @needs_bytecode
     def testRequire(self):
-        if not hasattr(dep, 'extract_constant'):
-            # skip on non-bytecode platformsh
-            return
-
         req = Require('Email','1.0.3','email')
 
-        self.assertEqual(req.name, 'Email')
-        self.assertEqual(req.module, 'email')
-        self.assertEqual(req.requested_version, '1.0.3')
-        self.assertEqual(req.attribute, '__version__')
-        self.assertEqual(req.full_name(), 'Email-1.0.3')
+        assert req.name == 'Email'
+        assert req.module == 'email'
+        assert req.requested_version == '1.0.3'
+        assert req.attribute == '__version__'
+        assert req.full_name() == 'Email-1.0.3'
 
         from email import __version__
-        self.assertEqual(req.get_version(), __version__)
-        self.assertTrue(req.version_ok('1.0.9'))
-        self.assertTrue(not req.version_ok('0.9.1'))
-        self.assertTrue(not req.version_ok('unknown'))
+        assert req.get_version() == __version__
+        assert req.version_ok('1.0.9')
+        assert not req.version_ok('0.9.1')
+        assert not req.version_ok('unknown')
 
-        self.assertTrue(req.is_present())
-        self.assertTrue(req.is_current())
+        assert req.is_present()
+        assert req.is_current()
 
         req = Require('Email 3000','03000','email',format=LooseVersion)
-        self.assertTrue(req.is_present())
-        self.assertTrue(not req.is_current())
-        self.assertTrue(not req.version_ok('unknown'))
+        assert req.is_present()
+        assert not req.is_current()
+        assert not req.version_ok('unknown')
 
         req = Require('Do-what-I-mean','1.0','d-w-i-m')
-        self.assertTrue(not req.is_present())
-        self.assertTrue(not req.is_current())
+        assert not req.is_present()
+        assert not req.is_current()
 
         req = Require('Tests', None, 'tests', homepage="http://example.com")
-        self.assertEqual(req.format, None)
-        self.assertEqual(req.attribute, None)
-        self.assertEqual(req.requested_version, None)
-        self.assertEqual(req.full_name(), 'Tests')
-        self.assertEqual(req.homepage, 'http://example.com')
+        assert req.format is None
+        assert req.attribute is None
+        assert req.requested_version is None
+        assert req.full_name() == 'Tests'
+        assert req.homepage == 'http://example.com'
 
         paths = [os.path.dirname(p) for p in __path__]
-        self.assertTrue(req.is_present(paths))
-        self.assertTrue(req.is_current(paths))
+        assert req.is_present(paths)
+        assert req.is_current(paths)
 
 
-class DistroTests(unittest.TestCase):
+class TestDistro:
 
-    def setUp(self):
+    def setup_method(self, method):
         self.e1 = Extension('bar.ext',['bar.c'])
         self.e2 = Extension('c.y', ['y.c'])
 
@@ -147,21 +135,21 @@
         )
 
     def testDistroType(self):
-        self.assertTrue(isinstance(self.dist,setuptools.dist.Distribution))
+        assert isinstance(self.dist,setuptools.dist.Distribution)
 
     def testExcludePackage(self):
         self.dist.exclude_package('a')
-        self.assertEqual(self.dist.packages, ['b','c'])
+        assert self.dist.packages == ['b','c']
 
         self.dist.exclude_package('b')
-        self.assertEqual(self.dist.packages, ['c'])
-        self.assertEqual(self.dist.py_modules, ['x'])
-        self.assertEqual(self.dist.ext_modules, [self.e1, self.e2])
+        assert self.dist.packages == ['c']
+        assert self.dist.py_modules == ['x']
+        assert self.dist.ext_modules == [self.e1, self.e2]
 
         self.dist.exclude_package('c')
-        self.assertEqual(self.dist.packages, [])
-        self.assertEqual(self.dist.py_modules, ['x'])
-        self.assertEqual(self.dist.ext_modules, [self.e1])
+        assert self.dist.packages == []
+        assert self.dist.py_modules == ['x']
+        assert self.dist.ext_modules == [self.e1]
 
         # test removals from unspecified options
         makeSetup().exclude_package('x')
@@ -169,21 +157,21 @@
     def testIncludeExclude(self):
         # remove an extension
         self.dist.exclude(ext_modules=[self.e1])
-        self.assertEqual(self.dist.ext_modules, [self.e2])
+        assert self.dist.ext_modules == [self.e2]
 
         # add it back in
         self.dist.include(ext_modules=[self.e1])
-        self.assertEqual(self.dist.ext_modules, [self.e2, self.e1])
+        assert self.dist.ext_modules == [self.e2, self.e1]
 
         # should not add duplicate
         self.dist.include(ext_modules=[self.e1])
-        self.assertEqual(self.dist.ext_modules, [self.e2, self.e1])
+        assert self.dist.ext_modules == [self.e2, self.e1]
 
     def testExcludePackages(self):
         self.dist.exclude(packages=['c','b','a'])
-        self.assertEqual(self.dist.packages, [])
-        self.assertEqual(self.dist.py_modules, ['x'])
-        self.assertEqual(self.dist.ext_modules, [self.e1])
+        assert self.dist.packages == []
+        assert self.dist.py_modules == ['x']
+        assert self.dist.ext_modules == [self.e1]
 
     def testEmpty(self):
         dist = makeSetup()
@@ -192,49 +180,41 @@
         dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2])
 
     def testContents(self):
-        self.assertTrue(self.dist.has_contents_for('a'))
+        assert self.dist.has_contents_for('a')
         self.dist.exclude_package('a')
-        self.assertTrue(not self.dist.has_contents_for('a'))
+        assert not self.dist.has_contents_for('a')
 
-        self.assertTrue(self.dist.has_contents_for('b'))
+        assert self.dist.has_contents_for('b')
         self.dist.exclude_package('b')
-        self.assertTrue(not self.dist.has_contents_for('b'))
+        assert not self.dist.has_contents_for('b')
 
-        self.assertTrue(self.dist.has_contents_for('c'))
+        assert self.dist.has_contents_for('c')
         self.dist.exclude_package('c')
-        self.assertTrue(not self.dist.has_contents_for('c'))
+        assert not self.dist.has_contents_for('c')
 
     def testInvalidIncludeExclude(self):
-        self.assertRaises(DistutilsSetupError,
-            self.dist.include, nonexistent_option='x'
-        )
-        self.assertRaises(DistutilsSetupError,
-            self.dist.exclude, nonexistent_option='x'
-        )
-        self.assertRaises(DistutilsSetupError,
-            self.dist.include, packages={'x':'y'}
-        )
-        self.assertRaises(DistutilsSetupError,
-            self.dist.exclude, packages={'x':'y'}
-        )
-        self.assertRaises(DistutilsSetupError,
-            self.dist.include, ext_modules={'x':'y'}
-        )
-        self.assertRaises(DistutilsSetupError,
-            self.dist.exclude, ext_modules={'x':'y'}
-        )
-
-        self.assertRaises(DistutilsSetupError,
-            self.dist.include, package_dir=['q']
-        )
-        self.assertRaises(DistutilsSetupError,
-            self.dist.exclude, package_dir=['q']
-        )
+        with pytest.raises(DistutilsSetupError):
+            self.dist.include(nonexistent_option='x')
+        with pytest.raises(DistutilsSetupError):
+            self.dist.exclude(nonexistent_option='x')
+        with pytest.raises(DistutilsSetupError):
+            self.dist.include(packages={'x':'y'})
+        with pytest.raises(DistutilsSetupError):
+            self.dist.exclude(packages={'x':'y'})
+        with pytest.raises(DistutilsSetupError):
+            self.dist.include(ext_modules={'x':'y'})
+        with pytest.raises(DistutilsSetupError):
+            self.dist.exclude(ext_modules={'x':'y'})
+
+        with pytest.raises(DistutilsSetupError):
+            self.dist.include(package_dir=['q'])
+        with pytest.raises(DistutilsSetupError):
+            self.dist.exclude(package_dir=['q'])
 
 
-class FeatureTests(unittest.TestCase):
+class TestFeatures:
 
-    def setUp(self):
+    def setup_method(self, method):
         self.req = Require('Distutils','1.0.3','distutils')
         self.dist = makeSetup(
             features={
@@ -256,80 +236,75 @@
         )
 
     def testDefaults(self):
-        self.assertTrue(not
-            Feature(
-                "test",standard=True,remove='x',available=False
-            ).include_by_default()
-        )
-        self.assertTrue(
-            Feature("test",standard=True,remove='x').include_by_default()
-        )
+        assert not Feature(
+            "test",standard=True,remove='x',available=False
+        ).include_by_default()
+        assert Feature("test",standard=True,remove='x').include_by_default()
         # Feature must have either kwargs, removes, or require_features
-        self.assertRaises(DistutilsSetupError, Feature, "test")
+        with pytest.raises(DistutilsSetupError):
+            Feature("test")
 
     def testAvailability(self):
-        self.assertRaises(
-            DistutilsPlatformError,
-            self.dist.features['dwim'].include_in, self.dist
-        )
+        with pytest.raises(DistutilsPlatformError):
+            self.dist.features['dwim'].include_in(self.dist)
 
     def testFeatureOptions(self):
         dist = self.dist
-        self.assertTrue(
+        assert (
             ('with-dwim',None,'include DWIM') in dist.feature_options
         )
-        self.assertTrue(
+        assert (
             ('without-dwim',None,'exclude DWIM (default)') in dist.feature_options
         )
-        self.assertTrue(
+        assert (
             ('with-bar',None,'include bar (default)') in dist.feature_options
         )
-        self.assertTrue(
+        assert (
             ('without-bar',None,'exclude bar') in dist.feature_options
         )
-        self.assertEqual(dist.feature_negopt['without-foo'],'with-foo')
-        self.assertEqual(dist.feature_negopt['without-bar'],'with-bar')
-        self.assertEqual(dist.feature_negopt['without-dwim'],'with-dwim')
-        self.assertTrue(not 'without-baz' in dist.feature_negopt)
+        assert dist.feature_negopt['without-foo'] == 'with-foo'
+        assert dist.feature_negopt['without-bar'] == 'with-bar'
+        assert dist.feature_negopt['without-dwim'] == 'with-dwim'
+        assert (not 'without-baz' in dist.feature_negopt)
 
     def testUseFeatures(self):
         dist = self.dist
-        self.assertEqual(dist.with_foo,1)
-        self.assertEqual(dist.with_bar,0)
-        self.assertEqual(dist.with_baz,1)
-        self.assertTrue(not 'bar_et' in dist.py_modules)
-        self.assertTrue(not 'pkg.bar' in dist.packages)
-        self.assertTrue('pkg.baz' in dist.packages)
-        self.assertTrue('scripts/baz_it' in dist.scripts)
-        self.assertTrue(('libfoo','foo/foofoo.c') in dist.libraries)
-        self.assertEqual(dist.ext_modules,[])
-        self.assertEqual(dist.require_features, [self.req])
+        assert dist.with_foo == 1
+        assert dist.with_bar == 0
+        assert dist.with_baz == 1
+        assert (not 'bar_et' in dist.py_modules)
+        assert (not 'pkg.bar' in dist.packages)
+        assert ('pkg.baz' in dist.packages)
+        assert ('scripts/baz_it' in dist.scripts)
+        assert (('libfoo','foo/foofoo.c') in dist.libraries)
+        assert dist.ext_modules == []
+        assert dist.require_features == [self.req]
 
         # If we ask for bar, it should fail because we explicitly disabled
         # it on the command line
-        self.assertRaises(DistutilsOptionError, dist.include_feature, 'bar')
+        with pytest.raises(DistutilsOptionError):
+            dist.include_feature('bar')
 
     def testFeatureWithInvalidRemove(self):
-        self.assertRaises(
-            SystemExit, makeSetup, features = {'x':Feature('x', remove='y')}
-        )
+        with pytest.raises(SystemExit):
+            makeSetup(features={'x':Feature('x', remove='y')})
 
-class TestCommandTests(unittest.TestCase):
+class TestCommandTests:
 
     def testTestIsCommand(self):
         test_cmd = makeSetup().get_command_obj('test')
-        self.assertTrue(isinstance(test_cmd, distutils.cmd.Command))
+        assert (isinstance(test_cmd, distutils.cmd.Command))
 
     def testLongOptSuiteWNoDefault(self):
         ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite'])
         ts1 = ts1.get_command_obj('test')
         ts1.ensure_finalized()
-        self.assertEqual(ts1.test_suite, 'foo.tests.suite')
+        assert ts1.test_suite == 'foo.tests.suite'
 
     def testDefaultSuite(self):
         ts2 = makeSetup(test_suite='bar.tests.suite').get_command_obj('test')
         ts2.ensure_finalized()
-        self.assertEqual(ts2.test_suite, 'bar.tests.suite')
+        assert ts2.test_suite == 'bar.tests.suite'
 
     def testDefaultWModuleOnCmdLine(self):
         ts3 = makeSetup(
@@ -337,16 +312,17 @@
             script_args=['test','-m','foo.tests']
         ).get_command_obj('test')
         ts3.ensure_finalized()
-        self.assertEqual(ts3.test_module, 'foo.tests')
-        self.assertEqual(ts3.test_suite,  'foo.tests.test_suite')
+        assert ts3.test_module == 'foo.tests'
+        assert ts3.test_suite == 'foo.tests.test_suite'
 
     def testConflictingOptions(self):
         ts4 = makeSetup(
             script_args=['test','-m','bar.tests', '-s','foo.tests.suite']
         ).get_command_obj('test')
-        self.assertRaises(DistutilsOptionError, ts4.ensure_finalized)
+        with pytest.raises(DistutilsOptionError):
+            ts4.ensure_finalized()
 
     def testNoSuite(self):
         ts5 = makeSetup().get_command_obj('test')
         ts5.ensure_finalized()
-        self.assertEqual(ts5.test_suite, None)
+        assert ts5.test_suite == None
diff -Nru python-setuptools-3.3/setuptools/tests/py26compat.py python-setuptools-20.1.1/setuptools/tests/py26compat.py
--- python-setuptools-3.3/setuptools/tests/py26compat.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/py26compat.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,14 +1,14 @@
-import unittest
+import sys
+import tarfile
+import contextlib
 
-try:
-	# provide skipIf for Python 2.4-2.6
-	skipIf = unittest.skipIf
-except AttributeError:
-	def skipIf(condition, reason):
-		def skipper(func):
-			def skip(*args, **kwargs):
-				return
-			if condition:
-				return skip
-			return func
-		return skipper
+def _tarfile_open_ex(*args, **kwargs):
+	"""
+	Extend result as a context manager.
+	"""
+	return contextlib.closing(tarfile.open(*args, **kwargs))
+
+if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 2):
+    tarfile_open = _tarfile_open_ex
+else:
+    tarfile_open = tarfile.open
diff -Nru python-setuptools-3.3/setuptools/tests/server.py python-setuptools-20.1.1/setuptools/tests/server.py
--- python-setuptools-3.3/setuptools/tests/server.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/server.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,13 +1,13 @@
 """Basic http server for tests to simulate PyPI or custom indexes
 """
-import sys
+
 import time
 import threading
-from setuptools.compat import BaseHTTPRequestHandler
-from setuptools.compat import (urllib2, URLError, HTTPServer,
-                               SimpleHTTPRequestHandler)
 
-class IndexServer(HTTPServer):
+from setuptools.extern.six.moves import BaseHTTPServer, SimpleHTTPServer
+
+
+class IndexServer(BaseHTTPServer.HTTPServer):
     """Basic single-threaded http server simulating a package index
 
     You can use this server in unittest like this::
@@ -19,16 +19,13 @@
         s.stop()
     """
     def __init__(self, server_address=('', 0),
-            RequestHandlerClass=SimpleHTTPRequestHandler):
-        HTTPServer.__init__(self, server_address, RequestHandlerClass)
+            RequestHandlerClass=SimpleHTTPServer.SimpleHTTPRequestHandler):
+        BaseHTTPServer.HTTPServer.__init__(self, server_address,
+            RequestHandlerClass)
         self._run = True
 
-    def serve(self):
-        while self._run:
-            self.handle_request()
-
     def start(self):
-        self.thread = threading.Thread(target=self.serve)
+        self.thread = threading.Thread(target=self.serve_forever)
         self.thread.start()
 
     def stop(self):
@@ -37,19 +34,7 @@
         # Let the server finish the last request and wait for a new one.
         time.sleep(0.1)
 
-        # self.shutdown is not supported on python < 2.6, so just
-        #  set _run to false, and make a request, causing it to
-        #  terminate.
-        self._run = False
-        url = 'http://127.0.0.1:%(server_port)s/' % vars(self)
-        try:
-            if sys.version_info >= (2, 6):
-                urllib2.urlopen(url, timeout=5)
-            else:
-                urllib2.urlopen(url)
-        except URLError:
-            # ignore any errors; all that's important is the request
-            pass
+        self.shutdown()
         self.thread.join()
         self.socket.close()
 
@@ -57,19 +42,20 @@
         port = self.server_port
         return 'http://127.0.0.1:%s/setuptools/tests/indexes/' % port
 
-class RequestRecorder(BaseHTTPRequestHandler):
+class RequestRecorder(BaseHTTPServer.BaseHTTPRequestHandler):
     def do_GET(self):
         requests = vars(self.server).setdefault('requests', [])
         requests.append(self)
         self.send_response(200, 'OK')
 
-class MockServer(HTTPServer, threading.Thread):
+class MockServer(BaseHTTPServer.HTTPServer, threading.Thread):
     """
     A simple HTTP Server that records the requests made to it.
     """
     def __init__(self, server_address=('', 0),
             RequestHandlerClass=RequestRecorder):
-        HTTPServer.__init__(self, server_address, RequestHandlerClass)
+        BaseHTTPServer.HTTPServer.__init__(self, server_address,
+            RequestHandlerClass)
         threading.Thread.__init__(self)
         self.setDaemon(True)
         self.requests = []
@@ -77,6 +63,6 @@
     def run(self):
         self.serve_forever()
 
+    @property
     def url(self):
         return 'http://localhost:%(server_port)s/' % vars(self)
-    url = property(url)
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy13.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy13.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy14.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy14.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy15.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy15.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy16.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy16.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy17.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy17.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy18.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy18.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/dummy.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/dummy.zip differ
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/svn13_example.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/svn13_example.zip differ
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn13_ext_list.txt python-setuptools-20.1.1/setuptools/tests/svn_data/svn13_ext_list.txt
--- python-setuptools-3.3/setuptools/tests/svn_data/svn13_ext_list.txt	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn13_ext_list.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-third_party3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party2 -r3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party -r1 file:///C:/development/svn_example/repos/svn13/extra1
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn13_info.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn13_info.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn13_info.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn13_info.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,121 +0,0 @@
-
-
-
-file:///C:/development/svn_example/repos/svn13/main
-
-file:///C:/development/svn_example/repos/svn13/main
-d2996769-47b0-9946-b618-da1aa3eceda3
-
-
-normal
-2013-07-13T15:33:23.187500Z
-
-
-ptt
-2013-07-13T15:33:28.359375Z
-
-
-
-file:///C:/development/svn_example/repos/svn13/main/a%20file
-
-file:///C:/development/svn_example/repos/svn13/main
-d2996769-47b0-9946-b618-da1aa3eceda3
-
-
-normal
-2013-07-13T15:33:21.109375Z
-a6166e5e98a5a503089cde9bc8031293
-
-
-ptt
-2013-07-13T15:33:21.312500Z
-
-
-
-file:///C:/development/svn_example/repos/svn13/main/to_delete
-
-file:///C:/development/svn_example/repos/svn13/main
-d2996769-47b0-9946-b618-da1aa3eceda3
-
-
-delete
-2013-07-13T15:33:28.140625Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:33:28.359375Z
-
-
-
-file:///C:/development/svn_example/repos/svn13/main/folder
-
-file:///C:/development/svn_example/repos/svn13/main
-d2996769-47b0-9946-b618-da1aa3eceda3
-
-
-normal
-2013-07-13T15:33:26.187500Z
-
-
-ptt
-2013-07-13T15:33:26.312500Z
-
-
-
-file:///C:/development/svn_example/repos/svn13/main/folder/quest.txt
-
-file:///C:/development/svn_example/repos/svn13/main
-d2996769-47b0-9946-b618-da1aa3eceda3
-
-
-normal
-2013-07-13T15:33:20.109375Z
-795240c6a830c14f83961e57e07dad12
-
-
-ptt
-2013-07-13T15:33:20.312500Z
-
-
-
-file:///C:/development/svn_example/repos/svn13/main/folder/lalala.txt
-
-file:///C:/development/svn_example/repos/svn13/main
-d2996769-47b0-9946-b618-da1aa3eceda3
-
-
-normal
-2013-07-13T15:33:19.375000Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:33:19.609375Z
-
-
-
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/svn14_example.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/svn14_example.zip differ
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn14_ext_list.txt python-setuptools-20.1.1/setuptools/tests/svn_data/svn14_ext_list.txt
--- python-setuptools-3.3/setuptools/tests/svn_data/svn14_ext_list.txt	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn14_ext_list.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-third_party3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party2 -r3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party -r1 file:///C:/development/svn_example/repos/svn13/extra1
-
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn14_info.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn14_info.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn14_info.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn14_info.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,119 +0,0 @@
-
-
-
-file:///C:/development/svn_example/repos/svn14/main
-
-file:///C:/development/svn_example/repos/svn14/main
-c75942e5-8b7a-354d-b1cf-73dee23fa94f
-
-
-normal
-
-
-ptt
-2013-07-13T15:34:14.406250Z
-
-
-
-file:///C:/development/svn_example/repos/svn14/main/a%20file
-
-file:///C:/development/svn_example/repos/svn14/main
-c75942e5-8b7a-354d-b1cf-73dee23fa94f
-
-
-normal
-2013-07-13T15:34:08.109375Z
-a6166e5e98a5a503089cde9bc8031293
-
-
-ptt
-2013-07-13T15:34:08.390625Z
-
-
-
-file:///C:/development/svn_example/repos/svn14/main/to_delete
-
-file:///C:/development/svn_example/repos/svn14/main
-c75942e5-8b7a-354d-b1cf-73dee23fa94f
-
-
-delete
-2013-07-13T15:34:14.125000Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:34:14.406250Z
-
-
-
-file:///C:/development/svn_example/repos/svn14/main/folder
-
-file:///C:/development/svn_example/repos/svn14/main
-c75942e5-8b7a-354d-b1cf-73dee23fa94f
-
-
-normal
-
-
-ptt
-2013-07-13T15:34:12.390625Z
-
-
-
-file:///C:/development/svn_example/repos/svn14/main/folder/quest.txt
-
-file:///C:/development/svn_example/repos/svn14/main
-c75942e5-8b7a-354d-b1cf-73dee23fa94f
-
-
-normal
-2013-07-13T15:34:07.109375Z
-795240c6a830c14f83961e57e07dad12
-
-
-ptt
-2013-07-13T15:34:07.390625Z
-
-
-
-file:///C:/development/svn_example/repos/svn14/main/folder/lalala.txt
-
-file:///C:/development/svn_example/repos/svn14/main
-c75942e5-8b7a-354d-b1cf-73dee23fa94f
-
-
-normal
-2013-07-13T15:34:06.250000Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:34:06.531250Z
-
-
-
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/svn15_example.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_example.zip differ
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn15_ext_list.txt python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_ext_list.txt
--- python-setuptools-3.3/setuptools/tests/svn_data/svn15_ext_list.txt	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_ext_list.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-third_party3 file:///C:/development/svn_example/repos/svn15/extra1
--r3 file:///C:/development/svn_example/repos/svn15/extra1 third_party2
-file:///C:/development/svn_example/repos/svn15/extra1@r1 third_party
-
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn15_ext_list.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_ext_list.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn15_ext_list.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_ext_list.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-
-
-
-third_party3 file:///C:/development/svn_example/repos/svn15/extra2
--r3 file:///C:/development/svn_example/repos/svn15/extra2 third_party2
-file:///C:/development/svn_example/repos/svn15/extra2@r1 third_party大介
-
-
-
-third_party3 file:///C:/development/svn_example/repos/svn15/extra1
--r3 file:///C:/development/svn_example/repos/svn15/extra1 third_party2
-file:///C:/development/svn_example/repos/svn15/extra1@r1 third_party大介
-
-
-
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn15_info.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_info.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn15_info.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn15_info.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,125 +0,0 @@
-
-
-
-file:///C:/development/svn_example/repos/svn15/main
-
-file:///C:/development/svn_example/repos/svn15/main
-4eab6983-54fe-384b-a282-9306f52d948f
-
-
-normal
-infinity
-
-
-ptt
-2013-07-13T15:34:49.562500Z
-
-
-
-file:///C:/development/svn_example/repos/svn15/main/a%20file
-
-file:///C:/development/svn_example/repos/svn15/main
-4eab6983-54fe-384b-a282-9306f52d948f
-
-
-normal
-infinity
-2013-07-13T15:34:43.109375Z
-a6166e5e98a5a503089cde9bc8031293
-
-
-ptt
-2013-07-13T15:34:43.484375Z
-
-
-
-file:///C:/development/svn_example/repos/svn15/main/to_delete
-
-file:///C:/development/svn_example/repos/svn15/main
-4eab6983-54fe-384b-a282-9306f52d948f
-
-
-delete
-infinity
-2013-07-13T15:34:49.125000Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:34:49.562500Z
-
-
-
-file:///C:/development/svn_example/repos/svn15/main/folder
-
-file:///C:/development/svn_example/repos/svn15/main
-4eab6983-54fe-384b-a282-9306f52d948f
-
-
-normal
-infinity
-
-
-ptt
-2013-07-13T15:34:47.515625Z
-
-
-
-file:///C:/development/svn_example/repos/svn15/main/folder/quest.txt
-
-file:///C:/development/svn_example/repos/svn15/main
-4eab6983-54fe-384b-a282-9306f52d948f
-
-
-normal
-infinity
-2013-07-13T15:34:42.109375Z
-795240c6a830c14f83961e57e07dad12
-
-
-ptt
-2013-07-13T15:34:42.484375Z
-
-
-
-file:///C:/development/svn_example/repos/svn15/main/folder/lalala.txt
-
-file:///C:/development/svn_example/repos/svn15/main
-4eab6983-54fe-384b-a282-9306f52d948f
-
-
-normal
-infinity
-2013-07-13T15:34:41.375000Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:34:41.734375Z
-
-
-
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/svn16_example.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_example.zip differ
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn16_ext_list.txt python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_ext_list.txt
--- python-setuptools-3.3/setuptools/tests/svn_data/svn16_ext_list.txt	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_ext_list.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-"third party3" file:///C:/development/svn_example/repos/svn16/extra1 
-'third party3b' file:///C:/development/svn_example/repos/svn16/extra1 
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn16_ext_list.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_ext_list.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn16_ext_list.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_ext_list.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-
-
-
-"third party3" file:///C:/development/svn_example/repos/svn16/extra2 
--r3 file:///C:/development/svn_example/repos/svn16/extra2 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra2@r1 third_party大介
-
-
-
-"third party3" file:///C:/development/svn_example/repos/svn16/extra1 
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
-
-
-
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn16_info.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_info.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn16_info.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn16_info.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,125 +0,0 @@
-
-
-
-file:///C:/development/svn_example/repos/svn16/main
-
-file:///C:/development/svn_example/repos/svn16/main
-bd8d2cfc-1a74-de45-b166-262010c17c0a
-
-
-normal
-infinity
-
-
-ptt
-2013-07-13T15:35:17.390625Z
-
-
-
-file:///C:/development/svn_example/repos/svn16/main/a%20file
-
-file:///C:/development/svn_example/repos/svn16/main
-bd8d2cfc-1a74-de45-b166-262010c17c0a
-
-
-normal
-infinity
-2013-07-13T15:35:14.578125Z
-a6166e5e98a5a503089cde9bc8031293
-
-
-ptt
-2013-07-13T15:35:14.906250Z
-
-
-
-file:///C:/development/svn_example/repos/svn16/main/to_delete
-
-file:///C:/development/svn_example/repos/svn16/main
-bd8d2cfc-1a74-de45-b166-262010c17c0a
-
-
-delete
-infinity
-2013-07-13T15:35:17.046875Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:35:17.390625Z
-
-
-
-file:///C:/development/svn_example/repos/svn16/main/folder
-
-file:///C:/development/svn_example/repos/svn16/main
-bd8d2cfc-1a74-de45-b166-262010c17c0a
-
-
-normal
-infinity
-
-
-ptt
-2013-07-13T15:35:16.406250Z
-
-
-
-file:///C:/development/svn_example/repos/svn16/main/folder/quest.txt
-
-file:///C:/development/svn_example/repos/svn16/main
-bd8d2cfc-1a74-de45-b166-262010c17c0a
-
-
-normal
-infinity
-2013-07-13T15:35:14.078125Z
-795240c6a830c14f83961e57e07dad12
-
-
-ptt
-2013-07-13T15:35:14.421875Z
-
-
-
-file:///C:/development/svn_example/repos/svn16/main/folder/lalala.txt
-
-file:///C:/development/svn_example/repos/svn16/main
-bd8d2cfc-1a74-de45-b166-262010c17c0a
-
-
-normal
-infinity
-2013-07-13T15:35:12.171875Z
-d41d8cd98f00b204e9800998ecf8427e
-
-
-ptt
-2013-07-13T15:35:13.906250Z
-
-
-
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/svn17_example.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_example.zip differ
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn17_ext_list.txt python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_ext_list.txt
--- python-setuptools-3.3/setuptools/tests/svn_data/svn17_ext_list.txt	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_ext_list.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-"third party3" file:///C:/development/svn_example/repos/svn17/extra1 
-'third party3b' file:///C:/development/svn_example/repos/svn17/extra1 
--r3 file:///C:/development/svn_example/repos/svn17/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn17/extra1@r1 third_party
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn17_ext_list.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_ext_list.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn17_ext_list.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_ext_list.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-
-
-
-"third party3" file:///C:/development/svn_example/repos/svn16/extra1 
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
-
-
-
-"third party3" file:///C:/development/svn_example/repos/svn17/extra2 
--r3 file:///C:/development/svn_example/repos/svn17/extra2 third\ party2
-file:///C:/development/svn_example/repos/svn17/extra2@r1 third_party大介
-
-
-
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn17_info.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_info.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn17_info.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn17_info.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,130 +0,0 @@
-
-
-
-file:///C:/development/svn_example/repos/svn17/main
-
-file:///C:/development/svn_example/repos/svn17/main
-5ba45434-5197-164e-afab-81923f4744f5
-
-
-C:/development/svn_example/svn17_example
-normal
-infinity
-
-
-ptt
-2013-07-13T15:35:36.171875Z
-
-
-
-file:///C:/development/svn_example/repos/svn17/main/folder
-
-file:///C:/development/svn_example/repos/svn17/main
-5ba45434-5197-164e-afab-81923f4744f5
-
-
-C:/development/svn_example/svn17_example
-normal
-infinity
-
-
-ptt
-2013-07-13T15:35:34.859375Z
-
-
-
-file:///C:/development/svn_example/repos/svn17/main/folder/quest.txt
-
-file:///C:/development/svn_example/repos/svn17/main
-5ba45434-5197-164e-afab-81923f4744f5
-
-
-C:/development/svn_example/svn17_example
-normal
-infinity
-2013-07-13T15:35:32.812500Z
-bc80eba9e7a10c0a571a4678c520bc9683f3bac2
-
-
-ptt
-2013-07-13T15:35:33.109375Z
-
-
-
-file:///C:/development/svn_example/repos/svn17/main/folder/lalala.txt
-
-file:///C:/development/svn_example/repos/svn17/main
-5ba45434-5197-164e-afab-81923f4744f5
-
-
-C:/development/svn_example/svn17_example
-normal
-infinity
-2013-07-13T15:35:32.343750Z
-da39a3ee5e6b4b0d3255bfef95601890afd80709
-
-
-ptt
-2013-07-13T15:35:32.687500Z
-
-
-
-file:///C:/development/svn_example/repos/svn17/main/a%20file
-
-file:///C:/development/svn_example/repos/svn17/main
-5ba45434-5197-164e-afab-81923f4744f5
-
-
-C:/development/svn_example/svn17_example
-normal
-infinity
-2013-07-13T15:35:33.187500Z
-43785ab4b1816b49f242990883292813cd4f486c
-
-
-ptt
-2013-07-13T15:35:33.515625Z
-
-
-
-file:///C:/development/svn_example/repos/svn17/main/to_delete
-
-file:///C:/development/svn_example/repos/svn17/main
-5ba45434-5197-164e-afab-81923f4744f5
-
-
-C:/development/svn_example/svn17_example
-delete
-infinity
-da39a3ee5e6b4b0d3255bfef95601890afd80709
-
-
-ptt
-2013-07-13T15:35:36.171875Z
-
-
-
Binary files /tmp/tmpTFbNhb/FQ6elWSqZP/python-setuptools-3.3/setuptools/tests/svn_data/svn18_example.zip and /tmp/tmpTFbNhb/KYlEZPx_F_/python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_example.zip differ
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn18_ext_list.txt python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_ext_list.txt
--- python-setuptools-3.3/setuptools/tests/svn_data/svn18_ext_list.txt	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_ext_list.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-"third party3" file:///C:/development/svn_example/repos/svn18/extra1 
-'third party3b' file:///C:/development/svn_example/repos/svn18/extra1 
--r3 file:///C:/development/svn_example/repos/svn18/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn18/extra1@r1 third_party
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn18_ext_list.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_ext_list.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn18_ext_list.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_ext_list.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-
-
-
-"third party3" file:///C:/development/svn_example/repos/svn16/extra1 
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
-
-
-
-"third party3" file:///C:/development/svn_example/repos/svn18/extra2 
--r3 file:///C:/development/svn_example/repos/svn18/extra2 third\ party2
-file:///C:/development/svn_example/repos/svn18/extra2@r1 third_party大介
-
-
-
diff -Nru python-setuptools-3.3/setuptools/tests/svn_data/svn18_info.xml python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_info.xml
--- python-setuptools-3.3/setuptools/tests/svn_data/svn18_info.xml	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/svn_data/svn18_info.xml	1970-01-01 00:00:00.000000000 +0000
@@ -1,136 +0,0 @@
-
-
-
-file:///C:/development/svn_example/repos/svn18/main
-^/
-
-file:///C:/development/svn_example/repos/svn18/main
-3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9
-
-
-C:/development/svn_example/svn18_example
-normal
-infinity
-
-
-ptt
-2013-07-13T15:35:57.796875Z
-
-
-
-file:///C:/development/svn_example/repos/svn18/main/a%20file
-^/a%20file
-
-file:///C:/development/svn_example/repos/svn18/main
-3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9
-
-
-C:/development/svn_example/svn18_example
-normal
-infinity
-2013-07-13T15:35:54.906250Z
-43785ab4b1816b49f242990883292813cd4f486c
-
-
-ptt
-2013-07-13T15:35:55.265625Z
-
-
-
-file:///C:/development/svn_example/repos/svn18/main/to_delete
-^/to_delete
-
-file:///C:/development/svn_example/repos/svn18/main
-3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9
-
-
-C:/development/svn_example/svn18_example
-delete
-infinity
-da39a3ee5e6b4b0d3255bfef95601890afd80709
-
-
-ptt
-2013-07-13T15:35:57.796875Z
-
-
-
-file:///C:/development/svn_example/repos/svn18/main/folder
-^/folder
-
-file:///C:/development/svn_example/repos/svn18/main
-3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9
-
-
-C:/development/svn_example/svn18_example
-normal
-infinity
-
-
-ptt
-2013-07-13T15:35:56.750000Z
-
-
-
-file:///C:/development/svn_example/repos/svn18/main/folder/quest.txt
-^/folder/quest.txt
-
-file:///C:/development/svn_example/repos/svn18/main
-3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9
-
-
-C:/development/svn_example/svn18_example
-normal
-infinity
-2013-07-13T15:35:54.484375Z
-bc80eba9e7a10c0a571a4678c520bc9683f3bac2
-
-
-ptt
-2013-07-13T15:35:54.843750Z
-
-
-
-file:///C:/development/svn_example/repos/svn18/main/folder/lalala.txt
-^/folder/lalala.txt
-
-file:///C:/development/svn_example/repos/svn18/main
-3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9
-
-
-C:/development/svn_example/svn18_example
-normal
-infinity
-2013-07-13T15:35:54.015625Z
-da39a3ee5e6b4b0d3255bfef95601890afd80709
-
-
-ptt
-2013-07-13T15:35:54.375000Z
-
-
-
diff -Nru python-setuptools-3.3/setuptools/tests/test_bdist_egg.py python-setuptools-20.1.1/setuptools/tests/test_bdist_egg.py
--- python-setuptools-3.3/setuptools/tests/test_bdist_egg.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_bdist_egg.py	2016-02-07 14:25:06.000000000 +0000
@@ -2,52 +2,31 @@
 """
 import os
 import re
-import shutil
-import site
-import sys
-import tempfile
-import unittest
-
-from distutils.errors import DistutilsError
-from setuptools.compat import StringIO
-from setuptools.command.bdist_egg import bdist_egg
-from setuptools.command import easy_install as easy_install_pkg
+
+import pytest
+
 from setuptools.dist import Distribution
 
+from . import contexts
+
 SETUP_PY = """\
 from setuptools import setup
 
 setup(name='foo', py_modules=['hi'])
 """
 
-class TestDevelopTest(unittest.TestCase):
-
-    def setUp(self):
-        self.dir = tempfile.mkdtemp()
-        self.old_cwd = os.getcwd()
-        os.chdir(self.dir)
-        f = open('setup.py', 'w')
+@pytest.yield_fixture
+def setup_context(tmpdir):
+    with (tmpdir/'setup.py').open('w') as f:
         f.write(SETUP_PY)
-        f.close()
-        f = open('hi.py', 'w')
+    with (tmpdir/'hi.py').open('w') as f:
         f.write('1\n')
-        f.close()
-        if sys.version >= "2.6":
-            self.old_base = site.USER_BASE
-            site.USER_BASE = tempfile.mkdtemp()
-            self.old_site = site.USER_SITE
-            site.USER_SITE = tempfile.mkdtemp()
-
-    def tearDown(self):
-        os.chdir(self.old_cwd)
-        shutil.rmtree(self.dir)
-        if sys.version >= "2.6":
-            shutil.rmtree(site.USER_BASE)
-            shutil.rmtree(site.USER_SITE)
-            site.USER_BASE = self.old_base
-            site.USER_SITE = self.old_site
+    with tmpdir.as_cwd():
+        yield tmpdir
 
-    def test_bdist_egg(self):
+
+class Test:
+    def test_bdist_egg(self, setup_context, user_override):
         dist = Distribution(dict(
             script_name='setup.py',
             script_args=['bdist_egg'],
@@ -55,18 +34,10 @@
             py_modules=['hi']
             ))
         os.makedirs(os.path.join('build', 'src'))
-        old_stdout = sys.stdout
-        sys.stdout = o = StringIO()
-        try:
+        with contexts.quiet():
             dist.parse_command_line()
             dist.run_commands()
-        finally:
-            sys.stdout = old_stdout
 
         # let's see if we got our egg link at the right place
         [content] = os.listdir('dist')
-        self.assertTrue(re.match('foo-0.0.0-py[23].\d.egg$', content))
-
-def test_suite():
-    return unittest.makeSuite(TestDevelopTest)
-
+        assert re.match('foo-0.0.0-py[23].\d.egg$', content)
diff -Nru python-setuptools-3.3/setuptools/tests/test_build_ext.py python-setuptools-20.1.1/setuptools/tests/test_build_ext.py
--- python-setuptools-3.3/setuptools/tests/test_build_ext.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_build_ext.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,19 +1,18 @@
-"""build_ext tests
-"""
-import unittest
-from distutils.command.build_ext import build_ext as distutils_build_ext
+import distutils.command.build_ext as orig
+
 from setuptools.command.build_ext import build_ext
 from setuptools.dist import Distribution
 
-class TestBuildExtTest(unittest.TestCase):
-
+class TestBuildExt:
     def test_get_ext_filename(self):
-        # setuptools needs to give back the same
-        # result than distutils, even if the fullname
-        # is not in ext_map
+        """
+        Setuptools needs to give back the same
+        result as distutils, even if the fullname
+        is not in ext_map.
+        """
         dist = Distribution()
         cmd = build_ext(dist)
         cmd.ext_map['foo/bar'] = ''
         res = cmd.get_ext_filename('foo')
-        wanted = distutils_build_ext.get_ext_filename(cmd, 'foo')
+        wanted = orig.build_ext.get_ext_filename(cmd, 'foo')
         assert res == wanted
diff -Nru python-setuptools-3.3/setuptools/tests/test_develop.py python-setuptools-20.1.1/setuptools/tests/test_develop.py
--- python-setuptools-3.3/setuptools/tests/test_develop.py	2014-03-06 14:48:25.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_develop.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,17 +1,18 @@
 """develop tests
 """
 import os
-import shutil
 import site
 import sys
-import tempfile
-import unittest
+import io
+
+from setuptools.extern import six
+
+import pytest
 
-from distutils.errors import DistutilsError
 from setuptools.command.develop import develop
-from setuptools.command import easy_install as easy_install_pkg
-from setuptools.compat import StringIO
 from setuptools.dist import Distribution
+from . import contexts
+
 
 SETUP_PY = """\
 from setuptools import setup
@@ -25,100 +26,90 @@
 INIT_PY = """print "foo"
 """
 
-class TestDevelopTest(unittest.TestCase):
-
-    def setUp(self):
-        if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
-            return
-
-        # Directory structure
-        self.dir = tempfile.mkdtemp()
-        os.mkdir(os.path.join(self.dir, 'foo'))
-        # setup.py
-        setup = os.path.join(self.dir, 'setup.py')
-        f = open(setup, 'w')
+@pytest.yield_fixture
+def temp_user(monkeypatch):
+    with contexts.tempdir() as user_base:
+        with contexts.tempdir() as user_site:
+            monkeypatch.setattr('site.USER_BASE', user_base)
+            monkeypatch.setattr('site.USER_SITE', user_site)
+            yield
+
+
+@pytest.yield_fixture
+def test_env(tmpdir, temp_user):
+    target = tmpdir
+    foo = target.mkdir('foo')
+    setup = target / 'setup.py'
+    if setup.isfile():
+        raise ValueError(dir(target))
+    with setup.open('w') as f:
         f.write(SETUP_PY)
-        f.close()
-        self.old_cwd = os.getcwd()
-        # foo/__init__.py
-        init = os.path.join(self.dir, 'foo', '__init__.py')
-        f = open(init, 'w')
+    init = foo / '__init__.py'
+    with init.open('w') as f:
         f.write(INIT_PY)
-        f.close()
+    with target.as_cwd():
+        yield target
+
 
-        os.chdir(self.dir)
-        self.old_base = site.USER_BASE
-        site.USER_BASE = tempfile.mkdtemp()
-        self.old_site = site.USER_SITE
-        site.USER_SITE = tempfile.mkdtemp()
-
-    def tearDown(self):
-        if sys.version < "2.6" or hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
-            return
-
-        os.chdir(self.old_cwd)
-        shutil.rmtree(self.dir)
-        shutil.rmtree(site.USER_BASE)
-        shutil.rmtree(site.USER_SITE)
-        site.USER_BASE = self.old_base
-        site.USER_SITE = self.old_site
-
-    def test_develop(self):
-        if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
-            return
-        dist = Distribution(
-            dict(name='foo',
-                 packages=['foo'],
-                 use_2to3=True,
-                 version='0.0',
-                 ))
+class TestDevelop:
+    in_virtualenv = hasattr(sys, 'real_prefix')
+    in_venv = hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix
+    @pytest.mark.skipif(in_virtualenv or in_venv,
+        reason="Cannot run when invoked in a virtualenv or venv")
+    def test_2to3_user_mode(self, test_env):
+        settings = dict(
+            name='foo',
+            packages=['foo'],
+            use_2to3=True,
+            version='0.0',
+        )
+        dist = Distribution(settings)
         dist.script_name = 'setup.py'
         cmd = develop(dist)
         cmd.user = 1
         cmd.ensure_finalized()
         cmd.install_dir = site.USER_SITE
         cmd.user = 1
-        old_stdout = sys.stdout
-        #sys.stdout = StringIO()
-        try:
+        with contexts.quiet():
             cmd.run()
-        finally:
-            sys.stdout = old_stdout
 
         # let's see if we got our egg link at the right place
         content = os.listdir(site.USER_SITE)
         content.sort()
-        self.assertEqual(content, ['easy-install.pth', 'foo.egg-link'])
+        assert content == ['easy-install.pth', 'foo.egg-link']
 
         # Check that we are using the right code.
-        egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt')
-        try:
+        fn = os.path.join(site.USER_SITE, 'foo.egg-link')
+        with io.open(fn) as egg_link_file:
             path = egg_link_file.read().split()[0].strip()
-        finally:
-            egg_link_file.close()
-        init_file = open(os.path.join(path, 'foo', '__init__.py'), 'rt')
-        try:
+        fn = os.path.join(path, 'foo', '__init__.py')
+        with io.open(fn) as init_file:
             init = init_file.read().strip()
-        finally:
-            init_file.close()
-        if sys.version < "3":
-            self.assertEqual(init, 'print "foo"')
-        else:
-            self.assertEqual(init, 'print("foo")')
-
-    def notest_develop_with_setup_requires(self):
-
-        wanted = ("Could not find suitable distribution for "
-                  "Requirement.parse('I-DONT-EXIST')")
-        old_dir = os.getcwd()
-        os.chdir(self.dir)
-        try:
-            try:
-                dist = Distribution({'setup_requires': ['I_DONT_EXIST']})
-            except DistutilsError:
-                e = sys.exc_info()[1]
-                error = str(e)
-                if error ==  wanted:
-                    pass
-        finally:
-            os.chdir(old_dir)
+
+        expected = 'print("foo")' if six.PY3 else 'print "foo"'
+        assert init == expected
+
+    def test_console_scripts(self, tmpdir):
+        """
+        Test that console scripts are installed and that they reference
+        only the project by name and not the current version.
+        """
+        pytest.skip("TODO: needs a fixture to cause 'develop' "
+            "to be invoked without mutating environment.")
+        settings = dict(
+            name='foo',
+            packages=['foo'],
+            version='0.0',
+            entry_points={
+                'console_scripts': [
+                    'foocmd = foo:foo',
+                ],
+            },
+        )
+        dist = Distribution(settings)
+        dist.script_name = 'setup.py'
+        cmd = develop(dist)
+        cmd.ensure_finalized()
+        cmd.install_dir = tmpdir
+        cmd.run()
+        #assert '0.0' not in foocmd_text
diff -Nru python-setuptools-3.3/setuptools/tests/test_dist_info.py python-setuptools-20.1.1/setuptools/tests/test_dist_info.py
--- python-setuptools-3.3/setuptools/tests/test_dist_info.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_dist_info.py	2016-02-07 14:25:06.000000000 +0000
@@ -3,28 +3,22 @@
 import os
 import shutil
 import tempfile
-import unittest
-import textwrap
 
-try:
-    import ast
-except:
-    pass
+from setuptools.extern.six.moves import map
 
-import pkg_resources
+import pytest
 
-from setuptools.tests.py26compat import skipIf
+import pkg_resources
+from .textwrap import DALS
 
-def DALS(s):
-    "dedent and left-strip"
-    return textwrap.dedent(s).lstrip()
 
-class TestDistInfo(unittest.TestCase):
+class TestDistInfo:
 
     def test_distinfo(self):
-        dists = {}
-        for d in pkg_resources.find_distributions(self.tmpdir):
-            dists[d.project_name] = d
+        dists = dict(
+            (d.project_name, d)
+            for d in pkg_resources.find_distributions(self.tmpdir)
+        )
 
         assert len(dists) == 2, dists
 
@@ -34,50 +28,45 @@
         assert versioned.version == '2.718' # from filename
         assert unversioned.version == '0.3' # from METADATA
 
-    @skipIf('ast' not in globals(),
-        "ast is used to test conditional dependencies (Python >= 2.6)")
+    @pytest.mark.importorskip('ast')
     def test_conditional_dependencies(self):
-        requires = [pkg_resources.Requirement.parse('splort==4'),
-                    pkg_resources.Requirement.parse('quux>=1.1')]
+        specs = 'splort==4', 'quux>=1.1'
+        requires = list(map(pkg_resources.Requirement.parse, specs))
 
         for d in pkg_resources.find_distributions(self.tmpdir):
-            self.assertEqual(d.requires(), requires[:1])
-            self.assertEqual(d.requires(extras=('baz',)), requires)
-            self.assertEqual(d.extras, ['baz'])
+            assert d.requires() == requires[:1]
+            assert d.requires(extras=('baz',)) == requires
+            assert d.extras == ['baz']
+
+    metadata_template = DALS("""
+        Metadata-Version: 1.2
+        Name: {name}
+        {version}
+        Requires-Dist: splort (==4)
+        Provides-Extra: baz
+        Requires-Dist: quux (>=1.1); extra == 'baz'
+        """)
 
-    def setUp(self):
+    def setup_method(self, method):
         self.tmpdir = tempfile.mkdtemp()
-        versioned = os.path.join(self.tmpdir,
-                                 'VersionedDistribution-2.718.dist-info')
+        dist_info_name = 'VersionedDistribution-2.718.dist-info'
+        versioned = os.path.join(self.tmpdir, dist_info_name)
         os.mkdir(versioned)
-        metadata_file = open(os.path.join(versioned, 'METADATA'), 'w+')
-        try:
-            metadata_file.write(DALS(
-                """
-                Metadata-Version: 1.2
-                Name: VersionedDistribution
-                Requires-Dist: splort (4)
-                Provides-Extra: baz
-                Requires-Dist: quux (>=1.1); extra == 'baz'
-                """))
-        finally:
-            metadata_file.close()
-        unversioned = os.path.join(self.tmpdir,
-                                   'UnversionedDistribution.dist-info')
+        with open(os.path.join(versioned, 'METADATA'), 'w+') as metadata_file:
+            metadata = self.metadata_template.format(
+                name='VersionedDistribution',
+                version='',
+            ).replace('\n\n', '\n')
+            metadata_file.write(metadata)
+        dist_info_name = 'UnversionedDistribution.dist-info'
+        unversioned = os.path.join(self.tmpdir, dist_info_name)
         os.mkdir(unversioned)
-        metadata_file = open(os.path.join(unversioned, 'METADATA'), 'w+')
-        try:
-            metadata_file.write(DALS(
-                """
-                Metadata-Version: 1.2
-                Name: UnversionedDistribution
-                Version: 0.3
-                Requires-Dist: splort (==4)
-                Provides-Extra: baz
-                Requires-Dist: quux (>=1.1); extra == 'baz'
-                """))
-        finally:
-            metadata_file.close()
+        with open(os.path.join(unversioned, 'METADATA'), 'w+') as metadata_file:
+            metadata = self.metadata_template.format(
+                name='UnversionedDistribution',
+                version='Version: 0.3',
+            )
+            metadata_file.write(metadata)
 
-    def tearDown(self):
+    def teardown_method(self, method):
         shutil.rmtree(self.tmpdir)
diff -Nru python-setuptools-3.3/setuptools/tests/test_easy_install.py python-setuptools-20.1.1/setuptools/tests/test_easy_install.py
--- python-setuptools-3.3/setuptools/tests/test_easy_install.py	2014-03-15 12:37:21.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_easy_install.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,29 +1,47 @@
+# -*- coding: utf-8 -*-
+
 """Easy install Tests
 """
+from __future__ import absolute_import
+
 import sys
 import os
 import shutil
 import tempfile
-import unittest
 import site
 import contextlib
-import textwrap
 import tarfile
 import logging
-import distutils.core
-
-from setuptools.compat import StringIO, BytesIO, next, urlparse
-from setuptools.sandbox import run_setup, SandboxViolation
-from setuptools.command.easy_install import (
-    easy_install, fix_jython_executable, get_script_args, nt_quote_arg)
+import itertools
+import distutils.errors
+import io
+
+from setuptools.extern import six
+from setuptools.extern.six.moves import urllib
+import time
+
+import pytest
+try:
+    from unittest import mock
+except ImportError:
+    import mock
+
+from setuptools import sandbox
+from setuptools.sandbox import run_setup
+import setuptools.command.easy_install as ei
 from setuptools.command.easy_install import PthDistributions
 from setuptools.command import easy_install as easy_install_pkg
 from setuptools.dist import Distribution
-from pkg_resources import working_set, VersionConflict
+from pkg_resources import working_set
 from pkg_resources import Distribution as PRDistribution
 import setuptools.tests.server
 import pkg_resources
 
+from .py26compat import tarfile_open
+from . import contexts, is_ascii
+from .textwrap import DALS
+
+
 class FakeDist(object):
     def get_entry_map(self, group):
         if group != 'console_scripts':
@@ -33,218 +51,219 @@
     def as_requirement(self):
         return 'spec'
 
-WANTED = """\
-#!%s
-# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
-__requires__ = 'spec'
-import sys
-from pkg_resources import load_entry_point
+SETUP_PY = DALS("""
+    from setuptools import setup
 
-if __name__ == '__main__':
-    sys.exit(
-        load_entry_point('spec', 'console_scripts', 'name')()
-    )
-""" % nt_quote_arg(fix_jython_executable(sys.executable, ""))
+    setup(name='foo')
+    """)
 
-SETUP_PY = """\
-from setuptools import setup
-
-setup(name='foo')
-"""
-
-class TestEasyInstallTest(unittest.TestCase):
+class TestEasyInstallTest:
 
     def test_install_site_py(self):
         dist = Distribution()
-        cmd = easy_install(dist)
+        cmd = ei.easy_install(dist)
         cmd.sitepy_installed = False
         cmd.install_dir = tempfile.mkdtemp()
         try:
             cmd.install_site_py()
             sitepy = os.path.join(cmd.install_dir, 'site.py')
-            self.assertTrue(os.path.exists(sitepy))
+            assert os.path.exists(sitepy)
         finally:
             shutil.rmtree(cmd.install_dir)
 
     def test_get_script_args(self):
+        header = ei.CommandSpec.best().from_environment().as_header()
+        expected = header + DALS("""
+            # EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
+            __requires__ = 'spec'
+            import sys
+            from pkg_resources import load_entry_point
+
+            if __name__ == '__main__':
+                sys.exit(
+                    load_entry_point('spec', 'console_scripts', 'name')()
+                )
+            """)
         dist = FakeDist()
 
-        old_platform = sys.platform
-        try:
-            name, script = [i for i in next(get_script_args(dist))][0:2]
-        finally:
-            sys.platform = old_platform
+        args = next(ei.ScriptWriter.get_args(dist))
+        name, script = itertools.islice(args, 2)
 
-        self.assertEqual(script, WANTED)
+        assert script == expected
 
     def test_no_find_links(self):
         # new option '--no-find-links', that blocks find-links added at
         # the project level
         dist = Distribution()
-        cmd = easy_install(dist)
+        cmd = ei.easy_install(dist)
         cmd.check_pth_processing = lambda: True
         cmd.no_find_links = True
         cmd.find_links = ['link1', 'link2']
         cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
         cmd.args = ['ok']
         cmd.ensure_finalized()
-        self.assertEqual(cmd.package_index.scanned_urls, {})
+        assert cmd.package_index.scanned_urls == {}
 
         # let's try without it (default behavior)
-        cmd = easy_install(dist)
+        cmd = ei.easy_install(dist)
         cmd.check_pth_processing = lambda: True
         cmd.find_links = ['link1', 'link2']
         cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
         cmd.args = ['ok']
         cmd.ensure_finalized()
         keys = sorted(cmd.package_index.scanned_urls.keys())
-        self.assertEqual(keys, ['link1', 'link2'])
+        assert keys == ['link1', 'link2']
+
+    def test_write_exception(self):
+        """
+        Test that `cant_write_to_target` is rendered as a DistutilsError.
+        """
+        dist = Distribution()
+        cmd = ei.easy_install(dist)
+        cmd.install_dir = os.getcwd()
+        with pytest.raises(distutils.errors.DistutilsError):
+            cmd.cant_write_to_target()
 
 
-class TestPTHFileWriter(unittest.TestCase):
+class TestPTHFileWriter:
     def test_add_from_cwd_site_sets_dirty(self):
         '''a pth file manager should set dirty
         if a distribution is in site but also the cwd
         '''
         pth = PthDistributions('does-not_exist', [os.getcwd()])
-        self.assertTrue(not pth.dirty)
+        assert not pth.dirty
         pth.add(PRDistribution(os.getcwd()))
-        self.assertTrue(pth.dirty)
+        assert pth.dirty
 
     def test_add_from_site_is_ignored(self):
-        if os.name != 'nt':
-            location = '/test/location/does-not-have-to-exist'
-        else:
-            location = 'c:\\does_not_exist'
+        location = '/test/location/does-not-have-to-exist'
+        # PthDistributions expects all locations to be normalized
+        location = pkg_resources.normalize_path(location)
         pth = PthDistributions('does-not_exist', [location, ])
-        self.assertTrue(not pth.dirty)
+        assert not pth.dirty
         pth.add(PRDistribution(location))
-        self.assertTrue(not pth.dirty)
+        assert not pth.dirty
 
 
-class TestUserInstallTest(unittest.TestCase):
-
-    def setUp(self):
-        self.dir = tempfile.mkdtemp()
-        setup = os.path.join(self.dir, 'setup.py')
-        f = open(setup, 'w')
+@pytest.yield_fixture
+def setup_context(tmpdir):
+    with (tmpdir/'setup.py').open('w') as f:
         f.write(SETUP_PY)
-        f.close()
-        self.old_cwd = os.getcwd()
-        os.chdir(self.dir)
-
-        self.old_enable_site = site.ENABLE_USER_SITE
-        self.old_file = easy_install_pkg.__file__
-        self.old_base = site.USER_BASE
-        site.USER_BASE = tempfile.mkdtemp()
-        self.old_site = site.USER_SITE
-        site.USER_SITE = tempfile.mkdtemp()
-        easy_install_pkg.__file__ = site.USER_SITE
-
-    def tearDown(self):
-        os.chdir(self.old_cwd)
-        shutil.rmtree(self.dir)
-
-        shutil.rmtree(site.USER_BASE)
-        shutil.rmtree(site.USER_SITE)
-        site.USER_BASE = self.old_base
-        site.USER_SITE = self.old_site
-        site.ENABLE_USER_SITE = self.old_enable_site
-        easy_install_pkg.__file__ = self.old_file
-
-    def test_user_install_implied(self):
-        site.ENABLE_USER_SITE = True # disabled sometimes
-        #XXX: replace with something meaningfull
+    with tmpdir.as_cwd():
+        yield tmpdir
+
+
+@pytest.mark.usefixtures("user_override")
+@pytest.mark.usefixtures("setup_context")
+class TestUserInstallTest:
+
+    # prevent check that site-packages is writable. easy_install
+    # shouldn't be writing to system site-packages during finalize
+    # options, but while it does, bypass the behavior.
+    prev_sp_write = mock.patch(
+        'setuptools.command.easy_install.easy_install.check_site_dir',
+        mock.Mock(),
+    )
+
+    # simulate setuptools installed in user site packages
+    @mock.patch('setuptools.command.easy_install.__file__', site.USER_SITE)
+    @mock.patch('site.ENABLE_USER_SITE', True)
+    @prev_sp_write
+    def test_user_install_not_implied_user_site_enabled(self):
+        self.assert_not_user_site()
+
+    @mock.patch('site.ENABLE_USER_SITE', False)
+    @prev_sp_write
+    def test_user_install_not_implied_user_site_disabled(self):
+        self.assert_not_user_site()
+
+    @staticmethod
+    def assert_not_user_site():
+        # create a finalized easy_install command
         dist = Distribution()
         dist.script_name = 'setup.py'
-        cmd = easy_install(dist)
+        cmd = ei.easy_install(dist)
         cmd.args = ['py']
         cmd.ensure_finalized()
-        self.assertTrue(cmd.user, 'user should be implied')
+        assert not cmd.user, 'user should not be implied'
 
     def test_multiproc_atexit(self):
-        try:
-            __import__('multiprocessing')
-        except ImportError:
-            # skip the test if multiprocessing is not available
-            return
+        pytest.importorskip('multiprocessing')
 
         log = logging.getLogger('test_easy_install')
         logging.basicConfig(level=logging.INFO, stream=sys.stderr)
         log.info('this should not break')
 
-    def test_user_install_not_implied_without_usersite_enabled(self):
-        site.ENABLE_USER_SITE = False # usually enabled
-        #XXX: replace with something meaningfull
+    @pytest.fixture()
+    def foo_package(self, tmpdir):
+        egg_file = tmpdir / 'foo-1.0.egg-info'
+        with egg_file.open('w') as f:
+            f.write('Name: foo\n')
+        return str(tmpdir)
+
+    @pytest.yield_fixture()
+    def install_target(self, tmpdir):
+        target = str(tmpdir)
+        with mock.patch('sys.path', sys.path + [target]):
+            python_path = os.path.pathsep.join(sys.path)
+            with mock.patch.dict(os.environ, PYTHONPATH=python_path):
+                yield target
+
+    def test_local_index(self, foo_package, install_target):
+        """
+        The local index must be used when easy_install locates installed
+        packages.
+        """
         dist = Distribution()
         dist.script_name = 'setup.py'
-        cmd = easy_install(dist)
-        cmd.args = ['py']
-        cmd.initialize_options()
-        self.assertFalse(cmd.user, 'NOT user should be implied')
-
-    def test_local_index(self):
-        # make sure the local index is used
-        # when easy_install looks for installed
-        # packages
-        new_location = tempfile.mkdtemp()
-        target = tempfile.mkdtemp()
-        egg_file = os.path.join(new_location, 'foo-1.0.egg-info')
-        f = open(egg_file, 'w')
-        try:
-            f.write('Name: foo\n')
-        finally:
-            f.close()
+        cmd = ei.easy_install(dist)
+        cmd.install_dir = install_target
+        cmd.args = ['foo']
+        cmd.ensure_finalized()
+        cmd.local_index.scan([foo_package])
+        res = cmd.easy_install('foo')
+        actual = os.path.normcase(os.path.realpath(res.location))
+        expected = os.path.normcase(os.path.realpath(foo_package))
+        assert actual == expected
 
-        sys.path.append(target)
-        old_ppath = os.environ.get('PYTHONPATH')
-        os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
-        try:
-            dist = Distribution()
-            dist.script_name = 'setup.py'
-            cmd = easy_install(dist)
-            cmd.install_dir = target
-            cmd.args = ['foo']
-            cmd.ensure_finalized()
-            cmd.local_index.scan([new_location])
-            res = cmd.easy_install('foo')
-            actual = os.path.normcase(os.path.realpath(res.location))
-            expected = os.path.normcase(os.path.realpath(new_location))
-            self.assertEqual(actual, expected)
-        finally:
-            sys.path.remove(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:
-                del os.environ['PYTHONPATH']
-
-    def test_setup_requires(self):
-        """Regression test for Distribute issue #318
-
-        Ensure that a package with setup_requires can be installed when
-        setuptools is installed in the user site-packages without causing a
-        SandboxViolation.
+    @contextlib.contextmanager
+    def user_install_setup_context(self, *args, **kwargs):
+        """
+        Wrap sandbox.setup_context to patch easy_install in that context to
+        appear as user-installed.
         """
+        with self.orig_context(*args, **kwargs):
+            import setuptools.command.easy_install as ei
+            ei.__file__ = site.USER_SITE
+            yield
+
+    def patched_setup_context(self):
+        self.orig_context = sandbox.setup_context
+
+        return mock.patch(
+            'setuptools.sandbox.setup_context',
+            self.user_install_setup_context,
+        )
+
+
+@pytest.yield_fixture
+def distutils_package():
+    distutils_setup_py = SETUP_PY.replace(
+        'from setuptools import setup',
+        'from distutils.core import setup',
+    )
+    with contexts.tempdir(cd=os.chdir):
+        with open('setup.py', 'w') as f:
+            f.write(distutils_setup_py)
+        yield
 
-        test_pkg = create_setup_requires_package(self.dir)
-        test_setup_py = os.path.join(test_pkg, 'setup.py')
 
-        try:
-            with quiet_context():
-                with reset_setup_stop_context():
-                    run_setup(test_setup_py, ['install'])
-        except SandboxViolation:
-            self.fail('Installation caused SandboxViolation')
+class TestDistutilsPackage:
+    def test_bdist_egg_available_on_distutils_pkg(self, distutils_package):
+        run_setup('setup.py', ['bdist_egg'])
 
 
-class TestSetupRequires(unittest.TestCase):
+class TestSetupRequires:
 
     def test_setup_requires_honors_fetch_params(self):
         """
@@ -256,30 +275,32 @@
         p_index = setuptools.tests.server.MockServer()
         p_index.start()
         netloc = 1
-        p_index_loc = urlparse(p_index.url)[netloc]
+        p_index_loc = urllib.parse.urlparse(p_index.url)[netloc]
         if p_index_loc.endswith(':0'):
             # Some platforms (Jython) don't find a port to which to bind,
             #  so skip this test for them.
             return
-        with quiet_context():
+        with contexts.quiet():
             # create an sdist that has a build-time dependency.
             with TestSetupRequires.create_sdist() as dist_file:
-                with tempdir_context() as temp_install_dir:
-                    with environment_context(PYTHONPATH=temp_install_dir):
-                        ei_params = ['--index-url', p_index.url,
+                with contexts.tempdir() as temp_install_dir:
+                    with contexts.environment(PYTHONPATH=temp_install_dir):
+                        ei_params = [
+                            '--index-url', p_index.url,
                             '--allow-hosts', p_index_loc,
-                            '--exclude-scripts', '--install-dir', temp_install_dir,
-                            dist_file]
-                        with reset_setup_stop_context():
-                            with argv_context(['easy_install']):
-                                # attempt to install the dist. It should fail because
-                                #  it doesn't exist.
-                                self.assertRaises(SystemExit,
-                                    easy_install_pkg.main, ei_params)
+                            '--exclude-scripts',
+                            '--install-dir', temp_install_dir,
+                            dist_file,
+                        ]
+                        with sandbox.save_argv(['easy_install']):
+                            # attempt to install the dist. It should fail because
+                            #  it doesn't exist.
+                            with pytest.raises(SystemExit):
+                                easy_install_pkg.main(ei_params)
         # there should have been two or three requests to the server
         #  (three happens on Python 3.3a)
-        self.assertTrue(2 <= len(p_index.requests) <= 3)
-        self.assertEqual(p_index.requests[0].path, '/does-not-exist/')
+        assert 2 <= len(p_index.requests) <= 3
+        assert p_index.requests[0].path == '/does-not-exist/'
 
     @staticmethod
     @contextlib.contextmanager
@@ -288,64 +309,183 @@
         Return an sdist with a setup_requires dependency (of something that
         doesn't exist)
         """
-        with tempdir_context() as dir:
+        with contexts.tempdir() as dir:
             dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz')
-            make_trivial_sdist(
-                dist_path,
-                textwrap.dedent("""
+            make_sdist(dist_path, [
+                ('setup.py', DALS("""
                     import setuptools
                     setuptools.setup(
                         name="setuptools-test-fetcher",
                         version="1.0",
                         setup_requires = ['does-not-exist'],
                     )
-                """).lstrip())
+                """))])
             yield dist_path
 
     def test_setup_requires_overrides_version_conflict(self):
         """
-        Regression test for issue #323.
+        Regression test for distribution issue 323:
+        https://bitbucket.org/tarek/distribute/issues/323
 
         Ensures that a distribution's setup_requires requirements can still be
         installed and used locally even if a conflicting version of that
         requirement is already on the path.
         """
 
-        pr_state = pkg_resources.__getstate__()
         fake_dist = PRDistribution('does-not-matter', project_name='foobar',
                                    version='0.0')
         working_set.add(fake_dist)
 
-        try:
-            with tempdir_context() as temp_dir:
+        with contexts.save_pkg_resources_state():
+            with contexts.tempdir() as temp_dir:
                 test_pkg = create_setup_requires_package(temp_dir)
                 test_setup_py = os.path.join(test_pkg, 'setup.py')
-                with quiet_context() as (stdout, stderr):
-                    with reset_setup_stop_context():
-                        try:
-                            # Don't even need to install the package, just
-                            # running the setup.py at all is sufficient
-                            run_setup(test_setup_py, ['--name'])
-                        except VersionConflict:
-                            self.fail('Installing setup.py requirements '
-                                'caused a VersionConflict')
+                with contexts.quiet() as (stdout, stderr):
+                    # Don't even need to install the package, just
+                    # running the setup.py at all is sufficient
+                    run_setup(test_setup_py, ['--name'])
 
                 lines = stdout.readlines()
-                self.assertTrue(len(lines) > 0)
-                self.assertTrue(lines[-1].strip(), 'test_pkg')
-        finally:
-            pkg_resources.__setstate__(pr_state)
+                assert len(lines) > 0
+                assert lines[-1].strip(), 'test_pkg'
+
+    def test_setup_requires_override_nspkg(self):
+        """
+        Like ``test_setup_requires_overrides_version_conflict`` but where the
+        ``setup_requires`` package is part of a namespace package that has
+        *already* been imported.
+        """
 
+        with contexts.save_pkg_resources_state():
+            with contexts.tempdir() as temp_dir:
+                foobar_1_archive = os.path.join(temp_dir, 'foo.bar-0.1.tar.gz')
+                make_nspkg_sdist(foobar_1_archive, 'foo.bar', '0.1')
+                # Now actually go ahead an extract to the temp dir and add the
+                # extracted path to sys.path so foo.bar v0.1 is importable
+                foobar_1_dir = os.path.join(temp_dir, 'foo.bar-0.1')
+                os.mkdir(foobar_1_dir)
+                with tarfile_open(foobar_1_archive) as tf:
+                    tf.extractall(foobar_1_dir)
+                sys.path.insert(1, foobar_1_dir)
+
+                dist = PRDistribution(foobar_1_dir, project_name='foo.bar',
+                                      version='0.1')
+                working_set.add(dist)
+
+                template = DALS("""\
+                    import foo  # Even with foo imported first the
+                                # setup_requires package should override
+                    import setuptools
+                    setuptools.setup(**%r)
 
-def create_setup_requires_package(path):
+                    if not (hasattr(foo, '__path__') and
+                            len(foo.__path__) == 2):
+                        print('FAIL')
+
+                    if 'foo.bar-0.2' not in foo.__path__[0]:
+                        print('FAIL')
+                """)
+
+                test_pkg = create_setup_requires_package(
+                    temp_dir, 'foo.bar', '0.2', make_nspkg_sdist, template)
+
+                test_setup_py = os.path.join(test_pkg, 'setup.py')
+
+                with contexts.quiet() as (stdout, stderr):
+                    try:
+                        # Don't even need to install the package, just
+                        # running the setup.py at all is sufficient
+                        run_setup(test_setup_py, ['--name'])
+                    except pkg_resources.VersionConflict:
+                        self.fail('Installing setup.py requirements '
+                            'caused a VersionConflict')
+
+                assert 'FAIL' not in stdout.getvalue()
+                lines = stdout.readlines()
+                assert len(lines) > 0
+                assert lines[-1].strip() == 'test_pkg'
+
+
+def make_trivial_sdist(dist_path, distname, version):
+    """
+    Create a simple sdist tarball at dist_path, containing just a simple
+    setup.py.
+    """
+
+    make_sdist(dist_path, [
+        ('setup.py',
+         DALS("""\
+             import setuptools
+             setuptools.setup(
+                 name=%r,
+                 version=%r
+             )
+         """ % (distname, version)))])
+
+
+def make_nspkg_sdist(dist_path, distname, version):
+    """
+    Make an sdist tarball with distname and version which also contains one
+    package with the same name as distname.  The top-level package is
+    designated a namespace package).
+    """
+
+    parts = distname.split('.')
+    nspackage = parts[0]
+
+    packages = ['.'.join(parts[:idx]) for idx in range(1, len(parts) + 1)]
+
+    setup_py = DALS("""\
+        import setuptools
+        setuptools.setup(
+            name=%r,
+            version=%r,
+            packages=%r,
+            namespace_packages=[%r]
+        )
+    """ % (distname, version, packages, nspackage))
+
+    init = "__import__('pkg_resources').declare_namespace(__name__)"
+
+    files = [('setup.py', setup_py),
+             (os.path.join(nspackage, '__init__.py'), init)]
+    for package in packages[1:]:
+        filename = os.path.join(*(package.split('.') + ['__init__.py']))
+        files.append((filename, ''))
+
+    make_sdist(dist_path, files)
+
+
+def make_sdist(dist_path, files):
+    """
+    Create a simple sdist tarball at dist_path, containing the files
+    listed in ``files`` as ``(filename, content)`` tuples.
+    """
+
+    with tarfile_open(dist_path, 'w:gz') as dist:
+        for filename, content in files:
+            file_bytes = io.BytesIO(content.encode('utf-8'))
+            file_info = tarfile.TarInfo(name=filename)
+            file_info.size = len(file_bytes.getvalue())
+            file_info.mtime = int(time.time())
+            dist.addfile(file_info, fileobj=file_bytes)
+
+
+def create_setup_requires_package(path, distname='foobar', version='0.1',
+                                  make_package=make_trivial_sdist,
+                                  setup_py_template=None):
     """Creates a source tree under path for a trivial test package that has a
     single requirement in setup_requires--a tarball for that requirement is
     also created and added to the dependency_links argument.
+
+    ``distname`` and ``version`` refer to the name/version of the package that
+    the test package requires via ``setup_requires``.  The name of the test
+    package itself is just 'test_pkg'.
     """
 
     test_setup_attrs = {
         'name': 'test_pkg', 'version': '0.0',
-        'setup_requires': ['foobar==0.1'],
+        'setup_requires': ['%s==%s' % (distname, version)],
         'dependency_links': [os.path.abspath(path)]
     }
 
@@ -353,23 +493,17 @@
     test_setup_py = os.path.join(test_pkg, 'setup.py')
     os.mkdir(test_pkg)
 
-    f = open(test_setup_py, 'w')
-    f.write(textwrap.dedent("""\
-        import setuptools
-        setuptools.setup(**%r)
-    """ % test_setup_attrs))
-    f.close()
-
-    foobar_path = os.path.join(path, 'foobar-0.1.tar.gz')
-    make_trivial_sdist(
-        foobar_path,
-        textwrap.dedent("""\
+    if setup_py_template is None:
+        setup_py_template = DALS("""\
             import setuptools
-            setuptools.setup(
-                name='foobar',
-                version='0.1'
-            )
-        """))
+            setuptools.setup(**%r)
+        """)
+
+    with open(test_setup_py, 'w') as f:
+        f.write(setup_py_template % test_setup_attrs)
+
+    foobar_path = os.path.join(path, '%s-%s.tar.gz' % (distname, version))
+    make_package(foobar_path, distname, version)
 
     return test_pkg
 
@@ -380,78 +514,91 @@
     """
 
     setup_py_file = tarfile.TarInfo(name='setup.py')
-    try:
-        # Python 3 (StringIO gets converted to io module)
-        MemFile = BytesIO
-    except AttributeError:
-        MemFile = StringIO
-    setup_py_bytes = MemFile(setup_py.encode('utf-8'))
+    setup_py_bytes = io.BytesIO(setup_py.encode('utf-8'))
     setup_py_file.size = len(setup_py_bytes.getvalue())
-    dist = tarfile.open(dist_path, 'w:gz')
-    try:
+    with tarfile_open(dist_path, 'w:gz') as dist:
         dist.addfile(setup_py_file, fileobj=setup_py_bytes)
-    finally:
-        dist.close()
 
 
-@contextlib.contextmanager
-def tempdir_context(cd=lambda dir:None):
-    temp_dir = tempfile.mkdtemp()
-    orig_dir = os.getcwd()
-    try:
-        cd(temp_dir)
-        yield temp_dir
-    finally:
-        cd(orig_dir)
-        shutil.rmtree(temp_dir)
-
-@contextlib.contextmanager
-def environment_context(**updates):
-    old_env = os.environ.copy()
-    os.environ.update(updates)
-    try:
-        yield
-    finally:
-        for key in updates:
-            del os.environ[key]
-        os.environ.update(old_env)
-
-@contextlib.contextmanager
-def argv_context(repl):
-    old_argv = sys.argv[:]
-    sys.argv[:] = repl
-    yield
-    sys.argv[:] = old_argv
+class TestScriptHeader:
+    non_ascii_exe = '/Users/José/bin/python'
+    exe_with_spaces = r'C:\Program Files\Python33\python.exe'
+
+    @pytest.mark.skipif(
+        sys.platform.startswith('java') and ei.is_sh(sys.executable),
+        reason="Test cannot run under java when executable is sh"
+    )
+    def test_get_script_header(self):
+        expected = '#!%s\n' % ei.nt_quote_arg(os.path.normpath(sys.executable))
+        actual = ei.ScriptWriter.get_script_header('#!/usr/local/bin/python')
+        assert actual == expected
+
+        expected = '#!%s -x\n' % ei.nt_quote_arg(os.path.normpath
+            (sys.executable))
+        actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python -x')
+        assert actual == expected
+
+        actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
+            executable=self.non_ascii_exe)
+        expected = '#!%s -x\n' % self.non_ascii_exe
+        assert actual == expected
+
+        actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
+            executable='"'+self.exe_with_spaces+'"')
+        expected = '#!"%s"\n' % self.exe_with_spaces
+        assert actual == expected
 
-@contextlib.contextmanager
-def reset_setup_stop_context():
-    """
-    When the setuptools tests are run using setup.py test, and then
-    one wants to invoke another setup() command (such as easy_install)
-    within those tests, it's necessary to reset the global variable
-    in distutils.core so that the setup() command will run naturally.
-    """
-    setup_stop_after = distutils.core._setup_stop_after
-    distutils.core._setup_stop_after = None
-    yield
-    distutils.core._setup_stop_after = setup_stop_after
 
+class TestCommandSpec:
+    def test_custom_launch_command(self):
+        """
+        Show how a custom CommandSpec could be used to specify a #! executable
+        which takes parameters.
+        """
+        cmd = ei.CommandSpec(['/usr/bin/env', 'python3'])
+        assert cmd.as_header() == '#!/usr/bin/env python3\n'
+
+    def test_from_param_for_CommandSpec_is_passthrough(self):
+        """
+        from_param should return an instance of a CommandSpec
+        """
+        cmd = ei.CommandSpec(['python'])
+        cmd_new = ei.CommandSpec.from_param(cmd)
+        assert cmd is cmd_new
+
+    @mock.patch('sys.executable', TestScriptHeader.exe_with_spaces)
+    @mock.patch.dict(os.environ)
+    def test_from_environment_with_spaces_in_executable(self):
+        os.environ.pop('__PYVENV_LAUNCHER__', None)
+        cmd = ei.CommandSpec.from_environment()
+        assert len(cmd) == 1
+        assert cmd.as_header().startswith('#!"')
+
+    def test_from_simple_string_uses_shlex(self):
+        """
+        In order to support `executable = /usr/bin/env my-python`, make sure
+        from_param invokes shlex on that input.
+        """
+        cmd = ei.CommandSpec.from_param('/usr/bin/env my-python')
+        assert len(cmd) == 2
+        assert '"' not in cmd.as_header()
+
+    def test_sys_executable(self):
+        """
+        CommandSpec.from_string(sys.executable) should contain just that param.
+        """
+        writer = ei.ScriptWriter.best()
+        cmd = writer.command_spec_class.from_string(sys.executable)
+        assert len(cmd) == 1
+        assert cmd[0] == sys.executable
 
-@contextlib.contextmanager
-def quiet_context():
-    """
-    Redirect stdout/stderr to StringIO objects to prevent console output from
-    distutils commands.
-    """
 
-    old_stdout = sys.stdout
-    old_stderr = sys.stderr
-    new_stdout = sys.stdout = StringIO()
-    new_stderr = sys.stderr = StringIO()
-    try:
-        yield new_stdout, new_stderr
-    finally:
-        new_stdout.seek(0)
-        new_stderr.seek(0)
-        sys.stdout = old_stdout
-        sys.stderr = old_stderr
+class TestWindowsScriptWriter:
+    def test_header(self):
+        hdr = ei.WindowsScriptWriter.get_script_header('')
+        assert hdr.startswith('#!')
+        assert hdr.endswith('\n')
+        hdr = hdr.lstrip('#!')
+        hdr = hdr.rstrip('\n')
+        # header should not start with an escaped quote
+        assert not hdr.startswith('\\"')
diff -Nru python-setuptools-3.3/setuptools/tests/test_egg_info.py python-setuptools-20.1.1/setuptools/tests/test_egg_info.py
--- python-setuptools-3.3/setuptools/tests/test_egg_info.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_egg_info.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,173 +1,125 @@
-
 import os
-import sys
-import tempfile
-import shutil
-import unittest
-
-import pkg_resources
-import warnings
-from setuptools.command import egg_info
-from setuptools import svn_utils
-from setuptools.tests import environment, test_svn
-from setuptools.tests.py26compat import skipIf
-
-ENTRIES_V10 = pkg_resources.resource_string(__name__, 'entries-v10')
-"An entries file generated with svn 1.6.17 against the legacy Setuptools repo"
-
-
-class TestEggInfo(unittest.TestCase):
-
-    def setUp(self):
-        self.test_dir = tempfile.mkdtemp()
-        os.mkdir(os.path.join(self.test_dir, '.svn'))
-
-        self.old_cwd = os.getcwd()
-        os.chdir(self.test_dir)
-
-    def tearDown(self):
-        os.chdir(self.old_cwd)
-        shutil.rmtree(self.test_dir)
-
-    def _write_entries(self, entries):
-        fn = os.path.join(self.test_dir, '.svn', 'entries')
-        entries_f = open(fn, 'wb')
-        entries_f.write(entries)
-        entries_f.close()
-   
-    @skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
-    def test_version_10_format(self):
-        """
-        """
-        #keeping this set for 1.6 is a good check on the get_svn_revision
-        #to ensure I return using svnversion what would had been returned
-        version_str = svn_utils.SvnInfo.get_svn_version()
-        version = [int(x) for x in version_str.split('.')[:2]]
-        if version != [1, 6]:
-            if hasattr(self, 'skipTest'):
-                self.skipTest('')
-            else:
-                sys.stderr.write('\n   Skipping due to SVN Version\n')
-                return
-
-        self._write_entries(ENTRIES_V10)
-        rev = egg_info.egg_info.get_svn_revision()
-        self.assertEqual(rev, '89000')
-
-    def test_version_10_format_legacy_parser(self):
-        """
-        """
-        path_variable = None
-        for env in os.environ:
-            if env.lower() == 'path':
-                path_variable = env
-
-        if path_variable:
-            old_path = os.environ[path_variable]
-            os.environ[path_variable] = ''
-        #catch_warnings not available until py26
-        warning_filters = warnings.filters
-        warnings.filters = warning_filters[:]
-        try:
-            warnings.simplefilter("ignore", DeprecationWarning)
-            self._write_entries(ENTRIES_V10)
-            rev = egg_info.egg_info.get_svn_revision()
-        finally:
-            #restore the warning filters
-            warnings.filters = warning_filters
-            #restore the os path
-            if path_variable:
-                os.environ[path_variable] = old_path
-
-        self.assertEqual(rev, '89000')
-
-DUMMY_SOURCE_TXT = """CHANGES.txt
-CONTRIBUTORS.txt
-HISTORY.txt
-LICENSE
-MANIFEST.in
-README.txt
-setup.py
-dummy/__init__.py
-dummy/test.txt
-dummy.egg-info/PKG-INFO
-dummy.egg-info/SOURCES.txt
-dummy.egg-info/dependency_links.txt
-dummy.egg-info/top_level.txt"""
-
-
-class TestSvnDummy(environment.ZippedEnvironment):
-
-    def setUp(self):
-        version = svn_utils.SvnInfo.get_svn_version()
-        if not version:  # None or Empty
-            return None
-
-        self.base_version = tuple([int(x) for x in version.split('.')][:2])
-
-        if not self.base_version:
-            raise ValueError('No SVN tools installed')
-        elif self.base_version < (1, 3):
-            raise ValueError('Insufficient SVN Version %s' % version)
-        elif self.base_version >= (1, 9):
-            #trying the latest version
-            self.base_version = (1, 8)
-
-        self.dataname = "dummy%i%i" % self.base_version
-        self.datafile = os.path.join('setuptools', 'tests',
-                                     'svn_data', self.dataname + ".zip")
-        super(TestSvnDummy, self).setUp()
-
-    @skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
-    def test_sources(self):
-        code, data = environment.run_setup_py(["sdist"],
-                                              pypath=self.old_cwd,
-                                              data_stream=1)
-        if code:
-            raise AssertionError(data)
+import stat
 
-        sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
-        infile = open(sources, 'r')
-        try:
-            read_contents = infile.read()
-        finally:
-            infile.close()
-            del infile
-
-        self.assertEqual(DUMMY_SOURCE_TXT, read_contents)
-
-        return data
-
-
-class TestSvnDummyLegacy(environment.ZippedEnvironment):
-
-    def setUp(self):
-        self.base_version = (1, 6)
-        self.dataname = "dummy%i%i" % self.base_version
-        self.datafile = os.path.join('setuptools', 'tests',
-                                     'svn_data', self.dataname + ".zip")
-        super(TestSvnDummyLegacy, self).setUp()
-
-    def test_sources(self):
-        code, data = environment.run_setup_py(["sdist"],
-                                              pypath=self.old_cwd,
-                                              path="",
-                                              data_stream=1)
-        if code:
-            raise AssertionError(data)
+from setuptools.extern.six.moves import map
 
-        sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
-        infile = open(sources, 'r')
-        try:
-            read_contents = infile.read()
-        finally:
-            infile.close()
-            del infile
-
-        self.assertEqual(DUMMY_SOURCE_TXT, read_contents)
-
-        return data
+import pytest
 
+from . import environment
+from .files import build_files
+from .textwrap import DALS
+from . import contexts
+
+
+class Environment(str):
+    pass
+
+
+class TestEggInfo(object):
+
+    setup_script = DALS("""
+        from setuptools import setup
+
+        setup(
+            name='foo',
+            py_modules=['hello'],
+            entry_points={'console_scripts': ['hi = hello.run']},
+            zip_safe=False,
+        )
+        """)
+
+    def _create_project(self):
+        build_files({
+            'setup.py': self.setup_script,
+            'hello.py': DALS("""
+                def run():
+                    print('hello')
+                """)
+        })
+
+    @pytest.yield_fixture
+    def env(self):
+        with contexts.tempdir(prefix='setuptools-test.') as env_dir:
+            env = Environment(env_dir)
+            os.chmod(env_dir, stat.S_IRWXU)
+            subs = 'home', 'lib', 'scripts', 'data', 'egg-base'
+            env.paths = dict(
+                (dirname, os.path.join(env_dir, dirname))
+                for dirname in subs
+            )
+            list(map(os.mkdir, env.paths.values()))
+            build_files({
+                env.paths['home']: {
+                    '.pydistutils.cfg': DALS("""
+                    [egg_info]
+                    egg-base = %(egg-base)s
+                    """ % env.paths)
+                }
+            })
+            yield env
+
+    def test_egg_base_installed_egg_info(self, tmpdir_cwd, env):
+        self._create_project()
+
+        self._run_install_command(tmpdir_cwd, env)
+        actual = self._find_egg_info_files(env.paths['lib'])
+
+        expected = [
+            'PKG-INFO',
+            'SOURCES.txt',
+            'dependency_links.txt',
+            'entry_points.txt',
+            'not-zip-safe',
+            'top_level.txt',
+        ]
+        assert sorted(actual) == expected
+
+    def test_manifest_template_is_read(self, tmpdir_cwd, env):
+        self._create_project()
+        build_files({
+            'MANIFEST.in': DALS("""
+                recursive-include docs *.rst
+            """),
+            'docs': {
+                'usage.rst': "Run 'hi'",
+            }
+        })
+        self._run_install_command(tmpdir_cwd, env)
+        egg_info_dir = self._find_egg_info_files(env.paths['lib']).base
+        sources_txt = os.path.join(egg_info_dir, 'SOURCES.txt')
+        assert 'docs/usage.rst' in open(sources_txt).read().split('\n')
+
+    def _run_install_command(self, tmpdir_cwd, env):
+        environ = os.environ.copy().update(
+            HOME=env.paths['home'],
+        )
+        cmd = [
+            'install',
+            '--home', env.paths['home'],
+            '--install-lib', env.paths['lib'],
+            '--install-scripts', env.paths['scripts'],
+            '--install-data', env.paths['data'],
+        ]
+        code, data = environment.run_setup_py(
+            cmd=cmd,
+            pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
+            data_stream=1,
+            env=environ,
+        )
+        if code:
+            raise AssertionError(data)
 
-def test_suite():
-    return unittest.defaultTestLoader.loadTestsFromName(__name__)
+    def _find_egg_info_files(self, root):
+        class DirList(list):
+            def __init__(self, files, base):
+                super(DirList, self).__init__(files)
+                self.base = base
+
+        results = (
+            DirList(filenames, dirpath)
+            for dirpath, dirnames, filenames in os.walk(root)
+            if os.path.basename(dirpath) == 'EGG-INFO'
+        )
+        # expect exactly one result
+        result, = results
+        return result
diff -Nru python-setuptools-3.3/setuptools/tests/test_find_packages.py python-setuptools-20.1.1/setuptools/tests/test_find_packages.py
--- python-setuptools-3.3/setuptools/tests/test_find_packages.py	2014-03-16 08:53:16.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_find_packages.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,19 +1,45 @@
 """Tests for setuptools.find_packages()."""
 import os
+import sys
 import shutil
 import tempfile
-import unittest
+import platform
 
+import pytest
+
+import setuptools
 from setuptools import find_packages
 
+find_420_packages = setuptools.PEP420PackageFinder.find
+
+# modeled after CPython's test.support.can_symlink
+def can_symlink():
+    TESTFN = tempfile.mktemp()
+    symlink_path = TESTFN + "can_symlink"
+    try:
+        os.symlink(TESTFN, symlink_path)
+        can = True
+    except (OSError, NotImplementedError, AttributeError):
+        can = False
+    else:
+        os.remove(symlink_path)
+    globals().update(can_symlink=lambda: can)
+    return can
+
+def has_symlink():
+    bad_symlink = (
+        # Windows symlink directory detection is broken on Python 3.2
+        platform.system() == 'Windows' and sys.version_info[:2] == (3,2)
+    )
+    return can_symlink() and not bad_symlink
 
-class TestFindPackages(unittest.TestCase):
+class TestFindPackages:
 
-    def setUp(self):
+    def setup_method(self, method):
         self.dist_dir = tempfile.mkdtemp()
         self._make_pkg_structure()
 
-    def tearDown(self):
+    def teardown_method(self, method):
         shutil.rmtree(self.dist_dir)
 
     def _make_pkg_structure(self):
@@ -61,7 +87,12 @@
     def test_regular_package(self):
         self._touch('__init__.py', self.pkg_dir)
         packages = find_packages(self.dist_dir)
-        self.assertEqual(packages, ['pkg', 'pkg.subpkg'])
+        assert packages == ['pkg', 'pkg.subpkg']
+
+    def test_exclude(self):
+        self._touch('__init__.py', self.pkg_dir)
+        packages = find_packages(self.dist_dir, exclude=('pkg.*',))
+        assert packages == ['pkg']
 
     def test_include_excludes_other(self):
         """
@@ -71,7 +102,7 @@
         alt_dir = self._mkdir('other_pkg', self.dist_dir)
         self._touch('__init__.py', alt_dir)
         packages = find_packages(self.dist_dir, include=['other_pkg'])
-        self.assertEqual(packages, ['other_pkg'])
+        assert packages == ['other_pkg']
 
     def test_dir_with_dot_is_skipped(self):
         shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
@@ -79,4 +110,61 @@
         self._touch('__init__.py', data_dir)
         self._touch('file.dat', data_dir)
         packages = find_packages(self.dist_dir)
-        self.assertTrue('pkg.some.data' not in packages)
+        assert 'pkg.some.data' not in packages
+
+    def test_dir_with_packages_in_subdir_is_excluded(self):
+        """
+        Ensure that a package in a non-package such as build/pkg/__init__.py
+        is excluded.
+        """
+        build_dir = self._mkdir('build', self.dist_dir)
+        build_pkg_dir = self._mkdir('pkg', build_dir)
+        self._touch('__init__.py', build_pkg_dir)
+        packages = find_packages(self.dist_dir)
+        assert 'build.pkg' not in packages
+
+    @pytest.mark.skipif(not has_symlink(), reason='Symlink support required')
+    def test_symlinked_packages_are_included(self):
+        """
+        A symbolically-linked directory should be treated like any other
+        directory when matched as a package.
+
+        Create a link from lpkg -> pkg.
+        """
+        self._touch('__init__.py', self.pkg_dir)
+        linked_pkg = os.path.join(self.dist_dir, 'lpkg')
+        os.symlink('pkg', linked_pkg)
+        assert os.path.isdir(linked_pkg)
+        packages = find_packages(self.dist_dir)
+        assert 'lpkg' in packages
+
+    def _assert_packages(self, actual, expected):
+        assert set(actual) == set(expected)
+
+    def test_pep420_ns_package(self):
+        packages = find_420_packages(
+            self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets'])
+        self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
+
+    def test_pep420_ns_package_no_includes(self):
+        packages = find_420_packages(
+            self.dist_dir, exclude=['pkg.subpkg.assets'])
+        self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
+
+    def test_pep420_ns_package_no_includes_or_excludes(self):
+        packages = find_420_packages(self.dist_dir)
+        expected = [
+            'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
+        self._assert_packages(packages, expected)
+
+    def test_regular_package_with_nested_pep420_ns_packages(self):
+        self._touch('__init__.py', self.pkg_dir)
+        packages = find_420_packages(
+            self.dist_dir, exclude=['docs', 'pkg.subpkg.assets'])
+        self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
+
+    def test_pep420_ns_package_no_non_package_dirs(self):
+        shutil.rmtree(self.docs_dir)
+        shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
+        packages = find_420_packages(self.dist_dir)
+        self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
diff -Nru python-setuptools-3.3/setuptools/tests/test_integration.py python-setuptools-20.1.1/setuptools/tests/test_integration.py
--- python-setuptools-3.3/setuptools/tests/test_integration.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_integration.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,99 @@
+"""Run some integration tests.
+
+Try to install a few packages.
+"""
+
+import glob
+import os
+import sys
+
+from setuptools.extern.six.moves import urllib
+import pytest
+
+from setuptools.command.easy_install import easy_install
+from setuptools.command import easy_install as easy_install_pkg
+from setuptools.dist import Distribution
+
+
+def setup_module(module):
+    packages = 'stevedore', 'virtualenvwrapper', 'pbr', 'novaclient'
+    for pkg in packages:
+        try:
+            __import__(pkg)
+            tmpl = "Integration tests cannot run when {pkg} is installed"
+            pytest.skip(tmpl.format(**locals()))
+        except ImportError:
+            pass
+
+    try:
+        urllib.request.urlopen('https://pypi.python.org/pypi')
+    except Exception as exc:
+        pytest.skip(str(exc))
+
+
+@pytest.fixture
+def install_context(request, tmpdir, monkeypatch):
+    """Fixture to set up temporary installation directory.
+    """
+    # Save old values so we can restore them.
+    new_cwd = tmpdir.mkdir('cwd')
+    user_base = tmpdir.mkdir('user_base')
+    user_site = tmpdir.mkdir('user_site')
+    install_dir = tmpdir.mkdir('install_dir')
+
+    def fin():
+        # undo the monkeypatch, particularly needed under
+        # windows because of kept handle on cwd
+        monkeypatch.undo()
+        new_cwd.remove()
+        user_base.remove()
+        user_site.remove()
+        install_dir.remove()
+    request.addfinalizer(fin)
+
+    # Change the environment and site settings to control where the
+    # files are installed and ensure we do not overwrite anything.
+    monkeypatch.chdir(new_cwd)
+    monkeypatch.setattr(easy_install_pkg, '__file__', user_site.strpath)
+    monkeypatch.setattr('site.USER_BASE', user_base.strpath)
+    monkeypatch.setattr('site.USER_SITE', user_site.strpath)
+    monkeypatch.setattr('sys.path', sys.path + [install_dir.strpath])
+    monkeypatch.setenv('PYTHONPATH', os.path.pathsep.join(sys.path))
+
+    # Set up the command for performing the installation.
+    dist = Distribution()
+    cmd = easy_install(dist)
+    cmd.install_dir = install_dir.strpath
+    return cmd
+
+
+def _install_one(requirement, cmd, pkgname, modulename):
+    cmd.args = [requirement]
+    cmd.ensure_finalized()
+    cmd.run()
+    target = cmd.install_dir
+    dest_path = glob.glob(os.path.join(target, pkgname + '*.egg'))
+    assert dest_path
+    assert os.path.exists(os.path.join(dest_path[0], pkgname, modulename))
+
+
+def test_stevedore(install_context):
+    _install_one('stevedore', install_context,
+                 'stevedore', 'extension.py')
+
+
+@pytest.mark.xfail
+def test_virtualenvwrapper(install_context):
+    _install_one('virtualenvwrapper', install_context,
+                 'virtualenvwrapper', 'hook_loader.py')
+
+
+def test_pbr(install_context):
+    _install_one('pbr', install_context,
+                 'pbr', 'core.py')
+
+
+@pytest.mark.xfail
+def test_python_novaclient(install_context):
+    _install_one('python-novaclient', install_context,
+                 'novaclient', 'base.py')
diff -Nru python-setuptools-3.3/setuptools/tests/test_markerlib.py python-setuptools-20.1.1/setuptools/tests/test_markerlib.py
--- python-setuptools-3.3/setuptools/tests/test_markerlib.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_markerlib.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,48 +1,43 @@
 import os
-import unittest
-from setuptools.tests.py26compat import skipIf
 
-try:
-    import ast
-except ImportError:
-    pass
+import pytest
 
-class TestMarkerlib(unittest.TestCase):
 
-    @skipIf('ast' not in globals(),
-        "ast not available (Python < 2.6?)")
+class TestMarkerlib:
+
+    @pytest.mark.importorskip('ast')
     def test_markers(self):
         from _markerlib import interpret, default_environment, compile
-        
+
         os_name = os.name
-        
-        self.assertTrue(interpret(""))
-        
-        self.assertTrue(interpret("os.name != 'buuuu'"))
-        self.assertTrue(interpret("os_name != 'buuuu'"))
-        self.assertTrue(interpret("python_version > '1.0'"))
-        self.assertTrue(interpret("python_version < '5.0'"))
-        self.assertTrue(interpret("python_version <= '5.0'"))
-        self.assertTrue(interpret("python_version >= '1.0'"))
-        self.assertTrue(interpret("'%s' in os.name" % os_name))
-        self.assertTrue(interpret("'%s' in os_name" % os_name))
-        self.assertTrue(interpret("'buuuu' not in os.name"))
-        
-        self.assertFalse(interpret("os.name == 'buuuu'"))
-        self.assertFalse(interpret("os_name == 'buuuu'"))
-        self.assertFalse(interpret("python_version < '1.0'"))
-        self.assertFalse(interpret("python_version > '5.0'"))
-        self.assertFalse(interpret("python_version >= '5.0'"))
-        self.assertFalse(interpret("python_version <= '1.0'"))
-        self.assertFalse(interpret("'%s' not in os.name" % os_name))
-        self.assertFalse(interpret("'buuuu' in os.name and python_version >= '5.0'"))    
-        self.assertFalse(interpret("'buuuu' in os_name and python_version >= '5.0'"))    
-        
+
+        assert interpret("")
+
+        assert interpret("os.name != 'buuuu'")
+        assert interpret("os_name != 'buuuu'")
+        assert interpret("python_version > '1.0'")
+        assert interpret("python_version < '5.0'")
+        assert interpret("python_version <= '5.0'")
+        assert interpret("python_version >= '1.0'")
+        assert interpret("'%s' in os.name" % os_name)
+        assert interpret("'%s' in os_name" % os_name)
+        assert interpret("'buuuu' not in os.name")
+
+        assert not interpret("os.name == 'buuuu'")
+        assert not interpret("os_name == 'buuuu'")
+        assert not interpret("python_version < '1.0'")
+        assert not interpret("python_version > '5.0'")
+        assert not interpret("python_version >= '5.0'")
+        assert not interpret("python_version <= '1.0'")
+        assert not interpret("'%s' not in os.name" % os_name)
+        assert not interpret("'buuuu' in os.name and python_version >= '5.0'")
+        assert not interpret("'buuuu' in os_name and python_version >= '5.0'")
+
         environment = default_environment()
         environment['extra'] = 'test'
-        self.assertTrue(interpret("extra == 'test'", environment))
-        self.assertFalse(interpret("extra == 'doc'", environment))
-        
+        assert interpret("extra == 'test'", environment)
+        assert not interpret("extra == 'doc'", environment)
+
         def raises_nameError():
             try:
                 interpret("python.version == '42'")
@@ -50,9 +45,9 @@
                 pass
             else:
                 raise Exception("Expected NameError")
-        
+
         raises_nameError()
-        
+
         def raises_syntaxError():
             try:
                 interpret("(x for x in (4,))")
@@ -60,9 +55,9 @@
                 pass
             else:
                 raise Exception("Expected SyntaxError")
-            
+
         raises_syntaxError()
-        
+
         statement = "python_version == '5'"
-        self.assertEqual(compile(statement).__doc__, statement)
-        
+        assert compile(statement).__doc__ == statement
+
diff -Nru python-setuptools-3.3/setuptools/tests/test_msvc9compiler.py python-setuptools-20.1.1/setuptools/tests/test_msvc9compiler.py
--- python-setuptools-3.3/setuptools/tests/test_msvc9compiler.py	1970-01-01 00:00:00.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_msvc9compiler.py	2016-02-07 14:25:06.000000000 +0000
@@ -0,0 +1,179 @@
+"""
+Tests for msvc9compiler.
+"""
+
+import os
+import contextlib
+import distutils.errors
+
+import pytest
+try:
+    from unittest import mock
+except ImportError:
+    import mock
+
+from . import contexts
+
+# importing only setuptools should apply the patch
+__import__('setuptools')
+
+pytest.importorskip("distutils.msvc9compiler")
+
+
+def mock_reg(hkcu=None, hklm=None):
+    """
+    Return a mock for distutils.msvc9compiler.Reg, patched
+    to mock out the functions that access the registry.
+    """
+
+    _winreg = getattr(distutils.msvc9compiler, '_winreg', None)
+    winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg)
+
+    hives = {
+        winreg.HKEY_CURRENT_USER: hkcu or {},
+        winreg.HKEY_LOCAL_MACHINE: hklm or {},
+    }
+
+    @classmethod
+    def read_keys(cls, base, key):
+        """Return list of registry keys."""
+        hive = hives.get(base, {})
+        return [
+            k.rpartition('\\')[2]
+            for k in hive if k.startswith(key.lower())
+        ]
+
+    @classmethod
+    def read_values(cls, base, key):
+        """Return dict of registry keys and values."""
+        hive = hives.get(base, {})
+        return dict(
+            (k.rpartition('\\')[2], hive[k])
+            for k in hive if k.startswith(key.lower())
+        )
+
+    return mock.patch.multiple(distutils.msvc9compiler.Reg,
+        read_keys=read_keys, read_values=read_values)
+
+
+class TestModulePatch:
+    """
+    Ensure that importing setuptools is sufficient to replace
+    the standard find_vcvarsall function with a version that
+    recognizes the "Visual C++ for Python" package.
+    """
+
+    key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir'
+    key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir'
+
+    def test_patched(self):
+        "Test the module is actually patched"
+        mod_name = distutils.msvc9compiler.find_vcvarsall.__module__
+        assert mod_name == "setuptools.msvc9_support", "find_vcvarsall unpatched"
+
+    def test_no_registry_entryies_means_nothing_found(self):
+        """
+        No registry entries or environment variable should lead to an error
+        directing the user to download vcpython27.
+        """
+        find_vcvarsall = distutils.msvc9compiler.find_vcvarsall
+        query_vcvarsall = distutils.msvc9compiler.query_vcvarsall
+
+        with contexts.environment(VS90COMNTOOLS=None):
+            with mock_reg():
+                assert find_vcvarsall(9.0) is None
+
+                expected = distutils.errors.DistutilsPlatformError
+                with pytest.raises(expected) as exc:
+                    query_vcvarsall(9.0)
+                assert 'aka.ms/vcpython27' in str(exc)
+
+    @pytest.yield_fixture
+    def user_preferred_setting(self):
+        """
+        Set up environment with different install dirs for user vs. system
+        and yield the user_install_dir for the expected result.
+        """
+        with self.mock_install_dir() as user_install_dir:
+            with self.mock_install_dir() as system_install_dir:
+                reg = mock_reg(
+                    hkcu={
+                        self.key_32: user_install_dir,
+                    },
+                    hklm={
+                        self.key_32: system_install_dir,
+                        self.key_64: system_install_dir,
+                    },
+                )
+                with reg:
+                    yield user_install_dir
+
+    def test_prefer_current_user(self, user_preferred_setting):
+        """
+        Ensure user's settings are preferred.
+        """
+        result = distutils.msvc9compiler.find_vcvarsall(9.0)
+        expected = os.path.join(user_preferred_setting, 'vcvarsall.bat')
+        assert expected == result
+
+    @pytest.yield_fixture
+    def local_machine_setting(self):
+        """
+        Set up environment with only the system environment configured.
+        """
+        with self.mock_install_dir() as system_install_dir:
+            reg = mock_reg(
+                hklm={
+                    self.key_32: system_install_dir,
+                },
+            )
+            with reg:
+                yield system_install_dir
+
+    def test_local_machine_recognized(self, local_machine_setting):
+        """
+        Ensure machine setting is honored if user settings are not present.
+        """
+        result = distutils.msvc9compiler.find_vcvarsall(9.0)
+        expected = os.path.join(local_machine_setting, 'vcvarsall.bat')
+        assert expected == result
+
+    @pytest.yield_fixture
+    def x64_preferred_setting(self):
+        """
+        Set up environment with 64-bit and 32-bit system settings configured
+        and yield the canonical location.
+        """
+        with self.mock_install_dir() as x32_dir:
+            with self.mock_install_dir() as x64_dir:
+                reg = mock_reg(
+                    hklm={
+                        # This *should* only exist on 32-bit machines
+                        self.key_32: x32_dir,
+                        # This *should* only exist on 64-bit machines
+                        self.key_64: x64_dir,
+                    },
+                )
+                with reg:
+                    yield x32_dir
+
+    def test_ensure_64_bit_preferred(self, x64_preferred_setting):
+        """
+        Ensure 64-bit system key is preferred.
+        """
+        result = distutils.msvc9compiler.find_vcvarsall(9.0)
+        expected = os.path.join(x64_preferred_setting, 'vcvarsall.bat')
+        assert expected == result
+
+    @staticmethod
+    @contextlib.contextmanager
+    def mock_install_dir():
+        """
+        Make a mock install dir in a unique location so that tests can
+        distinguish which dir was detected in a given scenario.
+        """
+        with contexts.tempdir() as result:
+            vcvarsall = os.path.join(result, 'vcvarsall.bat')
+            with open(vcvarsall, 'w'):
+                pass
+            yield result
diff -Nru python-setuptools-3.3/setuptools/tests/test_packageindex.py python-setuptools-20.1.1/setuptools/tests/test_packageindex.py
--- python-setuptools-3.3/setuptools/tests/test_packageindex.py	2014-02-12 03:53:22.000000000 +0000
+++ python-setuptools-20.1.1/setuptools/tests/test_packageindex.py	2016-02-07 14:25:06.000000000 +0000
@@ -1,26 +1,29 @@
-"""Package Index Tests
-"""
+from __future__ import absolute_import
+
 import sys
 import os
-import unittest
-import pkg_resources
-from setuptools.compat import urllib2, httplib, HTTPError, unicode, pathname2url
 import distutils.errors
+
+from setuptools.extern import six
+from setuptools.extern.six.moves import urllib, http_client
+
+from .textwrap import DALS
+import pkg_resources
 import setuptools.package_index
 from setuptools.tests.server import IndexServer
 
-class TestPackageIndex(unittest.TestCase):
+
+class TestPackageIndex:
 
     def test_bad_url_bad_port(self):
         index = setuptools.package_index.PackageIndex()
         url = 'http://127.0.0.1:0/nonesuch/test_package_index'
         try:
             v = index.open_url(url)
-        except Exception:
-            v = sys.exc_info()[1]
-            self.assertTrue(url in str(v))
+        except Exception as v:
+            assert url in str(v)
         else:
-            self.assertTrue(isinstance(v, HTTPError))
+            assert isinstance(v, urllib.error.HTTPError)
 
     def test_bad_url_typo(self):
         # issue 16
@@ -33,11 +36,10 @@
         url = 'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk'
         try:
             v = index.open_url(url)
-        except Exception:
-            v = sys.exc_info()[1]
-            self.assertTrue(url in str(v))
+        except Exception as v:
+            assert url in str(v)
         else:
-            self.assertTrue(isinstance(v, HTTPError))
+            assert isinstance(v, urllib.error.HTTPError)
 
     def test_bad_url_bad_status_line(self):
         index = setuptools.package_index.PackageIndex(
@@ -45,15 +47,14 @@
         )
 
         def _urlopen(*args):
-            raise httplib.BadStatusLine('line')
+            raise http_client.BadStatusLine('line')
 
         index.opener = _urlopen
         url = 'http://example.com'
         try:
             v = index.open_url(url)
-        except Exception:
-            v = sys.exc_info()[1]
-            self.assertTrue('line' in str(v))
+        except Exception as v:
+            assert 'line' in str(v)
         else:
             raise AssertionError('Should have raise here!')
 
@@ -69,9 +70,8 @@
         url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk'
         try:
             index.open_url(url)
-        except distutils.errors.DistutilsError:
-            error = sys.exc_info()[1]
-            msg = unicode(error)
+        except distutils.errors.DistutilsError as error:
+            msg = six.text_type(error)
             assert 'nonnumeric port' in msg or 'getaddrinfo failed' in msg or 'Name or service not known' in msg
             return
         raise RuntimeError("Did not raise")
@@ -94,7 +94,7 @@
             hosts=('www.example.com',)
         )
         url = 'file:///tmp/test_package_index'
-        self.assertTrue(index.url_ok(url, True))
+        assert index.url_ok(url, True)
 
     def test_links_priority(self):
         """
@@ -127,21 +127,30 @@
         server.stop()
 
         # the distribution has been found
-        self.assertTrue('foobar' in pi)
+        assert 'foobar' in pi
         # we have only one link, because links are compared without md5
-        self.assertTrue(len(pi['foobar'])==1)
+        assert len(pi['foobar'])==1
         # the link should be from the index
-        self.assertTrue('correct_md5' in pi['foobar'][0].location)
+        assert 'correct_md5' in pi['foobar'][0].location
 
     def test_parse_bdist_wininst(self):
-        self.assertEqual(setuptools.package_index.parse_bdist_wininst(
-            'reportlab-2.5.win32-py2.4.exe'), ('reportlab-2.5', '2.4', 'win32'))
-        self.assertEqual(setuptools.package_index.parse_bdist_wininst(
-            'reportlab-2.5.win32.exe'), ('reportlab-2.5', None, 'win32'))
-        self.assertEqual(setuptools.package_index.parse_bdist_wininst(
-            'reportlab-2.5.win-amd64-py2.7.exe'), ('reportlab-2.5', '2.7', 'win-amd64'))
-        self.assertEqual(setuptools.package_index.parse_bdist_wininst(
-            'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64'))
+        parse = setuptools.package_index.parse_bdist_wininst
+
+        actual = parse('reportlab-2.5.win32-py2.4.exe')
+        expected = 'reportlab-2.5', '2.4', 'win32'
+        assert actual == expected
+
+        actual = parse('reportlab-2.5.win32.exe')
+        expected = 'reportlab-2.5', None, 'win32'
+        assert actual == expected
+
+        actual = parse('reportlab-2.5.win-amd64-py2.7.exe')
+        expected = 'reportlab-2.5', '2.7', 'win-amd64'
+        assert actual == expected
+
+        actual = parse('reportlab-2.5.win-amd64.exe')
+        expected = 'reportlab-2.5', None, 'win-amd64'
+        assert actual == expected
 
     def test__vcs_split_rev_from_url(self):
         """
@@ -149,55 +158,68 @@
         """
         vsrfu = setuptools.package_index.PackageIndex._vcs_split_rev_from_url
         url, rev = vsrfu('https://example.com/bar@2995')
-        self.assertEqual(url, 'https://example.com/bar')
-        self.assertEqual(rev, '2995')
+        assert url == 'https://example.com/bar'
+        assert rev == '2995'
 
-    def test_local_index(self):
+    def test_local_index(self, tmpdir):
         """
         local_open should be able to read an index from the file system.
         """
-        f = open('index.html', 'w')
-        f.write('
content
') - f.close() - try: - url = 'file:' + pathname2url(os.getcwd()) + '/' - res = setuptools.package_index.local_open(url) - finally: - os.remove('index.html') + index_file = tmpdir / 'index.html' + with index_file.open('w') as f: + f.write('
content
') + url = 'file:' + urllib.request.pathname2url(str(tmpdir)) + '/' + res = setuptools.package_index.local_open(url) assert 'content' in res.read() -class TestContentCheckers(unittest.TestCase): +class TestContentCheckers: def test_md5(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') checker.feed('You should probably not be using MD5'.encode('ascii')) - self.assertEqual(checker.hash.hexdigest(), - 'f12895fdffbd45007040d2e44df98478') - self.assertTrue(checker.is_valid()) + assert checker.hash.hexdigest() == 'f12895fdffbd45007040d2e44df98478' + assert checker.is_valid() def test_other_fragment(self): "Content checks should succeed silently if no hash is present" checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#something%20completely%20different') checker.feed('anything'.encode('ascii')) - self.assertTrue(checker.is_valid()) + assert checker.is_valid() def test_blank_md5(self): "Content checks should succeed if a hash is empty" checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=') checker.feed('anything'.encode('ascii')) - self.assertTrue(checker.is_valid()) + assert checker.is_valid() def test_get_hash_name_md5(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') - self.assertEqual(checker.hash_name, 'md5') + assert checker.hash_name == 'md5' def test_report(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') rep = checker.report(lambda x: x, 'My message about %s') - self.assertEqual(rep, 'My message about md5') + assert rep == 'My message about md5' + + +class TestPyPIConfig: + def test_percent_in_password(self, tmpdir, monkeypatch): + monkeypatch.setitem(os.environ, 'HOME', str(tmpdir)) + pypirc = tmpdir / '.pypirc' + with pypirc.open('w') as strm: + strm.write(DALS(""" + [pypi] + repository=https://pypi.python.org + username=jaraco + password=pity% + """)) + cfg = setuptools.package_index.PyPIConfig() + cred = cfg.creds_by_repository['https://pypi.python.org'] + assert cred.username == 'jaraco' + assert cred.password == 'pity%' diff -Nru python-setuptools-3.3/setuptools/tests/test_resources.py python-setuptools-20.1.1/setuptools/tests/test_resources.py --- python-setuptools-3.3/setuptools/tests/test_resources.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_resources.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,620 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# NOTE: the shebang and encoding lines are for ScriptHeaderTests do not remove - -import os -import sys -import tempfile -import shutil -from unittest import TestCase - -import pkg_resources -from pkg_resources import (parse_requirements, VersionConflict, parse_version, - Distribution, EntryPoint, Requirement, safe_version, safe_name, - WorkingSet) - -from setuptools.command.easy_install import (get_script_header, is_sh, - nt_quote_arg) -from setuptools.compat import StringIO, iteritems - -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) < pkg_resources._MAX_LENGTH: - return result - return result[:pkg_resources._MAX_LENGTH] + ' [truncated]...' - -class Metadata(pkg_resources.EmptyProvider): - """Mock object to return metadata as if from an on-disk distribution""" - - def __init__(self,*pairs): - self.metadata = dict(pairs) - - def has_metadata(self,name): - return name in self.metadata - - def get_metadata(self,name): - return self.metadata[name] - - def get_metadata_lines(self,name): - return pkg_resources.yield_lines(self.get_metadata(name)) - -dist_from_fn = pkg_resources.Distribution.from_filename - -class DistroTests(TestCase): - - def testCollection(self): - # empty path should produce no distributions - ad = pkg_resources.Environment([], platform=None, python=None) - self.assertEqual(list(ad), []) - self.assertEqual(ad['FooPkg'],[]) - ad.add(dist_from_fn("FooPkg-1.3_1.egg")) - ad.add(dist_from_fn("FooPkg-1.4-py2.4-win32.egg")) - ad.add(dist_from_fn("FooPkg-1.2-py2.4.egg")) - - # Name is in there now - self.assertTrue(ad['FooPkg']) - # But only 1 package - self.assertEqual(list(ad), ['foopkg']) - - # Distributions sort by version - self.assertEqual( - [dist.version for dist in ad['FooPkg']], ['1.4','1.3-1','1.2'] - ) - # Removing a distribution leaves sequence alone - ad.remove(ad['FooPkg'][1]) - self.assertEqual( - [dist.version for dist in ad['FooPkg']], ['1.4','1.2'] - ) - # And inserting adds them in order - ad.add(dist_from_fn("FooPkg-1.9.egg")) - self.assertEqual( - [dist.version for dist in ad['FooPkg']], ['1.9','1.4','1.2'] - ) - - ws = WorkingSet([]) - foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg") - foo14 = dist_from_fn("FooPkg-1.4-py2.4-win32.egg") - req, = parse_requirements("FooPkg>=1.3") - - # Nominal case: no distros on path, should yield all applicable - self.assertEqual(ad.best_match(req,ws).version, '1.9') - # If a matching distro is already installed, should return only that - ws.add(foo14) - self.assertEqual(ad.best_match(req,ws).version, '1.4') - - # If the first matching distro is unsuitable, it's a version conflict - ws = WorkingSet([]) - ws.add(foo12) - ws.add(foo14) - self.assertRaises(VersionConflict, ad.best_match, req, ws) - - # If more than one match on the path, the first one takes precedence - ws = WorkingSet([]) - ws.add(foo14) - ws.add(foo12) - ws.add(foo14) - self.assertEqual(ad.best_match(req,ws).version, '1.4') - - def checkFooPkg(self,d): - self.assertEqual(d.project_name, "FooPkg") - self.assertEqual(d.key, "foopkg") - self.assertEqual(d.version, "1.3-1") - self.assertEqual(d.py_version, "2.4") - self.assertEqual(d.platform, "win32") - self.assertEqual(d.parsed_version, parse_version("1.3-1")) - - def testDistroBasics(self): - d = Distribution( - "/some/path", - project_name="FooPkg",version="1.3-1",py_version="2.4",platform="win32" - ) - self.checkFooPkg(d) - - d = Distribution("/some/path") - self.assertEqual(d.py_version, sys.version[:3]) - self.assertEqual(d.platform, None) - - def testDistroParse(self): - d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg") - self.checkFooPkg(d) - d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg-info") - self.checkFooPkg(d) - - def testDistroMetadata(self): - d = Distribution( - "/some/path", project_name="FooPkg", py_version="2.4", platform="win32", - metadata = Metadata( - ('PKG-INFO',"Metadata-Version: 1.0\nVersion: 1.3-1\n") - ) - ) - self.checkFooPkg(d) - - def distRequires(self, txt): - return Distribution("/foo", metadata=Metadata(('depends.txt', txt))) - - def checkRequires(self, dist, txt, extras=()): - self.assertEqual( - list(dist.requires(extras)), - list(parse_requirements(txt)) - ) - - def testDistroDependsSimple(self): - for v in "Twisted>=1.5", "Twisted>=1.5\nZConfig>=2.0": - self.checkRequires(self.distRequires(v), v) - - def testResolve(self): - ad = pkg_resources.Environment([]) - ws = WorkingSet([]) - # Resolving no requirements -> nothing to install - self.assertEqual(list(ws.resolve([],ad)), []) - # Request something not in the collection -> DistributionNotFound - self.assertRaises( - pkg_resources.DistributionNotFound, ws.resolve, parse_requirements("Foo"), ad - ) - Foo = Distribution.from_filename( - "/foo_dir/Foo-1.2.egg", - metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")) - ) - ad.add(Foo) - ad.add(Distribution.from_filename("Foo-0.9.egg")) - - # Request thing(s) that are available -> list to activate - for i in range(3): - targets = list(ws.resolve(parse_requirements("Foo"), ad)) - self.assertEqual(targets, [Foo]) - list(map(ws.add,targets)) - self.assertRaises(VersionConflict, ws.resolve, - parse_requirements("Foo==0.9"), ad) - ws = WorkingSet([]) # reset - - # Request an extra that causes an unresolved dependency for "Baz" - self.assertRaises( - pkg_resources.DistributionNotFound, ws.resolve,parse_requirements("Foo[bar]"), ad - ) - Baz = Distribution.from_filename( - "/foo_dir/Baz-2.1.egg", metadata=Metadata(('depends.txt', "Foo")) - ) - ad.add(Baz) - - # Activation list now includes resolved dependency - self.assertEqual( - list(ws.resolve(parse_requirements("Foo[bar]"), ad)), [Foo,Baz] - ) - # Requests for conflicting versions produce VersionConflict - self.assertRaises(VersionConflict, - ws.resolve, parse_requirements("Foo==1.2\nFoo!=1.2"), ad) - - def testDistroDependsOptions(self): - d = self.distRequires(""" - Twisted>=1.5 - [docgen] - ZConfig>=2.0 - docutils>=0.3 - [fastcgi] - fcgiapp>=0.1""") - self.checkRequires(d,"Twisted>=1.5") - self.checkRequires( - d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3".split(), ["docgen"] - ) - self.checkRequires( - d,"Twisted>=1.5 fcgiapp>=0.1".split(), ["fastcgi"] - ) - self.checkRequires( - d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3 fcgiapp>=0.1".split(), - ["docgen","fastcgi"] - ) - self.checkRequires( - d,"Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), - ["fastcgi", "docgen"] - ) - self.assertRaises(pkg_resources.UnknownExtra, d.requires, ["foo"]) - - -class EntryPointTests(TestCase): - - def assertfields(self, ep): - self.assertEqual(ep.name,"foo") - self.assertEqual(ep.module_name,"setuptools.tests.test_resources") - self.assertEqual(ep.attrs, ("EntryPointTests",)) - self.assertEqual(ep.extras, ("x",)) - self.assertTrue(ep.load() is EntryPointTests) - self.assertEqual( - str(ep), - "foo = setuptools.tests.test_resources:EntryPointTests [x]" - ) - - def setUp(self): - self.dist = Distribution.from_filename( - "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt','[x]'))) - - def testBasics(self): - ep = EntryPoint( - "foo", "setuptools.tests.test_resources", ["EntryPointTests"], - ["x"], self.dist - ) - self.assertfields(ep) - - def testParse(self): - s = "foo = setuptools.tests.test_resources:EntryPointTests [x]" - ep = EntryPoint.parse(s, self.dist) - self.assertfields(ep) - - ep = EntryPoint.parse("bar baz= spammity[PING]") - self.assertEqual(ep.name,"bar baz") - self.assertEqual(ep.module_name,"spammity") - self.assertEqual(ep.attrs, ()) - self.assertEqual(ep.extras, ("ping",)) - - ep = EntryPoint.parse(" fizzly = wocka:foo") - self.assertEqual(ep.name,"fizzly") - self.assertEqual(ep.module_name,"wocka") - self.assertEqual(ep.attrs, ("foo",)) - self.assertEqual(ep.extras, ()) - - def testRejects(self): - for ep in [ - "foo", "x=1=2", "x=a:b:c", "q=x/na", "fez=pish:tush-z", "x=f[a]>2", - ]: - try: EntryPoint.parse(ep) - except ValueError: pass - else: raise AssertionError("Should've been bad", ep) - - def checkSubMap(self, m): - self.assertEqual(len(m), len(self.submap_expect)) - for key, ep in iteritems(self.submap_expect): - self.assertEqual(repr(m.get(key)), repr(ep)) - - submap_expect = dict( - feature1=EntryPoint('feature1', 'somemodule', ['somefunction']), - feature2=EntryPoint('feature2', 'another.module', ['SomeClass'], ['extra1','extra2']), - feature3=EntryPoint('feature3', 'this.module', extras=['something']) - ) - submap_str = """ - # define features for blah blah - feature1 = somemodule:somefunction - feature2 = another.module:SomeClass [extra1,extra2] - feature3 = this.module [something] - """ - - def testParseList(self): - self.checkSubMap(EntryPoint.parse_group("xyz", self.submap_str)) - self.assertRaises(ValueError, EntryPoint.parse_group, "x a", "foo=bar") - self.assertRaises(ValueError, EntryPoint.parse_group, "x", - ["foo=baz", "foo=bar"]) - - def testParseMap(self): - m = EntryPoint.parse_map({'xyz':self.submap_str}) - self.checkSubMap(m['xyz']) - self.assertEqual(list(m.keys()),['xyz']) - m = EntryPoint.parse_map("[xyz]\n"+self.submap_str) - self.checkSubMap(m['xyz']) - self.assertEqual(list(m.keys()),['xyz']) - self.assertRaises(ValueError, EntryPoint.parse_map, ["[xyz]", "[xyz]"]) - self.assertRaises(ValueError, EntryPoint.parse_map, self.submap_str) - -class RequirementsTests(TestCase): - - def testBasics(self): - r = Requirement.parse("Twisted>=1.2") - self.assertEqual(str(r),"Twisted>=1.2") - self.assertEqual(repr(r),"Requirement.parse('Twisted>=1.2')") - self.assertEqual(r, Requirement("Twisted", [('>=','1.2')], ())) - self.assertEqual(r, Requirement("twisTed", [('>=','1.2')], ())) - self.assertNotEqual(r, Requirement("Twisted", [('>=','2.0')], ())) - self.assertNotEqual(r, Requirement("Zope", [('>=','1.2')], ())) - self.assertNotEqual(r, Requirement("Zope", [('>=','3.0')], ())) - self.assertNotEqual(r, Requirement.parse("Twisted[extras]>=1.2")) - - def testOrdering(self): - r1 = Requirement("Twisted", [('==','1.2c1'),('>=','1.2')], ()) - r2 = Requirement("Twisted", [('>=','1.2'),('==','1.2c1')], ()) - self.assertEqual(r1,r2) - self.assertEqual(str(r1),str(r2)) - self.assertEqual(str(r2),"Twisted==1.2c1,>=1.2") - - def testBasicContains(self): - r = Requirement("Twisted", [('>=','1.2')], ()) - foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg") - twist11 = Distribution.from_filename("Twisted-1.1.egg") - twist12 = Distribution.from_filename("Twisted-1.2.egg") - self.assertTrue(parse_version('1.2') in r) - self.assertTrue(parse_version('1.1') not in r) - self.assertTrue('1.2' in r) - self.assertTrue('1.1' not in r) - self.assertTrue(foo_dist not in r) - self.assertTrue(twist11 not in r) - self.assertTrue(twist12 in r) - - def testAdvancedContains(self): - r, = parse_requirements("Foo>=1.2,<=1.3,==1.9,>2.0,!=2.5,<3.0,==4.5") - for v in ('1.2','1.2.2','1.3','1.9','2.0.1','2.3','2.6','3.0c1','4.5'): - self.assertTrue(v in r, (v,r)) - for v in ('1.2c1','1.3.1','1.5','1.9.1','2.0','2.5','3.0','4.0'): - self.assertTrue(v not in r, (v,r)) - - def testOptionsAndHashing(self): - r1 = Requirement.parse("Twisted[foo,bar]>=1.2") - r2 = Requirement.parse("Twisted[bar,FOO]>=1.2") - r3 = Requirement.parse("Twisted[BAR,FOO]>=1.2.0") - self.assertEqual(r1,r2) - self.assertEqual(r1,r3) - self.assertEqual(r1.extras, ("foo","bar")) - self.assertEqual(r2.extras, ("bar","foo")) # extras are normalized - self.assertEqual(hash(r1), hash(r2)) - self.assertEqual( - hash(r1), hash(("twisted", ((">=",parse_version("1.2")),), - frozenset(["foo","bar"]))) - ) - - def testVersionEquality(self): - r1 = Requirement.parse("foo==0.3a2") - r2 = Requirement.parse("foo!=0.3a4") - d = Distribution.from_filename - - self.assertTrue(d("foo-0.3a4.egg") not in r1) - self.assertTrue(d("foo-0.3a1.egg") not in r1) - self.assertTrue(d("foo-0.3a4.egg") not in r2) - - self.assertTrue(d("foo-0.3a2.egg") in r1) - self.assertTrue(d("foo-0.3a2.egg") in r2) - self.assertTrue(d("foo-0.3a3.egg") in r2) - self.assertTrue(d("foo-0.3a5.egg") in r2) - - def testSetuptoolsProjectName(self): - """ - The setuptools project should implement the setuptools package. - """ - - self.assertEqual( - Requirement.parse('setuptools').project_name, 'setuptools') - # setuptools 0.7 and higher means setuptools. - self.assertEqual( - Requirement.parse('setuptools == 0.7').project_name, 'setuptools') - self.assertEqual( - Requirement.parse('setuptools == 0.7a1').project_name, 'setuptools') - self.assertEqual( - Requirement.parse('setuptools >= 0.7').project_name, 'setuptools') - - -class ParseTests(TestCase): - - def testEmptyParse(self): - self.assertEqual(list(parse_requirements('')), []) - - def testYielding(self): - for inp,out in [ - ([], []), ('x',['x']), ([[]],[]), (' x\n y', ['x','y']), - (['x\n\n','y'], ['x','y']), - ]: - self.assertEqual(list(pkg_resources.yield_lines(inp)),out) - - def testSplitting(self): - sample = """ - x - [Y] - z - - a - [b ] - # foo - c - [ d] - [q] - v - """ - self.assertEqual(list(pkg_resources.split_sections(sample)), - [(None,["x"]), ("Y",["z","a"]), ("b",["c"]), ("d",[]), ("q",["v"])] - ) - self.assertRaises(ValueError,list,pkg_resources.split_sections("[foo")) - - def testSafeName(self): - self.assertEqual(safe_name("adns-python"), "adns-python") - self.assertEqual(safe_name("WSGI Utils"), "WSGI-Utils") - self.assertEqual(safe_name("WSGI Utils"), "WSGI-Utils") - self.assertEqual(safe_name("Money$$$Maker"), "Money-Maker") - self.assertNotEqual(safe_name("peak.web"), "peak-web") - - def testSafeVersion(self): - self.assertEqual(safe_version("1.2-1"), "1.2-1") - self.assertEqual(safe_version("1.2 alpha"), "1.2.alpha") - self.assertEqual(safe_version("2.3.4 20050521"), "2.3.4.20050521") - self.assertEqual(safe_version("Money$$$Maker"), "Money-Maker") - self.assertEqual(safe_version("peak.web"), "peak.web") - - def testSimpleRequirements(self): - self.assertEqual( - list(parse_requirements('Twis-Ted>=1.2-1')), - [Requirement('Twis-Ted',[('>=','1.2-1')], ())] - ) - self.assertEqual( - list(parse_requirements('Twisted >=1.2, \ # more\n<2.0')), - [Requirement('Twisted',[('>=','1.2'),('<','2.0')], ())] - ) - self.assertEqual( - Requirement.parse("FooBar==1.99a3"), - Requirement("FooBar", [('==','1.99a3')], ()) - ) - self.assertRaises(ValueError,Requirement.parse,">=2.3") - self.assertRaises(ValueError,Requirement.parse,"x\\") - self.assertRaises(ValueError,Requirement.parse,"x==2 q") - self.assertRaises(ValueError,Requirement.parse,"X==1\nY==2") - self.assertRaises(ValueError,Requirement.parse,"#") - - def testVersionEquality(self): - def c(s1,s2): - 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('1.2a1', '1.2.a.1') - c('1.2...a', '1.2a') - - def testVersionOrdering(self): - def c(s1,s2): - p1, p2 = parse_version(s1),parse_version(s2) - self.assertTrue(p1= (3,) and os.environ.get("LC_CTYPE") - in (None, "C", "POSIX")): - return - - class java: - class lang: - class System: - @staticmethod - def getProperty(property): - return "" - sys.modules["java"] = java - - platform = sys.platform - sys.platform = 'java1.5.0_13' - stdout, stderr = sys.stdout, sys.stderr - try: - # A mock sys.executable that uses a shebang line (this file) - exe = os.path.normpath(os.path.splitext(__file__)[0] + '.py') - self.assertEqual( - get_script_header('#!/usr/local/bin/python', executable=exe), - '#!/usr/bin/env %s\n' % exe) - - # Ensure we generate what is basically a broken shebang line - # when there's options, with a warning emitted - sys.stdout = sys.stderr = StringIO() - self.assertEqual(get_script_header('#!/usr/bin/python -x', - executable=exe), - '#!%s -x\n' % exe) - self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue()) - sys.stdout = sys.stderr = StringIO() - self.assertEqual(get_script_header('#!/usr/bin/python', - executable=self.non_ascii_exe), - '#!%s -x\n' % self.non_ascii_exe) - self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue()) - finally: - del sys.modules["java"] - sys.platform = platform - sys.stdout, sys.stderr = stdout, stderr - - -class NamespaceTests(TestCase): - - def setUp(self): - self._ns_pkgs = pkg_resources._namespace_packages.copy() - self._tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-") - os.makedirs(os.path.join(self._tmpdir, "site-pkgs")) - self._prev_sys_path = sys.path[:] - sys.path.append(os.path.join(self._tmpdir, "site-pkgs")) - - def tearDown(self): - shutil.rmtree(self._tmpdir) - 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 - Create namespace packages in the following tree : - site-packages-1/pkg1/pkg2 - site-packages-2/pkg1/pkg2 - Check both are in the _namespace_packages dict and that their __path__ - is correct - """ - sys.path.append(os.path.join(self._tmpdir, "site-pkgs2")) - os.makedirs(os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2")) - os.makedirs(os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2")) - ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" - for site in ["site-pkgs", "site-pkgs2"]: - pkg1_init = open(os.path.join(self._tmpdir, site, - "pkg1", "__init__.py"), "w") - pkg1_init.write(ns_str) - pkg1_init.close() - pkg2_init = open(os.path.join(self._tmpdir, site, - "pkg1", "pkg2", "__init__.py"), "w") - pkg2_init.write(ns_str) - pkg2_init.close() - import pkg1 - self._assertIn("pkg1", pkg_resources._namespace_packages.keys()) - try: - import pkg1.pkg2 - except ImportError: - self.fail("Setuptools tried to import the parent namespace package") - # check the _namespace_packages dict - 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__, [ - os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"), - os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2")]) diff -Nru python-setuptools-3.3/setuptools/tests/test_sandbox.py python-setuptools-20.1.1/setuptools/tests/test_sandbox.py --- python-setuptools-3.3/setuptools/tests/test_sandbox.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_sandbox.py 2016-02-07 14:25:06.000000000 +0000 @@ -1,69 +1,43 @@ """develop tests """ -import sys import os -import shutil -import unittest -import tempfile import types +import pytest + import pkg_resources import setuptools.sandbox -from setuptools.sandbox import DirectorySandbox, SandboxViolation +from setuptools.sandbox import DirectorySandbox + + +class TestSandbox: -def has_win32com(): - """ - Run this to determine if the local machine has win32com, and if it - does, include additional tests. - """ - if not sys.platform.startswith('win32'): - return False - try: - mod = __import__('win32com') - except ImportError: - return False - return True - -class TestSandbox(unittest.TestCase): - - def setUp(self): - self.dir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.dir) - - def test_devnull(self): - if sys.version < '2.4': - return - sandbox = DirectorySandbox(self.dir) + def test_devnull(self, tmpdir): + sandbox = DirectorySandbox(str(tmpdir)) sandbox.run(self._file_writer(os.devnull)) + @staticmethod def _file_writer(path): def do_write(): - f = open(path, 'w') - f.write('xxx') - f.close() + with open(path, 'w') as f: + f.write('xxx') return do_write - _file_writer = staticmethod(_file_writer) - - if has_win32com(): - def test_win32com(self): - """ - win32com should not be prevented from caching COM interfaces - in gen_py. - """ - import win32com - gen_py = win32com.__gen_path__ - target = os.path.join(gen_py, 'test_write') - sandbox = DirectorySandbox(self.dir) - try: - try: - sandbox.run(self._file_writer(target)) - except SandboxViolation: - self.fail("Could not create gen_py file due to SandboxViolation") - finally: - if os.path.exists(target): os.remove(target) + def test_win32com(self, tmpdir): + """ + win32com should not be prevented from caching COM interfaces + in gen_py. + """ + win32com = pytest.importorskip('win32com') + gen_py = win32com.__gen_path__ + target = os.path.join(gen_py, 'test_write') + sandbox = DirectorySandbox(str(tmpdir)) + try: + # attempt to create gen_py file + sandbox.run(self._file_writer(target)) + finally: + if os.path.exists(target): + os.remove(target) def test_setup_py_with_BOM(self): """ @@ -72,8 +46,96 @@ target = pkg_resources.resource_filename(__name__, 'script-with-bom.py') namespace = types.ModuleType('namespace') - setuptools.sandbox.execfile(target, vars(namespace)) + setuptools.sandbox._execfile(target, vars(namespace)) assert namespace.result == 'passed' -if __name__ == '__main__': - unittest.main() + def test_setup_py_with_CRLF(self, tmpdir): + setup_py = tmpdir / 'setup.py' + with setup_py.open('wb') as stream: + stream.write(b'"degenerate script"\r\n') + setuptools.sandbox._execfile(str(setup_py), globals()) + + +class TestExceptionSaver: + def test_exception_trapped(self): + with setuptools.sandbox.ExceptionSaver(): + raise ValueError("details") + + def test_exception_resumed(self): + with setuptools.sandbox.ExceptionSaver() as saved_exc: + raise ValueError("details") + + with pytest.raises(ValueError) as caught: + saved_exc.resume() + + assert isinstance(caught.value, ValueError) + assert str(caught.value) == 'details' + + def test_exception_reconstructed(self): + orig_exc = ValueError("details") + + with setuptools.sandbox.ExceptionSaver() as saved_exc: + raise orig_exc + + with pytest.raises(ValueError) as caught: + saved_exc.resume() + + assert isinstance(caught.value, ValueError) + assert caught.value is not orig_exc + + def test_no_exception_passes_quietly(self): + with setuptools.sandbox.ExceptionSaver() as saved_exc: + pass + + saved_exc.resume() + + def test_unpickleable_exception(self): + class CantPickleThis(Exception): + "This Exception is unpickleable because it's not in globals" + + with setuptools.sandbox.ExceptionSaver() as saved_exc: + raise CantPickleThis('detail') + + with pytest.raises(setuptools.sandbox.UnpickleableException) as caught: + saved_exc.resume() + + assert str(caught.value) == "CantPickleThis('detail',)" + + def test_unpickleable_exception_when_hiding_setuptools(self): + """ + As revealed in #440, an infinite recursion can occur if an unpickleable + exception while setuptools is hidden. Ensure this doesn't happen. + """ + class ExceptionUnderTest(Exception): + """ + An unpickleable exception (not in globals). + """ + + with pytest.raises(setuptools.sandbox.UnpickleableException) as caught: + with setuptools.sandbox.save_modules(): + setuptools.sandbox.hide_setuptools() + raise ExceptionUnderTest() + + msg, = caught.value.args + assert msg == 'ExceptionUnderTest()' + + def test_sandbox_violation_raised_hiding_setuptools(self, tmpdir): + """ + When in a sandbox with setuptools hidden, a SandboxViolation + should reflect a proper exception and not be wrapped in + an UnpickleableException. + """ + def write_file(): + "Trigger a SandboxViolation by writing outside the sandbox" + with open('/etc/foo', 'w'): + pass + sandbox = DirectorySandbox(str(tmpdir)) + with pytest.raises(setuptools.sandbox.SandboxViolation) as caught: + with setuptools.sandbox.save_modules(): + setuptools.sandbox.hide_setuptools() + sandbox.run(write_file) + + cmd, args, kwargs = caught.value.args + assert cmd == 'open' + assert args == ('/etc/foo', 'w') + assert kwargs == {} diff -Nru python-setuptools-3.3/setuptools/tests/test_sdist.py python-setuptools-20.1.1/setuptools/tests/test_sdist.py --- python-setuptools-3.3/setuptools/tests/test_sdist.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_sdist.py 2016-02-07 14:25:06.000000000 +0000 @@ -1,23 +1,28 @@ # -*- coding: utf-8 -*- """sdist tests""" -import locale import os import shutil import sys import tempfile -import unittest import unicodedata -import re -from setuptools.tests import environment, test_svn -from setuptools.tests.py26compat import skipIf - -from setuptools.compat import StringIO, unicode -from setuptools.tests.py26compat import skipIf -from setuptools.command.sdist import sdist, walk_revctrl +import contextlib +import io + +from setuptools.extern import six +from setuptools.extern.six.moves import map + +import pytest + +import pkg_resources +from setuptools.command.sdist import sdist from setuptools.command.egg_info import manifest_maker from setuptools.dist import Distribution -from setuptools import svn_utils +from setuptools.tests import fail_on_ascii + + +py3_only = pytest.mark.xfail(six.PY2, reason="Test runs on Python 3 only") + SETUP_ATTRS = { 'name': 'sdist_test', @@ -34,32 +39,33 @@ """ % SETUP_ATTRS -if sys.version_info >= (3,): +if six.PY3: LATIN1_FILENAME = 'smörbröd.py'.encode('latin-1') else: LATIN1_FILENAME = 'sm\xf6rbr\xf6d.py' # Cannot use context manager because of Python 2.4 +@contextlib.contextmanager def quiet(): - global old_stdout, old_stderr old_stdout, old_stderr = sys.stdout, sys.stderr - sys.stdout, sys.stderr = StringIO(), StringIO() - -def unquiet(): - sys.stdout, sys.stderr = old_stdout, old_stderr + sys.stdout, sys.stderr = six.StringIO(), six.StringIO() + try: + yield + finally: + sys.stdout, sys.stderr = old_stdout, old_stderr # Fake byte literals for Python <= 2.5 def b(s, encoding='utf-8'): - if sys.version_info >= (3,): + if six.PY3: return s.encode(encoding) return s # Convert to POSIX path def posix(path): - if sys.version_info >= (3,) and not isinstance(path, str): + if six.PY3 and not isinstance(path, str): return path.replace(os.sep.encode('ascii'), b('/')) else: return path.replace(os.sep, '/') @@ -67,24 +73,30 @@ # HFS Plus uses decomposed UTF-8 def decompose(path): - if isinstance(path, unicode): + if isinstance(path, six.text_type): return unicodedata.normalize('NFD', path) try: path = path.decode('utf-8') path = unicodedata.normalize('NFD', path) path = path.encode('utf-8') except UnicodeError: - pass # Not UTF-8 + pass # Not UTF-8 return path -class TestSdistTest(unittest.TestCase): +def read_all_bytes(filename): + with io.open(filename, 'rb') as fp: + return fp.read() + - def setUp(self): +class TestSdistTest: + + def setup_method(self, method): self.temp_dir = tempfile.mkdtemp() f = open(os.path.join(self.temp_dir, 'setup.py'), 'w') f.write(SETUP_PY) f.close() + # Set up the rest of the test package test_pkg = os.path.join(self.temp_dir, 'sdist_test') os.mkdir(test_pkg) @@ -97,7 +109,7 @@ self.old_cwd = os.getcwd() os.chdir(self.temp_dir) - def tearDown(self): + def teardown_method(self, method): os.chdir(self.old_cwd) shutil.rmtree(self.temp_dir) @@ -112,18 +124,42 @@ cmd = sdist(dist) cmd.ensure_finalized() - # squelch output - quiet() - try: + with quiet(): cmd.run() - finally: - unquiet() manifest = cmd.filelist.files - self.assertTrue(os.path.join('sdist_test', 'a.txt') in manifest) - self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest) - self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest) + assert os.path.join('sdist_test', 'a.txt') in manifest + assert os.path.join('sdist_test', 'b.txt') in manifest + assert os.path.join('sdist_test', 'c.rst') not in manifest + + + def test_defaults_case_sensitivity(self): + """ + Make sure default files (README.*, etc.) are added in a case-sensitive + way to avoid problems with packages built on Windows. + """ + + open(os.path.join(self.temp_dir, 'readme.rst'), 'w').close() + open(os.path.join(self.temp_dir, 'SETUP.cfg'), 'w').close() + + dist = Distribution(SETUP_ATTRS) + # the extension deliberately capitalized for this test + # to make sure the actual filename (not capitalized) gets added + # to the manifest + dist.script_name = 'setup.PY' + cmd = sdist(dist) + cmd.ensure_finalized() + + with quiet(): + cmd.run() + # lowercase all names so we can test in a case-insensitive way to make sure the files are not included + manifest = map(lambda x: x.lower(), cmd.filelist.files) + assert 'readme.rst' not in manifest, manifest + assert 'setup.py' not in manifest, manifest + assert 'setup.cfg' not in manifest, manifest + + @fail_on_ascii def test_manifest_is_written_with_utf8_encoding(self): # Test for #303. dist = Distribution(SETUP_ATTRS) @@ -135,113 +171,99 @@ # UTF-8 filename filename = os.path.join('sdist_test', 'smörbröd.py') + # Must create the file or it will get stripped. + open(filename, 'w').close() + # Add UTF-8 filename and write manifest - quiet() - try: + with quiet(): mm.run() - mm.filelist.files.append(filename) + mm.filelist.append(filename) mm.write_manifest() - finally: - unquiet() - manifest = open(mm.manifest, 'rbU') - contents = manifest.read() - manifest.close() + contents = read_all_bytes(mm.manifest) # The manifest should be UTF-8 encoded - try: - u_contents = contents.decode('UTF-8') - except UnicodeDecodeError: - e = sys.exc_info()[1] - self.fail(e) + u_contents = contents.decode('UTF-8') # The manifest should contain the UTF-8 filename - if sys.version_info >= (3,): - self.assertTrue(posix(filename) in u_contents) - else: - self.assertTrue(posix(filename) in contents) + if six.PY2: + fs_enc = sys.getfilesystemencoding() + filename = filename.decode(fs_enc) - # Python 3 only - if sys.version_info >= (3,): + assert posix(filename) in u_contents - def test_write_manifest_allows_utf8_filenames(self): - # Test for #303. - dist = Distribution(SETUP_ATTRS) - dist.script_name = 'setup.py' - mm = manifest_maker(dist) - mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') - os.mkdir('sdist_test.egg-info') + @py3_only + @fail_on_ascii + def test_write_manifest_allows_utf8_filenames(self): + # Test for #303. + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + mm = manifest_maker(dist) + mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') + os.mkdir('sdist_test.egg-info') - # UTF-8 filename - filename = os.path.join(b('sdist_test'), b('smörbröd.py')) + # UTF-8 filename + filename = os.path.join(b('sdist_test'), b('smörbröd.py')) - # Add filename and write manifest - quiet() - try: - mm.run() - u_filename = filename.decode('utf-8') - mm.filelist.files.append(u_filename) - # Re-write manifest - mm.write_manifest() - finally: - unquiet() - - manifest = open(mm.manifest, 'rbU') - contents = manifest.read() - manifest.close() + # Must touch the file or risk removal + open(filename, "w").close() - # The manifest should be UTF-8 encoded - try: - contents.decode('UTF-8') - except UnicodeDecodeError: - e = sys.exc_info()[1] - self.fail(e) + # Add filename and write manifest + with quiet(): + mm.run() + u_filename = filename.decode('utf-8') + mm.filelist.files.append(u_filename) + # Re-write manifest + mm.write_manifest() - # The manifest should contain the UTF-8 filename - self.assertTrue(posix(filename) in contents) + contents = read_all_bytes(mm.manifest) - # The filelist should have been updated as well - self.assertTrue(u_filename in mm.filelist.files) + # The manifest should be UTF-8 encoded + contents.decode('UTF-8') - def test_write_manifest_skips_non_utf8_filenames(self): - # Test for #303. - dist = Distribution(SETUP_ATTRS) - dist.script_name = 'setup.py' - mm = manifest_maker(dist) - mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') - os.mkdir('sdist_test.egg-info') + # The manifest should contain the UTF-8 filename + assert posix(filename) in contents - # Latin-1 filename - filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) + # The filelist should have been updated as well + assert u_filename in mm.filelist.files - # Add filename with surrogates and write manifest - quiet() - try: - mm.run() - u_filename = filename.decode('utf-8', 'surrogateescape') - mm.filelist.files.append(u_filename) - # Re-write manifest - mm.write_manifest() - finally: - unquiet() - - manifest = open(mm.manifest, 'rbU') - contents = manifest.read() - manifest.close() + @py3_only + def test_write_manifest_skips_non_utf8_filenames(self): + """ + Files that cannot be encoded to UTF-8 (specifically, those that + weren't originally successfully decoded and have surrogate + escapes) should be omitted from the manifest. + See https://bitbucket.org/tarek/distribute/issue/303 for history. + """ + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + mm = manifest_maker(dist) + mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') + os.mkdir('sdist_test.egg-info') - # The manifest should be UTF-8 encoded - try: - contents.decode('UTF-8') - except UnicodeDecodeError: - e = sys.exc_info()[1] - self.fail(e) + # Latin-1 filename + filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) - # The Latin-1 filename should have been skipped - self.assertFalse(posix(filename) in contents) + # Add filename with surrogates and write manifest + with quiet(): + mm.run() + u_filename = filename.decode('utf-8', 'surrogateescape') + mm.filelist.append(u_filename) + # Re-write manifest + mm.write_manifest() + + contents = read_all_bytes(mm.manifest) + + # The manifest should be UTF-8 encoded + contents.decode('UTF-8') + + # The Latin-1 filename should have been skipped + assert posix(filename) not in contents - # The filelist should have been updated as well - self.assertFalse(u_filename in mm.filelist.files) + # The filelist should have been updated as well + assert u_filename not in mm.filelist.files + @fail_on_ascii def test_manifest_is_read_with_utf8_encoding(self): # Test for #303. dist = Distribution(SETUP_ATTRS) @@ -250,17 +272,14 @@ cmd.ensure_finalized() # Create manifest - quiet() - try: + with quiet(): cmd.run() - finally: - unquiet() # Add UTF-8 filename to manifest filename = os.path.join(b('sdist_test'), b('smörbröd.py')) cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') manifest = open(cmd.manifest, 'ab') - manifest.write(b('\n')+filename) + manifest.write(b('\n') + filename) manifest.close() # The file must exist to be included in the filelist @@ -268,62 +287,46 @@ # Re-read manifest cmd.filelist.files = [] - quiet() - try: + with quiet(): cmd.read_manifest() - finally: - unquiet() # The filelist should contain the UTF-8 filename - if sys.version_info >= (3,): + if six.PY3: filename = filename.decode('utf-8') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files - # Python 3 only - if sys.version_info >= (3,): + @py3_only + def test_read_manifest_skips_non_utf8_filenames(self): + # Test for #303. + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + cmd = sdist(dist) + cmd.ensure_finalized() - def test_read_manifest_skips_non_utf8_filenames(self): - # Test for #303. - dist = Distribution(SETUP_ATTRS) - dist.script_name = 'setup.py' - cmd = sdist(dist) - cmd.ensure_finalized() + # Create manifest + with quiet(): + cmd.run() - # Create manifest - quiet() - try: - cmd.run() - finally: - unquiet() - - # Add Latin-1 filename to manifest - filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) - cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') - manifest = open(cmd.manifest, 'ab') - manifest.write(b('\n')+filename) - manifest.close() - - # The file must exist to be included in the filelist - open(filename, 'w').close() - - # Re-read manifest - cmd.filelist.files = [] - quiet() - try: - try: - cmd.read_manifest() - except UnicodeDecodeError: - e = sys.exc_info()[1] - self.fail(e) - finally: - unquiet() - - # The Latin-1 filename should have been skipped - filename = filename.decode('latin-1') - self.assertFalse(filename in cmd.filelist.files) + # Add Latin-1 filename to manifest + filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) + cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') + manifest = open(cmd.manifest, 'ab') + manifest.write(b('\n') + filename) + manifest.close() + + # The file must exist to be included in the filelist + open(filename, 'w').close() - @skipIf(sys.version_info >= (3,) and locale.getpreferredencoding() != 'UTF-8', - 'Unittest fails if locale is not utf-8 but the manifests is recorded correctly') + # Re-read manifest + cmd.filelist.files = [] + with quiet(): + cmd.read_manifest() + + # The Latin-1 filename should have been skipped + filename = filename.decode('latin-1') + assert filename not in cmd.filelist.files + + @fail_on_ascii def test_sdist_with_utf8_encoded_filename(self): # Test for #303. dist = Distribution(SETUP_ATTRS) @@ -335,31 +338,28 @@ filename = os.path.join(b('sdist_test'), b('smörbröd.py')) open(filename, 'w').close() - quiet() - try: + with quiet(): cmd.run() - finally: - unquiet() if sys.platform == 'darwin': filename = decompose(filename) - if sys.version_info >= (3,): + if six.PY3: fs_enc = sys.getfilesystemencoding() if sys.platform == 'win32': if fs_enc == 'cp1252': # Python 3 mangles the UTF-8 filename filename = filename.decode('cp1252') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: filename = filename.decode('mbcs') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: filename = filename.decode('utf-8') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files def test_sdist_with_latin1_encoded_filename(self): # Test for #303. @@ -371,16 +371,13 @@ # Latin-1 filename filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) open(filename, 'w').close() - self.assertTrue(os.path.isfile(filename)) + assert os.path.isfile(filename) - quiet() - try: + with quiet(): cmd.run() - finally: - unquiet() - if sys.version_info >= (3,): - #not all windows systems have a default FS encoding of cp1252 + if six.PY3: + # not all windows systems have a default FS encoding of cp1252 if sys.platform == 'win32': # Latin-1 is similar to Windows-1252 however # on mbcs filesys it is not in latin-1 encoding @@ -390,146 +387,37 @@ else: filename = filename.decode('latin-1') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: # The Latin-1 filename should have been skipped filename = filename.decode('latin-1') - self.assertFalse(filename in cmd.filelist.files) + filename not in cmd.filelist.files else: - # No conversion takes place under Python 2 and the file - # is included. We shall keep it that way for BBB. - self.assertTrue(filename in cmd.filelist.files) - - -class TestDummyOutput(environment.ZippedEnvironment): - - def setUp(self): - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', "dummy.zip") - self.dataname = "dummy" - super(TestDummyOutput, self).setUp() - - def _run(self): - code, data = environment.run_setup_py(["sdist"], - pypath=self.old_cwd, - data_stream=0) - if code: - info = "DIR: " + os.path.abspath('.') - info += "\n SDIST RETURNED: %i\n\n" % code - info += data - raise AssertionError(info) - - datalines = data.splitlines() - - possible = ( - "running sdist", - "running egg_info", - "creating dummy\.egg-info", - "writing dummy\.egg-info", - "writing top-level names to dummy\.egg-info", - "writing dependency_links to dummy\.egg-info", - "writing manifest file 'dummy\.egg-info", - "reading manifest file 'dummy\.egg-info", - "reading manifest template 'MANIFEST\.in'", - "writing manifest file 'dummy\.egg-info", - "creating dummy-0.1.1", - "making hard links in dummy-0\.1\.1", - "copying files to dummy-0\.1\.1", - "copying \S+ -> dummy-0\.1\.1", - "copying dummy", - "copying dummy\.egg-info", - "hard linking \S+ -> dummy-0\.1\.1", - "hard linking dummy", - "hard linking dummy\.egg-info", - "Writing dummy-0\.1\.1", - "creating dist", - "creating 'dist", - "Creating tar archive", - "running check", - "adding 'dummy-0\.1\.1", - "tar .+ dist/dummy-0\.1\.1\.tar dummy-0\.1\.1", - "gzip .+ dist/dummy-0\.1\.1\.tar", - "removing 'dummy-0\.1\.1' \\(and everything under it\\)", - ) - - print(" DIR: " + os.path.abspath('.')) - for line in datalines: - found = False - for pattern in possible: - if re.match(pattern, line): - print(" READ: " + line) - found = True - break - if not found: - raise AssertionError("Unexpexected: %s\n-in-\n%s" - % (line, data)) - - return data - - def test_sources(self): - self._run() - - -class TestSvn(environment.ZippedEnvironment): - - def setUp(self): - version = svn_utils.SvnInfo.get_svn_version() - if not version: # None or Empty - return - - self.base_version = tuple([int(x) for x in version.split('.')][:2]) - - if not self.base_version: - raise ValueError('No SVN tools installed') - elif self.base_version < (1, 3): - raise ValueError('Insufficient SVN Version %s' % version) - elif self.base_version >= (1, 9): - #trying the latest version - self.base_version = (1, 8) - - self.dataname = "svn%i%i_example" % self.base_version - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', self.dataname + ".zip") - super(TestSvn, self).setUp() - - @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") - def test_walksvn(self): - if self.base_version >= (1, 6): - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - - #TODO is this right - expected = set([ - os.path.join('a file'), - os.path.join(folder2, 'Changes.txt'), - os.path.join(folder2, 'MD5SUMS'), - os.path.join(folder2, 'README.txt'), - os.path.join(folder3, 'Changes.txt'), - os.path.join(folder3, 'MD5SUMS'), - os.path.join(folder3, 'README.txt'), - os.path.join(folder3, 'TODO.txt'), - os.path.join(folder3, 'fin'), - os.path.join('third_party', 'README.txt'), - os.path.join('folder', folder2, 'Changes.txt'), - os.path.join('folder', folder2, 'MD5SUMS'), - os.path.join('folder', folder2, 'WatashiNiYomimasu.txt'), - os.path.join('folder', folder3, 'Changes.txt'), - os.path.join('folder', folder3, 'fin'), - os.path.join('folder', folder3, 'MD5SUMS'), - os.path.join('folder', folder3, 'oops'), - os.path.join('folder', folder3, 'WatashiNiYomimasu.txt'), - os.path.join('folder', folder3, 'ZuMachen.txt'), - os.path.join('folder', 'third_party', 'WatashiNiYomimasu.txt'), - os.path.join('folder', 'lalala.txt'), - os.path.join('folder', 'quest.txt'), - # The example will have a deleted file - # (or should) but shouldn't return it - ]) - self.assertEqual(set(x for x in walk_revctrl()), expected) + # Under Python 2 there seems to be no decoded string in the + # filelist. However, due to decode and encoding of the + # file name to get utf-8 Manifest the latin1 maybe excluded + try: + # fs_enc should match how one is expect the decoding to + # be proformed for the manifest output. + fs_enc = sys.getfilesystemencoding() + filename.decode(fs_enc) + assert filename in cmd.filelist.files + except UnicodeDecodeError: + filename not in cmd.filelist.files -def test_suite(): - return unittest.defaultTestLoader.loadTestsFromName(__name__) +def test_default_revctrl(): + """ + When _default_revctrl was removed from the `setuptools.command.sdist` + module in 10.0, it broke some systems which keep an old install of + setuptools (Distribute) around. Those old versions require that the + setuptools package continue to implement that interface, so this + function provides that interface, stubbed. See #320 for details. + + This interface must be maintained until Ubuntu 12.04 is no longer + supported (by Setuptools). + """ + ep_def = 'svn_cvs = setuptools.command.sdist:_default_revctrl' + ep = pkg_resources.EntryPoint.parse(ep_def) + res = ep.resolve() + assert hasattr(res, '__iter__') diff -Nru python-setuptools-3.3/setuptools/tests/test_setuptools.py python-setuptools-20.1.1/setuptools/tests/test_setuptools.py --- python-setuptools-3.3/setuptools/tests/test_setuptools.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_setuptools.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,48 @@ +import os + +import pytest + +import setuptools + + +@pytest.fixture +def example_source(tmpdir): + tmpdir.mkdir('foo') + (tmpdir / 'foo/bar.py').write('') + (tmpdir / 'readme.txt').write('') + return tmpdir + + +def test_findall(example_source): + found = list(setuptools.findall(str(example_source))) + expected = ['readme.txt', 'foo/bar.py'] + expected = [example_source.join(fn) for fn in expected] + assert found == expected + + +def test_findall_curdir(example_source): + with example_source.as_cwd(): + found = list(setuptools.findall()) + expected = ['readme.txt', os.path.join('foo', 'bar.py')] + assert found == expected + + +@pytest.fixture +def can_symlink(tmpdir): + """ + Skip if cannot create a symbolic link + """ + link_fn = 'link' + target_fn = 'target' + try: + os.symlink(target_fn, link_fn) + except (OSError, NotImplementedError, AttributeError): + pytest.skip("Cannot create symbolic links") + os.remove(link_fn) + + +def test_findall_missing_symlink(tmpdir, can_symlink): + with tmpdir.as_cwd(): + os.symlink('foo', 'bar') + found = list(setuptools.findall()) + assert found == [] diff -Nru python-setuptools-3.3/setuptools/tests/test_svn.py python-setuptools-20.1.1/setuptools/tests/test_svn.py --- python-setuptools-3.3/setuptools/tests/test_svn.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_svn.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -# -*- coding: utf-8 -*- -"""svn tests""" - -import io -import os -import subprocess -import sys -import unittest -from setuptools.tests import environment -from setuptools.compat import unicode, unichr - -from setuptools import svn_utils -from setuptools.tests.py26compat import skipIf - - -def _do_svn_check(): - try: - subprocess.check_call(["svn", "--version"], - shell=(sys.platform == 'win32')) - return True - except (OSError, subprocess.CalledProcessError): - return False -_svn_check = _do_svn_check() - - -class TestSvnVersion(unittest.TestCase): - - def test_no_svn_found(self): - path_variable = None - for env in os.environ: - if env.lower() == 'path': - path_variable = env - - if path_variable is None: - try: - self.skipTest('Cannot figure out how to modify path') - except AttributeError: # PY26 doesn't have this - return - - old_path = os.environ[path_variable] - os.environ[path_variable] = '' - try: - version = svn_utils.SvnInfo.get_svn_version() - self.assertEqual(version, '') - finally: - os.environ[path_variable] = old_path - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_svn_should_exist(self): - version = svn_utils.SvnInfo.get_svn_version() - self.assertNotEqual(version, '') - -def _read_utf8_file(path): - fileobj = None - try: - fileobj = io.open(path, 'r', encoding='utf-8') - data = fileobj.read() - return data - finally: - if fileobj: - fileobj.close() - - -class ParserInfoXML(unittest.TestCase): - - def parse_tester(self, svn_name, ext_spaces): - path = os.path.join('setuptools', 'tests', - 'svn_data', svn_name + '_info.xml') - #Remember these are pre-generated to test XML parsing - # so these paths might not valid on your system - example_base = "%s_example" % svn_name - - data = _read_utf8_file(path) - - expected = set([ - ("\\".join((example_base, 'a file')), 'file'), - ("\\".join((example_base, 'folder')), 'dir'), - ("\\".join((example_base, 'folder', 'lalala.txt')), 'file'), - ("\\".join((example_base, 'folder', 'quest.txt')), 'file'), - ]) - self.assertEqual(set(x for x in svn_utils.parse_dir_entries(data)), - expected) - - def test_svn13(self): - self.parse_tester('svn13', False) - - def test_svn14(self): - self.parse_tester('svn14', False) - - def test_svn15(self): - self.parse_tester('svn15', False) - - def test_svn16(self): - self.parse_tester('svn16', True) - - def test_svn17(self): - self.parse_tester('svn17', True) - - def test_svn18(self): - self.parse_tester('svn18', True) - -class ParserExternalXML(unittest.TestCase): - - def parse_tester(self, svn_name, ext_spaces): - path = os.path.join('setuptools', 'tests', - 'svn_data', svn_name + '_ext_list.xml') - example_base = svn_name + '_example' - data = _read_utf8_file(path) - - if ext_spaces: - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - - expected = set([ - os.sep.join((example_base, folder2)), - os.sep.join((example_base, folder3)), - # folder is third_party大介 - os.sep.join((example_base, - unicode('third_party') + - unichr(0x5927) + unichr(0x4ecb))), - os.sep.join((example_base, 'folder', folder2)), - os.sep.join((example_base, 'folder', folder3)), - os.sep.join((example_base, 'folder', - unicode('third_party') + - unichr(0x5927) + unichr(0x4ecb))), - ]) - - expected = set(os.path.normpath(x) for x in expected) - dir_base = os.sep.join(('C:', 'development', 'svn_example')) - self.assertEqual(set(x for x - in svn_utils.parse_externals_xml(data, dir_base)), expected) - - def test_svn15(self): - self.parse_tester('svn15', False) - - def test_svn16(self): - self.parse_tester('svn16', True) - - def test_svn17(self): - self.parse_tester('svn17', True) - - def test_svn18(self): - self.parse_tester('svn18', True) - - -class ParseExternal(unittest.TestCase): - - def parse_tester(self, svn_name, ext_spaces): - path = os.path.join('setuptools', 'tests', - 'svn_data', svn_name + '_ext_list.txt') - data = _read_utf8_file(path) - - if ext_spaces: - expected = set(['third party2', 'third party3', - 'third party3b', 'third_party']) - else: - expected = set(['third_party2', 'third_party3', 'third_party']) - - self.assertEqual(set(x for x in svn_utils.parse_external_prop(data)), - expected) - - def test_svn13(self): - self.parse_tester('svn13', False) - - def test_svn14(self): - self.parse_tester('svn14', False) - - def test_svn15(self): - self.parse_tester('svn15', False) - - def test_svn16(self): - self.parse_tester('svn16', True) - - def test_svn17(self): - self.parse_tester('svn17', True) - - def test_svn18(self): - self.parse_tester('svn18', True) - - -class TestSvn(environment.ZippedEnvironment): - - def setUp(self): - version = svn_utils.SvnInfo.get_svn_version() - if not version: # empty or null - self.dataname = None - self.datafile = None - return - - self.base_version = tuple([int(x) for x in version.split('.')[:2]]) - - if self.base_version < (1,3): - raise ValueError('Insufficient SVN Version %s' % version) - elif self.base_version >= (1,9): - #trying the latest version - self.base_version = (1,8) - - self.dataname = "svn%i%i_example" % self.base_version - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', self.dataname + ".zip") - super(TestSvn, self).setUp() - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_revision(self): - rev = svn_utils.SvnInfo.load('.').get_revision() - self.assertEqual(rev, 6) - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_entries(self): - expected = set([ - (os.path.join('a file'), 'file'), - (os.path.join('folder'), 'dir'), - (os.path.join('folder', 'lalala.txt'), 'file'), - (os.path.join('folder', 'quest.txt'), 'file'), - #The example will have a deleted file (or should) - #but shouldn't return it - ]) - info = svn_utils.SvnInfo.load('.') - self.assertEqual(set(x for x in info.entries), expected) - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_externals(self): - if self.base_version >= (1,6): - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - - expected = set([ - os.path.join(folder2), - os.path.join(folder3), - os.path.join('third_party'), - os.path.join('folder', folder2), - os.path.join('folder', folder3), - os.path.join('folder', 'third_party'), - ]) - info = svn_utils.SvnInfo.load('.') - self.assertEqual(set([x for x in info.externals]), expected) - -def test_suite(): - return unittest.defaultTestLoader.loadTestsFromName(__name__) diff -Nru python-setuptools-3.3/setuptools/tests/test_test.py python-setuptools-20.1.1/setuptools/tests/test_test.py --- python-setuptools-3.3/setuptools/tests/test_test.py 2014-03-06 14:48:25.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_test.py 2016-02-07 14:25:06.000000000 +0000 @@ -1,126 +1,92 @@ # -*- coding: UTF-8 -*- -"""develop tests -""" +from __future__ import unicode_literals + import os -import shutil import site -import sys -import tempfile -import unittest - from distutils.errors import DistutilsError -from setuptools.compat import StringIO + +import pytest + from setuptools.command.test import test -from setuptools.command import easy_install as easy_install_pkg from setuptools.dist import Distribution -SETUP_PY = """\ -from setuptools import setup - -setup(name='foo', - packages=['name', 'name.space', 'name.space.tests'], - namespace_packages=['name'], - test_suite='name.space.tests.test_suite', -) -""" - -NS_INIT = """# -*- coding: Latin-1 -*- -# Söme Arbiträry Ünicode to test Issüé 310 -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - from pkgutil import extend_path - __path__ = extend_path(__path__, __name__) -""" -# Make sure this is Latin-1 binary, before writing: -if sys.version_info < (3,): - NS_INIT = NS_INIT.decode('UTF-8') -NS_INIT = NS_INIT.encode('Latin-1') +from .textwrap import DALS +from . import contexts -TEST_PY = """import unittest +SETUP_PY = DALS(""" + from setuptools import setup -class TestTest(unittest.TestCase): - def test_test(self): - print "Foo" # Should fail under Python 3 unless 2to3 is used + setup(name='foo', + packages=['name', 'name.space', 'name.space.tests'], + namespace_packages=['name'], + test_suite='name.space.tests.test_suite', + ) + """) + +NS_INIT = DALS(""" + # -*- coding: Latin-1 -*- + # Söme Arbiträry Ünicode to test Distribute Issüé 310 + try: + __import__('pkg_resources').declare_namespace(__name__) + except ImportError: + from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) + """) + +TEST_PY = DALS(""" + import unittest + + class TestTest(unittest.TestCase): + def test_test(self): + print "Foo" # Should fail under Python 3 unless 2to3 is used + + test_suite = unittest.makeSuite(TestTest) + """) + + +@pytest.fixture +def sample_test(tmpdir_cwd): + os.makedirs('name/space/tests') -test_suite = unittest.makeSuite(TestTest) -""" + # setup.py + with open('setup.py', 'wt') as f: + f.write(SETUP_PY) -class TestTestTest(unittest.TestCase): + # name/__init__.py + with open('name/__init__.py', 'wb') as f: + f.write(NS_INIT.encode('Latin-1')) - def setUp(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): - return - - # Directory structure - self.dir = tempfile.mkdtemp() - os.mkdir(os.path.join(self.dir, 'name')) - os.mkdir(os.path.join(self.dir, 'name', 'space')) - os.mkdir(os.path.join(self.dir, 'name', 'space', 'tests')) - # setup.py - setup = os.path.join(self.dir, 'setup.py') - f = open(setup, 'wt') - f.write(SETUP_PY) - f.close() - self.old_cwd = os.getcwd() - # name/__init__.py - init = os.path.join(self.dir, 'name', '__init__.py') - f = open(init, 'wb') - f.write(NS_INIT) - f.close() - # name/space/__init__.py - init = os.path.join(self.dir, 'name', 'space', '__init__.py') - f = open(init, 'wt') + # name/space/__init__.py + with open('name/space/__init__.py', 'wt') as f: f.write('#empty\n') - f.close() - # name/space/tests/__init__.py - init = os.path.join(self.dir, 'name', 'space', 'tests', '__init__.py') - f = open(init, 'wt') + + # name/space/tests/__init__.py + with open('name/space/tests/__init__.py', 'wt') as f: f.write(TEST_PY) - f.close() - os.chdir(self.dir) - self.old_base = site.USER_BASE - site.USER_BASE = tempfile.mkdtemp() - self.old_site = site.USER_SITE - site.USER_SITE = tempfile.mkdtemp() - - def tearDown(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): - return - - os.chdir(self.old_cwd) - shutil.rmtree(self.dir) - shutil.rmtree(site.USER_BASE) - shutil.rmtree(site.USER_SITE) - site.USER_BASE = self.old_base - site.USER_SITE = self.old_site - def test_test(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): - return +@pytest.mark.skipif('hasattr(sys, "real_prefix")') +@pytest.mark.usefixtures('user_override') +@pytest.mark.usefixtures('sample_test') +class TestTestTest: - dist = Distribution(dict( + def test_test(self): + params = dict( name='foo', packages=['name', 'name.space', 'name.space.tests'], namespace_packages=['name'], test_suite='name.space.tests.test_suite', use_2to3=True, - )) + ) + dist = Distribution(params) dist.script_name = 'setup.py' cmd = test(dist) cmd.user = 1 cmd.ensure_finalized() cmd.install_dir = site.USER_SITE cmd.user = 1 - old_stdout = sys.stdout - sys.stdout = StringIO() - try: - try: # try/except/finally doesn't work in Python 2.4, so we need nested try-statements. + with contexts.quiet(): + # The test runner calls sys.exit + with contexts.suppress_exceptions(SystemExit): cmd.run() - except SystemExit: # The test runner calls sys.exit, stop that making an error. - pass - finally: - sys.stdout = old_stdout - diff -Nru python-setuptools-3.3/setuptools/tests/test_unicode_utils.py python-setuptools-20.1.1/setuptools/tests/test_unicode_utils.py --- python-setuptools-3.3/setuptools/tests/test_unicode_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_unicode_utils.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,10 @@ +from setuptools import unicode_utils + + +def test_filesys_decode_fs_encoding_is_None(monkeypatch): + """ + Test filesys_decode does not raise TypeError when + getfilesystemencoding returns None. + """ + monkeypatch.setattr('sys.getfilesystemencoding', lambda: None) + unicode_utils.filesys_decode(b'test') diff -Nru python-setuptools-3.3/setuptools/tests/test_upload_docs.py python-setuptools-20.1.1/setuptools/tests/test_upload_docs.py --- python-setuptools-3.3/setuptools/tests/test_upload_docs.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_upload_docs.py 2016-02-07 14:25:06.000000000 +0000 @@ -1,72 +1,59 @@ -"""build_ext tests -""" -import sys, os, shutil, tempfile, unittest, site, zipfile +import os +import zipfile +import contextlib + +import pytest + from setuptools.command.upload_docs import upload_docs from setuptools.dist import Distribution -SETUP_PY = """\ -from setuptools import setup +from .textwrap import DALS +from . import contexts + + +SETUP_PY = DALS( + """ + from setuptools import setup + + setup(name='foo') + """) -setup(name='foo') -""" -class TestUploadDocsTest(unittest.TestCase): - def setUp(self): - self.dir = tempfile.mkdtemp() - setup = os.path.join(self.dir, 'setup.py') - f = open(setup, 'w') +@pytest.fixture +def sample_project(tmpdir_cwd): + # setup.py + with open('setup.py', 'wt') as f: f.write(SETUP_PY) - f.close() - self.old_cwd = os.getcwd() - os.chdir(self.dir) - self.upload_dir = os.path.join(self.dir, 'build') - os.mkdir(self.upload_dir) + os.mkdir('build') - # A test document. - f = open(os.path.join(self.upload_dir, 'index.html'), 'w') + # A test document. + with open('build/index.html', 'w') as f: f.write("Hello world.") - f.close() - # An empty folder. - os.mkdir(os.path.join(self.upload_dir, 'empty')) + # An empty folder. + os.mkdir('build/empty') - if sys.version >= "2.6": - self.old_base = site.USER_BASE - site.USER_BASE = upload_docs.USER_BASE = tempfile.mkdtemp() - self.old_site = site.USER_SITE - site.USER_SITE = upload_docs.USER_SITE = tempfile.mkdtemp() - - def tearDown(self): - os.chdir(self.old_cwd) - shutil.rmtree(self.dir) - if sys.version >= "2.6": - shutil.rmtree(site.USER_BASE) - shutil.rmtree(site.USER_SITE) - site.USER_BASE = self.old_base - site.USER_SITE = self.old_site + +@pytest.mark.usefixtures('sample_project') +@pytest.mark.usefixtures('user_override') +class TestUploadDocsTest: def test_create_zipfile(self): - # Test to make sure zipfile creation handles common cases. - # This explicitly includes a folder containing an empty folder. + """ + Ensure zipfile creation handles common cases, including a folder + containing an empty folder. + """ dist = Distribution() cmd = upload_docs(dist) - cmd.upload_dir = self.upload_dir - cmd.target_dir = self.upload_dir - tmp_dir = tempfile.mkdtemp() - tmp_file = os.path.join(tmp_dir, 'foo.zip') - try: + cmd.target_dir = cmd.upload_dir = 'build' + with contexts.tempdir() as tmp_dir: + tmp_file = os.path.join(tmp_dir, 'foo.zip') zip_file = cmd.create_zipfile(tmp_file) assert zipfile.is_zipfile(tmp_file) - zip_file = zipfile.ZipFile(tmp_file) # woh... - - assert zip_file.namelist() == ['index.html'] - - zip_file.close() - finally: - shutil.rmtree(tmp_dir) - + with contextlib.closing(zipfile.ZipFile(tmp_file)) as zip_file: + assert zip_file.namelist() == ['index.html'] diff -Nru python-setuptools-3.3/setuptools/tests/test_windows_wrappers.py python-setuptools-20.1.1/setuptools/tests/test_windows_wrappers.py --- python-setuptools-3.3/setuptools/tests/test_windows_wrappers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/test_windows_wrappers.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,183 @@ +""" +Python Script Wrapper for Windows +================================= + +setuptools includes wrappers for Python scripts that allows them to be +executed like regular windows programs. There are 2 wrappers, one +for command-line programs, cli.exe, and one for graphical programs, +gui.exe. These programs are almost identical, function pretty much +the same way, and are generated from the same source file. The +wrapper programs are used by copying them to the directory containing +the script they are to wrap and with the same name as the script they +are to wrap. +""" + +from __future__ import absolute_import + +import sys +import textwrap +import subprocess + +import pytest + +from setuptools.command.easy_install import nt_quote_arg +import pkg_resources + + +pytestmark = pytest.mark.skipif(sys.platform != 'win32', reason="Windows only") + + +class WrapperTester: + + @classmethod + def prep_script(cls, template): + python_exe = nt_quote_arg(sys.executable) + return template % locals() + + @classmethod + def create_script(cls, tmpdir): + """ + Create a simple script, foo-script.py + + Note that the script starts with a Unix-style '#!' line saying which + Python executable to run. The wrapper will use this line to find the + correct Python executable. + """ + + script = cls.prep_script(cls.script_tmpl) + + with (tmpdir / cls.script_name).open('w') as f: + f.write(script) + + # also copy cli.exe to the sample directory + with (tmpdir / cls.wrapper_name).open('wb') as f: + w = pkg_resources.resource_string('setuptools', cls.wrapper_source) + f.write(w) + + +class TestCLI(WrapperTester): + script_name = 'foo-script.py' + wrapper_source = 'cli-32.exe' + wrapper_name = 'foo.exe' + script_tmpl = textwrap.dedent(""" + #!%(python_exe)s + import sys + input = repr(sys.stdin.read()) + print(sys.argv[0][-14:]) + print(sys.argv[1:]) + print(input) + if __debug__: + print('non-optimized') + """).lstrip() + + def test_basic(self, tmpdir): + """ + When the copy of cli.exe, foo.exe in this example, runs, it examines + the path name it was run with and computes a Python script path name + by removing the '.exe' suffix and adding the '-script.py' suffix. (For + GUI programs, the suffix '-script.pyw' is added.) This is why we + named out script the way we did. Now we can run out script by running + the wrapper: + + This example was a little pathological in that it exercised windows + (MS C runtime) quoting rules: + + - Strings containing spaces are surrounded by double quotes. + + - Double quotes in strings need to be escaped by preceding them with + back slashes. + + - One or more backslashes preceding double quotes need to be escaped + by preceding each of them with back slashes. + """ + self.create_script(tmpdir) + cmd = [ + str(tmpdir / 'foo.exe'), + 'arg1', + 'arg 2', + 'arg "2\\"', + 'arg 4\\', + 'arg5 a\\\\b', + ] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii')) + actual = stdout.decode('ascii').replace('\r\n', '\n') + expected = textwrap.dedent(r""" + \foo-script.py + ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] + 'hello\nworld\n' + non-optimized + """).lstrip() + assert actual == expected + + def test_with_options(self, tmpdir): + """ + Specifying Python Command-line Options + -------------------------------------- + + You can specify a single argument on the '#!' line. This can be used + to specify Python options like -O, to run in optimized mode or -i + to start the interactive interpreter. You can combine multiple + options as usual. For example, to run in optimized mode and + enter the interpreter after running the script, you could use -Oi: + """ + self.create_script(tmpdir) + tmpl = textwrap.dedent(""" + #!%(python_exe)s -Oi + import sys + input = repr(sys.stdin.read()) + print(sys.argv[0][-14:]) + print(sys.argv[1:]) + print(input) + if __debug__: + print('non-optimized') + sys.ps1 = '---' + """).lstrip() + with (tmpdir / 'foo-script.py').open('w') as f: + f.write(self.prep_script(tmpl)) + cmd = [str(tmpdir / 'foo.exe')] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, stderr = proc.communicate() + actual = stdout.decode('ascii').replace('\r\n', '\n') + expected = textwrap.dedent(r""" + \foo-script.py + [] + '' + --- + """).lstrip() + assert actual == expected + + +class TestGUI(WrapperTester): + """ + Testing the GUI Version + ----------------------- + """ + script_name = 'bar-script.pyw' + wrapper_source = 'gui-32.exe' + wrapper_name = 'bar.exe' + + script_tmpl = textwrap.dedent(""" + #!%(python_exe)s + import sys + f = open(sys.argv[1], 'wb') + bytes_written = f.write(repr(sys.argv[2]).encode('utf-8')) + f.close() + """).strip() + + def test_basic(self, tmpdir): + """Test the GUI version with the simple scipt, bar-script.py""" + self.create_script(tmpdir) + + cmd = [ + str(tmpdir / 'bar.exe'), + str(tmpdir / 'test_output.txt'), + 'Test Argument', + ] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, stderr = proc.communicate() + assert not stdout + assert not stderr + with (tmpdir / 'test_output.txt').open('rb') as f_out: + actual = f_out.read().decode('ascii') + assert actual == repr('Test Argument') diff -Nru python-setuptools-3.3/setuptools/tests/textwrap.py python-setuptools-20.1.1/setuptools/tests/textwrap.py --- python-setuptools-3.3/setuptools/tests/textwrap.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/textwrap.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +import textwrap + + +def DALS(s): + "dedent and left-strip" + return textwrap.dedent(s).lstrip() diff -Nru python-setuptools-3.3/setuptools/tests/win_script_wrapper.txt python-setuptools-20.1.1/setuptools/tests/win_script_wrapper.txt --- python-setuptools-3.3/setuptools/tests/win_script_wrapper.txt 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/tests/win_script_wrapper.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -Python Script Wrapper for Windows -================================= - -setuptools includes wrappers for Python scripts that allows them to be -executed like regular windows programs. There are 2 wrappers, once -for command-line programs, cli.exe, and one for graphica programs, -gui.exe. These programs are almost identical, function pretty much -the same way, and are generated from the same source file. The -wrapper programs are used by copying them to the directory containing -the script they are to wrap and with the same name as the script they -are to wrap. In the rest of this document, we'll give an example that -will illustrate this. - -Let's create a simple script, foo-script.py: - - >>> import os, sys, tempfile - >>> from setuptools.command.easy_install import nt_quote_arg - >>> sample_directory = tempfile.mkdtemp() - >>> f = open(os.path.join(sample_directory, 'foo-script.py'), 'w') - >>> bytes_written = f.write( - ... """#!%(python_exe)s - ... import sys - ... input = repr(sys.stdin.read()) - ... print(sys.argv[0][-14:]) - ... print(sys.argv[1:]) - ... print(input) - ... if __debug__: - ... print('non-optimized') - ... """ % dict(python_exe=nt_quote_arg(sys.executable))) - >>> f.close() - -Note that the script starts with a Unix-style '#!' line saying which -Python executable to run. The wrapper will use this to find the -correct Python executable. - -We'll also copy cli.exe to the sample-directory with the name foo.exe: - - >>> import pkg_resources - >>> f = open(os.path.join(sample_directory, 'foo.exe'), 'wb') - >>> bytes_written = f.write( - ... pkg_resources.resource_string('setuptools', 'cli-32.exe') - ... ) - >>> f.close() - -When the copy of cli.exe, foo.exe in this example, runs, it examines -the path name it was run with and computes a Python script path name -by removing the '.exe' suffic and adding the '-script.py' suffix. (For -GUI programs, the suffix '-script-pyw' is added.) This is why we -named out script the way we did. Now we can run out script by running -the wrapper: - - >>> import subprocess - >>> cmd = [os.path.join(sample_directory, 'foo.exe'), 'arg1', 'arg 2', - ... 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] - >>> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) - >>> stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii')) - >>> bytes = sys.stdout.write(stdout.decode('ascii').replace('\r\n', '\n')) - \foo-script.py - ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] - 'hello\nworld\n' - non-optimized - -This example was a little pathological in that it exercised windows -(MS C runtime) quoting rules: - -- Strings containing spaces are surrounded by double quotes. - -- Double quotes in strings need to be escaped by preceding them with - back slashes. - -- One or more backslashes preceding double quotes quotes need to be - escaped by preceding each of them them with back slashes. - - -Specifying Python Command-line Options --------------------------------------- - -You can specify a single argument on the '#!' line. This can be used -to specify Python options like -O, to run in optimized mode or -i -to start the interactive interpreter. You can combine multiple -options as usual. For example, to run in optimized mode and -enter the interpreter after running the script, you could use -Oi: - - >>> f = open(os.path.join(sample_directory, 'foo-script.py'), 'w') - >>> bytes_written = f.write( - ... """#!%(python_exe)s -Oi - ... import sys - ... input = repr(sys.stdin.read()) - ... print(sys.argv[0][-14:]) - ... print(sys.argv[1:]) - ... print(input) - ... if __debug__: - ... print('non-optimized') - ... sys.ps1 = '---' - ... """ % dict(python_exe=nt_quote_arg(sys.executable))) - >>> f.close() - >>> cmd = [os.path.join(sample_directory, 'foo.exe')] - >>> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) - >>> stdout, stderr = proc.communicate() - >>> bytes = sys.stdout.write(stdout.decode('ascii').replace('\r\n', '\n')) - \foo-script.py - [] - '' - --- - -Testing the GUI Version ------------------------ - -Now let's test the GUI version with the simple scipt, bar-script.py: - - >>> import os, sys, tempfile - >>> from setuptools.command.easy_install import nt_quote_arg - >>> sample_directory = tempfile.mkdtemp() - >>> f = open(os.path.join(sample_directory, 'bar-script.pyw'), 'w') - >>> bytes_written = f.write( - ... """#!%(python_exe)s - ... import sys - ... f = open(sys.argv[1], 'wb') - ... bytes_written = f.write(repr(sys.argv[2]).encode('utf-8')) - ... f.close() - ... """ % dict(python_exe=nt_quote_arg(sys.executable))) - >>> f.close() - -We'll also copy gui.exe to the sample-directory with the name bar.exe: - - >>> import pkg_resources - >>> f = open(os.path.join(sample_directory, 'bar.exe'), 'wb') - >>> bytes_written = f.write( - ... pkg_resources.resource_string('setuptools', 'gui-32.exe') - ... ) - >>> f.close() - -Finally, we'll run the script and check the result: - - >>> cmd = [ - ... os.path.join(sample_directory, 'bar.exe'), - ... os.path.join(sample_directory, 'test_output.txt'), - ... 'Test Argument', - ... ] - >>> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) - >>> stdout, stderr = proc.communicate() - >>> print(stdout.decode('ascii')) - - >>> f_out = open(os.path.join(sample_directory, 'test_output.txt'), 'rb') - >>> print(f_out.read().decode('ascii')) - 'Test Argument' - >>> f_out.close() - - -We're done with the sample_directory: - - >>> import shutil - >>> shutil.rmtree(sample_directory) - diff -Nru python-setuptools-3.3/setuptools/unicode_utils.py python-setuptools-20.1.1/setuptools/unicode_utils.py --- python-setuptools-3.3/setuptools/unicode_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/unicode_utils.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,43 @@ +import unicodedata +import sys + +from setuptools.extern import six + +# HFS Plus uses decomposed UTF-8 +def decompose(path): + if isinstance(path, six.text_type): + return unicodedata.normalize('NFD', path) + try: + path = path.decode('utf-8') + path = unicodedata.normalize('NFD', path) + path = path.encode('utf-8') + except UnicodeError: + pass # Not UTF-8 + return path + + +def filesys_decode(path): + """ + Ensure that the given path is decoded, + NONE when no expected encoding works + """ + + if isinstance(path, six.text_type): + return path + + fs_enc = sys.getfilesystemencoding() or 'utf-8' + candidates = fs_enc, 'utf-8' + + for enc in candidates: + try: + return path.decode(enc) + except UnicodeDecodeError: + continue + + +def try_encode(string, enc): + "turn unicode encoding into a functional routine" + try: + return string.encode(enc) + except UnicodeEncodeError: + return None diff -Nru python-setuptools-3.3/setuptools/utils.py python-setuptools-20.1.1/setuptools/utils.py --- python-setuptools-3.3/setuptools/utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/utils.py 2016-01-30 17:43:56.000000000 +0000 @@ -0,0 +1,11 @@ +import os +import os.path + + +def cs_path_exists(fspath): + if not os.path.exists(fspath): + return False + # make absolute so we always have a directory + abspath = os.path.abspath(fspath) + directory, filename = os.path.split(abspath) + return filename in os.listdir(directory) \ No newline at end of file diff -Nru python-setuptools-3.3/setuptools/version.py python-setuptools-20.1.1/setuptools/version.py --- python-setuptools-3.3/setuptools/version.py 2014-03-16 08:01:53.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/version.py 2016-02-12 16:11:07.000000000 +0000 @@ -1 +1 @@ -__version__ = '3.3' +__version__ = '20.1.1' diff -Nru python-setuptools-3.3/setuptools/windows_support.py python-setuptools-20.1.1/setuptools/windows_support.py --- python-setuptools-3.3/setuptools/windows_support.py 1970-01-01 00:00:00.000000000 +0000 +++ python-setuptools-20.1.1/setuptools/windows_support.py 2016-02-07 14:25:06.000000000 +0000 @@ -0,0 +1,29 @@ +import platform +import ctypes + + +def windows_only(func): + if platform.system() != 'Windows': + return lambda *args, **kwargs: None + return func + + +@windows_only +def hide_file(path): + """ + Set the hidden attribute on a file or directory. + + From http://stackoverflow.com/questions/19622133/ + + `path` must be text. + """ + __import__('ctypes.wintypes') + SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW + SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD + SetFileAttributes.restype = ctypes.wintypes.BOOL + + FILE_ATTRIBUTE_HIDDEN = 0x02 + + ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) + if not ret: + raise ctypes.WinError() diff -Nru python-setuptools-3.3/setuptools.egg-info/dependency_links.txt python-setuptools-20.1.1/setuptools.egg-info/dependency_links.txt --- python-setuptools-3.3/setuptools.egg-info/dependency_links.txt 2014-03-16 09:04:36.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/dependency_links.txt 2016-02-12 16:11:10.000000000 +0000 @@ -1,2 +1,2 @@ -https://pypi.python.org/packages/source/c/certifi/certifi-1.0.1.tar.gz#md5=45f5cb94b8af9e1df0f9450a8f61b790 +https://pypi.python.org/packages/source/c/certifi/certifi-2015.11.20.tar.gz#md5=25134646672c695c1ff1593c2dd75d08 https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2 diff -Nru python-setuptools-3.3/setuptools.egg-info/dependency_links.txt.orig python-setuptools-20.1.1/setuptools.egg-info/dependency_links.txt.orig --- python-setuptools-3.3/setuptools.egg-info/dependency_links.txt.orig 2014-03-16 07:58:41.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/dependency_links.txt.orig 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -https://pypi.python.org/packages/source/c/certifi/certifi-1.0.1.tar.gz#md5=45f5cb94b8af9e1df0f9450a8f61b790 -https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2 diff -Nru python-setuptools-3.3/setuptools.egg-info/entry_points.txt python-setuptools-20.1.1/setuptools.egg-info/entry_points.txt --- python-setuptools-3.3/setuptools.egg-info/entry_points.txt 2014-03-16 09:04:36.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/entry_points.txt 2016-02-12 16:11:10.000000000 +0000 @@ -1,62 +1,62 @@ -[setuptools.installation] -eggsecutable = setuptools.command.easy_install:bootstrap +[console_scripts] +easy_install = setuptools.command.easy_install:main +easy_install-3.5 = setuptools.command.easy_install:main + +[distutils.commands] +alias = setuptools.command.alias:alias +bdist_egg = setuptools.command.bdist_egg:bdist_egg +bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm +bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst +build_ext = setuptools.command.build_ext:build_ext +build_py = setuptools.command.build_py:build_py +develop = setuptools.command.develop:develop +easy_install = setuptools.command.easy_install:easy_install +egg_info = setuptools.command.egg_info:egg_info +install = setuptools.command.install:install +install_egg_info = setuptools.command.install_egg_info:install_egg_info +install_lib = setuptools.command.install_lib:install_lib +install_scripts = setuptools.command.install_scripts:install_scripts +register = setuptools.command.register:register +rotate = setuptools.command.rotate:rotate +saveopts = setuptools.command.saveopts:saveopts +sdist = setuptools.command.sdist:sdist +setopt = setuptools.command.setopt:setopt +test = setuptools.command.test:test +upload = setuptools.command.upload:upload +upload_docs = setuptools.command.upload_docs:upload_docs [distutils.setup_keywords] -packages = setuptools.dist:check_packages +convert_2to3_doctests = setuptools.dist:assert_string_list +dependency_links = setuptools.dist:assert_string_list +eager_resources = setuptools.dist:assert_string_list entry_points = setuptools.dist:check_entry_points -test_suite = setuptools.dist:check_test_suite -include_package_data = setuptools.dist:assert_bool exclude_package_data = setuptools.dist:check_package_data -convert_2to3_doctests = setuptools.dist:assert_string_list extras_require = setuptools.dist:check_extras +include_package_data = setuptools.dist:assert_bool install_requires = setuptools.dist:check_requirements -use_2to3_fixers = setuptools.dist:assert_string_list -zip_safe = setuptools.dist:assert_bool namespace_packages = setuptools.dist:check_nsp +package_data = setuptools.dist:check_package_data +packages = setuptools.dist:check_packages +setup_requires = setuptools.dist:check_requirements test_loader = setuptools.dist:check_importable -use_2to3 = setuptools.dist:assert_bool -eager_resources = setuptools.dist:assert_string_list -dependency_links = setuptools.dist:assert_string_list +test_runner = setuptools.dist:check_importable +test_suite = setuptools.dist:check_test_suite tests_require = setuptools.dist:check_requirements -package_data = setuptools.dist:check_package_data +use_2to3 = setuptools.dist:assert_bool use_2to3_exclude_fixers = setuptools.dist:assert_string_list - -[setuptools.file_finders] -svn_cvs = setuptools.command.sdist:_default_revctrl - -[distutils.commands] -setopt = setuptools.command.setopt:setopt -easy_install = setuptools.command.easy_install:easy_install -bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst -register = setuptools.command.register:register -test = setuptools.command.test:test -install_scripts = setuptools.command.install_scripts:install_scripts -install = setuptools.command.install:install -alias = setuptools.command.alias:alias -bdist_egg = setuptools.command.bdist_egg:bdist_egg -build_py = setuptools.command.build_py:build_py -install_lib = setuptools.command.install_lib:install_lib -rotate = setuptools.command.rotate:rotate -bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm -egg_info = setuptools.command.egg_info:egg_info -develop = setuptools.command.develop:develop -install_egg_info = setuptools.command.install_egg_info:install_egg_info -build_ext = setuptools.command.build_ext:build_ext -sdist = setuptools.command.sdist:sdist -saveopts = setuptools.command.saveopts:saveopts -upload_docs = setuptools.command.upload_docs:upload_docs +use_2to3_fixers = setuptools.dist:assert_string_list +zip_safe = setuptools.dist:assert_bool [egg_info.writers] -namespace_packages.txt = setuptools.command.egg_info:overwrite_arg -eager_resources.txt = setuptools.command.egg_info:overwrite_arg -entry_points.txt = setuptools.command.egg_info:write_entries PKG-INFO = setuptools.command.egg_info:write_pkg_info -depends.txt = setuptools.command.egg_info:warn_depends_obsolete dependency_links.txt = setuptools.command.egg_info:overwrite_arg -top_level.txt = setuptools.command.egg_info:write_toplevel_names +depends.txt = setuptools.command.egg_info:warn_depends_obsolete +eager_resources.txt = setuptools.command.egg_info:overwrite_arg +entry_points.txt = setuptools.command.egg_info:write_entries +namespace_packages.txt = setuptools.command.egg_info:overwrite_arg requires.txt = setuptools.command.egg_info:write_requirements +top_level.txt = setuptools.command.egg_info:write_toplevel_names -[console_scripts] -easy_install = setuptools.command.easy_install:main -easy_install-3.4 = setuptools.command.easy_install:main +[setuptools.installation] +eggsecutable = setuptools.command.easy_install:bootstrap diff -Nru python-setuptools-3.3/setuptools.egg-info/entry_points.txt.orig python-setuptools-20.1.1/setuptools.egg-info/entry_points.txt.orig --- python-setuptools-3.3/setuptools.egg-info/entry_points.txt.orig 2014-03-16 07:59:06.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/entry_points.txt.orig 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -[setuptools.installation] -eggsecutable = setuptools.command.easy_install:bootstrap - -[setuptools.file_finders] -svn_cvs = setuptools.command.sdist:_default_revctrl - -[distutils.setup_keywords] -tests_require = setuptools.dist:check_requirements -entry_points = setuptools.dist:check_entry_points -namespace_packages = setuptools.dist:check_nsp -eager_resources = setuptools.dist:assert_string_list -use_2to3_fixers = setuptools.dist:assert_string_list -packages = setuptools.dist:check_packages -package_data = setuptools.dist:check_package_data -test_loader = setuptools.dist:check_importable -convert_2to3_doctests = setuptools.dist:assert_string_list -dependency_links = setuptools.dist:assert_string_list -extras_require = setuptools.dist:check_extras -zip_safe = setuptools.dist:assert_bool -install_requires = setuptools.dist:check_requirements -include_package_data = setuptools.dist:assert_bool -use_2to3_exclude_fixers = setuptools.dist:assert_string_list -test_suite = setuptools.dist:check_test_suite -use_2to3 = setuptools.dist:assert_bool -exclude_package_data = setuptools.dist:check_package_data - -[egg_info.writers] -namespace_packages.txt = setuptools.command.egg_info:overwrite_arg -dependency_links.txt = setuptools.command.egg_info:overwrite_arg -PKG-INFO = setuptools.command.egg_info:write_pkg_info -entry_points.txt = setuptools.command.egg_info:write_entries -eager_resources.txt = setuptools.command.egg_info:overwrite_arg -requires.txt = setuptools.command.egg_info:write_requirements -depends.txt = setuptools.command.egg_info:warn_depends_obsolete -top_level.txt = setuptools.command.egg_info:write_toplevel_names - -[distutils.commands] -test = setuptools.command.test:test -install = setuptools.command.install:install -egg_info = setuptools.command.egg_info:egg_info -sdist = setuptools.command.sdist:sdist -upload_docs = setuptools.command.upload_docs:upload_docs -build_py = setuptools.command.build_py:build_py -bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst -setopt = setuptools.command.setopt:setopt -install_lib = setuptools.command.install_lib:install_lib -bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm -rotate = setuptools.command.rotate:rotate -bdist_egg = setuptools.command.bdist_egg:bdist_egg -install_scripts = setuptools.command.install_scripts:install_scripts -alias = setuptools.command.alias:alias -install_egg_info = setuptools.command.install_egg_info:install_egg_info -easy_install = setuptools.command.easy_install:easy_install -build_ext = setuptools.command.build_ext:build_ext -saveopts = setuptools.command.saveopts:saveopts -register = setuptools.command.register:register -develop = setuptools.command.develop:develop - -[console_scripts] -easy_install-3.4 = setuptools.command.easy_install:main -easy_install = setuptools.command.easy_install:main - diff -Nru python-setuptools-3.3/setuptools.egg-info/PKG-INFO python-setuptools-20.1.1/setuptools.egg-info/PKG-INFO --- python-setuptools-3.3/setuptools.egg-info/PKG-INFO 2014-03-16 09:04:36.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/PKG-INFO 2016-02-12 16:11:10.000000000 +0000 @@ -1,1879 +1,261 @@ -Metadata-Version: 1.1 -Name: setuptools -Version: 3.3 -Summary: Easily download, build, install, upgrade, and uninstall Python packages -Home-page: https://pypi.python.org/pypi/setuptools -Author: Python Packaging Authority -Author-email: distutils-sig@python.org -License: PSF or ZPL -Description: =============================== - Installing and Using Setuptools - =============================== - - .. contents:: **Table of Contents** - - - ------------------------- - Installation Instructions - ------------------------- - - The recommended way to bootstrap setuptools on any system is to download - `ez_setup.py`_ and run it using the target Python environment. Different - operating systems have different recommended techniques to accomplish this - basic routine, so below are some examples to get you started. - - Setuptools requires Python 2.6 or later. To install setuptools - on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x - `_. - - The link provided to ez_setup.py is a bookmark to bootstrap script for the - latest known stable release. - - .. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py - - Windows 8 (Powershell) - ====================== - - For best results, uninstall previous versions FIRST (see `Uninstalling`_). - - Using Windows 8 or later, it's possible to install with one simple Powershell - command. Start up Powershell and paste this command:: - - > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | python - - - You must start the Powershell with Administrative privileges or you may choose - to install a user-local installation:: - - > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | python - --user - - If you have Python 3.3 or later, you can use the ``py`` command to install to - different Python versions. For example, to install to Python 3.3 if you have - Python 2.7 installed:: - - > (Invoke-WebRequest https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py).Content | py -3 - - - The recommended way to install setuptools on Windows is to download - `ez_setup.py`_ and run it. The script will download the appropriate .egg - file and install it for you. - - Once installation is complete, you will find an ``easy_install`` program in - your Python ``Scripts`` subdirectory. For simple invocation and best results, - add this directory to your ``PATH`` environment variable, if it is not already - present. If you did a user-local install, the ``Scripts`` subdirectory is - ``$env:APPDATA\Python\Scripts``. - - - Windows 7 (or graphical install) - ================================ - - For Windows 7 and earlier, download `ez_setup.py`_ using your favorite web - browser or other technique and "run" that file. - - - Unix (wget) - =========== - - Most Linux distributions come with wget. - - Download `ez_setup.py`_ and run it using the target Python version. The script - will download the appropriate version and install it for you:: - - > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python - - Note that you will may need to invoke the command with superuser privileges to - install to the system Python:: - - > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | sudo python - - Alternatively, Setuptools may be installed to a user-local path:: - - > wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python - --user - - Unix including Mac OS X (curl) - ============================== - - If your system has curl installed, follow the ``wget`` instructions but - replace ``wget`` with ``curl`` and ``-O`` with ``-o``. For example:: - - > curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -o - | python - - - Advanced Installation - ===================== - - For more advanced installation options, such as installing to custom - locations or prefixes, download and extract the source - tarball from `Setuptools on PyPI `_ - and run setup.py with any supported distutils and Setuptools options. - For example:: - - setuptools-x.x$ python setup.py install --prefix=/opt/setuptools - - Use ``--help`` to get a full options list, but we recommend consulting - the `EasyInstall manual`_ for detailed instructions, especially `the section - on custom installation locations`_. - - .. _EasyInstall manual: https://pythonhosted.org/setuptools/EasyInstall - .. _the section on custom installation locations: https://pythonhosted.org/setuptools/EasyInstall#custom-installation-locations - - - Downloads - ========= - - All setuptools downloads can be found at `the project's home page in the Python - Package Index`_. Scroll to the very bottom of the page to find the links. - - .. _the project's home page in the Python Package Index: https://pypi.python.org/pypi/setuptools - - In addition to the PyPI downloads, the development version of ``setuptools`` - is available from the `Bitbucket repo`_, and in-development versions of the - `0.6 branch`_ are available as well. - - .. _Bitbucket repo: https://bitbucket.org/pypa/setuptools/get/default.tar.gz#egg=setuptools-dev - .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 - - Uninstalling - ============ - - On Windows, if Setuptools was installed using an ``.exe`` or ``.msi`` - installer, simply use the uninstall feature of "Add/Remove Programs" in the - Control Panel. - - Otherwise, to uninstall Setuptools or Distribute, regardless of the Python - version, delete all ``setuptools*`` and ``distribute*`` files and - directories from your system's ``site-packages`` directory - (and any other ``sys.path`` directories) FIRST. - - If you are upgrading or otherwise plan to re-install Setuptools or Distribute, - nothing further needs to be done. If you want to completely remove Setuptools, - you may also want to remove the 'easy_install' and 'easy_install-x.x' scripts - and associated executables installed to the Python scripts directory. - - -------------------------------- - Using Setuptools and EasyInstall - -------------------------------- - - Here are some of the available manuals, tutorials, and other resources for - learning about Setuptools, Python Eggs, and EasyInstall: - - * `The EasyInstall user's guide and reference manual`_ - * `The setuptools Developer's Guide`_ - * `The pkg_resources API reference`_ - * `Package Compatibility Notes`_ (user-maintained) - * `The Internal Structure of Python Eggs`_ - - Questions, comments, and bug reports should be directed to the `distutils-sig - mailing list`_. If you have written (or know of) any tutorials, documentation, - plug-ins, or other resources for setuptools users, please let us know about - them there, so this reference list can be updated. If you have working, - *tested* patches to correct problems or add features, you may submit them to - the `setuptools bug tracker`_. - - .. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/issues - .. _Package Compatibility Notes: https://pythonhosted.org/setuptools/PackageNotes - .. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html - .. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html - .. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html - .. _The EasyInstall user's guide and reference manual: https://pythonhosted.org/setuptools/easy_install.html - .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ - - - ------- - Credits - ------- - - * The original design for the ``.egg`` format and the ``pkg_resources`` API was - co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first - version of ``pkg_resources``, and supplied the OS X operating system version - compatibility algorithm. - - * Ian Bicking implemented many early "creature comfort" features of - easy_install, including support for downloading via Sourceforge and - Subversion repositories. Ian's comments on the Web-SIG about WSGI - application deployment also inspired the concept of "entry points" in eggs, - and he has given talks at PyCon and elsewhere to inform and educate the - community about eggs and setuptools. - - * Jim Fulton contributed time and effort to build automated tests of various - aspects of ``easy_install``, and supplied the doctests for the command-line - ``.exe`` wrappers on Windows. - - * Phillip J. Eby is the seminal author of setuptools, and - first proposed the idea of an importable binary distribution format for - Python application plug-ins. - - * Significant parts of the implementation of setuptools were funded by the Open - Source Applications Foundation, to provide a plug-in infrastructure for the - Chandler PIM application. In addition, many OSAF staffers (such as Mike - "Code Bear" Taylor) contributed their time and stress as guinea pigs for the - use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) - - * Tarek Ziadé is the principal author of the Distribute fork, which - re-invigorated the community on the project, encouraged renewed innovation, - and addressed many defects. - - * Since the merge with Distribute, Jason R. Coombs is the - maintainer of setuptools. The project is maintained in coordination with - the Python Packaging Authority (PyPA) and the larger Python community. - - .. _files: - - ======= - CHANGES - ======= - - --- - 3.3 - --- - - * Add ``include`` parameter to ``setuptools.find_packages()``. - - --- - 3.2 - --- - - * `Pull Request #39 `_: Add support for C++ targets from Cython ``.pyx`` files. - * `Issue #162 `_: Update dependency on certifi to 1.0.1. - * `Issue #164 `_: Update dependency on wincertstore to 0.2. - - --- - 3.1 - --- - - * `Issue #161 `_: Restore Features functionality to allow backward compatibility - (for Features) until the uses of that functionality is sufficiently removed. - - ----- - 3.0.2 - ----- - - * Correct typo in previous bugfix. - - ----- - 3.0.1 - ----- - - * `Issue #157 `_: Restore support for Python 2.6 in bootstrap script where - ``zipfile.ZipFile`` does not yet have support for context managers. - - --- - 3.0 - --- - - * `Issue #125 `_: Prevent Subversion support from creating a ~/.subversion - directory just for checking the presence of a Subversion repository. - * `Issue #12 `_: Namespace packages are now imported lazily. That is, the mere - declaration of a namespace package in an egg on ``sys.path`` no longer - causes it to be imported when ``pkg_resources`` is imported. Note that this - change means that all of a namespace package's ``__init__.py`` files must - include a ``declare_namespace()`` call in order to ensure that they will be - handled properly at runtime. In 2.x it was possible to get away without - including the declaration, but only at the cost of forcing namespace - packages to be imported early, which 3.0 no longer does. - * `Issue #148 `_: When building (bdist_egg), setuptools no longer adds - ``__init__.py`` files to namespace packages. Any packages that rely on this - behavior will need to create ``__init__.py`` files and include the - ``declare_namespace()``. - * `Issue #7 `_: Setuptools itself is now distributed as a zip archive in addition to - tar archive. ez_setup.py now uses zip archive. This approach avoids the potential - security vulnerabilities presented by use of tar archives in ez_setup.py. - It also leverages the security features added to ZipFile.extract in Python 2.7.4. - * `Issue #65 `_: Removed deprecated Features functionality. - * `Pull Request #28 `_: Remove backport of ``_bytecode_filenames`` which is - available in Python 2.6 and later, but also has better compatibility with - Python 3 environments. - * `Issue #156 `_: Fix spelling of __PYVENV_LAUNCHER__ variable. - - --- - 2.2 - --- - - * `Issue #141 `_: Restored fix for allowing setup_requires dependencies to - override installed dependencies during setup. - * `Issue #128 `_: Fixed issue where only the first dependency link was honored - in a distribution where multiple dependency links were supplied. - - ----- - 2.1.2 - ----- - - * `Issue #144 `_: Read long_description using codecs module to avoid errors - installing on systems where LANG=C. - - ----- - 2.1.1 - ----- - - * `Issue #139 `_: Fix regression in re_finder for CVS repos (and maybe Git repos - as well). - - --- - 2.1 - --- - - * `Issue #129 `_: Suppress inspection of ``*.whl`` files when searching for files - in a zip-imported file. - * `Issue #131 `_: Fix RuntimeError when constructing an egg fetcher. - - ----- - 2.0.2 - ----- - - * Fix NameError during installation with Python implementations (e.g. Jython) - not containing parser module. - * Fix NameError in ``sdist:re_finder``. - - ----- - 2.0.1 - ----- - - * `Issue #124 `_: Fixed error in list detection in upload_docs. - - --- - 2.0 - --- - - * `Issue #121 `_: Exempt lib2to3 pickled grammars from DirectorySandbox. - * `Issue #41 `_: Dropped support for Python 2.4 and Python 2.5. Clients requiring - setuptools for those versions of Python should use setuptools 1.x. - * Removed ``setuptools.command.easy_install.HAS_USER_SITE``. Clients - expecting this boolean variable should use ``site.ENABLE_USER_SITE`` - instead. - * Removed ``pkg_resources.ImpWrapper``. Clients that expected this class - should use ``pkgutil.ImpImporter`` instead. - - ----- - 1.4.2 - ----- - - * `Issue #116 `_: Correct TypeError when reading a local package index on Python - 3. - - ----- - 1.4.1 - ----- - - * `Issue #114 `_: Use ``sys.getfilesystemencoding`` for decoding config in - ``bdist_wininst`` distributions. - - * `Issue #105 `_ and `Issue #113 `_: Establish a more robust technique for - determining the terminal encoding:: - - 1. Try ``getpreferredencoding`` - 2. If that returns US_ASCII or None, try the encoding from - ``getdefaultlocale``. If that encoding was a "fallback" because Python - could not figure it out from the environment or OS, encoding remains - unresolved. - 3. If the encoding is resolved, then make sure Python actually implements - the encoding. - 4. On the event of an error or unknown codec, revert to fallbacks - (UTF-8 on Darwin, ASCII on everything else). - 5. On the encoding is 'mac-roman' on Darwin, use UTF-8 as 'mac-roman' was - a bug on older Python releases. - - On a side note, it would seem that the encoding only matters for when SVN - does not yet support ``--xml`` and when getting repository and svn version - numbers. The ``--xml`` technique should yield UTF-8 according to some - messages on the SVN mailing lists. So if the version numbers are always - 7-bit ASCII clean, it may be best to only support the file parsing methods - for legacy SVN releases and support for SVN without the subprocess command - would simple go away as support for the older SVNs does. - - --- - 1.4 - --- - - * `Issue #27 `_: ``easy_install`` will now use credentials from .pypirc if - present for connecting to the package index. - * `Pull Request #21 `_: Omit unwanted newlines in ``package_index._encode_auth`` - when the username/password pair length indicates wrapping. - - ----- - 1.3.2 - ----- - - * `Issue #99 `_: Fix filename encoding issues in SVN support. - - ----- - 1.3.1 - ----- - - * Remove exuberant warning in SVN support when SVN is not used. - - --- - 1.3 - --- - - * Address security vulnerability in SSL match_hostname check as reported in - `Python #17997 `_. - * Prefer `backports.ssl_match_hostname - `_ for backport - implementation if present. - * Correct NameError in ``ssl_support`` module (``socket.error``). - - --- - 1.2 - --- - - * `Issue #26 `_: Add support for SVN 1.7. Special thanks to Philip Thiem for the - contribution. - * `Issue #93 `_: Wheels are now distributed with every release. Note that as - reported in `Issue #108 `_, as of Pip 1.4, scripts aren't installed properly - from wheels. Therefore, if using Pip to install setuptools from a wheel, - the ``easy_install`` command will not be available. - * Setuptools "natural" launcher support, introduced in 1.0, is now officially - supported. - - ----- - 1.1.7 - ----- - - * Fixed behavior of NameError handling in 'script template (dev).py' (script - launcher for 'develop' installs). - * ``ez_setup.py`` now ensures partial downloads are cleaned up following - a failed download. - * `Distribute #363 `_ and `Issue #55 `_: Skip an sdist test that fails on locales - other than UTF-8. - - ----- - 1.1.6 - ----- - - * `Distribute #349 `_: ``sandbox.execfile`` now opens the target file in binary - mode, thus honoring a BOM in the file when compiled. - - ----- - 1.1.5 - ----- - - * `Issue #69 `_: Second attempt at fix (logic was reversed). - - ----- - 1.1.4 - ----- - - * `Issue #77 `_: Fix error in upload command (Python 2.4). - - ----- - 1.1.3 - ----- - - * Fix NameError in previous patch. - - ----- - 1.1.2 - ----- - - * `Issue #69 `_: Correct issue where 404 errors are returned for URLs with - fragments in them (such as #egg=). - - ----- - 1.1.1 - ----- - - * `Issue #75 `_: Add ``--insecure`` option to ez_setup.py to accommodate - environments where a trusted SSL connection cannot be validated. - * `Issue #76 `_: Fix AttributeError in upload command with Python 2.4. - - --- - 1.1 - --- - - * `Issue #71 `_ (`Distribute #333 `_): EasyInstall now puts less emphasis on the - condition when a host is blocked via ``--allow-hosts``. - * `Issue #72 `_: Restored Python 2.4 compatibility in ``ez_setup.py``. - - --- - 1.0 - --- - - * `Issue #60 `_: On Windows, Setuptools supports deferring to another launcher, - such as Vinay Sajip's `pylauncher `_ - (included with Python 3.3) to launch console and GUI scripts and not install - its own launcher executables. This experimental functionality is currently - only enabled if the ``SETUPTOOLS_LAUNCHER`` environment variable is set to - "natural". In the future, this behavior may become default, but only after - it has matured and seen substantial adoption. The ``SETUPTOOLS_LAUNCHER`` - also accepts "executable" to force the default behavior of creating launcher - executables. - * `Issue #63 `_: Bootstrap script (ez_setup.py) now prefers Powershell, curl, or - wget for retrieving the Setuptools tarball for improved security of the - install. The script will still fall back to a simple ``urlopen`` on - platforms that do not have these tools. - * `Issue #65 `_: Deprecated the ``Features`` functionality. - * `Issue #52 `_: In ``VerifyingHTTPSConn``, handle a tunnelled (proxied) - connection. - - Backward-Incompatible Changes - ============================= - - This release includes a couple of backward-incompatible changes, but most if - not all users will find 1.0 a drop-in replacement for 0.9. - - * `Issue #50 `_: Normalized API of environment marker support. Specifically, - removed line number and filename from SyntaxErrors when returned from - `pkg_resources.invalid_marker`. Any clients depending on the specific - string representation of exceptions returned by that function may need to - be updated to account for this change. - * `Issue #50 `_: SyntaxErrors generated by `pkg_resources.invalid_marker` are - normalized for cross-implementation consistency. - * Removed ``--ignore-conflicts-at-my-risk`` and ``--delete-conflicting`` - options to easy_install. These options have been deprecated since 0.6a11. - - ----- - 0.9.8 - ----- - - * `Issue #53 `_: Fix NameErrors in `_vcs_split_rev_from_url`. - - ----- - 0.9.7 - ----- - - * `Issue #49 `_: Correct AttributeError on PyPy where a hashlib.HASH object does - not have a `.name` attribute. - * `Issue #34 `_: Documentation now refers to bootstrap script in code repository - referenced by bookmark. - * Add underscore-separated keys to environment markers (markerlib). - - ----- - 0.9.6 - ----- - - * `Issue #44 `_: Test failure on Python 2.4 when MD5 hash doesn't have a `.name` - attribute. - - ----- - 0.9.5 - ----- - - * `Python #17980 `_: Fix security vulnerability in SSL certificate validation. - - ----- - 0.9.4 - ----- - - * `Issue #43 `_: Fix issue (introduced in 0.9.1) with version resolution when - upgrading over other releases of Setuptools. - - ----- - 0.9.3 - ----- - - * `Issue #42 `_: Fix new ``AttributeError`` introduced in last fix. - - ----- - 0.9.2 - ----- - - * `Issue #42 `_: Fix regression where blank checksums would trigger an - ``AttributeError``. - - ----- - 0.9.1 - ----- - - * `Distribute #386 `_: Allow other positional and keyword arguments to os.open. - * Corrected dependency on certifi mis-referenced in 0.9. - - --- - 0.9 - --- - - * `package_index` now validates hashes other than MD5 in download links. - - --- - 0.8 - --- - - * Code base now runs on Python 2.4 - Python 3.3 without Python 2to3 - conversion. - - ----- - 0.7.8 - ----- - - * `Distribute #375 `_: Yet another fix for yet another regression. - - ----- - 0.7.7 - ----- - - * `Distribute #375 `_: Repair AttributeError created in last release (redo). - * `Issue #30 `_: Added test for get_cache_path. - - ----- - 0.7.6 - ----- - - * `Distribute #375 `_: Repair AttributeError created in last release. - - ----- - 0.7.5 - ----- - - * `Issue #21 `_: Restore Python 2.4 compatibility in ``test_easy_install``. - * `Distribute #375 `_: Merged additional warning from Distribute 0.6.46. - * Now honor the environment variable - ``SETUPTOOLS_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT`` in addition to the now - deprecated ``DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT``. - - ----- - 0.7.4 - ----- - - * `Issue #20 `_: Fix comparison of parsed SVN version on Python 3. - - ----- - 0.7.3 - ----- - - * `Issue #1 `_: Disable installation of Windows-specific files on non-Windows systems. - * Use new sysconfig module with Python 2.7 or >=3.2. - - ----- - 0.7.2 - ----- - - * `Issue #14 `_: Use markerlib when the `parser` module is not available. - * `Issue #10 `_: ``ez_setup.py`` now uses HTTPS to download setuptools from PyPI. - - ----- - 0.7.1 - ----- - - * Fix NameError (`Issue #3 `_) again - broken in bad merge. - - --- - 0.7 - --- - - * Merged Setuptools and Distribute. See docs/merge.txt for details. - - Added several features that were slated for setuptools 0.6c12: - - * Index URL now defaults to HTTPS. - * Added experimental environment marker support. Now clients may designate a - PEP-426 environment marker for "extra" dependencies. Setuptools uses this - feature in ``setup.py`` for optional SSL and certificate validation support - on older platforms. Based on Distutils-SIG discussions, the syntax is - somewhat tentative. There should probably be a PEP with a firmer spec before - the feature should be considered suitable for use. - * Added support for SSL certificate validation when installing packages from - an HTTPS service. - - ----- - 0.7b4 - ----- - - * `Issue #3 `_: Fixed NameError in SSL support. - - ------ - 0.6.49 - ------ - - * Move warning check in ``get_cache_path`` to follow the directory creation - to avoid errors when the cache path does not yet exist. Fixes the error - reported in `Distribute #375 `_. - - ------ - 0.6.48 - ------ - - * Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in - 0.6.46 (redo). - - ------ - 0.6.47 - ------ - - * Correct AttributeError in ``ResourceManager.get_cache_path`` introduced in - 0.6.46. - - ------ - 0.6.46 - ------ - - * `Distribute #375 `_: Issue a warning if the PYTHON_EGG_CACHE or otherwise - customized egg cache location specifies a directory that's group- or - world-writable. - - ------ - 0.6.45 - ------ - - * `Distribute #379 `_: ``distribute_setup.py`` now traps VersionConflict as well, - restoring ability to upgrade from an older setuptools version. - - ------ - 0.6.44 - ------ - - * ``distribute_setup.py`` has been updated to allow Setuptools 0.7 to - satisfy use_setuptools. - - ------ - 0.6.43 - ------ - - * `Distribute #378 `_: Restore support for Python 2.4 Syntax (regression in 0.6.42). - - ------ - 0.6.42 - ------ - - * External links finder no longer yields duplicate links. - * `Distribute #337 `_: Moved site.py to setuptools/site-patch.py (graft of very old - patch from setuptools trunk which inspired PR `#31 `_). - - ------ - 0.6.41 - ------ - - * `Distribute #27 `_: Use public api for loading resources from zip files rather than - the private method `_zip_directory_cache`. - * Added a new function ``easy_install.get_win_launcher`` which may be used by - third-party libraries such as buildout to get a suitable script launcher. - - ------ - 0.6.40 - ------ - - * `Distribute #376 `_: brought back cli.exe and gui.exe that were deleted in the - previous release. - - ------ - 0.6.39 - ------ - - * Add support for console launchers on ARM platforms. - * Fix possible issue in GUI launchers where the subsystem was not supplied to - the linker. - * Launcher build script now refactored for robustness. - * `Distribute #375 `_: Resources extracted from a zip egg to the file system now also - check the contents of the file against the zip contents during each - invocation of get_resource_filename. - - ------ - 0.6.38 - ------ - - * `Distribute #371 `_: The launcher manifest file is now installed properly. - - ------ - 0.6.37 - ------ - - * `Distribute #143 `_: Launcher scripts, including easy_install itself, are now - accompanied by a manifest on 32-bit Windows environments to avoid the - Installer Detection Technology and thus undesirable UAC elevation described - in `this Microsoft article - `_. - - ------ - 0.6.36 - ------ - - * `Pull Request #35 `_: In `Buildout #64 `_, it was reported that - under Python 3, installation of distutils scripts could attempt to copy - the ``__pycache__`` directory as a file, causing an error, apparently only - under Windows. Easy_install now skips all directories when processing - metadata scripts. - - ------ - 0.6.35 - ------ - - - Note this release is backward-incompatible with distribute 0.6.23-0.6.34 in - how it parses version numbers. - - * `Distribute #278 `_: Restored compatibility with distribute 0.6.22 and setuptools - 0.6. Updated the documentation to match more closely with the version - parsing as intended in setuptools 0.6. - - ------ - 0.6.34 - ------ - - * `Distribute #341 `_: 0.6.33 fails to build under Python 2.4. - - ------ - 0.6.33 - ------ - - * Fix 2 errors with Jython 2.5. - * Fix 1 failure with Jython 2.5 and 2.7. - * Disable workaround for Jython scripts on Linux systems. - * `Distribute #336 `_: `setup.py` no longer masks failure exit code when tests fail. - * Fix issue in pkg_resources where try/except around a platform-dependent - import would trigger hook load failures on Mercurial. See pull request 32 - for details. - * `Distribute #341 `_: Fix a ResourceWarning. - - ------ - 0.6.32 - ------ - - * Fix test suite with Python 2.6. - * Fix some DeprecationWarnings and ResourceWarnings. - * `Distribute #335 `_: Backed out `setup_requires` superceding installed requirements - until regression can be addressed. - - ------ - 0.6.31 - ------ - - * `Distribute #303 `_: Make sure the manifest only ever contains UTF-8 in Python 3. - * `Distribute #329 `_: Properly close files created by tests for compatibility with - Jython. - * Work around `Jython #1980 `_ and `Jython #1981 `_. - * `Distribute #334 `_: Provide workaround for packages that reference `sys.__stdout__` - such as numpy does. This change should address - `virtualenv `#359 `_ `_ as long - as the system encoding is UTF-8 or the IO encoding is specified in the - environment, i.e.:: - - PYTHONIOENCODING=utf8 pip install numpy - - * Fix for encoding issue when installing from Windows executable on Python 3. - * `Distribute #323 `_: Allow `setup_requires` requirements to supercede installed - requirements. Added some new keyword arguments to existing pkg_resources - methods. Also had to updated how __path__ is handled for namespace packages - to ensure that when a new egg distribution containing a namespace package is - placed on sys.path, the entries in __path__ are found in the same order they - would have been in had that egg been on the path when pkg_resources was - first imported. - - ------ - 0.6.30 - ------ - - * `Distribute #328 `_: Clean up temporary directories in distribute_setup.py. - * Fix fatal bug in distribute_setup.py. - - ------ - 0.6.29 - ------ - - * `Pull Request #14 `_: Honor file permissions in zip files. - * `Distribute #327 `_: Merged pull request `#24 `_ to fix a dependency problem with pip. - * Merged pull request `#23 `_ to fix https://github.com/pypa/virtualenv/issues/301. - * If Sphinx is installed, the `upload_docs` command now runs `build_sphinx` - to produce uploadable documentation. - * `Distribute #326 `_: `upload_docs` provided mangled auth credentials under Python 3. - * `Distribute #320 `_: Fix check for "createable" in distribute_setup.py. - * `Distribute #305 `_: Remove a warning that was triggered during normal operations. - * `Distribute #311 `_: Print metadata in UTF-8 independent of platform. - * `Distribute #303 `_: Read manifest file with UTF-8 encoding under Python 3. - * `Distribute #301 `_: Allow to run tests of namespace packages when using 2to3. - * `Distribute #304 `_: Prevent import loop in site.py under Python 3.3. - * `Distribute #283 `_: Reenable scanning of `*.pyc` / `*.pyo` files on Python 3.3. - * `Distribute #299 `_: The develop command didn't work on Python 3, when using 2to3, - as the egg link would go to the Python 2 source. Linking to the 2to3'd code - in build/lib makes it work, although you will have to rebuild the module - before testing it. - * `Distribute #306 `_: Even if 2to3 is used, we build in-place under Python 2. - * `Distribute #307 `_: Prints the full path when .svn/entries is broken. - * `Distribute #313 `_: Support for sdist subcommands (Python 2.7) - * `Distribute #314 `_: test_local_index() would fail an OS X. - * `Distribute #310 `_: Non-ascii characters in a namespace __init__.py causes errors. - * `Distribute #218 `_: Improved documentation on behavior of `package_data` and - `include_package_data`. Files indicated by `package_data` are now included - in the manifest. - * `distribute_setup.py` now allows a `--download-base` argument for retrieving - distribute from a specified location. - - ------ - 0.6.28 - ------ - - * `Distribute #294 `_: setup.py can now be invoked from any directory. - * Scripts are now installed honoring the umask. - * Added support for .dist-info directories. - * `Distribute #283 `_: Fix and disable scanning of `*.pyc` / `*.pyo` files on - Python 3.3. - - ------ - 0.6.27 - ------ - - * Support current snapshots of CPython 3.3. - * Distribute now recognizes README.rst as a standard, default readme file. - * Exclude 'encodings' modules when removing modules from sys.modules. - Workaround for `#285 `_. - * `Distribute #231 `_: Don't fiddle with system python when used with buildout - (bootstrap.py) - - ------ - 0.6.26 - ------ - - * `Distribute #183 `_: Symlinked files are now extracted from source distributions. - * `Distribute #227 `_: Easy_install fetch parameters are now passed during the - installation of a source distribution; now fulfillment of setup_requires - dependencies will honor the parameters passed to easy_install. - - ------ - 0.6.25 - ------ - - * `Distribute #258 `_: Workaround a cache issue - * `Distribute #260 `_: distribute_setup.py now accepts the --user parameter for - Python 2.6 and later. - * `Distribute #262 `_: package_index.open_with_auth no longer throws LookupError - on Python 3. - * `Distribute #269 `_: AttributeError when an exception occurs reading Manifest.in - on late releases of Python. - * `Distribute #272 `_: Prevent TypeError when namespace package names are unicode - and single-install-externally-managed is used. Also fixes PIP issue - 449. - * `Distribute #273 `_: Legacy script launchers now install with Python2/3 support. - - ------ - 0.6.24 - ------ - - * `Distribute #249 `_: Added options to exclude 2to3 fixers - - ------ - 0.6.23 - ------ - - * `Distribute #244 `_: Fixed a test - * `Distribute #243 `_: Fixed a test - * `Distribute #239 `_: Fixed a test - * `Distribute #240 `_: Fixed a test - * `Distribute #241 `_: Fixed a test - * `Distribute #237 `_: Fixed a test - * `Distribute #238 `_: easy_install now uses 64bit executable wrappers on 64bit Python - * `Distribute #208 `_: Fixed parsed_versions, it now honors post-releases as noted in the documentation - * `Distribute #207 `_: Windows cli and gui wrappers pass CTRL-C to child python process - * `Distribute #227 `_: easy_install now passes its arguments to setup.py bdist_egg - * `Distribute #225 `_: Fixed a NameError on Python 2.5, 2.4 - - ------ - 0.6.21 - ------ - - * `Distribute #225 `_: FIxed a regression on py2.4 - - ------ - 0.6.20 - ------ - - * `Distribute #135 `_: Include url in warning when processing URLs in package_index. - * `Distribute #212 `_: Fix issue where easy_instal fails on Python 3 on windows installer. - * `Distribute #213 `_: Fix typo in documentation. - - ------ - 0.6.19 - ------ - - * `Distribute #206 `_: AttributeError: 'HTTPMessage' object has no attribute 'getheaders' - - ------ - 0.6.18 - ------ - - * `Distribute #210 `_: Fixed a regression introduced by `Distribute #204 `_ fix. - - ------ - 0.6.17 - ------ - - * Support 'DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT' environment - variable to allow to disable installation of easy_install-${version} script. - * Support Python >=3.1.4 and >=3.2.1. - * `Distribute #204 `_: Don't try to import the parent of a namespace package in - declare_namespace - * `Distribute #196 `_: Tolerate responses with multiple Content-Length headers - * `Distribute #205 `_: Sandboxing doesn't preserve working_set. Leads to setup_requires - problems. - - ------ - 0.6.16 - ------ - - * Builds sdist gztar even on Windows (avoiding `Distribute #193 `_). - * `Distribute #192 `_: Fixed metadata omitted on Windows when package_dir - specified with forward-slash. - * `Distribute #195 `_: Cython build support. - * `Distribute #200 `_: Issues with recognizing 64-bit packages on Windows. - - ------ - 0.6.15 - ------ - - * Fixed typo in bdist_egg - * Several issues under Python 3 has been solved. - * `Distribute #146 `_: Fixed missing DLL files after easy_install of windows exe package. - - ------ - 0.6.14 - ------ - - * `Distribute #170 `_: Fixed unittest failure. Thanks to Toshio. - * `Distribute #171 `_: Fixed race condition in unittests cause deadlocks in test suite. - * `Distribute #143 `_: Fixed a lookup issue with easy_install. - Thanks to David and Zooko. - * `Distribute #174 `_: Fixed the edit mode when its used with setuptools itself - - ------ - 0.6.13 - ------ - - * `Distribute #160 `_: 2.7 gives ValueError("Invalid IPv6 URL") - * `Distribute #150 `_: Fixed using ~/.local even in a --no-site-packages virtualenv - * `Distribute #163 `_: scan index links before external links, and don't use the md5 when - comparing two distributions - - ------ - 0.6.12 - ------ - - * `Distribute #149 `_: Fixed various failures on 2.3/2.4 - - ------ - 0.6.11 - ------ - - * Found another case of SandboxViolation - fixed - * `Distribute #15 `_ and `Distribute #48 `_: Introduced a socket timeout of 15 seconds on url openings - * Added indexsidebar.html into MANIFEST.in - * `Distribute #108 `_: Fixed TypeError with Python3.1 - * `Distribute #121 `_: Fixed --help install command trying to actually install. - * `Distribute #112 `_: Added an os.makedirs so that Tarek's solution will work. - * `Distribute #133 `_: Added --no-find-links to easy_install - * Added easy_install --user - * `Distribute #100 `_: Fixed develop --user not taking '.' in PYTHONPATH into account - * `Distribute #134 `_: removed spurious UserWarnings. Patch by VanLindberg - * `Distribute #138 `_: cant_write_to_target error when setup_requires is used. - * `Distribute #147 `_: respect the sys.dont_write_bytecode flag - - ------ - 0.6.10 - ------ - - * Reverted change made for the DistributionNotFound exception because - zc.buildout uses the exception message to get the name of the - distribution. - - ----- - 0.6.9 - ----- - - * `Distribute #90 `_: unknown setuptools version can be added in the working set - * `Distribute #87 `_: setupt.py doesn't try to convert distribute_setup.py anymore - Initial Patch by arfrever. - * `Distribute #89 `_: added a side bar with a download link to the doc. - * `Distribute #86 `_: fixed missing sentence in pkg_resources doc. - * Added a nicer error message when a DistributionNotFound is raised. - * `Distribute #80 `_: test_develop now works with Python 3.1 - * `Distribute #93 `_: upload_docs now works if there is an empty sub-directory. - * `Distribute #70 `_: exec bit on non-exec files - * `Distribute #99 `_: now the standalone easy_install command doesn't uses a - "setup.cfg" if any exists in the working directory. It will use it - only if triggered by ``install_requires`` from a setup.py call - (install, develop, etc). - * `Distribute #101 `_: Allowing ``os.devnull`` in Sandbox - * `Distribute #92 `_: Fixed the "no eggs" found error with MacPort - (platform.mac_ver() fails) - * `Distribute #103 `_: test_get_script_header_jython_workaround not run - anymore under py3 with C or POSIX local. Contributed by Arfrever. - * `Distribute #104 `_: remvoved the assertion when the installation fails, - with a nicer message for the end user. - * `Distribute #100 `_: making sure there's no SandboxViolation when - the setup script patches setuptools. - - ----- - 0.6.8 - ----- - - * Added "check_packages" in dist. (added in Setuptools 0.6c11) - * Fixed the DONT_PATCH_SETUPTOOLS state. - - ----- - 0.6.7 - ----- - - * `Distribute #58 `_: Added --user support to the develop command - * `Distribute #11 `_: Generated scripts now wrap their call to the script entry point - in the standard "if name == 'main'" - * Added the 'DONT_PATCH_SETUPTOOLS' environment variable, so virtualenv - can drive an installation that doesn't patch a global setuptools. - * Reviewed unladen-swallow specific change from - http://code.google.com/p/unladen-swallow/source/detail?spec=svn875&r=719 - and determined that it no longer applies. Distribute should work fine with - Unladen Swallow 2009Q3. - * `Distribute #21 `_: Allow PackageIndex.open_url to gracefully handle all cases of a - httplib.HTTPException instead of just InvalidURL and BadStatusLine. - * Removed virtual-python.py from this distribution and updated documentation - to point to the actively maintained virtualenv instead. - * `Distribute #64 `_: use_setuptools no longer rebuilds the distribute egg every - time it is run - * use_setuptools now properly respects the requested version - * use_setuptools will no longer try to import a distribute egg for the - wrong Python version - * `Distribute #74 `_: no_fake should be True by default. - * `Distribute #72 `_: avoid a bootstrapping issue with easy_install -U - - ----- - 0.6.6 - ----- - - * Unified the bootstrap file so it works on both py2.x and py3k without 2to3 - (patch by Holger Krekel) - - ----- - 0.6.5 - ----- - - * `Distribute #65 `_: cli.exe and gui.exe are now generated at build time, - depending on the platform in use. - - * `Distribute #67 `_: Fixed doc typo (PEP 381/382) - - * Distribute no longer shadows setuptools if we require a 0.7-series - setuptools. And an error is raised when installing a 0.7 setuptools with - distribute. - - * When run from within buildout, no attempt is made to modify an existing - setuptools egg, whether in a shared egg directory or a system setuptools. - - * Fixed a hole in sandboxing allowing builtin file to write outside of - the sandbox. - - ----- - 0.6.4 - ----- - - * Added the generation of `distribute_setup_3k.py` during the release. - This closes `Distribute #52 `_. - - * Added an upload_docs command to easily upload project documentation to - PyPI's https://pythonhosted.org. This close issue `Distribute #56 `_. - - * Fixed a bootstrap bug on the use_setuptools() API. - - ----- - 0.6.3 - ----- - - setuptools - ========== - - * Fixed a bunch of calls to file() that caused crashes on Python 3. - - bootstrapping - ============= - - * Fixed a bug in sorting that caused bootstrap to fail on Python 3. - - ----- - 0.6.2 - ----- - - setuptools - ========== - - * Added Python 3 support; see docs/python3.txt. - This closes `Old Setuptools #39 `_. - - * Added option to run 2to3 automatically when installing on Python 3. - This closes issue `Distribute #31 `_. - - * Fixed invalid usage of requirement.parse, that broke develop -d. - This closes `Old Setuptools #44 `_. - - * Fixed script launcher for 64-bit Windows. - This closes `Old Setuptools #2 `_. - - * KeyError when compiling extensions. - This closes `Old Setuptools #41 `_. - - bootstrapping - ============= - - * Fixed bootstrap not working on Windows. This closes issue `Distribute #49 `_. - - * Fixed 2.6 dependencies. This closes issue `Distribute #50 `_. - - * Make sure setuptools is patched when running through easy_install - This closes `Old Setuptools #40 `_. - - ----- - 0.6.1 - ----- - - setuptools - ========== - - * package_index.urlopen now catches BadStatusLine and malformed url errors. - This closes `Distribute #16 `_ and `Distribute #18 `_. - - * zip_ok is now False by default. This closes `Old Setuptools #33 `_. - - * Fixed invalid URL error catching. `Old Setuptools #20 `_. - - * Fixed invalid bootstraping with easy_install installation (`Distribute #40 `_). - Thanks to Florian Schulze for the help. - - * Removed buildout/bootstrap.py. A new repository will create a specific - bootstrap.py script. - - - bootstrapping - ============= - - * The boostrap process leave setuptools alone if detected in the system - and --root or --prefix is provided, but is not in the same location. - This closes `Distribute #10 `_. - - --- - 0.6 - --- - - setuptools - ========== - - * Packages required at build time where not fully present at install time. - This closes `Distribute #12 `_. - - * Protected against failures in tarfile extraction. This closes `Distribute #10 `_. - - * Made Jython api_tests.txt doctest compatible. This closes `Distribute #7 `_. - - * sandbox.py replaced builtin type file with builtin function open. This - closes `Distribute #6 `_. - - * Immediately close all file handles. This closes `Distribute #3 `_. - - * Added compatibility with Subversion 1.6. This references `Distribute #1 `_. - - pkg_resources - ============= - - * Avoid a call to /usr/bin/sw_vers on OSX and use the official platform API - instead. Based on a patch from ronaldoussoren. This closes issue `#5 `_. - - * Fixed a SandboxViolation for mkdir that could occur in certain cases. - This closes `Distribute #13 `_. - - * Allow to find_on_path on systems with tight permissions to fail gracefully. - This closes `Distribute #9 `_. - - * Corrected inconsistency between documentation and code of add_entry. - This closes `Distribute #8 `_. - - * Immediately close all file handles. This closes `Distribute #3 `_. - - easy_install - ============ - - * Immediately close all file handles. This closes `Distribute #3 `_. - - ----- - 0.6c9 - ----- - - * Fixed a missing files problem when using Windows source distributions on - non-Windows platforms, due to distutils not handling manifest file line - endings correctly. - - * Updated Pyrex support to work with Pyrex 0.9.6 and higher. - - * Minor changes for Jython compatibility, including skipping tests that can't - work on Jython. - - * Fixed not installing eggs in ``install_requires`` if they were also used for - ``setup_requires`` or ``tests_require``. - - * Fixed not fetching eggs in ``install_requires`` when running tests. - - * Allow ``ez_setup.use_setuptools()`` to upgrade existing setuptools - installations when called from a standalone ``setup.py``. - - * Added a warning if a namespace package is declared, but its parent package - is not also declared as a namespace. - - * Support Subversion 1.5 - - * Removed use of deprecated ``md5`` module if ``hashlib`` is available - - * Fixed ``bdist_wininst upload`` trying to upload the ``.exe`` twice - - * Fixed ``bdist_egg`` putting a ``native_libs.txt`` in the source package's - ``.egg-info``, when it should only be in the built egg's ``EGG-INFO``. - - * Ensure that _full_name is set on all shared libs before extensions are - checked for shared lib usage. (Fixes a bug in the experimental shared - library build support.) - - * Fix to allow unpacked eggs containing native libraries to fail more - gracefully under Google App Engine (with an ``ImportError`` loading the - C-based module, instead of getting a ``NameError``). - - ----- - 0.6c7 - ----- - - * Fixed ``distutils.filelist.findall()`` crashing on broken symlinks, and - ``egg_info`` command failing on new, uncommitted SVN directories. - - * Fix import problems with nested namespace packages installed via - ``--root`` or ``--single-version-externally-managed``, due to the - parent package not having the child package as an attribute. - - ----- - 0.6c6 - ----- - - * Added ``--egg-path`` option to ``develop`` command, allowing you to force - ``.egg-link`` files to use relative paths (allowing them to be shared across - platforms on a networked drive). - - * Fix not building binary RPMs correctly. - - * Fix "eggsecutables" (such as setuptools' own egg) only being runnable with - bash-compatible shells. - - * Fix ``#!`` parsing problems in Windows ``.exe`` script wrappers, when there - was whitespace inside a quoted argument or at the end of the ``#!`` line - (a regression introduced in 0.6c4). - - * Fix ``test`` command possibly failing if an older version of the project - being tested was installed on ``sys.path`` ahead of the test source - directory. - - * Fix ``find_packages()`` treating ``ez_setup`` and directories with ``.`` in - their names as packages. - - ----- - 0.6c5 - ----- - - * Fix uploaded ``bdist_rpm`` packages being described as ``bdist_egg`` - packages under Python versions less than 2.5. - - * Fix uploaded ``bdist_wininst`` packages being described as suitable for - "any" version by Python 2.5, even if a ``--target-version`` was specified. - - ----- - 0.6c4 - ----- - - * Overhauled Windows script wrapping to support ``bdist_wininst`` better. - Scripts installed with ``bdist_wininst`` will always use ``#!python.exe`` or - ``#!pythonw.exe`` as the executable name (even when built on non-Windows - platforms!), and the wrappers will look for the executable in the script's - parent directory (which should find the right version of Python). - - * Fix ``upload`` command not uploading files built by ``bdist_rpm`` or - ``bdist_wininst`` under Python 2.3 and 2.4. - - * Add support for "eggsecutable" headers: a ``#!/bin/sh`` script that is - prepended to an ``.egg`` file to allow it to be run as a script on Unix-ish - platforms. (This is mainly so that setuptools itself can have a single-file - installer on Unix, without doing multiple downloads, dealing with firewalls, - etc.) - - * Fix problem with empty revision numbers in Subversion 1.4 ``entries`` files - - * Use cross-platform relative paths in ``easy-install.pth`` when doing - ``develop`` and the source directory is a subdirectory of the installation - target directory. - - * Fix a problem installing eggs with a system packaging tool if the project - contained an implicit namespace package; for example if the ``setup()`` - listed a namespace package ``foo.bar`` without explicitly listing ``foo`` - as a namespace package. - - ----- - 0.6c3 - ----- - - * Fixed breakages caused by Subversion 1.4's new "working copy" format - - ----- - 0.6c2 - ----- - - * The ``ez_setup`` module displays the conflicting version of setuptools (and - its installation location) when a script requests a version that's not - available. - - * Running ``setup.py develop`` on a setuptools-using project will now install - setuptools if needed, instead of only downloading the egg. - - ----- - 0.6c1 - ----- - - * Fixed ``AttributeError`` when trying to download a ``setup_requires`` - dependency when a distribution lacks a ``dependency_links`` setting. - - * Made ``zip-safe`` and ``not-zip-safe`` flag files contain a single byte, so - as to play better with packaging tools that complain about zero-length - files. - - * Made ``setup.py develop`` respect the ``--no-deps`` option, which it - previously was ignoring. - - * Support ``extra_path`` option to ``setup()`` when ``install`` is run in - backward-compatibility mode. - - * Source distributions now always include a ``setup.cfg`` file that explicitly - sets ``egg_info`` options such that they produce an identical version number - to the source distribution's version number. (Previously, the default - version number could be different due to the use of ``--tag-date``, or if - the version was overridden on the command line that built the source - distribution.) - - ----- - 0.6b4 - ----- - - * Fix ``register`` not obeying name/version set by ``egg_info`` command, if - ``egg_info`` wasn't explicitly run first on the same command line. - - * Added ``--no-date`` and ``--no-svn-revision`` options to ``egg_info`` - command, to allow suppressing tags configured in ``setup.cfg``. - - * Fixed redundant warnings about missing ``README`` file(s); it should now - appear only if you are actually a source distribution. - - ----- - 0.6b3 - ----- - - * Fix ``bdist_egg`` not including files in subdirectories of ``.egg-info``. - - * Allow ``.py`` files found by the ``include_package_data`` option to be - automatically included. Remove duplicate data file matches if both - ``include_package_data`` and ``package_data`` are used to refer to the same - files. - - ----- - 0.6b1 - ----- - - * Strip ``module`` from the end of compiled extension modules when computing - the name of a ``.py`` loader/wrapper. (Python's import machinery ignores - this suffix when searching for an extension module.) - - ------ - 0.6a11 - ------ - - * Added ``test_loader`` keyword to support custom test loaders - - * Added ``setuptools.file_finders`` entry point group to allow implementing - revision control plugins. - - * Added ``--identity`` option to ``upload`` command. - - * Added ``dependency_links`` to allow specifying URLs for ``--find-links``. - - * Enhanced test loader to scan packages as well as modules, and call - ``additional_tests()`` if present to get non-unittest tests. - - * Support namespace packages in conjunction with system packagers, by omitting - the installation of any ``__init__.py`` files for namespace packages, and - adding a special ``.pth`` file to create a working package in - ``sys.modules``. - - * Made ``--single-version-externally-managed`` automatic when ``--root`` is - used, so that most system packagers won't require special support for - setuptools. - - * Fixed ``setup_requires``, ``tests_require``, etc. not using ``setup.cfg`` or - other configuration files for their option defaults when installing, and - also made the install use ``--multi-version`` mode so that the project - directory doesn't need to support .pth files. - - * ``MANIFEST.in`` is now forcibly closed when any errors occur while reading - it. Previously, the file could be left open and the actual error would be - masked by problems trying to remove the open file on Windows systems. - - ------ - 0.6a10 - ------ - - * Fixed the ``develop`` command ignoring ``--find-links``. - - ----- - 0.6a9 - ----- - - * The ``sdist`` command no longer uses the traditional ``MANIFEST`` file to - create source distributions. ``MANIFEST.in`` is still read and processed, - as are the standard defaults and pruning. But the manifest is built inside - the project's ``.egg-info`` directory as ``SOURCES.txt``, and it is rebuilt - every time the ``egg_info`` command is run. - - * Added the ``include_package_data`` keyword to ``setup()``, allowing you to - automatically include any package data listed in revision control or - ``MANIFEST.in`` - - * Added the ``exclude_package_data`` keyword to ``setup()``, allowing you to - trim back files included via the ``package_data`` and - ``include_package_data`` options. - - * Fixed ``--tag-svn-revision`` not working when run from a source - distribution. - - * Added warning for namespace packages with missing ``declare_namespace()`` - - * Added ``tests_require`` keyword to ``setup()``, so that e.g. packages - requiring ``nose`` to run unit tests can make this dependency optional - unless the ``test`` command is run. - - * Made all commands that use ``easy_install`` respect its configuration - options, as this was causing some problems with ``setup.py install``. - - * Added an ``unpack_directory()`` driver to ``setuptools.archive_util``, so - that you can process a directory tree through a processing filter as if it - were a zipfile or tarfile. - - * Added an internal ``install_egg_info`` command to use as part of old-style - ``install`` operations, that installs an ``.egg-info`` directory with the - package. - - * Added a ``--single-version-externally-managed`` option to the ``install`` - command so that you can more easily wrap a "flat" egg in a system package. - - * Enhanced ``bdist_rpm`` so that it installs single-version eggs that - don't rely on a ``.pth`` file. The ``--no-egg`` option has been removed, - since all RPMs are now built in a more backwards-compatible format. - - * Support full roundtrip translation of eggs to and from ``bdist_wininst`` - format. Running ``bdist_wininst`` on a setuptools-based package wraps the - egg in an .exe that will safely install it as an egg (i.e., with metadata - and entry-point wrapper scripts), and ``easy_install`` can turn the .exe - back into an ``.egg`` file or directory and install it as such. - - - ----- - 0.6a8 - ----- - - * Fixed some problems building extensions when Pyrex was installed, especially - with Python 2.4 and/or packages using SWIG. - - * Made ``develop`` command accept all the same options as ``easy_install``, - and use the ``easy_install`` command's configuration settings as defaults. - - * Made ``egg_info --tag-svn-revision`` fall back to extracting the revision - number from ``PKG-INFO`` in case it is being run on a source distribution of - a snapshot taken from a Subversion-based project. - - * Automatically detect ``.dll``, ``.so`` and ``.dylib`` files that are being - installed as data, adding them to ``native_libs.txt`` automatically. - - * Fixed some problems with fresh checkouts of projects that don't include - ``.egg-info/PKG-INFO`` under revision control and put the project's source - code directly in the project directory. If such a package had any - requirements that get processed before the ``egg_info`` command can be run, - the setup scripts would fail with a "Missing 'Version:' header and/or - PKG-INFO file" error, because the egg runtime interpreted the unbuilt - metadata in a directory on ``sys.path`` (i.e. the current directory) as - being a corrupted egg. Setuptools now monkeypatches the distribution - metadata cache to pretend that the egg has valid version information, until - it has a chance to make it actually be so (via the ``egg_info`` command). - - ----- - 0.6a5 - ----- - - * Fixed missing gui/cli .exe files in distribution. Fixed bugs in tests. - - ----- - 0.6a3 - ----- - - * Added ``gui_scripts`` entry point group to allow installing GUI scripts - on Windows and other platforms. (The special handling is only for Windows; - other platforms are treated the same as for ``console_scripts``.) - - ----- - 0.6a2 - ----- - - * Added ``console_scripts`` entry point group to allow installing scripts - without the need to create separate script files. On Windows, console - scripts get an ``.exe`` wrapper so you can just type their name. On other - platforms, the scripts are written without a file extension. - - ----- - 0.6a1 - ----- - - * Added support for building "old-style" RPMs that don't install an egg for - the target package, using a ``--no-egg`` option. - - * The ``build_ext`` command now works better when using the ``--inplace`` - option and multiple Python versions. It now makes sure that all extensions - match the current Python version, even if newer copies were built for a - different Python version. - - * The ``upload`` command no longer attaches an extra ``.zip`` when uploading - eggs, as PyPI now supports egg uploads without trickery. - - * The ``ez_setup`` script/module now displays a warning before downloading - the setuptools egg, and attempts to check the downloaded egg against an - internal MD5 checksum table. - - * Fixed the ``--tag-svn-revision`` option of ``egg_info`` not finding the - latest revision number; it was using the revision number of the directory - containing ``setup.py``, not the highest revision number in the project. - - * Added ``eager_resources`` setup argument - - * The ``sdist`` command now recognizes Subversion "deleted file" entries and - does not include them in source distributions. - - * ``setuptools`` now embeds itself more thoroughly into the distutils, so that - other distutils extensions (e.g. py2exe, py2app) will subclass setuptools' - versions of things, rather than the native distutils ones. - - * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``; - ``setup_requires`` allows you to automatically find and download packages - that are needed in order to *build* your project (as opposed to running it). - - * ``setuptools`` now finds its commands, ``setup()`` argument validators, and - metadata writers using entry points, so that they can be extended by - third-party packages. See `Creating distutils Extensions - `_ - for more details. - - * The vestigial ``depends`` command has been removed. It was never finished - or documented, and never would have worked without EasyInstall - which it - pre-dated and was never compatible with. - - ------ - 0.5a12 - ------ - - * The zip-safety scanner now checks for modules that might be used with - ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't - handle ``-m`` on zipped modules. - - ------ - 0.5a11 - ------ - - * Fix breakage of the "develop" command that was caused by the addition of - ``--always-unzip`` to the ``easy_install`` command. - - ----- - 0.5a9 - ----- - - * Include ``svn:externals`` directories in source distributions as well as - normal subversion-controlled files and directories. - - * Added ``exclude=patternlist`` option to ``setuptools.find_packages()`` - - * Changed --tag-svn-revision to include an "r" in front of the revision number - for better readability. - - * Added ability to build eggs without including source files (except for any - scripts, of course), using the ``--exclude-source-files`` option to - ``bdist_egg``. - - * ``setup.py install`` now automatically detects when an "unmanaged" package - or module is going to be on ``sys.path`` ahead of a package being installed, - thereby preventing the newer version from being imported. If this occurs, - a warning message is output to ``sys.stderr``, but installation proceeds - anyway. The warning message informs the user what files or directories - need deleting, and advises them they can also use EasyInstall (with the - ``--delete-conflicting`` option) to do it automatically. - - * The ``egg_info`` command now adds a ``top_level.txt`` file to the metadata - directory that lists all top-level modules and packages in the distribution. - This is used by the ``easy_install`` command to find possibly-conflicting - "unmanaged" packages when installing the distribution. - - * Added ``zip_safe`` and ``namespace_packages`` arguments to ``setup()``. - Added package analysis to determine zip-safety if the ``zip_safe`` flag - is not given, and advise the author regarding what code might need changing. - - * Fixed the swapped ``-d`` and ``-b`` options of ``bdist_egg``. - - ----- - 0.5a8 - ----- - - * The "egg_info" command now always sets the distribution metadata to "safe" - forms of the distribution name and version, so that distribution files will - be generated with parseable names (i.e., ones that don't include '-' in the - name or version). Also, this means that if you use the various ``--tag`` - options of "egg_info", any distributions generated will use the tags in the - version, not just egg distributions. - - * Added support for defining command aliases in distutils configuration files, - under the "[aliases]" section. To prevent recursion and to allow aliases to - call the command of the same name, a given alias can be expanded only once - per command-line invocation. You can define new aliases with the "alias" - command, either for the local, global, or per-user configuration. - - * Added "rotate" command to delete old distribution files, given a set of - patterns to match and the number of files to keep. (Keeps the most - recently-modified distribution files matching each pattern.) - - * Added "saveopts" command that saves all command-line options for the current - invocation to the local, global, or per-user configuration file. Useful for - setting defaults without having to hand-edit a configuration file. - - * Added a "setopt" command that sets a single option in a specified distutils - configuration file. - - ----- - 0.5a7 - ----- - - * Added "upload" support for egg and source distributions, including a bug - fix for "upload" and a temporary workaround for lack of .egg support in - PyPI. - - ----- - 0.5a6 - ----- - - * Beefed up the "sdist" command so that if you don't have a MANIFEST.in, it - will include all files under revision control (CVS or Subversion) in the - current directory, and it will regenerate the list every time you create a - source distribution, not just when you tell it to. This should make the - default "do what you mean" more often than the distutils' default behavior - did, while still retaining the old behavior in the presence of MANIFEST.in. - - * Fixed the "develop" command always updating .pth files, even if you - specified ``-n`` or ``--dry-run``. - - * Slightly changed the format of the generated version when you use - ``--tag-build`` on the "egg_info" command, so that you can make tagged - revisions compare *lower* than the version specified in setup.py (e.g. by - using ``--tag-build=dev``). - - ----- - 0.5a5 - ----- - - * Added ``develop`` command to ``setuptools``-based packages. This command - installs an ``.egg-link`` pointing to the package's source directory, and - script wrappers that ``execfile()`` the source versions of the package's - scripts. This lets you put your development checkout(s) on sys.path without - having to actually install them. (To uninstall the link, use - use ``setup.py develop --uninstall``.) - - * Added ``egg_info`` command to ``setuptools``-based packages. This command - just creates or updates the "projectname.egg-info" directory, without - building an egg. (It's used by the ``bdist_egg``, ``test``, and ``develop`` - commands.) - - * Enhanced the ``test`` command so that it doesn't install the package, but - instead builds any C extensions in-place, updates the ``.egg-info`` - metadata, adds the source directory to ``sys.path``, and runs the tests - directly on the source. This avoids an "unmanaged" installation of the - package to ``site-packages`` or elsewhere. - - * Made ``easy_install`` a standard ``setuptools`` command, moving it from - the ``easy_install`` module to ``setuptools.command.easy_install``. Note - that if you were importing or extending it, you must now change your imports - accordingly. ``easy_install.py`` is still installed as a script, but not as - a module. - - ----- - 0.5a4 - ----- - - * Setup scripts using setuptools can now list their dependencies directly in - the setup.py file, without having to manually create a ``depends.txt`` file. - The ``install_requires`` and ``extras_require`` arguments to ``setup()`` - are used to create a dependencies file automatically. If you are manually - creating ``depends.txt`` right now, please switch to using these setup - arguments as soon as practical, because ``depends.txt`` support will be - removed in the 0.6 release cycle. For documentation on the new arguments, - see the ``setuptools.dist.Distribution`` class. - - * Setup scripts using setuptools now always install using ``easy_install`` - internally, for ease of uninstallation and upgrading. - - ----- - 0.5a1 - ----- - - * Added support for "self-installation" bootstrapping. Packages can now - include ``ez_setup.py`` in their source distribution, and add the following - to their ``setup.py``, in order to automatically bootstrap installation of - setuptools as part of their setup process:: - - from ez_setup import use_setuptools - use_setuptools() - - from setuptools import setup - # etc... - - ----- - 0.4a2 - ----- - - * Added ``ez_setup.py`` installer/bootstrap script to make initial setuptools - installation easier, and to allow distributions using setuptools to avoid - having to include setuptools in their source distribution. - - * All downloads are now managed by the ``PackageIndex`` class (which is now - subclassable and replaceable), so that embedders can more easily override - download logic, give download progress reports, etc. The class has also - been moved to the new ``setuptools.package_index`` module. - - * The ``Installer`` class no longer handles downloading, manages a temporary - directory, or tracks the ``zip_ok`` option. Downloading is now handled - by ``PackageIndex``, and ``Installer`` has become an ``easy_install`` - command class based on ``setuptools.Command``. - - * There is a new ``setuptools.sandbox.run_setup()`` API to invoke a setup - script in a directory sandbox, and a new ``setuptools.archive_util`` module - with an ``unpack_archive()`` API. These were split out of EasyInstall to - allow reuse by other tools and applications. - - * ``setuptools.Command`` now supports reinitializing commands using keyword - arguments to set/reset options. Also, ``Command`` subclasses can now set - their ``command_consumes_arguments`` attribute to ``True`` in order to - receive an ``args`` option containing the rest of the command line. - - ----- - 0.3a2 - ----- - - * Added new options to ``bdist_egg`` to allow tagging the egg's version number - with a subversion revision number, the current date, or an explicit tag - value. Run ``setup.py bdist_egg --help`` to get more information. - - * Misc. bug fixes - - ----- - 0.3a1 - ----- - - * Initial release. - -Keywords: CPAN PyPI distutils eggs package management -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Python Software Foundation License -Classifier: License :: OSI Approved :: Zope Public License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.1 -Classifier: Programming Language :: Python :: 3.2 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Archiving :: Packaging -Classifier: Topic :: System :: Systems Administration -Classifier: Topic :: Utilities +Metadata-Version: 1.1 +Name: setuptools +Version: 20.1.1 +Summary: Easily download, build, install, upgrade, and uninstall Python packages +Home-page: https://bitbucket.org/pypa/setuptools +Author: Python Packaging Authority +Author-email: distutils-sig@python.org +License: UNKNOWN +Description: =============================== + Installing and Using Setuptools + =============================== + + .. contents:: **Table of Contents** + + + `Change History `_. + + ------------------------- + Installation Instructions + ------------------------- + + The recommended way to bootstrap setuptools on any system is to download + `ez_setup.py`_ and run it using the target Python environment. Different + operating systems have different recommended techniques to accomplish this + basic routine, so below are some examples to get you started. + + Setuptools requires Python 2.6 or later. To install setuptools + on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x + `_. + + The link provided to ez_setup.py is a bookmark to bootstrap script for the + latest known stable release. + + .. _ez_setup.py: https://bootstrap.pypa.io/ez_setup.py + + Windows (Powershell 3 or later) + =============================== + + For best results, uninstall previous versions FIRST (see `Uninstalling`_). + + Using Windows 8 (which includes PowerShell 3) or earlier versions of Windows + with PowerShell 3 installed, it's possible to install with one simple + Powershell command. Start up Powershell and paste this command:: + + > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - + + You must start the Powershell with Administrative privileges or you may choose + to install a user-local installation:: + + > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - --user + + If you have Python 3.3 or later, you can use the ``py`` command to install to + different Python versions. For example, to install to Python 3.3 if you have + Python 2.7 installed:: + + > (Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | py -3 - + + The recommended way to install setuptools on Windows is to download + `ez_setup.py`_ and run it. The script will download the appropriate + distribution file and install it for you. + + Once installation is complete, you will find an ``easy_install`` program in + your Python ``Scripts`` subdirectory. For simple invocation and best results, + add this directory to your ``PATH`` environment variable, if it is not already + present. If you did a user-local install, the ``Scripts`` subdirectory is + ``$env:APPDATA\Python\Scripts``. + + + Windows (simplified) + ==================== + + For Windows without PowerShell 3 or for installation without a command-line, + download `ez_setup.py`_ using your preferred web browser or other technique + and "run" that file. + + + Unix (wget) + =========== + + Most Linux distributions come with wget. + + Download `ez_setup.py`_ and run it using the target Python version. The script + will download the appropriate version and install it for you:: + + > wget https://bootstrap.pypa.io/ez_setup.py -O - | python + + Note that you will may need to invoke the command with superuser privileges to + install to the system Python:: + + > wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python + + Alternatively, Setuptools may be installed to a user-local path:: + + > wget https://bootstrap.pypa.io/ez_setup.py -O - | python - --user + + Note that on some older systems (noted on Debian 6 and CentOS 5 installations), + `wget` may refuse to download `ez_setup.py`, complaining that the certificate common name `*.c.ssl.fastly.net` + does not match the host name `bootstrap.pypa.io`. In addition, the `ez_setup.py` script may then encounter similar problems using + `wget` internally to download `setuptools-x.y.zip`, complaining that the certificate common name of `www.python.org` does not match the + host name `pypi.python.org`. Those are known issues, related to a bug in the older versions of `wget` + (see `Issue 59 `_). If you happen to encounter them, + install Setuptools as follows:: + + > wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py + > python ez_setup.py --insecure + + + Unix including Mac OS X (curl) + ============================== + + If your system has curl installed, follow the ``wget`` instructions but + replace ``wget`` with ``curl`` and ``-O`` with ``-o``. For example:: + + > curl https://bootstrap.pypa.io/ez_setup.py -o - | python + + + Advanced Installation + ===================== + + For more advanced installation options, such as installing to custom + locations or prefixes, download and extract the source + tarball from `Setuptools on PyPI `_ + and run setup.py with any supported distutils and Setuptools options. + For example:: + + setuptools-x.x$ python setup.py install --prefix=/opt/setuptools + + Use ``--help`` to get a full options list, but we recommend consulting + the `EasyInstall manual`_ for detailed instructions, especially `the section + on custom installation locations`_. + + .. _EasyInstall manual: https://pythonhosted.org/setuptools/EasyInstall + .. _the section on custom installation locations: https://pythonhosted.org/setuptools/EasyInstall#custom-installation-locations + + + Downloads + ========= + + All setuptools downloads can be found at `the project's home page in the Python + Package Index`_. Scroll to the very bottom of the page to find the links. + + .. _the project's home page in the Python Package Index: https://pypi.python.org/pypi/setuptools + + In addition to the PyPI downloads, the development version of ``setuptools`` + is available from the `Bitbucket repo`_, and in-development versions of the + `0.6 branch`_ are available as well. + + .. _Bitbucket repo: https://bitbucket.org/pypa/setuptools/get/default.tar.gz#egg=setuptools-dev + .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 + + Uninstalling + ============ + + On Windows, if Setuptools was installed using an ``.exe`` or ``.msi`` + installer, simply use the uninstall feature of "Add/Remove Programs" in the + Control Panel. + + Otherwise, to uninstall Setuptools or Distribute, regardless of the Python + version, delete all ``setuptools*`` and ``distribute*`` files and + directories from your system's ``site-packages`` directory + (and any other ``sys.path`` directories) FIRST. + + If you are upgrading or otherwise plan to re-install Setuptools or Distribute, + nothing further needs to be done. If you want to completely remove Setuptools, + you may also want to remove the 'easy_install' and 'easy_install-x.x' scripts + and associated executables installed to the Python scripts directory. + + -------------------------------- + Using Setuptools and EasyInstall + -------------------------------- + + Here are some of the available manuals, tutorials, and other resources for + learning about Setuptools, Python Eggs, and EasyInstall: + + * `The EasyInstall user's guide and reference manual`_ + * `The setuptools Developer's Guide`_ + * `The pkg_resources API reference`_ + * `The Internal Structure of Python Eggs`_ + + Questions, comments, and bug reports should be directed to the `distutils-sig + mailing list`_. If you have written (or know of) any tutorials, documentation, + plug-ins, or other resources for setuptools users, please let us know about + them there, so this reference list can be updated. If you have working, + *tested* patches to correct problems or add features, you may submit them to + the `setuptools bug tracker`_. + + .. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/issues + .. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html + .. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html + .. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html + .. _The EasyInstall user's guide and reference manual: https://pythonhosted.org/setuptools/easy_install.html + .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ + + + ------- + Credits + ------- + + * The original design for the ``.egg`` format and the ``pkg_resources`` API was + co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first + version of ``pkg_resources``, and supplied the OS X operating system version + compatibility algorithm. + + * Ian Bicking implemented many early "creature comfort" features of + easy_install, including support for downloading via Sourceforge and + Subversion repositories. Ian's comments on the Web-SIG about WSGI + application deployment also inspired the concept of "entry points" in eggs, + and he has given talks at PyCon and elsewhere to inform and educate the + community about eggs and setuptools. + + * Jim Fulton contributed time and effort to build automated tests of various + aspects of ``easy_install``, and supplied the doctests for the command-line + ``.exe`` wrappers on Windows. + + * Phillip J. Eby is the seminal author of setuptools, and + first proposed the idea of an importable binary distribution format for + Python application plug-ins. + + * Significant parts of the implementation of setuptools were funded by the Open + Source Applications Foundation, to provide a plug-in infrastructure for the + Chandler PIM application. In addition, many OSAF staffers (such as Mike + "Code Bear" Taylor) contributed their time and stress as guinea pigs for the + use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) + + * Tarek Ziadé is the principal author of the Distribute fork, which + re-invigorated the community on the project, encouraged renewed innovation, + and addressed many defects. + + * Since the merge with Distribute, Jason R. Coombs is the + maintainer of setuptools. The project is maintained in coordination with + the Python Packaging Authority (PyPA) and the larger Python community. + + .. _files: + + + --------------- + Code of Conduct + --------------- + + Everyone interacting in the setuptools project's codebases, issue trackers, + chat rooms, and mailing lists is expected to follow the + `PyPA Code of Conduct`_. + + .. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/ + +Keywords: CPAN PyPI distutils eggs package management +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities diff -Nru python-setuptools-3.3/setuptools.egg-info/requires.txt python-setuptools-20.1.1/setuptools.egg-info/requires.txt --- python-setuptools-3.3/setuptools.egg-info/requires.txt 2014-03-16 09:04:36.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/requires.txt 2016-02-12 16:11:10.000000000 +0000 @@ -1,7 +1,6 @@ +[certs] +certifi==2015.11.20 [ssl:sys_platform=='win32'] wincertstore==0.2 - -[certs] -certifi==1.0.1 \ No newline at end of file diff -Nru python-setuptools-3.3/setuptools.egg-info/requires.txt.orig python-setuptools-20.1.1/setuptools.egg-info/requires.txt.orig --- python-setuptools-3.3/setuptools.egg-info/requires.txt.orig 2014-03-16 07:58:41.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/requires.txt.orig 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ - - -[ssl:sys_platform=='win32'] -wincertstore==0.2 - -[certs] -certifi==1.0.1 \ No newline at end of file diff -Nru python-setuptools-3.3/setuptools.egg-info/SOURCES.txt python-setuptools-20.1.1/setuptools.egg-info/SOURCES.txt --- python-setuptools-3.3/setuptools.egg-info/SOURCES.txt 2014-03-16 09:04:38.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/SOURCES.txt 2016-02-12 16:11:11.000000000 +0000 @@ -1,12 +1,13 @@ -CHANGES (links).txt CHANGES.txt -DEVGUIDE.txt MANIFEST.in README.txt +bootstrap.py +conftest.py easy_install.py ez_setup.py launcher.c -pkg_resources.py +msvc-build-launcher.cmd +pytest.ini release.py setup.cfg setup.py @@ -14,29 +15,43 @@ _markerlib/markers.py docs/Makefile docs/conf.py +docs/developer-guide.txt docs/development.txt docs/easy_install.txt docs/formats.txt +docs/history.txt docs/index.txt -docs/merge-faq.txt -docs/merge.txt docs/pkg_resources.txt docs/python3.txt docs/releases.txt docs/roadmap.txt docs/setuptools.txt -docs/using.txt docs/_templates/indexsidebar.html docs/_theme/nature/theme.conf docs/_theme/nature/static/nature.css_t docs/_theme/nature/static/pygments.css +pkg_resources/__init__.py +pkg_resources/api_tests.txt +pkg_resources/_vendor/__init__.py +pkg_resources/_vendor/six.py +pkg_resources/_vendor/vendored.txt +pkg_resources/_vendor/packaging/__about__.py +pkg_resources/_vendor/packaging/__init__.py +pkg_resources/_vendor/packaging/_compat.py +pkg_resources/_vendor/packaging/_structures.py +pkg_resources/_vendor/packaging/specifiers.py +pkg_resources/_vendor/packaging/version.py +pkg_resources/extern/__init__.py +pkg_resources/tests/__init__.py +pkg_resources/tests/test_markers.py +pkg_resources/tests/test_pkg_resources.py +pkg_resources/tests/test_resources.py setuptools/__init__.py setuptools/archive_util.py setuptools/cli-32.exe setuptools/cli-64.exe setuptools/cli-arm-32.exe setuptools/cli.exe -setuptools/compat.py setuptools/depends.py setuptools/dist.py setuptools/extension.py @@ -44,26 +59,27 @@ setuptools/gui-64.exe setuptools/gui-arm-32.exe setuptools/gui.exe +setuptools/launch.py setuptools/lib2to3_ex.py +setuptools/msvc9_support.py setuptools/package_index.py setuptools/py26compat.py setuptools/py27compat.py setuptools/py31compat.py setuptools/sandbox.py -setuptools/script template (dev).py -setuptools/script template.py +setuptools/script (dev).tmpl +setuptools/script.tmpl setuptools/site-patch.py setuptools/ssl_support.py -setuptools/svn_utils.py +setuptools/unicode_utils.py +setuptools/utils.py setuptools/version.py +setuptools/windows_support.py setuptools.egg-info/PKG-INFO setuptools.egg-info/SOURCES.txt setuptools.egg-info/dependency_links.txt -setuptools.egg-info/dependency_links.txt.orig setuptools.egg-info/entry_points.txt -setuptools.egg-info/entry_points.txt.orig setuptools.egg-info/requires.txt -setuptools.egg-info/requires.txt.orig setuptools.egg-info/top_level.txt setuptools.egg-info/zip-safe setuptools/command/__init__.py @@ -87,11 +103,14 @@ setuptools/command/sdist.py setuptools/command/setopt.py setuptools/command/test.py +setuptools/command/upload.py setuptools/command/upload_docs.py +setuptools/extern/__init__.py setuptools/tests/__init__.py -setuptools/tests/doctest.py -setuptools/tests/entries-v10 +setuptools/tests/contexts.py setuptools/tests/environment.py +setuptools/tests/files.py +setuptools/tests/fixtures.py setuptools/tests/py26compat.py setuptools/tests/script-with-bom.py setuptools/tests/server.py @@ -102,54 +121,18 @@ setuptools/tests/test_easy_install.py setuptools/tests/test_egg_info.py setuptools/tests/test_find_packages.py +setuptools/tests/test_integration.py setuptools/tests/test_markerlib.py +setuptools/tests/test_msvc9compiler.py setuptools/tests/test_packageindex.py -setuptools/tests/test_resources.py setuptools/tests/test_sandbox.py setuptools/tests/test_sdist.py -setuptools/tests/test_svn.py +setuptools/tests/test_setuptools.py setuptools/tests/test_test.py +setuptools/tests/test_unicode_utils.py setuptools/tests/test_upload_docs.py -setuptools/tests/win_script_wrapper.txt +setuptools/tests/test_windows_wrappers.py +setuptools/tests/textwrap.py setuptools/tests/indexes/test_links_priority/external.html setuptools/tests/indexes/test_links_priority/simple/foobar/index.html -setuptools/tests/svn_data/dummy.zip -setuptools/tests/svn_data/dummy13.zip -setuptools/tests/svn_data/dummy14.zip -setuptools/tests/svn_data/dummy15.zip -setuptools/tests/svn_data/dummy16.zip -setuptools/tests/svn_data/dummy17.zip -setuptools/tests/svn_data/dummy18.zip -setuptools/tests/svn_data/svn13_example.zip -setuptools/tests/svn_data/svn13_ext_list.txt -setuptools/tests/svn_data/svn13_ext_list.xml -setuptools/tests/svn_data/svn13_info.xml -setuptools/tests/svn_data/svn14_example.zip -setuptools/tests/svn_data/svn14_ext_list.txt -setuptools/tests/svn_data/svn14_ext_list.xml -setuptools/tests/svn_data/svn14_info.xml -setuptools/tests/svn_data/svn15_example.zip -setuptools/tests/svn_data/svn15_ext_list.txt -setuptools/tests/svn_data/svn15_ext_list.xml -setuptools/tests/svn_data/svn15_info.xml -setuptools/tests/svn_data/svn16_example.zip -setuptools/tests/svn_data/svn16_ext_list.txt -setuptools/tests/svn_data/svn16_ext_list.xml -setuptools/tests/svn_data/svn16_info.xml -setuptools/tests/svn_data/svn17_example.zip -setuptools/tests/svn_data/svn17_ext_list.txt -setuptools/tests/svn_data/svn17_ext_list.xml -setuptools/tests/svn_data/svn17_info.xml -setuptools/tests/svn_data/svn18_example.zip -setuptools/tests/svn_data/svn18_ext_list.txt -setuptools/tests/svn_data/svn18_ext_list.xml -setuptools/tests/svn_data/svn18_info.xml -tests/api_tests.txt -tests/manual_test.py -tests/test_ez_setup.py -tests/test_pkg_resources.py -tests/shlib_test/hello.c -tests/shlib_test/hello.pyx -tests/shlib_test/hellolib.c -tests/shlib_test/setup.py -tests/shlib_test/test_hello.py \ No newline at end of file +tests/manual_test.py \ No newline at end of file diff -Nru python-setuptools-3.3/setuptools.egg-info/top_level.txt python-setuptools-20.1.1/setuptools.egg-info/top_level.txt --- python-setuptools-3.3/setuptools.egg-info/top_level.txt 2014-03-16 09:04:36.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/top_level.txt 2016-02-12 16:11:10.000000000 +0000 @@ -1,4 +1,4 @@ _markerlib +easy_install pkg_resources setuptools -easy_install diff -Nru python-setuptools-3.3/setuptools.egg-info/zip-safe python-setuptools-20.1.1/setuptools.egg-info/zip-safe --- python-setuptools-3.3/setuptools.egg-info/zip-safe 2014-03-16 07:43:12.000000000 +0000 +++ python-setuptools-20.1.1/setuptools.egg-info/zip-safe 2016-02-07 14:36:10.000000000 +0000 @@ -1 +1 @@ - + diff -Nru python-setuptools-3.3/tests/api_tests.txt python-setuptools-20.1.1/tests/api_tests.txt --- python-setuptools-3.3/tests/api_tests.txt 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/api_tests.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,424 +0,0 @@ -Pluggable Distributions of Python Software -========================================== - -Distributions -------------- - -A "Distribution" is a collection of files that represent a "Release" of a -"Project" as of a particular point in time, denoted by a -"Version":: - - >>> import sys, pkg_resources - >>> from pkg_resources import Distribution - >>> Distribution(project_name="Foo", version="1.2") - Foo 1.2 - -Distributions have a location, which can be a filename, URL, or really anything -else you care to use:: - - >>> dist = Distribution( - ... location="http://example.com/something", - ... project_name="Bar", version="0.9" - ... ) - - >>> dist - Bar 0.9 (http://example.com/something) - - -Distributions have various introspectable attributes:: - - >>> dist.location - 'http://example.com/something' - - >>> dist.project_name - 'Bar' - - >>> dist.version - '0.9' - - >>> dist.py_version == sys.version[:3] - True - - >>> print(dist.platform) - None - -Including various computed attributes:: - - >>> from pkg_resources import parse_version - >>> dist.parsed_version == parse_version(dist.version) - True - - >>> dist.key # case-insensitive form of the project name - 'bar' - -Distributions are compared (and hashed) by version first:: - - >>> Distribution(version='1.0') == Distribution(version='1.0') - True - >>> Distribution(version='1.0') == Distribution(version='1.1') - False - >>> Distribution(version='1.0') < Distribution(version='1.1') - True - -but also by project name (case-insensitive), platform, Python version, -location, etc.:: - - >>> Distribution(project_name="Foo",version="1.0") == \ - ... Distribution(project_name="Foo",version="1.0") - True - - >>> Distribution(project_name="Foo",version="1.0") == \ - ... Distribution(project_name="foo",version="1.0") - True - - >>> Distribution(project_name="Foo",version="1.0") == \ - ... Distribution(project_name="Foo",version="1.1") - False - - >>> Distribution(project_name="Foo",py_version="2.3",version="1.0") == \ - ... Distribution(project_name="Foo",py_version="2.4",version="1.0") - False - - >>> Distribution(location="spam",version="1.0") == \ - ... Distribution(location="spam",version="1.0") - True - - >>> Distribution(location="spam",version="1.0") == \ - ... Distribution(location="baz",version="1.0") - False - - - -Hash and compare distribution by prio/plat - -Get version from metadata -provider capabilities -egg_name() -as_requirement() -from_location, from_filename (w/path normalization) - -Releases may have zero or more "Requirements", which indicate -what releases of another project the release requires in order to -function. A Requirement names the other project, expresses some criteria -as to what releases of that project are acceptable, and lists any "Extras" -that the requiring release may need from that project. (An Extra is an -optional feature of a Release, that can only be used if its additional -Requirements are satisfied.) - - - -The Working Set ---------------- - -A collection of active distributions is called a Working Set. Note that a -Working Set can contain any importable distribution, not just pluggable ones. -For example, the Python standard library is an importable distribution that -will usually be part of the Working Set, even though it is not pluggable. -Similarly, when you are doing development work on a project, the files you are -editing are also a Distribution. (And, with a little attention to the -directory names used, and including some additional metadata, such a -"development distribution" can be made pluggable as well.) - - >>> from pkg_resources import WorkingSet - -A working set's entries are the sys.path entries that correspond to the active -distributions. By default, the working set's entries are the items on -``sys.path``:: - - >>> ws = WorkingSet() - >>> ws.entries == sys.path - True - -But you can also create an empty working set explicitly, and add distributions -to it:: - - >>> ws = WorkingSet([]) - >>> ws.add(dist) - >>> ws.entries - ['http://example.com/something'] - >>> dist in ws - True - >>> Distribution('foo',version="") in ws - False - -And you can iterate over its distributions:: - - >>> list(ws) - [Bar 0.9 (http://example.com/something)] - -Adding the same distribution more than once is a no-op:: - - >>> ws.add(dist) - >>> list(ws) - [Bar 0.9 (http://example.com/something)] - -For that matter, adding multiple distributions for the same project also does -nothing, because a working set can only hold one active distribution per -project -- the first one added to it:: - - >>> ws.add( - ... Distribution( - ... 'http://example.com/something', project_name="Bar", - ... version="7.2" - ... ) - ... ) - >>> list(ws) - [Bar 0.9 (http://example.com/something)] - -You can append a path entry to a working set using ``add_entry()``:: - - >>> ws.entries - ['http://example.com/something'] - >>> ws.add_entry(pkg_resources.__file__) - >>> ws.entries - ['http://example.com/something', '...pkg_resources.py...'] - -Multiple additions result in multiple entries, even if the entry is already in -the working set (because ``sys.path`` can contain the same entry more than -once):: - - >>> ws.add_entry(pkg_resources.__file__) - >>> ws.entries - ['...example.com...', '...pkg_resources...', '...pkg_resources...'] - -And you can specify the path entry a distribution was found under, using the -optional second parameter to ``add()``:: - - >>> ws = WorkingSet([]) - >>> ws.add(dist,"foo") - >>> ws.entries - ['foo'] - -But even if a distribution is found under multiple path entries, it still only -shows up once when iterating the working set: - - >>> ws.add_entry(ws.entries[0]) - >>> list(ws) - [Bar 0.9 (http://example.com/something)] - -You can ask a WorkingSet to ``find()`` a distribution matching a requirement:: - - >>> from pkg_resources import Requirement - >>> print(ws.find(Requirement.parse("Foo==1.0"))) # no match, return None - None - - >>> ws.find(Requirement.parse("Bar==0.9")) # match, return distribution - Bar 0.9 (http://example.com/something) - -Note that asking for a conflicting version of a distribution already in a -working set triggers a ``pkg_resources.VersionConflict`` error: - - >>> try: - ... ws.find(Requirement.parse("Bar==1.0")) - ... except pkg_resources.VersionConflict: - ... exc = sys.exc_info()[1] - ... print(str(exc)) - ... else: - ... raise AssertionError("VersionConflict was not raised") - (Bar 0.9 (http://example.com/something), Requirement.parse('Bar==1.0')) - -You can subscribe a callback function to receive notifications whenever a new -distribution is added to a working set. The callback is immediately invoked -once for each existing distribution in the working set, and then is called -again for new distributions added thereafter:: - - >>> def added(dist): print("Added %s" % dist) - >>> ws.subscribe(added) - Added Bar 0.9 - >>> foo12 = Distribution(project_name="Foo", version="1.2", location="f12") - >>> ws.add(foo12) - Added Foo 1.2 - -Note, however, that only the first distribution added for a given project name -will trigger a callback, even during the initial ``subscribe()`` callback:: - - >>> foo14 = Distribution(project_name="Foo", version="1.4", location="f14") - >>> ws.add(foo14) # no callback, because Foo 1.2 is already active - - >>> ws = WorkingSet([]) - >>> ws.add(foo12) - >>> ws.add(foo14) - >>> ws.subscribe(added) - Added Foo 1.2 - -And adding a callback more than once has no effect, either:: - - >>> ws.subscribe(added) # no callbacks - - # and no double-callbacks on subsequent additions, either - >>> just_a_test = Distribution(project_name="JustATest", version="0.99") - >>> ws.add(just_a_test) - Added JustATest 0.99 - - -Finding Plugins ---------------- - -``WorkingSet`` objects can be used to figure out what plugins in an -``Environment`` can be loaded without any resolution errors:: - - >>> from pkg_resources import Environment - - >>> plugins = Environment([]) # normally, a list of plugin directories - >>> plugins.add(foo12) - >>> plugins.add(foo14) - >>> plugins.add(just_a_test) - -In the simplest case, we just get the newest version of each distribution in -the plugin environment:: - - >>> ws = WorkingSet([]) - >>> ws.find_plugins(plugins) - ([JustATest 0.99, Foo 1.4 (f14)], {}) - -But if there's a problem with a version conflict or missing requirements, the -method falls back to older versions, and the error info dict will contain an -exception instance for each unloadable plugin:: - - >>> ws.add(foo12) # this will conflict with Foo 1.4 - >>> ws.find_plugins(plugins) - ([JustATest 0.99, Foo 1.2 (f12)], {Foo 1.4 (f14): VersionConflict(...)}) - -But if you disallow fallbacks, the failed plugin will be skipped instead of -trying older versions:: - - >>> ws.find_plugins(plugins, fallback=False) - ([JustATest 0.99], {Foo 1.4 (f14): VersionConflict(...)}) - - - -Platform Compatibility Rules ----------------------------- - -On the Mac, there are potential compatibility issues for modules compiled -on newer versions of Mac OS X than what the user is running. Additionally, -Mac OS X will soon have two platforms to contend with: Intel and PowerPC. - -Basic equality works as on other platforms:: - - >>> from pkg_resources import compatible_platforms as cp - >>> reqd = 'macosx-10.4-ppc' - >>> cp(reqd, reqd) - True - >>> cp("win32", reqd) - False - -Distributions made on other machine types are not compatible:: - - >>> cp("macosx-10.4-i386", reqd) - False - -Distributions made on earlier versions of the OS are compatible, as -long as they are from the same top-level version. The patchlevel version -number does not matter:: - - >>> cp("macosx-10.4-ppc", reqd) - True - >>> cp("macosx-10.3-ppc", reqd) - True - >>> cp("macosx-10.5-ppc", reqd) - False - >>> cp("macosx-9.5-ppc", reqd) - False - -Backwards compatibility for packages made via earlier versions of -setuptools is provided as well:: - - >>> cp("darwin-8.2.0-Power_Macintosh", reqd) - True - >>> cp("darwin-7.2.0-Power_Macintosh", reqd) - True - >>> cp("darwin-8.2.0-Power_Macintosh", "macosx-10.3-ppc") - False - - -Environment Markers -------------------- - - >>> from pkg_resources import invalid_marker as im, evaluate_marker as em - >>> import os - - >>> print(im("sys_platform")) - Comparison or logical expression expected - - >>> print(im("sys_platform==")) - invalid syntax - - >>> print(im("sys_platform=='win32'")) - False - - >>> print(im("sys=='x'")) - Unknown name 'sys' - - >>> print(im("(extra)")) - Comparison or logical expression expected - - >>> print(im("(extra")) - invalid syntax - - >>> print(im("os.open('foo')=='y'")) - Language feature not supported in environment markers - - >>> print(im("'x'=='y' and os.open('foo')=='y'")) # no short-circuit! - Language feature not supported in environment markers - - >>> print(im("'x'=='x' or os.open('foo')=='y'")) # no short-circuit! - Language feature not supported in environment markers - - >>> print(im("'x' < 'y'")) - '<' operator not allowed in environment markers - - >>> print(im("'x' < 'y' < 'z'")) - Chained comparison not allowed in environment markers - - >>> print(im("r'x'=='x'")) - Only plain strings allowed in environment markers - - >>> print(im("'''x'''=='x'")) - Only plain strings allowed in environment markers - - >>> print(im('"""x"""=="x"')) - Only plain strings allowed in environment markers - - >>> print(im(r"'x\n'=='x'")) - Only plain strings allowed in environment markers - - >>> print(im("os.open=='y'")) - Language feature not supported in environment markers - - >>> em('"x"=="x"') - True - - >>> em('"x"=="y"') - False - - >>> em('"x"=="y" and "x"=="x"') - False - - >>> em('"x"=="y" or "x"=="x"') - True - - >>> em('"x"=="y" and "x"=="q" or "z"=="z"') - True - - >>> em('"x"=="y" and ("x"=="q" or "z"=="z")') - False - - >>> em('"x"=="y" and "z"=="z" or "x"=="q"') - False - - >>> em('"x"=="x" and "z"=="z" or "x"=="q"') - True - - >>> em("sys_platform=='win32'") == (sys.platform=='win32') - True - - >>> em("'x' in 'yx'") - True - - >>> em("'yx' in 'x'") - False - - - - diff -Nru python-setuptools-3.3/tests/manual_test.py python-setuptools-20.1.1/tests/manual_test.py --- python-setuptools-3.3/tests/manual_test.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/manual_test.py 2016-02-07 14:25:06.000000000 +0000 @@ -7,7 +7,8 @@ import subprocess from distutils.command.install import INSTALL_SCHEMES from string import Template -from setuptools.compat import urlopen + +from six.moves import urllib def _system_call(*args): assert subprocess.call(args) == 0 @@ -76,7 +77,7 @@ f.write(SIMPLE_BUILDOUT) with open('bootstrap.py', 'w') as f: - f.write(urlopen(BOOTSTRAP).read()) + f.write(urllib.request.urlopen(BOOTSTRAP).read()) _system_call('bin/python', 'bootstrap.py') _system_call('bin/buildout', '-q') diff -Nru python-setuptools-3.3/tests/shlib_test/hello.c python-setuptools-20.1.1/tests/shlib_test/hello.c --- python-setuptools-3.3/tests/shlib_test/hello.c 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/shlib_test/hello.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -/* Generated by Pyrex 0.9.3 on Thu Jan 05 17:47:12 2006 */ - -#include "Python.h" -#include "structmember.h" -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif - - -typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ -typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ -static PyObject *__Pyx_UnpackItem(PyObject *, int); /*proto*/ -static int __Pyx_EndUnpack(PyObject *, int); /*proto*/ -static int __Pyx_PrintItem(PyObject *); /*proto*/ -static int __Pyx_PrintNewline(void); /*proto*/ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ -static void __Pyx_ReRaise(void); /*proto*/ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ -static PyObject *__Pyx_GetExcValue(void); /*proto*/ -static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name); /*proto*/ -static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/ -static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], int nargs, PyObject **args2, PyObject **kwds2); /*proto*/ -static void __Pyx_WriteUnraisable(char *name); /*proto*/ -static void __Pyx_AddTraceback(char *funcname); /*proto*/ -static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size); /*proto*/ -static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ -static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/ -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static int __pyx_lineno; -static char *__pyx_filename; -staticforward char **__pyx_f; - -/* Declarations from hello */ - -char (*(get_hello_msg(void))); /*proto*/ - -/* Implementation of hello */ - -static PyObject *__pyx_n_hello; - -static PyObject *__pyx_f_5hello_hello(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_f_5hello_hello(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_r; - PyObject *__pyx_1 = 0; - static char *__pyx_argnames[] = {0}; - if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0; - - /* "C:\cygwin\home\pje\setuptools\tests\shlib_test\hello.pyx":4 */ - __pyx_1 = PyString_FromString(get_hello_msg()); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;} - __pyx_r = __pyx_1; - __pyx_1 = 0; - goto __pyx_L0; - - __pyx_r = Py_None; Py_INCREF(__pyx_r); - goto __pyx_L0; - __pyx_L1:; - Py_XDECREF(__pyx_1); - __Pyx_AddTraceback("hello.hello"); - __pyx_r = 0; - __pyx_L0:; - return __pyx_r; -} - -static __Pyx_InternTabEntry __pyx_intern_tab[] = { - {&__pyx_n_hello, "hello"}, - {0, 0} -}; - -static struct PyMethodDef __pyx_methods[] = { - {"hello", (PyCFunction)__pyx_f_5hello_hello, METH_VARARGS|METH_KEYWORDS, 0}, - {0, 0, 0, 0} -}; - -DL_EXPORT(void) inithello(void); /*proto*/ -DL_EXPORT(void) inithello(void) { - __pyx_m = Py_InitModule4("hello", __pyx_methods, 0, 0, PYTHON_API_VERSION); - if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;}; - __pyx_b = PyImport_AddModule("__builtin__"); - if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;}; - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;}; - if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;}; - - /* "C:\cygwin\home\pje\setuptools\tests\shlib_test\hello.pyx":3 */ - return; - __pyx_L1:; - __Pyx_AddTraceback("hello"); -} - -static char *__pyx_filenames[] = { - "hello.pyx", -}; -statichere char **__pyx_f = __pyx_filenames; - -/* Runtime support code */ - -static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) { - while (t->p) { - *t->p = PyString_InternFromString(t->s); - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyObject *empty_tuple = 0; - PyObject *empty_string = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - py_srcfile = PyString_FromString(__pyx_filename); - if (!py_srcfile) goto bad; - py_funcname = PyString_FromString(funcname); - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - empty_tuple = PyTuple_New(0); - if (!empty_tuple) goto bad; - empty_string = PyString_FromString(""); - if (!empty_string) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - empty_string, /*PyObject *code,*/ - empty_tuple, /*PyObject *consts,*/ - empty_tuple, /*PyObject *names,*/ - empty_tuple, /*PyObject *varnames,*/ - empty_tuple, /*PyObject *freevars,*/ - empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - empty_string /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_Get(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(empty_tuple); - Py_XDECREF(empty_string); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} diff -Nru python-setuptools-3.3/tests/shlib_test/hellolib.c python-setuptools-20.1.1/tests/shlib_test/hellolib.c --- python-setuptools-3.3/tests/shlib_test/hellolib.c 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/shlib_test/hellolib.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -extern char* get_hello_msg() { - return "Hello, world!"; -} diff -Nru python-setuptools-3.3/tests/shlib_test/hello.pyx python-setuptools-20.1.1/tests/shlib_test/hello.pyx --- python-setuptools-3.3/tests/shlib_test/hello.pyx 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/shlib_test/hello.pyx 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -cdef extern char *get_hello_msg() - -def hello(): - return get_hello_msg() diff -Nru python-setuptools-3.3/tests/shlib_test/setup.py python-setuptools-20.1.1/tests/shlib_test/setup.py --- python-setuptools-3.3/tests/shlib_test/setup.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/shlib_test/setup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -from setuptools import setup, Extension, Library - -setup( - name="shlib_test", - ext_modules = [ - Library("hellolib", ["hellolib.c"]), - Extension("hello", ["hello.pyx"], libraries=["hellolib"]) - ], - test_suite="test_hello.HelloWorldTest", -) diff -Nru python-setuptools-3.3/tests/shlib_test/test_hello.py python-setuptools-20.1.1/tests/shlib_test/test_hello.py --- python-setuptools-3.3/tests/shlib_test/test_hello.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/shlib_test/test_hello.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -from unittest import TestCase - -class HelloWorldTest(TestCase): - def testHelloMsg(self): - from hello import hello - self.assertEqual(hello(), "Hello, world!") - diff -Nru python-setuptools-3.3/tests/test_ez_setup.py python-setuptools-20.1.1/tests/test_ez_setup.py --- python-setuptools-3.3/tests/test_ez_setup.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/test_ez_setup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -import sys -import os -import tempfile -import unittest -import shutil -import copy - -CURDIR = os.path.abspath(os.path.dirname(__file__)) -TOPDIR = os.path.split(CURDIR)[0] -sys.path.insert(0, TOPDIR) - -from ez_setup import (use_setuptools, _build_egg, _python_cmd, _do_download, - _install, DEFAULT_URL, DEFAULT_VERSION) -import ez_setup - -class TestSetup(unittest.TestCase): - - def urlopen(self, url): - return open(self.tarball, 'rb') - - def setUp(self): - self.old_sys_path = copy.copy(sys.path) - self.cwd = os.getcwd() - self.tmpdir = tempfile.mkdtemp() - os.chdir(TOPDIR) - _python_cmd("setup.py", "-q", "egg_info", "-RDb", "''", "sdist", - "--dist-dir", "%s" % self.tmpdir) - tarball = os.listdir(self.tmpdir)[0] - self.tarball = os.path.join(self.tmpdir, tarball) - from setuptools.compat import urllib2 - urllib2.urlopen = self.urlopen - - def tearDown(self): - shutil.rmtree(self.tmpdir) - os.chdir(self.cwd) - sys.path = copy.copy(self.old_sys_path) - - def test_build_egg(self): - # making it an egg - egg = _build_egg('Egg to be built', self.tarball, self.tmpdir) - - # now trying to import it - sys.path[0] = egg - import setuptools - self.assertTrue(setuptools.__file__.startswith(egg)) - - def test_do_download(self): - tmpdir = tempfile.mkdtemp() - _do_download(DEFAULT_VERSION, DEFAULT_URL, tmpdir, 1) - import setuptools - self.assertTrue(setuptools.bootstrap_install_from.startswith(tmpdir)) - - def test_install(self): - def _faked(*args): - return True - ez_setup.python_cmd = _faked - _install(self.tarball) - - def test_use_setuptools(self): - self.assertEqual(use_setuptools(), None) - -if __name__ == '__main__': - unittest.main() diff -Nru python-setuptools-3.3/tests/test_pkg_resources.py python-setuptools-20.1.1/tests/test_pkg_resources.py --- python-setuptools-3.3/tests/test_pkg_resources.py 2014-02-12 03:53:22.000000000 +0000 +++ python-setuptools-20.1.1/tests/test_pkg_resources.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -import sys -import tempfile -import os -import zipfile - -import pkg_resources - -try: - unicode -except NameError: - unicode = str - -class EggRemover(unicode): - def __call__(self): - if self in sys.path: - sys.path.remove(self) - if os.path.exists(self): - os.remove(self) - -class TestZipProvider(object): - finalizers = [] - - @classmethod - def setup_class(cls): - "create a zip egg and add it to sys.path" - egg = tempfile.NamedTemporaryFile(suffix='.egg', delete=False) - zip_egg = zipfile.ZipFile(egg, 'w') - zip_info = zipfile.ZipInfo() - zip_info.filename = 'mod.py' - zip_info.date_time = 2013, 5, 12, 13, 25, 0 - zip_egg.writestr(zip_info, 'x = 3\n') - zip_info = zipfile.ZipInfo() - zip_info.filename = 'data.dat' - zip_info.date_time = 2013, 5, 12, 13, 25, 0 - zip_egg.writestr(zip_info, 'hello, world!') - zip_egg.close() - egg.close() - - sys.path.append(egg.name) - cls.finalizers.append(EggRemover(egg.name)) - - @classmethod - def teardown_class(cls): - for finalizer in cls.finalizers: - finalizer() - - def test_resource_filename_rewrites_on_change(self): - """ - If a previous call to get_resource_filename has saved the file, but - the file has been subsequently mutated with different file of the - same size and modification time, it should not be overwritten on a - subsequent call to get_resource_filename. - """ - import mod - manager = pkg_resources.ResourceManager() - zp = pkg_resources.ZipProvider(mod) - filename = zp.get_resource_filename(manager, 'data.dat') - assert os.stat(filename).st_mtime == 1368379500 - f = open(filename, 'w') - f.write('hello, world?') - f.close() - os.utime(filename, (1368379500, 1368379500)) - filename = zp.get_resource_filename(manager, 'data.dat') - f = open(filename) - assert f.read() == 'hello, world!' - manager.cleanup_resources() - -class TestResourceManager(object): - def test_get_cache_path(self): - mgr = pkg_resources.ResourceManager() - path = mgr.get_cache_path('foo') - type_ = str(type(path)) - message = "Unexpected type from get_cache_path: " + type_ - assert isinstance(path, (unicode, str)), message