From 29d8e7f670c2369f09420a46705280b7119289ba Mon Sep 17 00:00:00 2001 From: Kenneth Reitz <me@kennethreitz.com> Date: Thu, 7 Mar 2013 20:36:03 -0500 Subject: [PATCH] update distribute to v0.6.35 --- vendor/distribute-0.6.35/CHANGES.txt | 498 +++ vendor/distribute-0.6.35/CONTRIBUTORS.txt | 30 + vendor/distribute-0.6.35/DEVGUIDE.txt | 22 + vendor/distribute-0.6.35/MANIFEST.in | 9 + vendor/distribute-0.6.35/PKG-INFO | 871 +++++ vendor/distribute-0.6.35/README.txt | 228 ++ .../distribute-0.6.35/_markerlib/__init__.py | 16 + .../distribute-0.6.35/_markerlib/markers.py | 115 + vendor/distribute-0.6.35/distribute_setup.py | 546 +++ vendor/distribute-0.6.35/docs/Makefile | 75 + .../docs/_templates/indexsidebar.html | 8 + .../docs/_theme/nature/static/nature.css_t | 237 ++ .../docs/_theme/nature/static/pygments.css | 54 + .../docs/_theme/nature/theme.conf | 4 + vendor/distribute-0.6.35/docs/conf.py | 197 + .../distribute-0.6.35/docs/easy_install.txt | 1597 ++++++++ vendor/distribute-0.6.35/docs/index.txt | 36 + .../distribute-0.6.35/docs/pkg_resources.txt | 1955 ++++++++++ vendor/distribute-0.6.35/docs/python3.txt | 121 + vendor/distribute-0.6.35/docs/roadmap.txt | 86 + vendor/distribute-0.6.35/docs/setuptools.txt | 3230 +++++++++++++++++ vendor/distribute-0.6.35/docs/using.txt | 21 + vendor/distribute-0.6.35/easy_install.py | 5 + vendor/distribute-0.6.35/launcher.c | 327 ++ vendor/distribute-0.6.35/pkg_resources.py | 2827 +++++++++++++++ vendor/distribute-0.6.35/release.py | 170 + vendor/distribute-0.6.35/setup.cfg | 21 + vendor/distribute-0.6.35/setup.py | 253 ++ .../distribute-0.6.35/setuptools/__init__.py | 104 + .../setuptools/archive_util.py | 214 ++ .../distribute-0.6.35/setuptools/cli-32.exe | Bin 0 -> 69632 bytes .../distribute-0.6.35/setuptools/cli-64.exe | Bin 0 -> 75264 bytes vendor/distribute-0.6.35/setuptools/cli.exe | Bin 0 -> 69632 bytes .../setuptools/command/__init__.py | 21 + .../setuptools/command/alias.py | 82 + .../setuptools/command/bdist_egg.py | 548 +++ .../setuptools/command/bdist_rpm.py | 82 + .../setuptools/command/bdist_wininst.py | 41 + .../setuptools/command/build_ext.py | 294 ++ .../setuptools/command/build_py.py | 280 ++ .../setuptools/command/develop.py | 167 + .../setuptools/command/easy_install.py | 1947 ++++++++++ .../setuptools/command/egg_info.py | 486 +++ .../setuptools/command/install.py | 124 + .../setuptools/command/install_egg_info.py | 125 + .../setuptools/command/install_lib.py | 82 + .../setuptools/command/install_scripts.py | 54 + .../setuptools/command/register.py | 10 + .../setuptools/command/rotate.py | 82 + .../setuptools/command/saveopts.py | 25 + .../setuptools/command/sdist.py | 313 ++ .../setuptools/command/setopt.py | 164 + .../setuptools/command/test.py | 198 + .../setuptools/command/upload.py | 185 + .../setuptools/command/upload_docs.py | 195 + .../distribute-0.6.35/setuptools/depends.py | 246 ++ vendor/distribute-0.6.35/setuptools/dist.py | 855 +++++ .../distribute-0.6.35/setuptools/extension.py | 46 + .../distribute-0.6.35/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../distribute-0.6.35/setuptools/gui-64.exe | Bin 0 -> 75264 bytes vendor/distribute-0.6.35/setuptools/gui.exe | Bin 0 -> 65536 bytes .../setuptools/package_index.py | 920 +++++ .../distribute-0.6.35/setuptools/sandbox.py | 293 ++ .../setuptools/script template (dev).py | 6 + .../setuptools/script template.py | 4 + .../setuptools/tests/__init__.py | 349 ++ .../setuptools/tests/doctest.py | 2683 ++++++++++++++ .../indexes/test_links_priority/external.html | 3 + .../simple/foobar/index.html | 4 + .../setuptools/tests/py26compat.py | 14 + .../setuptools/tests/server.py | 82 + .../setuptools/tests/test_bdist_egg.py | 69 + .../setuptools/tests/test_build_ext.py | 20 + .../setuptools/tests/test_develop.py | 118 + .../setuptools/tests/test_dist_info.py | 80 + .../setuptools/tests/test_easy_install.py | 460 +++ .../setuptools/tests/test_markerlib.py | 64 + .../setuptools/tests/test_packageindex.py | 145 + .../setuptools/tests/test_resources.py | 645 ++++ .../setuptools/tests/test_sandbox.py | 66 + .../setuptools/tests/test_sdist.py | 383 ++ .../setuptools/tests/test_test.py | 124 + .../setuptools/tests/test_upload_docs.py | 72 + .../setuptools/tests/win_script_wrapper.txt | 151 + vendor/distribute-0.6.35/site.py | 83 + vendor/distribute-0.6.35/tests/api_tests.txt | 330 ++ .../distribute-0.6.35/tests/install_test.py | 75 + vendor/distribute-0.6.35/tests/manual_test.py | 110 + .../tests/shlib_test/hello.c | 168 + .../tests/shlib_test/hello.pyx | 4 + .../tests/shlib_test/hellolib.c | 3 + .../tests/shlib_test/setup.py | 10 + .../tests/shlib_test/test_hello.py | 7 + .../tests/test_distribute_setup.py | 73 + 94 files changed, 28147 insertions(+) create mode 100644 vendor/distribute-0.6.35/CHANGES.txt create mode 100644 vendor/distribute-0.6.35/CONTRIBUTORS.txt create mode 100644 vendor/distribute-0.6.35/DEVGUIDE.txt create mode 100644 vendor/distribute-0.6.35/MANIFEST.in create mode 100644 vendor/distribute-0.6.35/PKG-INFO create mode 100644 vendor/distribute-0.6.35/README.txt create mode 100644 vendor/distribute-0.6.35/_markerlib/__init__.py create mode 100644 vendor/distribute-0.6.35/_markerlib/markers.py create mode 100644 vendor/distribute-0.6.35/distribute_setup.py create mode 100644 vendor/distribute-0.6.35/docs/Makefile create mode 100644 vendor/distribute-0.6.35/docs/_templates/indexsidebar.html create mode 100644 vendor/distribute-0.6.35/docs/_theme/nature/static/nature.css_t create mode 100644 vendor/distribute-0.6.35/docs/_theme/nature/static/pygments.css create mode 100644 vendor/distribute-0.6.35/docs/_theme/nature/theme.conf create mode 100644 vendor/distribute-0.6.35/docs/conf.py create mode 100644 vendor/distribute-0.6.35/docs/easy_install.txt create mode 100644 vendor/distribute-0.6.35/docs/index.txt create mode 100644 vendor/distribute-0.6.35/docs/pkg_resources.txt create mode 100644 vendor/distribute-0.6.35/docs/python3.txt create mode 100644 vendor/distribute-0.6.35/docs/roadmap.txt create mode 100644 vendor/distribute-0.6.35/docs/setuptools.txt create mode 100644 vendor/distribute-0.6.35/docs/using.txt create mode 100644 vendor/distribute-0.6.35/easy_install.py create mode 100644 vendor/distribute-0.6.35/launcher.c create mode 100644 vendor/distribute-0.6.35/pkg_resources.py create mode 100644 vendor/distribute-0.6.35/release.py create mode 100644 vendor/distribute-0.6.35/setup.cfg create mode 100644 vendor/distribute-0.6.35/setup.py create mode 100644 vendor/distribute-0.6.35/setuptools/__init__.py create mode 100644 vendor/distribute-0.6.35/setuptools/archive_util.py create mode 100755 vendor/distribute-0.6.35/setuptools/cli-32.exe create mode 100755 vendor/distribute-0.6.35/setuptools/cli-64.exe create mode 100755 vendor/distribute-0.6.35/setuptools/cli.exe create mode 100644 vendor/distribute-0.6.35/setuptools/command/__init__.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/alias.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/bdist_egg.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/bdist_rpm.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/bdist_wininst.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/build_ext.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/build_py.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/develop.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/easy_install.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/egg_info.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/install.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/install_egg_info.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/install_lib.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/install_scripts.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/register.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/rotate.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/saveopts.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/sdist.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/setopt.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/test.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/upload.py create mode 100644 vendor/distribute-0.6.35/setuptools/command/upload_docs.py create mode 100644 vendor/distribute-0.6.35/setuptools/depends.py create mode 100644 vendor/distribute-0.6.35/setuptools/dist.py create mode 100644 vendor/distribute-0.6.35/setuptools/extension.py create mode 100755 vendor/distribute-0.6.35/setuptools/gui-32.exe create mode 100755 vendor/distribute-0.6.35/setuptools/gui-64.exe create mode 100755 vendor/distribute-0.6.35/setuptools/gui.exe create mode 100644 vendor/distribute-0.6.35/setuptools/package_index.py create mode 100644 vendor/distribute-0.6.35/setuptools/sandbox.py create mode 100644 vendor/distribute-0.6.35/setuptools/script template (dev).py create mode 100644 vendor/distribute-0.6.35/setuptools/script template.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/__init__.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/doctest.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/external.html create mode 100644 vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html create mode 100644 vendor/distribute-0.6.35/setuptools/tests/py26compat.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/server.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_bdist_egg.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_build_ext.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_develop.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_dist_info.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_easy_install.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_markerlib.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_packageindex.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_resources.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_sandbox.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_sdist.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_test.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/test_upload_docs.py create mode 100644 vendor/distribute-0.6.35/setuptools/tests/win_script_wrapper.txt create mode 100644 vendor/distribute-0.6.35/site.py create mode 100644 vendor/distribute-0.6.35/tests/api_tests.txt create mode 100644 vendor/distribute-0.6.35/tests/install_test.py create mode 100644 vendor/distribute-0.6.35/tests/manual_test.py create mode 100644 vendor/distribute-0.6.35/tests/shlib_test/hello.c create mode 100644 vendor/distribute-0.6.35/tests/shlib_test/hello.pyx create mode 100644 vendor/distribute-0.6.35/tests/shlib_test/hellolib.c create mode 100644 vendor/distribute-0.6.35/tests/shlib_test/setup.py create mode 100644 vendor/distribute-0.6.35/tests/shlib_test/test_hello.py create mode 100644 vendor/distribute-0.6.35/tests/test_distribute_setup.py diff --git a/vendor/distribute-0.6.35/CHANGES.txt b/vendor/distribute-0.6.35/CHANGES.txt new file mode 100644 index 00000000..cae946e0 --- /dev/null +++ b/vendor/distribute-0.6.35/CHANGES.txt @@ -0,0 +1,498 @@ +======= +CHANGES +======= + +------ +0.6.35 +------ + +Note this release is backward-incompatible with distribute 0.6.23-0.6.34 in +how it parses version numbers. + +* Issue #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 +------ + +* Issue #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. +* Issue #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. +* Issue #341: Fix a ResourceWarning. + +------ +0.6.32 +------ + +* Fix test suite with Python 2.6. +* Fix some DeprecationWarnings and ResourceWarnings. +* Issue #335: Backed out `setup_requires` superceding installed requirements + until regression can be addressed. + +------ +0.6.31 +------ + +* Issue #303: Make sure the manifest only ever contains UTF-8 in Python 3. +* Issue #329: Properly close files created by tests for compatibility with + Jython. +* Work around Jython bugs `#1980 <http://bugs.jython.org/issue1980>`_ and + `#1981 <http://bugs.jython.org/issue1981>`_. +* Issue #334: Provide workaround for packages that reference `sys.__stdout__` + such as numpy does. This change should address + `virtualenv #359 <https://github.com/pypa/virtualenv/issues/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. +* Issue #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 +------ + +* Issue #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. +* Issue #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. +* Issue #326: `upload_docs` provided mangled auth credentials under Python 3. +* Issue #320: Fix check for "createable" in distribute_setup.py. +* Issue #305: Remove a warning that was triggered during normal operations. +* Issue #311: Print metadata in UTF-8 independent of platform. +* Issue #303: Read manifest file with UTF-8 encoding under Python 3. +* Issue #301: Allow to run tests of namespace packages when using 2to3. +* Issue #304: Prevent import loop in site.py under Python 3.3. +* Issue #283: Reenable scanning of `*.pyc` / `*.pyo` files on Python 3.3. +* Issue #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. +* Issue #306: Even if 2to3 is used, we build in-place under Python 2. +* Issue #307: Prints the full path when .svn/entries is broken. +* Issue #313: Support for sdist subcommands (Python 2.7) +* Issue #314: test_local_index() would fail an OS X. +* Issue #310: Non-ascii characters in a namespace __init__.py causes errors. +* Issue #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 +------ + +* Issue #294: setup.py can now be invoked from any directory. +* Scripts are now installed honoring the umask. +* Added support for .dist-info directories. +* Issue #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. +* Issue #231: Don't fiddle with system python when used with buildout + (bootstrap.py) + +------ +0.6.26 +------ + +* Issue #183: Symlinked files are now extracted from source distributions. +* Issue #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 +------ + +* Issue #258: Workaround a cache issue +* Issue #260: distribute_setup.py now accepts the --user parameter for + Python 2.6 and later. +* Issue #262: package_index.open_with_auth no longer throws LookupError + on Python 3. +* Issue #269: AttributeError when an exception occurs reading Manifest.in + on late releases of Python. +* Issue #272: Prevent TypeError when namespace package names are unicode + and single-install-externally-managed is used. Also fixes PIP issue + 449. +* Issue #273: Legacy script launchers now install with Python2/3 support. + +------ +0.6.24 +------ + +* Issue #249: Added options to exclude 2to3 fixers + +------ +0.6.23 +------ + +* Issue #244: Fixed a test +* Issue #243: Fixed a test +* Issue #239: Fixed a test +* Issue #240: Fixed a test +* Issue #241: Fixed a test +* Issue #237: Fixed a test +* Issue #238: easy_install now uses 64bit executable wrappers on 64bit Python +* Issue #208: Fixed parsed_versions, it now honors post-releases as noted in the documentation +* Issue #207: Windows cli and gui wrappers pass CTRL-C to child python process +* Issue #227: easy_install now passes its arguments to setup.py bdist_egg +* Issue #225: Fixed a NameError on Python 2.5, 2.4 + +------ +0.6.21 +------ + +* Issue #225: FIxed a regression on py2.4 + +------ +0.6.20 +------ + +* Issue #135: Include url in warning when processing URLs in package_index. +* Issue #212: Fix issue where easy_instal fails on Python 3 on windows installer. +* Issue #213: Fix typo in documentation. + +------ +0.6.19 +------ + +* Issue 206: AttributeError: 'HTTPMessage' object has no attribute 'getheaders' + +------ +0.6.18 +------ + +* Issue 210: Fixed a regression introduced by Issue 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. +* Issue 204: Don't try to import the parent of a namespace package in + declare_namespace +* Issue 196: Tolerate responses with multiple Content-Length headers +* Issue 205: Sandboxing doesn't preserve working_set. Leads to setup_requires + problems. + +------ +0.6.16 +------ + +* Builds sdist gztar even on Windows (avoiding Issue 193). +* Issue 192: Fixed metadata omitted on Windows when package_dir + specified with forward-slash. +* Issue 195: Cython build support. +* Issue 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. +* Issue 146: Fixed missing DLL files after easy_install of windows exe package. + +------ +0.6.14 +------ + +* Issue 170: Fixed unittest failure. Thanks to Toshio. +* Issue 171: Fixed race condition in unittests cause deadlocks in test suite. +* Issue 143: Fixed a lookup issue with easy_install. + Thanks to David and Zooko. +* Issue 174: Fixed the edit mode when its used with setuptools itself + +------ +0.6.13 +------ + +* Issue 160: 2.7 gives ValueError("Invalid IPv6 URL") +* Issue 150: Fixed using ~/.local even in a --no-site-packages virtualenv +* Issue 163: scan index links before external links, and don't use the md5 when + comparing two distributions + +------ +0.6.12 +------ + +* Issue 149: Fixed various failures on 2.3/2.4 + +------ +0.6.11 +------ + +* Found another case of SandboxViolation - fixed +* Issue 15 and 48: Introduced a socket timeout of 15 seconds on url openings +* Added indexsidebar.html into MANIFEST.in +* Issue 108: Fixed TypeError with Python3.1 +* Issue 121: Fixed --help install command trying to actually install. +* Issue 112: Added an os.makedirs so that Tarek's solution will work. +* Issue 133: Added --no-find-links to easy_install +* Added easy_install --user +* Issue 100: Fixed develop --user not taking '.' in PYTHONPATH into account +* Issue 134: removed spurious UserWarnings. Patch by VanLindberg +* Issue 138: cant_write_to_target error when setup_requires is used. +* Issue 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 +----- + +* Issue 90: unknown setuptools version can be added in the working set +* Issue 87: setupt.py doesn't try to convert distribute_setup.py anymore + Initial Patch by arfrever. +* Issue 89: added a side bar with a download link to the doc. +* Issue 86: fixed missing sentence in pkg_resources doc. +* Added a nicer error message when a DistributionNotFound is raised. +* Issue 80: test_develop now works with Python 3.1 +* Issue 93: upload_docs now works if there is an empty sub-directory. +* Issue 70: exec bit on non-exec files +* Issue 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). +* Issue 101: Allowing ``os.devnull`` in Sandbox +* Issue 92: Fixed the "no eggs" found error with MacPort + (platform.mac_ver() fails) +* Issue 103: test_get_script_header_jython_workaround not run + anymore under py3 with C or POSIX local. Contributed by Arfrever. +* Issue 104: remvoved the assertion when the installation fails, + with a nicer message for the end user. +* Issue 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 +----- + +* Issue 58: Added --user support to the develop command +* Issue 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. +* Issue 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. +* Issue 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 +* Issue 74: no_fake should be True by default. +* Issue 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 +----- + +* Issue 65: cli.exe and gui.exe are now generated at build time, + depending on the platform in use. + +* Issue 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 issue #52. + +* Added an upload_docs command to easily upload project documentation to + PyPI's http://packages.python.org. This close issue #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 http://bugs.python.org/setuptools/issue39. + +* Added option to run 2to3 automatically when installing on Python 3. + This closes issue #31. + +* Fixed invalid usage of requirement.parse, that broke develop -d. + This closes http://bugs.python.org/setuptools/issue44. + +* Fixed script launcher for 64-bit Windows. + This closes http://bugs.python.org/setuptools/issue2. + +* KeyError when compiling extensions. + This closes http://bugs.python.org/setuptools/issue41. + +bootstrapping +============= + +* Fixed bootstrap not working on Windows. This closes issue #49. + +* Fixed 2.6 dependencies. This closes issue #50. + +* Make sure setuptools is patched when running through easy_install + This closes http://bugs.python.org/setuptools/issue40. + +----- +0.6.1 +----- + +setuptools +========== + +* package_index.urlopen now catches BadStatusLine and malformed url errors. + This closes issue #16 and issue #18. + +* zip_ok is now False by default. This closes + http://bugs.python.org/setuptools/issue33. + +* Fixed invalid URL error catching. http://bugs.python.org/setuptools/issue20. + +* Fixed invalid bootstraping with easy_install installation (issue #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 issue #10. + +--- +0.6 +--- + +setuptools +========== + +* Packages required at build time where not fully present at install time. + This closes issue #12. + +* Protected against failures in tarfile extraction. This closes issue #10. + +* Made Jython api_tests.txt doctest compatible. This closes issue #7. + +* sandbox.py replaced builtin type file with builtin function open. This + closes issue #6. + +* Immediately close all file handles. This closes issue #3. + +* Added compatibility with Subversion 1.6. This references issue #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 issue #13. + +* Allow to find_on_path on systems with tight permissions to fail gracefully. + This closes issue #9. + +* Corrected inconsistency between documentation and code of add_entry. + This closes issue #8. + +* Immediately close all file handles. This closes issue #3. + +easy_install +============ + +* Immediately close all file handles. This closes issue #3. + diff --git a/vendor/distribute-0.6.35/CONTRIBUTORS.txt b/vendor/distribute-0.6.35/CONTRIBUTORS.txt new file mode 100644 index 00000000..22c90aba --- /dev/null +++ b/vendor/distribute-0.6.35/CONTRIBUTORS.txt @@ -0,0 +1,30 @@ +============ +Contributors +============ + +* Alex Grönholm +* Alice Bevan-McGregor +* Arfrever Frehtes Taifersar Arahesis +* Christophe Combelles +* Daniel Stutzbach +* Daniel Holth +* Hanno Schlichting +* Jannis Leidel +* Jason R. Coombs +* Jim Fulton +* Jonathan Lange +* Justin Azoff +* Lennart Regebro +* Marc Abramowitz +* Martin von Löwis +* Noufal Ibrahim +* Pete Hollobon +* Philip Jenvey +* Reinout van Rees +* Robert Myers +* Stefan H. Holek +* Tarek Ziadé +* Toshio Kuratomi + +If you think you name is missing, please add it (alpha order by first name) + diff --git a/vendor/distribute-0.6.35/DEVGUIDE.txt b/vendor/distribute-0.6.35/DEVGUIDE.txt new file mode 100644 index 00000000..8dcabfd1 --- /dev/null +++ b/vendor/distribute-0.6.35/DEVGUIDE.txt @@ -0,0 +1,22 @@ +============================ +Quick notes for contributors +============================ + +Distribute is using Mercurial. + +Grab the code at bitbucket:: + + $ hg clone https://bitbucket.org/tarek/distribute + +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 + +And remember that 0.6 (the only development line) is only bug fixes, and the +APIs should be fully backward compatible with Setuptools. + +You can run the tests via:: + + $ python setup.py test diff --git a/vendor/distribute-0.6.35/MANIFEST.in b/vendor/distribute-0.6.35/MANIFEST.in new file mode 100644 index 00000000..9837747a --- /dev/null +++ b/vendor/distribute-0.6.35/MANIFEST.in @@ -0,0 +1,9 @@ +recursive-include setuptools *.py *.txt *.exe +recursive-include tests *.py *.c *.pyx *.txt +recursive-include setuptools/tests *.html +recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html +recursive-include _markerlib *.py +include *.py +include *.txt +include MANIFEST.in +include launcher.c diff --git a/vendor/distribute-0.6.35/PKG-INFO b/vendor/distribute-0.6.35/PKG-INFO new file mode 100644 index 00000000..4a0374a7 --- /dev/null +++ b/vendor/distribute-0.6.35/PKG-INFO @@ -0,0 +1,871 @@ +Metadata-Version: 1.1 +Name: distribute +Version: 0.6.35 +Summary: Easily download, build, install, upgrade, and uninstall Python packages +Home-page: http://packages.python.org/distribute +Author: The fellowship of the packaging +Author-email: distutils-sig@python.org +License: PSF or ZPL +Description: =============================== + Installing and Using Distribute + =============================== + + .. contents:: **Table of Contents** + + ----------- + Disclaimers + ----------- + + About the fork + ============== + + `Distribute` is a fork of the `Setuptools` project. + + Distribute is intended to replace Setuptools as the standard method + for working with Python module distributions. + + The fork has two goals: + + - Providing a backward compatible version to replace Setuptools + and make all distributions that depend on Setuptools work as + before, but with less bugs and behaviorial issues. + + This work is done in the 0.6.x series. + + Starting with version 0.6.2, Distribute supports Python 3. + Installing and using distribute for Python 3 code works exactly + the same as for Python 2 code, but Distribute 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. See http://packages.python.org/distribute for more + information. + + - Refactoring the code, and releasing it in several distributions. + This work is being done in the 0.7.x series but not yet released. + + The roadmap is still evolving, and the page that is up-to-date is + located at : `http://packages.python.org/distribute/roadmap`. + + If you install `Distribute` and want to switch back for any reason to + `Setuptools`, get to the `Uninstallation instructions`_ section. + + More documentation + ================== + + You can get more information in the Sphinx-based documentation, located + at http://packages.python.org/distribute. This documentation includes the old + Setuptools documentation that is slowly replaced, and brand new content. + + About the installation process + ============================== + + The `Distribute` installer modifies your installation by de-activating an + existing installation of `Setuptools` in a bootstrap process. This process + has been tested in various installation schemes and contexts but in case of a + bug during this process your Python installation might be left in a broken + state. Since all modified files and directories are copied before the + installation starts, you will be able to get back to a normal state by reading + the instructions in the `Uninstallation instructions`_ section. + + In any case, it is recommended to save you `site-packages` directory before + you start the installation of `Distribute`. + + ------------------------- + Installation Instructions + ------------------------- + + Distribute is only released as a source distribution. + + It can be installed using pip, and can be done so with the source tarball, + or by using the ``distribute_setup.py`` script provided online. + + ``distribute_setup.py`` is the simplest and preferred way on all systems. + + distribute_setup.py + =================== + + Download + `distribute_setup.py <http://python-distribute.org/distribute_setup.py>`_ + and execute it, using the Python interpreter of your choice. + + If your shell has the ``curl`` program you can do:: + + $ curl -O http://python-distribute.org/distribute_setup.py + $ python distribute_setup.py + + Notice this file is also provided in the source release. + + pip + === + + Run easy_install or pip:: + + $ pip install distribute + + Source installation + =================== + + Download the source tarball, uncompress it, then run the install command:: + + $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.35.tar.gz + $ tar -xzvf distribute-0.6.35.tar.gz + $ cd distribute-0.6.35 + $ python setup.py install + + --------------------------- + Uninstallation Instructions + --------------------------- + + Like other distutils-based distributions, Distribute doesn't provide an + uninstaller yet. It's all done manually! We are all waiting for PEP 376 + support in Python. + + Distribute is installed in three steps: + + 1. it gets out of the way an existing installation of Setuptools + 2. it installs a `fake` setuptools installation + 3. it installs distribute + + Distribute can be removed like this: + + - remove the ``distribute*.egg`` file located in your site-packages directory + - remove the ``setuptools.pth`` file located in you site-packages directory + - remove the easy_install script located in you ``sys.prefix/bin`` directory + - remove the ``setuptools*.egg`` directory located in your site-packages directory, + if any. + + If you want to get back to setuptools: + + - reinstall setuptools using its instruction. + + Lastly: + + - remove the *.OLD.* directory located in your site-packages directory if any, + **once you have checked everything was working correctly again**. + + ------------------------- + Quick help for developers + ------------------------- + + To create an egg which is compatible with Distribute, use the same + practice as with Setuptools, e.g.:: + + from setuptools import setup + + setup(... + ) + + To use `pkg_resources` to access data files in the egg, you should + require the Setuptools distribution explicitly:: + + from setuptools import setup + + setup(... + install_requires=['setuptools'] + ) + + Only if you need Distribute-specific functionality should you depend + on it explicitly. In this case, replace the Setuptools dependency:: + + from setuptools import setup + + setup(... + install_requires=['distribute'] + ) + + ----------- + Install FAQ + ----------- + + - **Why is Distribute wrapping my Setuptools installation?** + + Since Distribute is a fork, and since it provides the same package + and modules, it renames the existing Setuptools egg and inserts a + new one which merely wraps the Distribute code. This way, full + backwards compatibility is kept for packages which rely on the + Setuptools modules. + + At the same time, packages can meet their dependency on Setuptools + without actually installing it (which would disable Distribute). + + - **How does Distribute interact with virtualenv?** + + Everytime you create a virtualenv it will install setuptools by default. + You either need to re-install Distribute in it right after or pass the + ``--distribute`` option when creating it. + + Once installed, your virtualenv will use Distribute transparently. + + Although, if you have Setuptools installed in your system-wide Python, + and if the virtualenv you are in was generated without the `--no-site-packages` + option, the Distribute installation will stop. + + You need in this case to build a virtualenv with the `--no-site-packages` + option or to install `Distribute` globally. + + - **How does Distribute interacts with zc.buildout?** + + You can use Distribute in your zc.buildout, with the --distribute option, + starting at zc.buildout 1.4.2:: + + $ python bootstrap.py --distribute + + For previous zc.buildout versions, *the only thing* you need to do + is use the bootstrap at `http://python-distribute.org/bootstrap.py`. Run + that bootstrap and ``bin/buildout`` (and all other buildout-generated + scripts) will transparently use distribute instead of setuptools. You do + not need a specific buildout release. + + A shared eggs directory is no problem (since 0.6.6): the setuptools egg is + left in place unmodified. So other buildouts that do not yet use the new + bootstrap continue to work just fine. And there is no need to list + ``distribute`` somewhere in your eggs: using the bootstrap is enough. + + The source code for the bootstrap script is located at + `http://bitbucket.org/tarek/buildout-distribute`. + + + + ----------------------------- + Feedback and getting involved + ----------------------------- + + - Mailing list: http://mail.python.org/mailman/listinfo/distutils-sig + - Issue tracker: http://bitbucket.org/tarek/distribute/issues/ + - Code Repository: http://bitbucket.org/tarek/distribute + + ======= + CHANGES + ======= + + ------ + 0.6.35 + ------ + + Note this release is backward-incompatible with distribute 0.6.23-0.6.34 in + how it parses version numbers. + + * `Issue #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 + ------ + + * `Issue #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. + * `Issue #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. + * `Issue #341`_: Fix a ResourceWarning. + + ------ + 0.6.32 + ------ + + * Fix test suite with Python 2.6. + * Fix some DeprecationWarnings and ResourceWarnings. + * `Issue #335`_: Backed out `setup_requires` superceding installed requirements + until regression can be addressed. + + ------ + 0.6.31 + ------ + + * `Issue #303`_: Make sure the manifest only ever contains UTF-8 in Python 3. + * `Issue #329`_: Properly close files created by tests for compatibility with + Jython. + * Work around Jython bugs `#1980 <http://bugs.jython.org/issue1980>`_ and + `#1981 <http://bugs.jython.org/issue1981>`_. + * `Issue #334`_: Provide workaround for packages that reference `sys.__stdout__` + such as numpy does. This change should address + `virtualenv #359 <https://github.com/pypa/virtualenv/issues/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. + * `Issue #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 + ------ + + * `Issue #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. + * `Issue #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. + * `Issue #326`_: `upload_docs` provided mangled auth credentials under Python 3. + * `Issue #320`_: Fix check for "createable" in distribute_setup.py. + * `Issue #305`_: Remove a warning that was triggered during normal operations. + * `Issue #311`_: Print metadata in UTF-8 independent of platform. + * `Issue #303`_: Read manifest file with UTF-8 encoding under Python 3. + * `Issue #301`_: Allow to run tests of namespace packages when using 2to3. + * `Issue #304`_: Prevent import loop in site.py under Python 3.3. + * `Issue #283`_: Reenable scanning of `*.pyc` / `*.pyo` files on Python 3.3. + * `Issue #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. + * `Issue #306`_: Even if 2to3 is used, we build in-place under Python 2. + * `Issue #307`_: Prints the full path when .svn/entries is broken. + * `Issue #313`_: Support for sdist subcommands (Python 2.7) + * `Issue #314`_: test_local_index() would fail an OS X. + * `Issue #310`_: Non-ascii characters in a namespace __init__.py causes errors. + * `Issue #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 + ------ + + * `Issue #294`_: setup.py can now be invoked from any directory. + * Scripts are now installed honoring the umask. + * Added support for .dist-info directories. + * `Issue #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. + * `Issue #231`_: Don't fiddle with system python when used with buildout + (bootstrap.py) + + ------ + 0.6.26 + ------ + + * `Issue #183`_: Symlinked files are now extracted from source distributions. + * `Issue #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 + ------ + + * `Issue #258`_: Workaround a cache issue + * `Issue #260`_: distribute_setup.py now accepts the --user parameter for + Python 2.6 and later. + * `Issue #262`_: package_index.open_with_auth no longer throws LookupError + on Python 3. + * `Issue #269`_: AttributeError when an exception occurs reading Manifest.in + on late releases of Python. + * `Issue #272`_: Prevent TypeError when namespace package names are unicode + and single-install-externally-managed is used. Also fixes PIP `issue + 449`_. + * `Issue #273`_: Legacy script launchers now install with Python2/3 support. + + ------ + 0.6.24 + ------ + + * `Issue #249`_: Added options to exclude 2to3 fixers + + ------ + 0.6.23 + ------ + + * `Issue #244`_: Fixed a test + * `Issue #243`_: Fixed a test + * `Issue #239`_: Fixed a test + * `Issue #240`_: Fixed a test + * `Issue #241`_: Fixed a test + * `Issue #237`_: Fixed a test + * `Issue #238`_: easy_install now uses 64bit executable wrappers on 64bit Python + * `Issue #208`_: Fixed parsed_versions, it now honors post-releases as noted in the documentation + * `Issue #207`_: Windows cli and gui wrappers pass CTRL-C to child python process + * `Issue #227`_: easy_install now passes its arguments to setup.py bdist_egg + * `Issue #225`_: Fixed a NameError on Python 2.5, 2.4 + + ------ + 0.6.21 + ------ + + * `Issue #225`_: FIxed a regression on py2.4 + + ------ + 0.6.20 + ------ + + * `Issue #135`_: Include url in warning when processing URLs in package_index. + * `Issue #212`_: Fix issue where easy_instal fails on Python 3 on windows installer. + * `Issue #213`_: Fix typo in documentation. + + ------ + 0.6.19 + ------ + + * `Issue 206`_: AttributeError: 'HTTPMessage' object has no attribute 'getheaders' + + ------ + 0.6.18 + ------ + + * `Issue 210`_: Fixed a regression introduced by `Issue 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. + * `Issue 204`_: Don't try to import the parent of a namespace package in + declare_namespace + * `Issue 196`_: Tolerate responses with multiple Content-Length headers + * `Issue 205`_: Sandboxing doesn't preserve working_set. Leads to setup_requires + problems. + + ------ + 0.6.16 + ------ + + * Builds sdist gztar even on Windows (avoiding `Issue 193`_). + * `Issue 192`_: Fixed metadata omitted on Windows when package_dir + specified with forward-slash. + * `Issue 195`_: Cython build support. + * `Issue 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. + * `Issue 146`_: Fixed missing DLL files after easy_install of windows exe package. + + ------ + 0.6.14 + ------ + + * `Issue 170`_: Fixed unittest failure. Thanks to Toshio. + * `Issue 171`_: Fixed race condition in unittests cause deadlocks in test suite. + * `Issue 143`_: Fixed a lookup issue with easy_install. + Thanks to David and Zooko. + * `Issue 174`_: Fixed the edit mode when its used with setuptools itself + + ------ + 0.6.13 + ------ + + * `Issue 160`_: 2.7 gives ValueError("Invalid IPv6 URL") + * `Issue 150`_: Fixed using ~/.local even in a --no-site-packages virtualenv + * `Issue 163`_: scan index links before external links, and don't use the md5 when + comparing two distributions + + ------ + 0.6.12 + ------ + + * `Issue 149`_: Fixed various failures on 2.3/2.4 + + ------ + 0.6.11 + ------ + + * Found another case of SandboxViolation - fixed + * `Issue 15`_ and 48: Introduced a socket timeout of 15 seconds on url openings + * Added indexsidebar.html into MANIFEST.in + * `Issue 108`_: Fixed TypeError with Python3.1 + * `Issue 121`_: Fixed --help install command trying to actually install. + * `Issue 112`_: Added an os.makedirs so that Tarek's solution will work. + * `Issue 133`_: Added --no-find-links to easy_install + * Added easy_install --user + * `Issue 100`_: Fixed develop --user not taking '.' in PYTHONPATH into account + * `Issue 134`_: removed spurious UserWarnings. Patch by VanLindberg + * `Issue 138`_: cant_write_to_target error when setup_requires is used. + * `Issue 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 + ----- + + * `Issue 90`_: unknown setuptools version can be added in the working set + * `Issue 87`_: setupt.py doesn't try to convert distribute_setup.py anymore + Initial Patch by arfrever. + * `Issue 89`_: added a side bar with a download link to the doc. + * `Issue 86`_: fixed missing sentence in pkg_resources doc. + * Added a nicer error message when a DistributionNotFound is raised. + * `Issue 80`_: test_develop now works with Python 3.1 + * `Issue 93`_: upload_docs now works if there is an empty sub-directory. + * `Issue 70`_: exec bit on non-exec files + * `Issue 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). + * `Issue 101`_: Allowing ``os.devnull`` in Sandbox + * `Issue 92`_: Fixed the "no eggs" found error with MacPort + (platform.mac_ver() fails) + * `Issue 103`_: test_get_script_header_jython_workaround not run + anymore under py3 with C or POSIX local. Contributed by Arfrever. + * `Issue 104`_: remvoved the assertion when the installation fails, + with a nicer message for the end user. + * `Issue 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 + ----- + + * `Issue 58`_: Added --user support to the develop command + * `Issue 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. + * `Issue 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. + * `Issue 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 + * `Issue 74`_: no_fake should be True by default. + * `Issue 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 + ----- + + * `Issue 65`_: cli.exe and gui.exe are now generated at build time, + depending on the platform in use. + + * `Issue 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 `issue #52`_. + + * Added an upload_docs command to easily upload project documentation to + PyPI's http://packages.python.org. This close `issue #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 http://bugs.python.org/setuptools/issue39. + + * Added option to run 2to3 automatically when installing on Python 3. + This closes `issue #31`_. + + * Fixed invalid usage of requirement.parse, that broke develop -d. + This closes http://bugs.python.org/setuptools/issue44. + + * Fixed script launcher for 64-bit Windows. + This closes http://bugs.python.org/setuptools/issue2. + + * KeyError when compiling extensions. + This closes http://bugs.python.org/setuptools/issue41. + + bootstrapping + ============= + + * Fixed bootstrap not working on Windows. This closes `issue #49`_. + + * Fixed 2.6 dependencies. This closes `issue #50`_. + + * Make sure setuptools is patched when running through easy_install + This closes http://bugs.python.org/setuptools/issue40. + + ----- + 0.6.1 + ----- + + setuptools + ========== + + * package_index.urlopen now catches BadStatusLine and malformed url errors. + This closes `issue #16`_ and `issue #18`_. + + * zip_ok is now False by default. This closes + http://bugs.python.org/setuptools/issue33. + + * Fixed invalid URL error catching. http://bugs.python.org/setuptools/issue20. + + * Fixed invalid bootstraping with easy_install installation (`issue #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 `issue #10`_. + + --- + 0.6 + --- + + setuptools + ========== + + * Packages required at build time where not fully present at install time. + This closes `issue #12`_. + + * Protected against failures in tarfile extraction. This closes `issue #10`_. + + * Made Jython api_tests.txt doctest compatible. This closes `issue #7`_. + + * sandbox.py replaced builtin type file with builtin function open. This + closes `issue #6`_. + + * Immediately close all file handles. This closes `issue #3`_. + + * Added compatibility with Subversion 1.6. This references `issue #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 `issue #13`_. + + * Allow to find_on_path on systems with tight permissions to fail gracefully. + This closes `issue #9`_. + + * Corrected inconsistency between documentation and code of add_entry. + This closes `issue #8`_. + + * Immediately close all file handles. This closes `issue #3`_. + + easy_install + ============ + + * Immediately close all file handles. This closes `issue #3`_. + + + .. _`Issue #135`: http://bitbucket.org/tarek/distribute/issue/135 + .. _`Issue #183`: http://bitbucket.org/tarek/distribute/issue/183 + .. _`Issue #207`: http://bitbucket.org/tarek/distribute/issue/207 + .. _`Issue #208`: http://bitbucket.org/tarek/distribute/issue/208 + .. _`Issue #212`: http://bitbucket.org/tarek/distribute/issue/212 + .. _`Issue #213`: http://bitbucket.org/tarek/distribute/issue/213 + .. _`Issue #218`: http://bitbucket.org/tarek/distribute/issue/218 + .. _`Issue #225`: http://bitbucket.org/tarek/distribute/issue/225 + .. _`Issue #227`: http://bitbucket.org/tarek/distribute/issue/227 + .. _`Issue #231`: http://bitbucket.org/tarek/distribute/issue/231 + .. _`Issue #237`: http://bitbucket.org/tarek/distribute/issue/237 + .. _`Issue #238`: http://bitbucket.org/tarek/distribute/issue/238 + .. _`Issue #239`: http://bitbucket.org/tarek/distribute/issue/239 + .. _`Issue #240`: http://bitbucket.org/tarek/distribute/issue/240 + .. _`Issue #241`: http://bitbucket.org/tarek/distribute/issue/241 + .. _`Issue #243`: http://bitbucket.org/tarek/distribute/issue/243 + .. _`Issue #244`: http://bitbucket.org/tarek/distribute/issue/244 + .. _`Issue #249`: http://bitbucket.org/tarek/distribute/issue/249 + .. _`Issue #258`: http://bitbucket.org/tarek/distribute/issue/258 + .. _`Issue #260`: http://bitbucket.org/tarek/distribute/issue/260 + .. _`Issue #262`: http://bitbucket.org/tarek/distribute/issue/262 + .. _`Issue #269`: http://bitbucket.org/tarek/distribute/issue/269 + .. _`Issue #272`: http://bitbucket.org/tarek/distribute/issue/272 + .. _`Issue #273`: http://bitbucket.org/tarek/distribute/issue/273 + .. _`Issue #278`: http://bitbucket.org/tarek/distribute/issue/278 + .. _`Issue #283`: http://bitbucket.org/tarek/distribute/issue/283 + .. _`Issue #294`: http://bitbucket.org/tarek/distribute/issue/294 + .. _`Issue #299`: http://bitbucket.org/tarek/distribute/issue/299 + .. _`Issue #301`: http://bitbucket.org/tarek/distribute/issue/301 + .. _`Issue #303`: http://bitbucket.org/tarek/distribute/issue/303 + .. _`Issue #304`: http://bitbucket.org/tarek/distribute/issue/304 + .. _`Issue #305`: http://bitbucket.org/tarek/distribute/issue/305 + .. _`Issue #306`: http://bitbucket.org/tarek/distribute/issue/306 + .. _`Issue #307`: http://bitbucket.org/tarek/distribute/issue/307 + .. _`Issue #310`: http://bitbucket.org/tarek/distribute/issue/310 + .. _`Issue #311`: http://bitbucket.org/tarek/distribute/issue/311 + .. _`Issue #313`: http://bitbucket.org/tarek/distribute/issue/313 + .. _`Issue #314`: http://bitbucket.org/tarek/distribute/issue/314 + .. _`Issue #320`: http://bitbucket.org/tarek/distribute/issue/320 + .. _`Issue #323`: http://bitbucket.org/tarek/distribute/issue/323 + .. _`Issue #326`: http://bitbucket.org/tarek/distribute/issue/326 + .. _`Issue #327`: http://bitbucket.org/tarek/distribute/issue/327 + .. _`Issue #328`: http://bitbucket.org/tarek/distribute/issue/328 + .. _`Issue #329`: http://bitbucket.org/tarek/distribute/issue/329 + .. _`Issue #334`: http://bitbucket.org/tarek/distribute/issue/334 + .. _`Issue #335`: http://bitbucket.org/tarek/distribute/issue/335 + .. _`Issue #336`: http://bitbucket.org/tarek/distribute/issue/336 + .. _`Issue #341`: http://bitbucket.org/tarek/distribute/issue/341 + .. _`Issue 100`: http://bitbucket.org/tarek/distribute/issue/100 + .. _`Issue 101`: http://bitbucket.org/tarek/distribute/issue/101 + .. _`Issue 103`: http://bitbucket.org/tarek/distribute/issue/103 + .. _`Issue 104`: http://bitbucket.org/tarek/distribute/issue/104 + .. _`Issue 108`: http://bitbucket.org/tarek/distribute/issue/108 + .. _`Issue 11`: http://bitbucket.org/tarek/distribute/issue/11 + .. _`Issue 112`: http://bitbucket.org/tarek/distribute/issue/112 + .. _`Issue 121`: http://bitbucket.org/tarek/distribute/issue/121 + .. _`Issue 133`: http://bitbucket.org/tarek/distribute/issue/133 + .. _`Issue 134`: http://bitbucket.org/tarek/distribute/issue/134 + .. _`Issue 138`: http://bitbucket.org/tarek/distribute/issue/138 + .. _`Issue 143`: http://bitbucket.org/tarek/distribute/issue/143 + .. _`Issue 146`: http://bitbucket.org/tarek/distribute/issue/146 + .. _`Issue 147`: http://bitbucket.org/tarek/distribute/issue/147 + .. _`Issue 149`: http://bitbucket.org/tarek/distribute/issue/149 + .. _`Issue 15`: http://bitbucket.org/tarek/distribute/issue/15 + .. _`Issue 150`: http://bitbucket.org/tarek/distribute/issue/150 + .. _`Issue 160`: http://bitbucket.org/tarek/distribute/issue/160 + .. _`Issue 163`: http://bitbucket.org/tarek/distribute/issue/163 + .. _`Issue 170`: http://bitbucket.org/tarek/distribute/issue/170 + .. _`Issue 171`: http://bitbucket.org/tarek/distribute/issue/171 + .. _`Issue 174`: http://bitbucket.org/tarek/distribute/issue/174 + .. _`Issue 192`: http://bitbucket.org/tarek/distribute/issue/192 + .. _`Issue 193`: http://bitbucket.org/tarek/distribute/issue/193 + .. _`Issue 195`: http://bitbucket.org/tarek/distribute/issue/195 + .. _`Issue 196`: http://bitbucket.org/tarek/distribute/issue/196 + .. _`Issue 200`: http://bitbucket.org/tarek/distribute/issue/200 + .. _`Issue 204`: http://bitbucket.org/tarek/distribute/issue/204 + .. _`Issue 205`: http://bitbucket.org/tarek/distribute/issue/205 + .. _`Issue 206`: http://bitbucket.org/tarek/distribute/issue/206 + .. _`Issue 21`: http://bitbucket.org/tarek/distribute/issue/21 + .. _`Issue 210`: http://bitbucket.org/tarek/distribute/issue/210 + .. _`Issue 58`: http://bitbucket.org/tarek/distribute/issue/58 + .. _`Issue 64`: http://bitbucket.org/tarek/distribute/issue/64 + .. _`Issue 65`: http://bitbucket.org/tarek/distribute/issue/65 + .. _`Issue 67`: http://bitbucket.org/tarek/distribute/issue/67 + .. _`Issue 70`: http://bitbucket.org/tarek/distribute/issue/70 + .. _`Issue 72`: http://bitbucket.org/tarek/distribute/issue/72 + .. _`Issue 74`: http://bitbucket.org/tarek/distribute/issue/74 + .. _`Issue 80`: http://bitbucket.org/tarek/distribute/issue/80 + .. _`Issue 86`: http://bitbucket.org/tarek/distribute/issue/86 + .. _`Issue 87`: http://bitbucket.org/tarek/distribute/issue/87 + .. _`Issue 89`: http://bitbucket.org/tarek/distribute/issue/89 + .. _`Issue 90`: http://bitbucket.org/tarek/distribute/issue/90 + .. _`Issue 92`: http://bitbucket.org/tarek/distribute/issue/92 + .. _`Issue 93`: http://bitbucket.org/tarek/distribute/issue/93 + .. _`Issue 99`: http://bitbucket.org/tarek/distribute/issue/99 + .. _`issue + 449`: http://bitbucket.org/tarek/distribute/issue/449 + .. _`issue #1`: http://bitbucket.org/tarek/distribute/issue/1 + .. _`issue #10`: http://bitbucket.org/tarek/distribute/issue/10 + .. _`issue #12`: http://bitbucket.org/tarek/distribute/issue/12 + .. _`issue #13`: http://bitbucket.org/tarek/distribute/issue/13 + .. _`issue #16`: http://bitbucket.org/tarek/distribute/issue/16 + .. _`issue #18`: http://bitbucket.org/tarek/distribute/issue/18 + .. _`issue #3`: http://bitbucket.org/tarek/distribute/issue/3 + .. _`issue #31`: http://bitbucket.org/tarek/distribute/issue/31 + .. _`issue #40`: http://bitbucket.org/tarek/distribute/issue/40 + .. _`issue #49`: http://bitbucket.org/tarek/distribute/issue/49 + .. _`issue #5`: http://bitbucket.org/tarek/distribute/issue/5 + .. _`issue #50`: http://bitbucket.org/tarek/distribute/issue/50 + .. _`issue #52`: http://bitbucket.org/tarek/distribute/issue/52 + .. _`issue #56`: http://bitbucket.org/tarek/distribute/issue/56 + .. _`issue #6`: http://bitbucket.org/tarek/distribute/issue/6 + .. _`issue #7`: http://bitbucket.org/tarek/distribute/issue/7 + .. _`issue #8`: http://bitbucket.org/tarek/distribute/issue/8 + .. _`issue #9`: http://bitbucket.org/tarek/distribute/issue/9 + + +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.4 +Classifier: Programming Language :: Python :: 2.5 +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: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities diff --git a/vendor/distribute-0.6.35/README.txt b/vendor/distribute-0.6.35/README.txt new file mode 100644 index 00000000..ea13a9bc --- /dev/null +++ b/vendor/distribute-0.6.35/README.txt @@ -0,0 +1,228 @@ +=============================== +Installing and Using Distribute +=============================== + +.. contents:: **Table of Contents** + +----------- +Disclaimers +----------- + +About the fork +============== + +`Distribute` is a fork of the `Setuptools` project. + +Distribute is intended to replace Setuptools as the standard method +for working with Python module distributions. + +The fork has two goals: + +- Providing a backward compatible version to replace Setuptools + and make all distributions that depend on Setuptools work as + before, but with less bugs and behaviorial issues. + + This work is done in the 0.6.x series. + + Starting with version 0.6.2, Distribute supports Python 3. + Installing and using distribute for Python 3 code works exactly + the same as for Python 2 code, but Distribute 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. See http://packages.python.org/distribute for more + information. + +- Refactoring the code, and releasing it in several distributions. + This work is being done in the 0.7.x series but not yet released. + +The roadmap is still evolving, and the page that is up-to-date is +located at : `http://packages.python.org/distribute/roadmap`. + +If you install `Distribute` and want to switch back for any reason to +`Setuptools`, get to the `Uninstallation instructions`_ section. + +More documentation +================== + +You can get more information in the Sphinx-based documentation, located +at http://packages.python.org/distribute. This documentation includes the old +Setuptools documentation that is slowly replaced, and brand new content. + +About the installation process +============================== + +The `Distribute` installer modifies your installation by de-activating an +existing installation of `Setuptools` in a bootstrap process. This process +has been tested in various installation schemes and contexts but in case of a +bug during this process your Python installation might be left in a broken +state. Since all modified files and directories are copied before the +installation starts, you will be able to get back to a normal state by reading +the instructions in the `Uninstallation instructions`_ section. + +In any case, it is recommended to save you `site-packages` directory before +you start the installation of `Distribute`. + +------------------------- +Installation Instructions +------------------------- + +Distribute is only released as a source distribution. + +It can be installed using pip, and can be done so with the source tarball, +or by using the ``distribute_setup.py`` script provided online. + +``distribute_setup.py`` is the simplest and preferred way on all systems. + +distribute_setup.py +=================== + +Download +`distribute_setup.py <http://python-distribute.org/distribute_setup.py>`_ +and execute it, using the Python interpreter of your choice. + +If your shell has the ``curl`` program you can do:: + + $ curl -O http://python-distribute.org/distribute_setup.py + $ python distribute_setup.py + +Notice this file is also provided in the source release. + +pip +=== + +Run easy_install or pip:: + + $ pip install distribute + +Source installation +=================== + +Download the source tarball, uncompress it, then run the install command:: + + $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.35.tar.gz + $ tar -xzvf distribute-0.6.35.tar.gz + $ cd distribute-0.6.35 + $ python setup.py install + +--------------------------- +Uninstallation Instructions +--------------------------- + +Like other distutils-based distributions, Distribute doesn't provide an +uninstaller yet. It's all done manually! We are all waiting for PEP 376 +support in Python. + +Distribute is installed in three steps: + +1. it gets out of the way an existing installation of Setuptools +2. it installs a `fake` setuptools installation +3. it installs distribute + +Distribute can be removed like this: + +- remove the ``distribute*.egg`` file located in your site-packages directory +- remove the ``setuptools.pth`` file located in you site-packages directory +- remove the easy_install script located in you ``sys.prefix/bin`` directory +- remove the ``setuptools*.egg`` directory located in your site-packages directory, + if any. + +If you want to get back to setuptools: + +- reinstall setuptools using its instruction. + +Lastly: + +- remove the *.OLD.* directory located in your site-packages directory if any, + **once you have checked everything was working correctly again**. + +------------------------- +Quick help for developers +------------------------- + +To create an egg which is compatible with Distribute, use the same +practice as with Setuptools, e.g.:: + + from setuptools import setup + + setup(... + ) + +To use `pkg_resources` to access data files in the egg, you should +require the Setuptools distribution explicitly:: + + from setuptools import setup + + setup(... + install_requires=['setuptools'] + ) + +Only if you need Distribute-specific functionality should you depend +on it explicitly. In this case, replace the Setuptools dependency:: + + from setuptools import setup + + setup(... + install_requires=['distribute'] + ) + +----------- +Install FAQ +----------- + +- **Why is Distribute wrapping my Setuptools installation?** + + Since Distribute is a fork, and since it provides the same package + and modules, it renames the existing Setuptools egg and inserts a + new one which merely wraps the Distribute code. This way, full + backwards compatibility is kept for packages which rely on the + Setuptools modules. + + At the same time, packages can meet their dependency on Setuptools + without actually installing it (which would disable Distribute). + +- **How does Distribute interact with virtualenv?** + + Everytime you create a virtualenv it will install setuptools by default. + You either need to re-install Distribute in it right after or pass the + ``--distribute`` option when creating it. + + Once installed, your virtualenv will use Distribute transparently. + + Although, if you have Setuptools installed in your system-wide Python, + and if the virtualenv you are in was generated without the `--no-site-packages` + option, the Distribute installation will stop. + + You need in this case to build a virtualenv with the `--no-site-packages` + option or to install `Distribute` globally. + +- **How does Distribute interacts with zc.buildout?** + + You can use Distribute in your zc.buildout, with the --distribute option, + starting at zc.buildout 1.4.2:: + + $ python bootstrap.py --distribute + + For previous zc.buildout versions, *the only thing* you need to do + is use the bootstrap at `http://python-distribute.org/bootstrap.py`. Run + that bootstrap and ``bin/buildout`` (and all other buildout-generated + scripts) will transparently use distribute instead of setuptools. You do + not need a specific buildout release. + + A shared eggs directory is no problem (since 0.6.6): the setuptools egg is + left in place unmodified. So other buildouts that do not yet use the new + bootstrap continue to work just fine. And there is no need to list + ``distribute`` somewhere in your eggs: using the bootstrap is enough. + + The source code for the bootstrap script is located at + `http://bitbucket.org/tarek/buildout-distribute`. + + + +----------------------------- +Feedback and getting involved +----------------------------- + +- Mailing list: http://mail.python.org/mailman/listinfo/distutils-sig +- Issue tracker: http://bitbucket.org/tarek/distribute/issues/ +- Code Repository: http://bitbucket.org/tarek/distribute + diff --git a/vendor/distribute-0.6.35/_markerlib/__init__.py b/vendor/distribute-0.6.35/_markerlib/__init__.py new file mode 100644 index 00000000..e2b237b1 --- /dev/null +++ b/vendor/distribute-0.6.35/_markerlib/__init__.py @@ -0,0 +1,16 @@ +try: + import ast + from _markerlib.markers import default_environment, compile, interpret +except ImportError: + if 'ast' in globals(): + raise + def default_environment(): + return {} + def compile(marker): + def marker_fn(environment=None, override=None): + # 'empty markers are True' heuristic won't install extra deps. + return not marker.strip() + marker_fn.__doc__ = marker + return marker_fn + def interpret(marker, environment=None, override=None): + return compile(marker)() diff --git a/vendor/distribute-0.6.35/_markerlib/markers.py b/vendor/distribute-0.6.35/_markerlib/markers.py new file mode 100644 index 00000000..c93d7f3b --- /dev/null +++ b/vendor/distribute-0.6.35/_markerlib/markers.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +"""Interpret PEP 345 environment markers. + +EXPR [in|==|!=|not in] EXPR [or|and] ... + +where EXPR belongs to any of those: + + python_version = '%s.%s' % (sys.version_info[0], sys.version_info[1]) + python_full_version = sys.version.split()[0] + os.name = os.name + sys.platform = sys.platform + platform.version = platform.version() + platform.machine = platform.machine() + platform.python_implementation = platform.python_implementation() + a free string, like '2.6', or 'win32' +""" + +__all__ = ['default_environment', 'compile', 'interpret'] + +import ast +import os +import platform +import sys +import weakref + +_builtin_compile = compile + +try: + from platform import python_implementation +except ImportError: + if os.name == "java": + # Jython 2.5 has ast module, but not platform.python_implementation() function. + def python_implementation(): + return "Jython" + else: + raise + + +# restricted set of variables +_VARS = {'sys.platform': sys.platform, + 'python_version': '%s.%s' % sys.version_info[:2], + # FIXME parsing sys.platform is not reliable, but there is no other + # way to get e.g. 2.7.2+, and the PEP is defined with sys.version + 'python_full_version': sys.version.split(' ', 1)[0], + 'os.name': os.name, + 'platform.version': platform.version(), + 'platform.machine': platform.machine(), + 'platform.python_implementation': python_implementation(), + 'extra': None # wheel extension + } + +def default_environment(): + """Return copy of default PEP 385 globals dictionary.""" + return dict(_VARS) + +class ASTWhitelist(ast.NodeTransformer): + def __init__(self, statement): + self.statement = statement # for error messages + + ALLOWED = (ast.Compare, ast.BoolOp, ast.Attribute, ast.Name, ast.Load, ast.Str) + # Bool operations + ALLOWED += (ast.And, ast.Or) + # Comparison operations + ALLOWED += (ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq, ast.NotIn) + + def visit(self, node): + """Ensure statement only contains allowed nodes.""" + if not isinstance(node, self.ALLOWED): + raise SyntaxError('Not allowed in environment markers.\n%s\n%s' % + (self.statement, + (' ' * node.col_offset) + '^')) + return ast.NodeTransformer.visit(self, node) + + def visit_Attribute(self, node): + """Flatten one level of attribute access.""" + new_node = ast.Name("%s.%s" % (node.value.id, node.attr), node.ctx) + return ast.copy_location(new_node, node) + +def parse_marker(marker): + tree = ast.parse(marker, mode='eval') + new_tree = ASTWhitelist(marker).generic_visit(tree) + return new_tree + +def compile_marker(parsed_marker): + return _builtin_compile(parsed_marker, '<environment marker>', 'eval', + dont_inherit=True) + +_cache = weakref.WeakValueDictionary() + +def compile(marker): + """Return compiled marker as a function accepting an environment dict.""" + try: + return _cache[marker] + except KeyError: + pass + if not marker.strip(): + def marker_fn(environment=None, override=None): + """""" + return True + else: + compiled_marker = compile_marker(parse_marker(marker)) + def marker_fn(environment=None, override=None): + """override updates environment""" + if override is None: + override = {} + if environment is None: + environment = default_environment() + environment.update(override) + return eval(compiled_marker, environment) + marker_fn.__doc__ = marker + _cache[marker] = marker_fn + return _cache[marker] + +def interpret(marker, environment=None): + return compile(marker)(environment) diff --git a/vendor/distribute-0.6.35/distribute_setup.py b/vendor/distribute-0.6.35/distribute_setup.py new file mode 100644 index 00000000..a447f7ec --- /dev/null +++ b/vendor/distribute-0.6.35/distribute_setup.py @@ -0,0 +1,546 @@ +#!python +"""Bootstrap distribute installation + +If you want to use setuptools in your package's setup.py, just include this +file in the same directory with it, and add this to the top of your setup.py:: + + from distribute_setup import use_setuptools + use_setuptools() + +If you want to require a specific version of setuptools, set a download +mirror, or use an alternate download directory, you can do so by supplying +the appropriate options to ``use_setuptools()``. + +This file can also be run as a script to install or upgrade setuptools. +""" +import os +import shutil +import sys +import time +import fnmatch +import tempfile +import tarfile +import optparse + +from distutils import log + +try: + from site import USER_SITE +except ImportError: + USER_SITE = None + +try: + import subprocess + + def _python_cmd(*args): + args = (sys.executable,) + args + return subprocess.call(args) == 0 + +except ImportError: + # will be used for python 2.3 + def _python_cmd(*args): + args = (sys.executable,) + args + # quoting arguments if windows + if sys.platform == 'win32': + def quote(arg): + if ' ' in arg: + return '"%s"' % arg + return arg + args = [quote(arg) for arg in args] + return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 + +DEFAULT_VERSION = "0.6.35" +DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" +SETUPTOOLS_FAKED_VERSION = "0.6c11" + +SETUPTOOLS_PKG_INFO = """\ +Metadata-Version: 1.0 +Name: setuptools +Version: %s +Summary: xxxx +Home-page: xxx +Author: xxx +Author-email: xxx +License: xxx +Description: xxx +""" % SETUPTOOLS_FAKED_VERSION + + +def _install(tarball, install_args=()): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # installing + log.warn('Installing Distribute') + if not _python_cmd('setup.py', 'install', *install_args): + log.warn('Something went wrong during the installation.') + log.warn('See the error message above.') + # exitcode will be 2 + return 2 + finally: + os.chdir(old_wd) + shutil.rmtree(tmpdir) + + +def _build_egg(egg, tarball, to_dir): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # building an egg + log.warn('Building a Distribute egg in %s', to_dir) + _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) + + finally: + os.chdir(old_wd) + shutil.rmtree(tmpdir) + # returning the result + log.warn(egg) + if not os.path.exists(egg): + raise IOError('Could not build the egg.') + + +def _do_download(version, download_base, to_dir, download_delay): + egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' + % (version, sys.version_info[0], sys.version_info[1])) + if not os.path.exists(egg): + tarball = download_setuptools(version, download_base, + to_dir, download_delay) + _build_egg(egg, tarball, to_dir) + sys.path.insert(0, egg) + import setuptools + setuptools.bootstrap_install_from = egg + + +def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, download_delay=15, no_fake=True): + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + was_imported = 'pkg_resources' in sys.modules or \ + 'setuptools' in sys.modules + try: + try: + import pkg_resources + if not hasattr(pkg_resources, '_distribute'): + if not no_fake: + _fake_setuptools() + raise ImportError + except ImportError: + return _do_download(version, download_base, to_dir, download_delay) + try: + pkg_resources.require("distribute>=" + version) + return + except pkg_resources.VersionConflict: + e = sys.exc_info()[1] + if was_imported: + sys.stderr.write( + "The required version of distribute (>=%s) is not available,\n" + "and can't be installed while this script is running. Please\n" + "install a more recent version first, using\n" + "'easy_install -U distribute'." + "\n\n(Currently using %r)\n" % (version, e.args[0])) + sys.exit(2) + else: + del pkg_resources, sys.modules['pkg_resources'] # reload ok + return _do_download(version, download_base, to_dir, + download_delay) + except pkg_resources.DistributionNotFound: + return _do_download(version, download_base, to_dir, + download_delay) + finally: + if not no_fake: + _create_fake_setuptools_pkg_info(to_dir) + + +def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, delay=15): + """Download distribute from a specified location and return its filename + + `version` should be a valid distribute version number that is available + as an egg 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. + """ + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + tgz_name = "distribute-%s.tar.gz" % version + url = download_base + tgz_name + saveto = os.path.join(to_dir, tgz_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + log.warn("Downloading %s", url) + src = urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = src.read() + dst = open(saveto, "wb") + dst.write(data) + finally: + if src: + src.close() + if dst: + dst.close() + return os.path.realpath(saveto) + + +def _no_sandbox(function): + def __no_sandbox(*args, **kw): + try: + from setuptools.sandbox import DirectorySandbox + if not hasattr(DirectorySandbox, '_old'): + def violation(*args): + pass + DirectorySandbox._old = DirectorySandbox._violation + DirectorySandbox._violation = violation + patched = True + else: + patched = False + except ImportError: + patched = False + + try: + return function(*args, **kw) + finally: + if patched: + DirectorySandbox._violation = DirectorySandbox._old + del DirectorySandbox._old + + return __no_sandbox + + +def _patch_file(path, content): + """Will backup the file then patch it""" + f = open(path) + existing_content = f.read() + f.close() + if existing_content == content: + # already patched + log.warn('Already patched.') + return False + log.warn('Patching...') + _rename_path(path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + return True + +_patch_file = _no_sandbox(_patch_file) + + +def _same_content(path, content): + f = open(path) + existing_content = f.read() + f.close() + return existing_content == content + + +def _rename_path(path): + new_name = path + '.OLD.%s' % time.time() + log.warn('Renaming %s to %s', path, new_name) + os.rename(path, new_name) + return new_name + + +def _remove_flat_installation(placeholder): + if not os.path.isdir(placeholder): + log.warn('Unkown installation at %s', placeholder) + return False + found = False + for file in os.listdir(placeholder): + if fnmatch.fnmatch(file, 'setuptools*.egg-info'): + found = True + break + if not found: + log.warn('Could not locate setuptools*.egg-info') + return + + log.warn('Moving elements out of the way...') + pkg_info = os.path.join(placeholder, file) + if os.path.isdir(pkg_info): + patched = _patch_egg_dir(pkg_info) + else: + patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) + + if not patched: + log.warn('%s already patched.', pkg_info) + return False + # now let's move the files out of the way + for element in ('setuptools', 'pkg_resources.py', 'site.py'): + element = os.path.join(placeholder, element) + if os.path.exists(element): + _rename_path(element) + else: + log.warn('Could not find the %s element of the ' + 'Setuptools distribution', element) + return True + +_remove_flat_installation = _no_sandbox(_remove_flat_installation) + + +def _after_install(dist): + log.warn('After install bootstrap.') + placeholder = dist.get_command_obj('install').install_purelib + _create_fake_setuptools_pkg_info(placeholder) + + +def _create_fake_setuptools_pkg_info(placeholder): + if not placeholder or not os.path.exists(placeholder): + log.warn('Could not find the install location') + return + pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) + setuptools_file = 'setuptools-%s-py%s.egg-info' % \ + (SETUPTOOLS_FAKED_VERSION, pyver) + pkg_info = os.path.join(placeholder, setuptools_file) + if os.path.exists(pkg_info): + log.warn('%s already exists', pkg_info) + return + + log.warn('Creating %s', pkg_info) + try: + f = open(pkg_info, 'w') + except EnvironmentError: + log.warn("Don't have permissions to write %s, skipping", pkg_info) + return + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + + pth_file = os.path.join(placeholder, 'setuptools.pth') + log.warn('Creating %s', pth_file) + f = open(pth_file, 'w') + try: + f.write(os.path.join(os.curdir, setuptools_file)) + finally: + f.close() + +_create_fake_setuptools_pkg_info = _no_sandbox( + _create_fake_setuptools_pkg_info +) + + +def _patch_egg_dir(path): + # let's check if it's already patched + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + if os.path.exists(pkg_info): + if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): + log.warn('%s already patched.', pkg_info) + return False + _rename_path(path) + os.mkdir(path) + os.mkdir(os.path.join(path, 'EGG-INFO')) + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + return True + +_patch_egg_dir = _no_sandbox(_patch_egg_dir) + + +def _before_install(): + log.warn('Before install bootstrap.') + _fake_setuptools() + + +def _under_prefix(location): + if 'install' not in sys.argv: + return True + args = sys.argv[sys.argv.index('install') + 1:] + for index, arg in enumerate(args): + for option in ('--root', '--prefix'): + if arg.startswith('%s=' % option): + top_dir = arg.split('root=')[-1] + return location.startswith(top_dir) + elif arg == option: + if len(args) > index: + top_dir = args[index + 1] + return location.startswith(top_dir) + if arg == '--user' and USER_SITE is not None: + return location.startswith(USER_SITE) + return True + + +def _fake_setuptools(): + log.warn('Scanning installed packages') + try: + import pkg_resources + except ImportError: + # we're cool + log.warn('Setuptools or Distribute does not seem to be installed.') + return + ws = pkg_resources.working_set + try: + setuptools_dist = ws.find( + pkg_resources.Requirement.parse('setuptools', replacement=False) + ) + except TypeError: + # old distribute API + setuptools_dist = ws.find( + pkg_resources.Requirement.parse('setuptools') + ) + + if setuptools_dist is None: + log.warn('No setuptools distribution found') + return + # detecting if it was already faked + setuptools_location = setuptools_dist.location + log.warn('Setuptools installation detected at %s', setuptools_location) + + # if --root or --preix was provided, and if + # setuptools is not located in them, we don't patch it + if not _under_prefix(setuptools_location): + log.warn('Not patching, --root or --prefix is installing Distribute' + ' in another location') + return + + # let's see if its an egg + if not setuptools_location.endswith('.egg'): + log.warn('Non-egg installation') + res = _remove_flat_installation(setuptools_location) + if not res: + return + else: + log.warn('Egg installation') + pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') + if (os.path.exists(pkg_info) and + _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): + log.warn('Already patched.') + return + log.warn('Patching...') + # let's create a fake egg replacing setuptools one + res = _patch_egg_dir(setuptools_location) + if not res: + return + log.warn('Patching complete.') + _relaunch() + + +def _relaunch(): + log.warn('Relaunching...') + # we have to relaunch the process + # pip marker to avoid a relaunch bug + _cmd1 = ['-c', 'install', '--single-version-externally-managed'] + _cmd2 = ['-c', 'install', '--record'] + if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2: + sys.argv[0] = 'setup.py' + args = [sys.executable] + sys.argv + sys.exit(subprocess.call(args)) + + +def _extractall(self, path=".", members=None): + """Extract all members from the archive to the current working + directory and set owner, modification time and permissions on + directories afterwards. `path' specifies a different directory + to extract to. `members' is optional and must be a subset of the + list returned by getmembers(). + """ + import copy + import operator + from tarfile import ExtractError + directories = [] + + if members is None: + members = self + + for tarinfo in members: + if tarinfo.isdir(): + # Extract directories with a safe mode. + directories.append(tarinfo) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 448 # decimal for oct 0700 + self.extract(tarinfo, path) + + # Reverse sort directories. + if sys.version_info < (2, 4): + def sorter(dir1, dir2): + return cmp(dir1.name, dir2.name) + directories.sort(sorter) + directories.reverse() + else: + directories.sort(key=operator.attrgetter('name'), reverse=True) + + # Set correct owner, mtime and filemode on directories. + for tarinfo in directories: + dirpath = os.path.join(path, tarinfo.name) + try: + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) + except ExtractError: + e = sys.exc_info()[1] + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + +def _build_install_args(options): + """ + Build the arguments to 'python setup.py install' on the distribute package + """ + install_args = [] + if options.user_install: + if sys.version_info < (2, 6): + log.warn("--user requires Python 2.6 or later") + raise SystemExit(1) + install_args.append('--user') + return install_args + +def _parse_args(): + """ + Parse the command line for options + """ + parser = optparse.OptionParser() + parser.add_option( + '--user', dest='user_install', action='store_true', default=False, + help='install in user site package (requires Python 2.6 or later)') + parser.add_option( + '--download-base', dest='download_base', metavar="URL", + default=DEFAULT_URL, + help='alternative URL from where to download the distribute package') + options, args = parser.parse_args() + # positional arguments are ignored + return options + +def main(version=DEFAULT_VERSION): + """Install or upgrade setuptools and EasyInstall""" + options = _parse_args() + tarball = download_setuptools(download_base=options.download_base) + return _install(tarball, _build_install_args(options)) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/vendor/distribute-0.6.35/docs/Makefile b/vendor/distribute-0.6.35/docs/Makefile new file mode 100644 index 00000000..30bf10a9 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/Makefile @@ -0,0 +1,75 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html web pickle htmlhelp latex changes linkcheck + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " changes to make an overview over all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + +clean: + -rm -rf build/* + +html: + mkdir -p build/html build/doctrees + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html + @echo + @echo "Build finished. The HTML pages are in build/html." + +pickle: + mkdir -p build/pickle build/doctrees + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +web: pickle + +json: + mkdir -p build/json build/doctrees + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + mkdir -p build/htmlhelp build/doctrees + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in build/htmlhelp." + +latex: + mkdir -p build/latex build/doctrees + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex + @echo + @echo "Build finished; the LaTeX files are in build/latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +changes: + mkdir -p build/changes build/doctrees + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes + @echo + @echo "The overview file is in build/changes." + +linkcheck: + mkdir -p build/linkcheck build/doctrees + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in build/linkcheck/output.txt." diff --git a/vendor/distribute-0.6.35/docs/_templates/indexsidebar.html b/vendor/distribute-0.6.35/docs/_templates/indexsidebar.html new file mode 100644 index 00000000..932909f3 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/_templates/indexsidebar.html @@ -0,0 +1,8 @@ +<h3>Download</h3> + +<p>Current version: <b>{{ version }}</b></p> +<p>Get Distribute from the <a href="http://pypi.python.org/pypi/distribute"> Python Package Index</a> + +<h3>Questions? Suggestions? Contributions?</h3> + +<p>Visit the <a href="http://bitbucket.org/tarek/distribute">Distribute project page</a> </p> diff --git a/vendor/distribute-0.6.35/docs/_theme/nature/static/nature.css_t b/vendor/distribute-0.6.35/docs/_theme/nature/static/nature.css_t new file mode 100644 index 00000000..1a654264 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/_theme/nature/static/nature.css_t @@ -0,0 +1,237 @@ +/** + * Sphinx stylesheet -- default theme + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Arial, sans-serif; + font-size: 100%; + background-color: #111111; + color: #555555; + margin: 0; + padding: 0; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 300px; +} + +hr{ + border: 1px solid #B1B4B6; +} + +div.document { + background-color: #fafafa; +} + +div.body { + background-color: #ffffff; + color: #3E4349; + padding: 1em 30px 30px 30px; + font-size: 0.9em; +} + +div.footer { + color: #555; + width: 100%; + padding: 13px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #444444; +} + +div.related { + background-color: #6BA81E; + line-height: 36px; + color: #ffffff; + text-shadow: 0px 1px 0 #444444; + font-size: 1.1em; +} + +div.related a { + color: #E2F3CC; +} + +div.related .right { + font-size: 0.9em; +} + +div.sphinxsidebar { + font-size: 0.9em; + line-height: 1.5em; + width: 300px; +} + +div.sphinxsidebarwrapper{ + padding: 20px 0; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Arial, sans-serif; + color: #222222; + font-size: 1.2em; + font-weight: bold; + margin: 0; + padding: 5px 10px; + text-shadow: 1px 1px 0 white +} + +div.sphinxsidebar h3 a { + color: #444444; +} + +div.sphinxsidebar p { + color: #888888; + padding: 5px 20px; + margin: 0.5em 0px; +} + +div.sphinxsidebar p.topless { +} + +div.sphinxsidebar ul { + margin: 10px 10px 10px 20px; + padding: 0; + color: #000000; +} + +div.sphinxsidebar a { + color: #444444; +} + +div.sphinxsidebar a:hover { + color: #E32E00; +} + +div.sphinxsidebar input { + border: 1px solid #cccccc; + font-family: sans-serif; + font-size: 1.1em; + padding: 0.15em 0.3em; +} + +div.sphinxsidebar input[type=text]{ + margin-left: 20px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #005B81; + text-decoration: none; +} + +a:hover { + color: #E32E00; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Arial, sans-serif; + font-weight: normal; + color: #212224; + margin: 30px 0px 10px 0px; + padding: 5px 0 5px 0px; + text-shadow: 0px 1px 0 white; + border-bottom: 1px solid #C8D5E3; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 150%; } +div.body h3 { font-size: 120%; } +div.body h4 { font-size: 110%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + line-height: 1.8em; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.highlight{ + background-color: white; +} + +div.note { + background-color: #eeeeee; + border: 1px solid #cccccc; +} + +div.seealso { + background-color: #ffffcc; + border: 1px solid #ffff66; +} + +div.topic { + background-color: #fafafa; + border-width: 0; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #ff6666; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 10px; + background-color: #fafafa; + color: #222222; + line-height: 1.5em; + font-size: 1.1em; + margin: 1.5em 0 1.5em 0; + -webkit-box-shadow: 0px 0px 4px #d8d8d8; + -moz-box-shadow: 0px 0px 4px #d8d8d8; + box-shadow: 0px 0px 4px #d8d8d8; +} + +tt { + color: #222222; + padding: 1px 2px; + font-size: 1.2em; + font-family: monospace; +} + +#table-of-contents ul { + padding-left: 2em; +} + diff --git a/vendor/distribute-0.6.35/docs/_theme/nature/static/pygments.css b/vendor/distribute-0.6.35/docs/_theme/nature/static/pygments.css new file mode 100644 index 00000000..652b7612 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/_theme/nature/static/pygments.css @@ -0,0 +1,54 @@ +.c { color: #999988; font-style: italic } /* Comment */ +.k { font-weight: bold } /* Keyword */ +.o { font-weight: bold } /* Operator */ +.cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.cp { color: #999999; font-weight: bold } /* Comment.preproc */ +.c1 { color: #999988; font-style: italic } /* Comment.Single */ +.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #aa0000 } /* Generic.Error */ +.gh { color: #999999 } /* Generic.Heading */ +.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.go { color: #111 } /* Generic.Output */ +.gp { color: #555555 } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #aaaaaa } /* Generic.Subheading */ +.gt { color: #aa0000 } /* Generic.Traceback */ +.kc { font-weight: bold } /* Keyword.Constant */ +.kd { font-weight: bold } /* Keyword.Declaration */ +.kp { font-weight: bold } /* Keyword.Pseudo */ +.kr { font-weight: bold } /* Keyword.Reserved */ +.kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.m { color: #009999 } /* Literal.Number */ +.s { color: #bb8844 } /* Literal.String */ +.na { color: #008080 } /* Name.Attribute */ +.nb { color: #999999 } /* Name.Builtin */ +.nc { color: #445588; font-weight: bold } /* Name.Class */ +.no { color: #ff99ff } /* Name.Constant */ +.ni { color: #800080 } /* Name.Entity */ +.ne { color: #990000; font-weight: bold } /* Name.Exception */ +.nf { color: #990000; font-weight: bold } /* Name.Function */ +.nn { color: #555555 } /* Name.Namespace */ +.nt { color: #000080 } /* Name.Tag */ +.nv { color: purple } /* Name.Variable */ +.ow { font-weight: bold } /* Operator.Word */ +.mf { color: #009999 } /* Literal.Number.Float */ +.mh { color: #009999 } /* Literal.Number.Hex */ +.mi { color: #009999 } /* Literal.Number.Integer */ +.mo { color: #009999 } /* Literal.Number.Oct */ +.sb { color: #bb8844 } /* Literal.String.Backtick */ +.sc { color: #bb8844 } /* Literal.String.Char */ +.sd { color: #bb8844 } /* Literal.String.Doc */ +.s2 { color: #bb8844 } /* Literal.String.Double */ +.se { color: #bb8844 } /* Literal.String.Escape */ +.sh { color: #bb8844 } /* Literal.String.Heredoc */ +.si { color: #bb8844 } /* Literal.String.Interpol */ +.sx { color: #bb8844 } /* Literal.String.Other */ +.sr { color: #808000 } /* Literal.String.Regex */ +.s1 { color: #bb8844 } /* Literal.String.Single */ +.ss { color: #bb8844 } /* Literal.String.Symbol */ +.bp { color: #999999 } /* Name.Builtin.Pseudo */ +.vc { color: #ff99ff } /* Name.Variable.Class */ +.vg { color: #ff99ff } /* Name.Variable.Global */ +.vi { color: #ff99ff } /* Name.Variable.Instance */ +.il { color: #009999 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/vendor/distribute-0.6.35/docs/_theme/nature/theme.conf b/vendor/distribute-0.6.35/docs/_theme/nature/theme.conf new file mode 100644 index 00000000..1cc40044 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/_theme/nature/theme.conf @@ -0,0 +1,4 @@ +[theme] +inherit = basic +stylesheet = nature.css +pygments_style = tango diff --git a/vendor/distribute-0.6.35/docs/conf.py b/vendor/distribute-0.6.35/docs/conf.py new file mode 100644 index 00000000..98380ba9 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/conf.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- +# +# Distribute documentation build configuration file, created by +# sphinx-quickstart on Fri Jul 17 14:22:37 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# The contents of this file are pickled, so don't put values in the namespace +# that aren't pickleable (module imports are okay, they're removed automatically). +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# 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('.')) + +# -- 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 = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.txt' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Distribute' +copyright = u'2009-2011, 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 +# built documents. +# +# The short X.Y version. +version = '0.6.35' +# The full version, including alpha/beta/rc tags. +release = '0.6.35' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'nature' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ['_theme'] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = "Distribute documentation" + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = "Distribute" + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +html_sidebars = {'index': 'indexsidebar.html'} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +html_use_modindex = False + +# If false, no index is generated. +html_use_index = False + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Distributedoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Distribute.tex', ur'Distribute Documentation', + ur'The fellowship of the packaging', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/vendor/distribute-0.6.35/docs/easy_install.txt b/vendor/distribute-0.6.35/docs/easy_install.txt new file mode 100644 index 00000000..9b4fcfbb --- /dev/null +++ b/vendor/distribute-0.6.35/docs/easy_install.txt @@ -0,0 +1,1597 @@ +============ +Easy Install +============ + +Easy Install is a python module (``easy_install``) bundled with ``setuptools`` +that lets you automatically download, build, install, and manage Python +packages. + +Please share your experiences with us! If you encounter difficulty installing +a package, please contact us via the `distutils mailing list +<http://mail.python.org/pipermail/distutils-sig/>`_. (Note: please DO NOT send +private email directly to the author of setuptools; it will be discarded. The +mailing list is a searchable archive of previously-asked and answered +questions; you should begin your research there before reporting something as a +bug -- and then do so via list discussion first.) + +(Also, if you'd like to learn about how you can use ``setuptools`` to make your +own packages work better with EasyInstall, or provide EasyInstall-like features +without requiring your users to use EasyInstall directly, you'll probably want +to check out the full `setuptools`_ documentation as well.) + +.. contents:: **Table of Contents** + + +Using "Easy Install" +==================== + + +.. _installation instructions: + +Installing "Easy Install" +------------------------- + +Please see the `setuptools PyPI page <http://pypi.python.org/pypi/setuptools>`_ +for download links and basic installation instructions for each of the +supported platforms. + +You will need at least Python 2.3.5, or if you are on a 64-bit platform, Python +2.4. An ``easy_install`` script will be 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 +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.) + +Note that ``easy_install`` normally works by downloading files from the +internet. If you are behind an NTLM-based firewall that prevents Python +programs from accessing the net directly, you may wish to first install and use +the `APS proxy server <http://ntlmaps.sf.net/>`_, which lets you get past such +firewalls in the same way that your web browser(s) do. + +(Alternately, if you do not wish easy_install to actually download anything, you +can restrict it from doing so with the ``--allow-hosts`` option; see the +sections on `restricting downloads with --allow-hosts`_ and `command-line +options`_ for more details.) + + +Troubleshooting +~~~~~~~~~~~~~~~ + +If EasyInstall/setuptools appears to install correctly, and you can run the +``easy_install`` command but it fails with an ``ImportError``, the most likely +cause is that you installed to a location other than ``site-packages``, +without taking any of the steps described in the `Custom Installation +Locations`_ section below. Please see that section and follow the steps to +make sure that your custom location will work correctly. Then re-install. + +Similarly, if you can run ``easy_install``, and it appears to be installing +packages, but then you can't import them, the most likely issue is that you +installed EasyInstall correctly but are using it to install packages to a +non-standard location that hasn't been properly prepared. Again, see the +section on `Custom Installation Locations`_ for more details. + + +Windows Notes +~~~~~~~~~~~~~ + +On Windows, an ``easy_install.exe`` launcher will also be installed, so that +you can just type ``easy_install`` as long as it's on your ``PATH``. If typing +``easy_install`` at the command prompt doesn't work, check to make sure your +``PATH`` includes the appropriate ``C:\\Python2X\\Scripts`` directory. On +most current versions of Windows, you can change the ``PATH`` by right-clicking +"My Computer", choosing "Properties" and selecting the "Advanced" tab, then +clicking the "Environment Variables" button. ``PATH`` will be in the "System +Variables" section, and you will need to exit and restart your command shell +(command.com, cmd.exe, bash, or other) for the change to take effect. Be sure +to add a ``;`` after the last item on ``PATH`` before adding the scripts +directory to it. + +Note that instead of changing your ``PATH`` to include the Python scripts +directory, you can also retarget the installation location for scripts so they +go on a directory that's already on the ``PATH``. For more information see the +sections below on `Command-Line Options`_ and `Configuration Files`_. You +can pass command line options (such as ``--script-dir``) to +``distribute_setup.py`` to control where ``easy_install.exe`` will be installed. + + + +Downloading and Installing a Package +------------------------------------ + +For basic use of ``easy_install``, you need only supply the filename or URL of +a source distribution or .egg file (`Python Egg`__). + +__ http://peak.telecommunity.com/DevCenter/PythonEggs + +**Example 1**. Install a package by name, searching PyPI for the latest +version, and automatically downloading, building, and installing it:: + + easy_install SQLObject + +**Example 2**. Install or upgrade a package by name and version by finding +links on a given "download page":: + + easy_install -f http://pythonpaste.org/package_index.html SQLObject + +**Example 3**. Download a source distribution from a specified URL, +automatically building and installing it:: + + easy_install http://example.com/path/to/MyPackage-1.2.3.tgz + +**Example 4**. Install an already-downloaded .egg file:: + + easy_install /my_downloads/OtherPackage-3.2.1-py2.3.egg + +**Example 5**. Upgrade an already-installed package to the latest version +listed on PyPI:: + + easy_install --upgrade PyProtocols + +**Example 6**. Install a source distribution that's already downloaded and +extracted in the current directory (New in 0.5a9):: + + easy_install . + +**Example 7**. (New in 0.6a1) Find a source distribution or Subversion +checkout URL for a package, and extract it or check it out to +``~/projects/sqlobject`` (the name will always be in all-lowercase), where it +can be examined or edited. (The package will not be installed, but it can +easily be installed with ``easy_install ~/projects/sqlobject``. See `Editing +and Viewing Source Packages`_ below for more info.):: + + easy_install --editable --build-directory ~/projects SQLObject + +**Example 7**. (New in 0.6.11) Install a distribution within your home dir:: + + easy_install --user SQLAlchemy + +Easy Install accepts URLs, filenames, PyPI package names (i.e., ``distutils`` +"distribution" names), and package+version specifiers. In each case, it will +attempt to locate the latest available version that meets your criteria. + +When downloading or processing downloaded files, Easy Install recognizes +distutils source distribution files with extensions of .tgz, .tar, .tar.gz, +.tar.bz2, or .zip. And of course it handles already-built .egg +distributions as well as ``.win32.exe`` installers built using distutils. + +By default, packages are installed to the running Python installation's +``site-packages`` directory, unless you provide the ``-d`` or ``--install-dir`` +option to specify an alternative directory, or specify an alternate location +using distutils configuration files. (See `Configuration Files`_, below.) + +By default, any scripts included with the package are installed to the running +Python installation's standard script installation location. However, if you +specify an installation directory via the command line or a config file, then +the default directory for installing scripts will be the same as the package +installation directory, to ensure that the script will have access to the +installed package. You can override this using the ``-s`` or ``--script-dir`` +option. + +Installed packages are added to an ``easy-install.pth`` file in the install +directory, so that Python will always use the most-recently-installed version +of the package. If you would like to be able to select which version to use at +runtime, you should use the ``-m`` or ``--multi-version`` option. + + +Upgrading a Package +------------------- + +You don't need to do anything special to upgrade a package: just install the +new version, either by requesting a specific version, e.g.:: + + easy_install "SomePackage==2.0" + +a version greater than the one you have now:: + + easy_install "SomePackage>2.0" + +using the upgrade flag, to find the latest available version on PyPI:: + + easy_install --upgrade SomePackage + +or by using a download page, direct download URL, or package filename:: + + easy_install -f http://example.com/downloads ExamplePackage + + easy_install http://example.com/downloads/ExamplePackage-2.0-py2.4.egg + + easy_install my_downloads/ExamplePackage-2.0.tgz + +If you're using ``-m`` or ``--multi-version`` , using the ``require()`` +function at runtime automatically selects the newest installed version of a +package that meets your version criteria. So, installing a newer version is +the only step needed to upgrade such packages. + +If you're installing to a directory on PYTHONPATH, or a configured "site" +directory (and not using ``-m``), installing a package automatically replaces +any previous version in the ``easy-install.pth`` file, so that Python will +import the most-recently installed version by default. So, again, installing +the newer version is the only upgrade step needed. + +If you haven't suppressed script installation (using ``--exclude-scripts`` or +``-x``), then the upgraded version's scripts will be installed, and they will +be automatically patched to ``require()`` the corresponding version of the +package, so that you can use them even if they are installed in multi-version +mode. + +``easy_install`` never actually deletes packages (unless you're installing a +package with the same name and version number as an existing package), so if +you want to get rid of older versions of a package, please see `Uninstalling +Packages`_, below. + + +Changing the Active Version +--------------------------- + +If you've upgraded a package, but need to revert to a previously-installed +version, you can do so like this:: + + easy_install PackageName==1.2.3 + +Where ``1.2.3`` is replaced by the exact version number you wish to switch to. +If a package matching the requested name and version is not already installed +in a directory on ``sys.path``, it will be located via PyPI and installed. + +If you'd like to switch to the latest installed version of ``PackageName``, you +can do so like this:: + + easy_install PackageName + +This will activate the latest installed version. (Note: if you have set any +``find_links`` via distutils configuration files, those download pages will be +checked for the latest available version of the package, and it will be +downloaded and installed if it is newer than your current version.) + +Note that changing the active version of a package will install the newly +active version's scripts, unless the ``--exclude-scripts`` or ``-x`` option is +specified. + + +Uninstalling Packages +--------------------- + +If you have replaced a package with another version, then you can just delete +the package(s) you don't need by deleting the PackageName-versioninfo.egg file +or directory (found in the installation directory). + +If you want to delete the currently installed version of a package (or all +versions of a package), you should first run:: + + easy_install -m PackageName + +This will ensure that Python doesn't continue to search for a package you're +planning to remove. After you've done this, you can safely delete the .egg +files or directories, along with any scripts you wish to remove. + + +Managing Scripts +---------------- + +Whenever you install, upgrade, or change versions of a package, EasyInstall +automatically installs the scripts for the selected package version, unless +you tell it not to with ``-x`` or ``--exclude-scripts``. If any scripts in +the script directory have the same name, they are overwritten. + +Thus, you do not normally need to manually delete scripts for older versions of +a package, unless the newer version of the package does not include a script +of the same name. However, if you are completely uninstalling a package, you +may wish to manually delete its scripts. + +EasyInstall's default behavior means that you can normally only run scripts +from one version of a package at a time. If you want to keep multiple versions +of a script available, however, you can simply use the ``--multi-version`` or +``-m`` option, and rename the scripts that EasyInstall creates. This works +because EasyInstall installs scripts as short code stubs that ``require()`` the +matching version of the package the script came from, so renaming the script +has no effect on what it executes. + +For example, suppose you want to use two versions of the ``rst2html`` tool +provided by the `docutils <http://docutils.sf.net/>`_ package. You might +first install one version:: + + easy_install -m docutils==0.3.9 + +then rename the ``rst2html.py`` to ``r2h_039``, and install another version:: + + easy_install -m docutils==0.3.10 + +This will create another ``rst2html.py`` script, this one using docutils +version 0.3.10 instead of 0.3.9. You now have two scripts, each using a +different version of the package. (Notice that we used ``-m`` for both +installations, so that Python won't lock us out of using anything but the most +recently-installed version of the package.) + + + +Tips & Techniques +----------------- + + +Multiple Python Versions +~~~~~~~~~~~~~~~~~~~~~~~~ + +As of version 0.6a11, EasyInstall installs itself under two names: +``easy_install`` and ``easy_install-N.N``, where ``N.N`` is the Python version +used to install it. Thus, if you install EasyInstall for both Python 2.3 and +2.4, you can use the ``easy_install-2.3`` or ``easy_install-2.4`` scripts to +install packages for Python 2.3 or 2.4, respectively. + +Also, if you're working with Python version 2.4 or higher, you can run Python +with ``-m easy_install`` to run that particular Python version's +``easy_install`` command. + + +Restricting Downloads with ``--allow-hosts`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the ``--allow-hosts`` (``-H``) option to restrict what domains +EasyInstall will look for links and downloads on. ``--allow-hosts=None`` +prevents downloading altogether. You can also use wildcards, for example +to restrict downloading to hosts in your own intranet. See the section below +on `Command-Line Options`_ for more details on the ``--allow-hosts`` option. + +By default, there are no host restrictions in effect, but you can change this +default by editing the appropriate `configuration files`_ and adding: + +.. code-block:: ini + + [easy_install] + allow_hosts = *.myintranet.example.com,*.python.org + +The above example would then allow downloads only from hosts in the +``python.org`` and ``myintranet.example.com`` domains, unless overridden on the +command line. + + +Installing on Un-networked Machines +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Just copy the eggs or source packages you need to a directory on the target +machine, then use the ``-f`` or ``--find-links`` option to specify that +directory's location. For example:: + + easy_install -H None -f somedir SomePackage + +will attempt to install SomePackage using only eggs and source packages found +in ``somedir`` and disallowing all remote access. You should of course make +sure you have all of SomePackage's dependencies available in somedir. + +If you have another machine of the same operating system and library versions +(or if the packages aren't platform-specific), you can create the directory of +eggs using a command like this:: + + easy_install -zmaxd somedir SomePackage + +This will tell EasyInstall to put zipped eggs or source packages for +SomePackage and all its dependencies into ``somedir``, without creating any +scripts or .pth files. You can then copy the contents of ``somedir`` to the +target machine. (``-z`` means zipped eggs, ``-m`` means multi-version, which +prevents .pth files from being used, ``-a`` means to copy all the eggs needed, +even if they're installed elsewhere on the machine, and ``-d`` indicates the +directory to place the eggs in.) + +You can also build the eggs from local development packages that were installed +with the ``setup.py develop`` command, by including the ``-l`` option, e.g.:: + + easy_install -zmaxld somedir SomePackage + +This will use locally-available source distributions to build the eggs. + + +Packaging Others' Projects As Eggs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Need to distribute a package that isn't published in egg form? You can use +EasyInstall to build eggs for a project. You'll want to use the ``--zip-ok``, +``--exclude-scripts``, and possibly ``--no-deps`` options (``-z``, ``-x`` and +``-N``, respectively). Use ``-d`` or ``--install-dir`` to specify the location +where you'd like the eggs placed. By placing them in a directory that is +published to the web, you can then make the eggs available for download, either +in an intranet or to the internet at large. + +If someone distributes a package in the form of a single ``.py`` file, you can +wrap it in an egg by tacking an ``#egg=name-version`` suffix on the file's URL. +So, something like this:: + + easy_install -f "http://some.example.com/downloads/foo.py#egg=foo-1.0" foo + +will install the package as an egg, and this:: + + easy_install -zmaxd. \ + -f "http://some.example.com/downloads/foo.py#egg=foo-1.0" foo + +will create a ``.egg`` file in the current directory. + + +Creating your own Package Index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In addition to local directories and the Python Package Index, EasyInstall can +find download links on most any web page whose URL is given to the ``-f`` +(``--find-links``) option. In the simplest case, you can simply have a web +page with links to eggs or Python source packages, even an automatically +generated directory listing (such as the Apache web server provides). + +If you are setting up an intranet site for package downloads, you may want to +configure the target machines to use your download site by default, adding +something like this to their `configuration files`_: + +.. code-block:: ini + + [easy_install] + find_links = http://mypackages.example.com/somedir/ + http://turbogears.org/download/ + http://peak.telecommunity.com/dist/ + +As you can see, you can list multiple URLs separated by whitespace, continuing +on multiple lines if necessary (as long as the subsequent lines are indented. + +If you are more ambitious, you can also create an entirely custom package index +or PyPI mirror. See the ``--index-url`` option under `Command-Line Options`_, +below, and also the section on `Package Index "API"`_. + + +Password-Protected Sites +------------------------ + +If a site you want to download from is password-protected using HTTP "Basic" +authentication, you can specify your credentials in the URL, like so:: + + http://some_userid:some_password@some.example.com/some_path/ + +You can do this with both index page URLs and direct download URLs. As long +as any HTML pages read by easy_install use *relative* links to point to the +downloads, the same user ID and password will be used to do the downloading. + + +Controlling Build Options +~~~~~~~~~~~~~~~~~~~~~~~~~ + +EasyInstall respects standard distutils `Configuration Files`_, so you can use +them to configure build options for packages that it installs from source. For +example, if you are on Windows using the MinGW compiler, you can configure the +default compiler by putting something like this: + +.. code-block:: ini + + [build] + compiler = mingw32 + +into the appropriate distutils configuration file. In fact, since this is just +normal distutils configuration, it will affect any builds using that config +file, not just ones done by EasyInstall. For example, if you add those lines +to ``distutils.cfg`` in the ``distutils`` package directory, it will be the +default compiler for *all* packages you build. See `Configuration Files`_ +below for a list of the standard configuration file locations, and links to +more documentation on using distutils configuration files. + + +Editing and Viewing Source Packages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes a package's source distribution contains additional documentation, +examples, configuration files, etc., that are not part of its actual code. If +you want to be able to examine these files, you can use the ``--editable`` +option to EasyInstall, and EasyInstall will look for a source distribution +or Subversion URL for the package, then download and extract it or check it out +as a subdirectory of the ``--build-directory`` you specify. If you then wish +to install the package after editing or configuring it, you can do so by +rerunning EasyInstall with that directory as the target. + +Note that using ``--editable`` stops EasyInstall from actually building or +installing the package; it just finds, obtains, and possibly unpacks it for +you. This allows you to make changes to the package if necessary, and to +either install it in development mode using ``setup.py develop`` (if the +package uses setuptools, that is), or by running ``easy_install projectdir`` +(where ``projectdir`` is the subdirectory EasyInstall created for the +downloaded package. + +In order to use ``--editable`` (``-e`` for short), you *must* also supply a +``--build-directory`` (``-b`` for short). The project will be placed in a +subdirectory of the build directory. The subdirectory will have the same +name as the project itself, but in all-lowercase. If a file or directory of +that name already exists, EasyInstall will print an error message and exit. + +Also, when using ``--editable``, you cannot use URLs or filenames as arguments. +You *must* specify project names (and optional version requirements) so that +EasyInstall knows what directory name(s) to create. If you need to force +EasyInstall to use a particular URL or filename, you should specify it as a +``--find-links`` item (``-f`` for short), and then also specify +the project name, e.g.:: + + easy_install -eb ~/projects \ + -fhttp://prdownloads.sourceforge.net/ctypes/ctypes-0.9.6.tar.gz?download \ + ctypes==0.9.6 + + +Dealing with Installation Conflicts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +(NOTE: As of 0.6a11, this section is obsolete; it is retained here only so that +people using older versions of EasyInstall can consult it. As of version +0.6a11, installation conflicts are handled automatically without deleting the +old or system-installed packages, and without ignoring the issue. Instead, +eggs are automatically shifted to the front of ``sys.path`` using special +code added to the ``easy-install.pth`` file. So, if you are using version +0.6a11 or better of setuptools, you do not need to worry about conflicts, +and the following issues do not apply to you.) + +EasyInstall installs distributions in a "managed" way, such that each +distribution can be independently activated or deactivated on ``sys.path``. +However, packages that were not installed by EasyInstall are "unmanaged", +in that they usually live all in one directory and cannot be independently +activated or deactivated. + +As a result, if you are using EasyInstall to upgrade an existing package, or +to install a package with the same name as an existing package, EasyInstall +will warn you of the conflict. (This is an improvement over ``setup.py +install``, becuase the ``distutils`` just install new packages on top of old +ones, possibly combining two unrelated packages or leaving behind modules that +have been deleted in the newer version of the package.) + +By default, EasyInstall will stop the installation if it detects a conflict +between an existing, "unmanaged" package, and a module or package in any of +the distributions you're installing. It will display a list of all of the +existing files and directories that would need to be deleted for the new +package to be able to function correctly. You can then either delete these +conflicting files and directories yourself and re-run EasyInstall, or you can +just use the ``--delete-conflicting`` or ``--ignore-conflicts-at-my-risk`` +options, as described under `Command-Line Options`_, below. + +Of course, once you've replaced all of your existing "unmanaged" packages with +versions managed by EasyInstall, you won't have any more conflicts to worry +about! + + +Compressed Installation +~~~~~~~~~~~~~~~~~~~~~~~ + +EasyInstall tries to install packages in zipped form, if it can. Zipping +packages can improve Python's overall import performance if you're not using +the ``--multi-version`` option, because Python processes zipfile entries on +``sys.path`` much faster than it does directories. + +As of version 0.5a9, EasyInstall analyzes packages to determine whether they +can be safely installed as a zipfile, and then acts on its analysis. (Previous +versions would not install a package as a zipfile unless you used the +``--zip-ok`` option.) + +The current analysis approach is fairly conservative; it currenly looks for: + + * Any use of the ``__file__`` or ``__path__`` variables (which should be + replaced with ``pkg_resources`` API calls) + + * Possible use of ``inspect`` functions that expect to manipulate source files + (e.g. ``inspect.getsource()``) + + * Top-level modules that might be scripts used with ``python -m`` (Python 2.4) + +If any of the above are found in the package being installed, EasyInstall will +assume that the package cannot be safely run from a zipfile, and unzip it to +a directory instead. You can override this analysis with the ``-zip-ok`` flag, +which will tell EasyInstall to install the package as a zipfile anyway. Or, +you can use the ``--always-unzip`` flag, in which case EasyInstall will always +unzip, even if its analysis says the package is safe to run as a zipfile. + +Normally, however, it is simplest to let EasyInstall handle the determination +of whether to zip or unzip, and only specify overrides when needed to work +around a problem. If you find you need to override EasyInstall's guesses, you +may want to contact the package author and the EasyInstall maintainers, so that +they can make appropriate changes in future versions. + +(Note: If a package uses ``setuptools`` in its setup script, the package author +has the option to declare the package safe or unsafe for zipped usage via the +``zip_safe`` argument to ``setup()``. If the package author makes such a +declaration, EasyInstall believes the package's author and does not perform its +own analysis. However, your command-line option, if any, will still override +the package author's choice.) + + +Reference Manual +================ + +Configuration Files +------------------- + +(New in 0.4a2) + +You may specify default options for EasyInstall using the standard +distutils configuration files, under the command heading ``easy_install``. +EasyInstall will look first for a ``setup.cfg`` file in the current directory, +then a ``~/.pydistutils.cfg`` or ``$HOME\\pydistutils.cfg`` (on Unix-like OSes +and Windows, respectively), and finally a ``distutils.cfg`` file in the +``distutils`` package directory. Here's a simple example: + +.. code-block:: ini + + [easy_install] + + # set the default location to install packages + install_dir = /home/me/lib/python + + # Notice that indentation can be used to continue an option + # value; this is especially useful for the "--find-links" + # option, which tells easy_install to use download links on + # these pages before consulting PyPI: + # + find_links = http://sqlobject.org/ + http://peak.telecommunity.com/dist/ + +In addition to accepting configuration for its own options under +``[easy_install]``, EasyInstall also respects defaults specified for other +distutils commands. For example, if you don't set an ``install_dir`` for +``[easy_install]``, but *have* set an ``install_lib`` for the ``[install]`` +command, this will become EasyInstall's default installation directory. Thus, +if you are already using distutils configuration files to set default install +locations, build options, etc., EasyInstall will respect your existing settings +until and unless you override them explicitly in an ``[easy_install]`` section. + +For more information, see also the current Python documentation on the `use and +location of distutils configuration files <http://docs.python.org/inst/config-syntax.html>`_. + +Notice that ``easy_install`` will use the ``setup.cfg`` from the current +working directory only if it was triggered from ``setup.py`` through the +``install_requires`` option. The standalone command will not use that file. + +Command-Line Options +-------------------- + +``--zip-ok, -z`` + Install all packages as zip files, even if they are marked as unsafe for + running as a zipfile. This can be useful when EasyInstall's analysis + of a non-setuptools package is too conservative, but keep in mind that + the package may not work correctly. (Changed in 0.5a9; previously this + option was required in order for zipped installation to happen at all.) + +``--always-unzip, -Z`` + Don't install any packages as zip files, even if the packages are marked + as safe for running as a zipfile. This can be useful if a package does + something unsafe, but not in a way that EasyInstall can easily detect. + EasyInstall's default analysis is currently very conservative, however, so + you should only use this option if you've had problems with a particular + package, and *after* reporting the problem to the package's maintainer and + to the EasyInstall maintainers. + + (Note: the ``-z/-Z`` options only affect the installation of newly-built + or downloaded packages that are not already installed in the target + directory; if you want to convert an existing installed version from + zipped to unzipped or vice versa, you'll need to delete the existing + version first, and re-run EasyInstall.) + +``--multi-version, -m`` + "Multi-version" mode. Specifying this option prevents ``easy_install`` from + adding an ``easy-install.pth`` entry for the package being installed, and + if an entry for any version the package already exists, it will be removed + upon successful installation. In multi-version mode, no specific version of + the package is available for importing, unless you use + ``pkg_resources.require()`` to put it on ``sys.path``. This can be as + simple as:: + + from pkg_resources import require + require("SomePackage", "OtherPackage", "MyPackage") + + which will put the latest installed version of the specified packages on + ``sys.path`` for you. (For more advanced uses, like selecting specific + versions and enabling optional dependencies, see the ``pkg_resources`` API + doc.) + + Changed in 0.6a10: this option is no longer silently enabled when + installing to a non-PYTHONPATH, non-"site" directory. You must always + explicitly use this option if you want it to be active. + +``--upgrade, -U`` (New in 0.5a4) + By default, EasyInstall only searches online if a project/version + requirement can't be met by distributions already installed + on sys.path or the installation directory. However, if you supply the + ``--upgrade`` or ``-U`` flag, EasyInstall will always check the package + index and ``--find-links`` URLs before selecting a version to install. In + this way, you can force EasyInstall to use the latest available version of + any package it installs (subject to any version requirements that might + exclude such later versions). + +``--install-dir=DIR, -d DIR`` + Set the installation directory. It is up to you to ensure that this + directory is on ``sys.path`` at runtime, and to use + ``pkg_resources.require()`` to enable the installed package(s) that you + need. + + (New in 0.4a2) If this option is not directly specified on the command line + or in a distutils configuration file, the distutils default installation + location is used. Normally, this would be the ``site-packages`` directory, + but if you are using distutils configuration files, setting things like + ``prefix`` or ``install_lib``, then those settings are taken into + account when computing the default installation directory, as is the + ``--prefix`` option. + +``--script-dir=DIR, -s DIR`` + Set the script installation directory. If you don't supply this option + (via the command line or a configuration file), but you *have* supplied + an ``--install-dir`` (via command line or config file), then this option + defaults to the same directory, so that the scripts will be able to find + their associated package installation. Otherwise, this setting defaults + to the location where the distutils would normally install scripts, taking + any distutils configuration file settings into account. + +``--exclude-scripts, -x`` + Don't install scripts. This is useful if you need to install multiple + versions of a package, but do not want to reset the version that will be + run by scripts that are already installed. + +``--user`` (New in 0.6.11) + Use the the user-site-packages as specified in :pep:`370` + instead of the global site-packages. + +``--always-copy, -a`` (New in 0.5a4) + Copy all needed distributions to the installation directory, even if they + are already present in a directory on sys.path. In older versions of + EasyInstall, this was the default behavior, but now you must explicitly + request it. By default, EasyInstall will no longer copy such distributions + from other sys.path directories to the installation directory, unless you + explicitly gave the distribution's filename on the command line. + + Note that as of 0.6a10, using this option excludes "system" and + "development" eggs from consideration because they can't be reliably + copied. This may cause EasyInstall to choose an older version of a package + than what you expected, or it may cause downloading and installation of a + fresh copy of something that's already installed. You will see warning + messages for any eggs that EasyInstall skips, before it falls back to an + older version or attempts to download a fresh copy. + +``--find-links=URLS_OR_FILENAMES, -f URLS_OR_FILENAMES`` + Scan the specified "download pages" or directories for direct links to eggs + or other distributions. Any existing file or directory names or direct + download URLs are immediately added to EasyInstall's search cache, and any + indirect URLs (ones that don't point to eggs or other recognized archive + formats) are added to a list of additional places to search for download + links. As soon as EasyInstall has to go online to find a package (either + because it doesn't exist locally, or because ``--upgrade`` or ``-U`` was + used), the specified URLs will be downloaded and scanned for additional + direct links. + + Eggs and archives found by way of ``--find-links`` are only downloaded if + they are needed to meet a requirement specified on the command line; links + to unneeded packages are ignored. + + If all requested packages can be found using links on the specified + download pages, the Python Package Index will not be consulted unless you + also specified the ``--upgrade`` or ``-U`` option. + + (Note: if you want to refer to a local HTML file containing links, you must + use a ``file:`` URL, as filenames that do not refer to a directory, egg, or + archive are ignored.) + + You may specify multiple URLs or file/directory names with this option, + separated by whitespace. Note that on the command line, you will probably + have to surround the URL list with quotes, so that it is recognized as a + single option value. You can also specify URLs in a configuration file; + see `Configuration Files`_, above. + + Changed in 0.6a10: previously all URLs and directories passed to this + option were scanned as early as possible, but from 0.6a10 on, only + directories and direct archive links are scanned immediately; URLs are not + retrieved unless a package search was already going to go online due to a + package not being available locally, or due to the use of the ``--update`` + or ``-U`` option. + +``--no-find-links`` Blocks the addition of any link. (New in Distribute 0.6.11) + This is useful if you want to avoid adding links defined in a project + easy_install is installing (wether it's a requested project or a + dependency.). When used, ``--find-links`` is ignored. + +``--delete-conflicting, -D`` (Removed in 0.6a11) + (As of 0.6a11, this option is no longer necessary; please do not use it!) + + If you are replacing a package that was previously installed *without* + using EasyInstall, the old version may end up on ``sys.path`` before the + version being installed with EasyInstall. EasyInstall will normally abort + the installation of a package if it detects such a conflict, and ask you to + manually remove the conflicting files or directories. If you specify this + option, however, EasyInstall will attempt to delete the files or + directories itself, and then proceed with the installation. + +``--ignore-conflicts-at-my-risk`` (Removed in 0.6a11) + (As of 0.6a11, this option is no longer necessary; please do not use it!) + + Ignore conflicting packages and proceed with installation anyway, even + though it means the package probably won't work properly. If the + conflicting package is in a directory you can't write to, this may be your + only option, but you will need to take more invasive measures to get the + installed package to work, like manually adding it to ``PYTHONPATH`` or to + ``sys.path`` at runtime. + +``--index-url=URL, -i URL`` (New in 0.4a1; default changed in 0.6c7) + Specifies the base URL of the Python Package Index. The default is + http://pypi.python.org/simple if not specified. When a package is requested + that is not locally available or linked from a ``--find-links`` download + page, the package index will be searched for download pages for the needed + package, and those download pages will be searched for links to download + an egg or source distribution. + +``--editable, -e`` (New in 0.6a1) + Only find and download source distributions for the specified projects, + unpacking them to subdirectories of the specified ``--build-directory``. + EasyInstall will not actually build or install the requested projects or + their dependencies; it will just find and extract them for you. See + `Editing and Viewing Source Packages`_ above for more details. + +``--build-directory=DIR, -b DIR`` (UPDATED in 0.6a1) + Set the directory used to build source packages. If a package is built + from a source distribution or checkout, it will be extracted to a + subdirectory of the specified directory. The subdirectory will have the + same name as the extracted distribution's project, but in all-lowercase. + If a file or directory of that name already exists in the given directory, + a warning will be printed to the console, and the build will take place in + a temporary directory instead. + + This option is most useful in combination with the ``--editable`` option, + which forces EasyInstall to *only* find and extract (but not build and + install) source distributions. See `Editing and Viewing Source Packages`_, + above, for more information. + +``--verbose, -v, --quiet, -q`` (New in 0.4a4) + Control the level of detail of EasyInstall's progress messages. The + default detail level is "info", which prints information only about + relatively time-consuming operations like running a setup script, unpacking + an archive, or retrieving a URL. Using ``-q`` or ``--quiet`` drops the + detail level to "warn", which will only display installation reports, + warnings, and errors. Using ``-v`` or ``--verbose`` increases the detail + level to include individual file-level operations, link analysis messages, + and distutils messages from any setup scripts that get run. If you include + the ``-v`` option more than once, the second and subsequent uses are passed + down to any setup scripts, increasing the verbosity of their reporting as + well. + +``--dry-run, -n`` (New in 0.4a4) + Don't actually install the package or scripts. This option is passed down + to any setup scripts run, so packages should not actually build either. + This does *not* skip downloading, nor does it skip extracting source + distributions to a temporary/build directory. + +``--optimize=LEVEL``, ``-O LEVEL`` (New in 0.4a4) + If you are installing from a source distribution, and are *not* using the + ``--zip-ok`` option, this option controls the optimization level for + compiling installed ``.py`` files to ``.pyo`` files. It does not affect + the compilation of modules contained in ``.egg`` files, only those in + ``.egg`` directories. The optimization level can be set to 0, 1, or 2; + the default is 0 (unless it's set under ``install`` or ``install_lib`` in + one of your distutils configuration files). + +``--record=FILENAME`` (New in 0.5a4) + Write a record of all installed files to FILENAME. This is basically the + same as the same option for the standard distutils "install" command, and + is included for compatibility with tools that expect to pass this option + to "setup.py install". + +``--site-dirs=DIRLIST, -S DIRLIST`` (New in 0.6a1) + Specify one or more custom "site" directories (separated by commas). + "Site" directories are directories where ``.pth`` files are processed, such + as the main Python ``site-packages`` directory. As of 0.6a10, EasyInstall + automatically detects whether a given directory processes ``.pth`` files + (or can be made to do so), so you should not normally need to use this + option. It is is now only necessary if you want to override EasyInstall's + judgment and force an installation directory to be treated as if it + supported ``.pth`` files. + +``--no-deps, -N`` (New in 0.6a6) + Don't install any dependencies. This is intended as a convenience for + tools that wrap eggs in a platform-specific packaging system. (We don't + recommend that you use it for anything else.) + +``--allow-hosts=PATTERNS, -H PATTERNS`` (New in 0.6a6) + Restrict downloading and spidering to hosts matching the specified glob + patterns. E.g. ``-H *.python.org`` restricts web access so that only + packages listed and downloadable from machines in the ``python.org`` + 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 + default pattern is ``*``, which matches anything. + + In general, this option is mainly useful for blocking EasyInstall's web + access altogether (e.g. ``-Hlocalhost``), or to restrict it to an intranet + or other trusted site. EasyInstall will do the best it can to satisfy + dependencies given your host restrictions, but of course can fail if it + can't find suitable packages. EasyInstall displays all blocked URLs, so + that you can adjust your ``--allow-hosts`` setting if it is more strict + than you intended. Some sites may wish to define a restrictive default + setting for this option in their `configuration files`_, and then manually + override the setting on the command line as needed. + +``--prefix=DIR`` (New in 0.6a10) + Use the specified directory as a base for computing the default + installation and script directories. On Windows, the resulting default + directories will be ``prefix\\Lib\\site-packages`` and ``prefix\\Scripts``, + while on other platforms the defaults will be + ``prefix/lib/python2.X/site-packages`` (with the appropriate version + substituted) for libraries and ``prefix/bin`` for scripts. + + Note that the ``--prefix`` option only sets the *default* installation and + script directories, and does not override the ones set on the command line + or in a configuration file. + +``--local-snapshots-ok, -l`` (New in 0.6c6) + Normally, EasyInstall prefers to only install *released* versions of + projects, not in-development ones, because such projects may not + have a currently-valid version number. So, it usually only installs them + when their ``setup.py`` directory is explicitly passed on the command line. + + However, if this option is used, then any in-development projects that were + installed using the ``setup.py develop`` command, will be used to build + eggs, effectively upgrading the "in-development" project to a snapshot + release. Normally, this option is used only in conjunction with the + ``--always-copy`` option to create a distributable snapshot of every egg + needed to run an application. + + Note that if you use this option, you must make sure that there is a valid + version number (such as an SVN revision number tag) for any in-development + projects that may be used, as otherwise EasyInstall may not be able to tell + what version of the project is "newer" when future installations or + upgrades are attempted. + + +.. _non-root installation: + +Custom Installation Locations +----------------------------- + +By default, EasyInstall installs python packages into Python's main ``site-packages`` directory, +and manages them using a custom ``.pth`` file in that same directory. + +Very often though, a user or developer wants ``easy_install`` to install and manage python packages +in an alternative location, usually for one of 3 reasons: + +1. They don't have access to write to the main Python site-packages directory. + +2. They want a user-specific stash of packages, that is not visible to other users. + +3. They want to isolate a set of packages to a specific python application, usually to minimize + the possibility of version conflicts. + +Historically, there have been many approaches to achieve custom installation. +The following section lists only the easiest and most relevant approaches [1]_. + +`Use the "--user" option`_ + +`Use the "--user" option and customize "PYTHONUSERBASE"`_ + +`Use "virtualenv"`_ + +.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by `PEP-370`_ in Python 2.6. + +.. _PEP-370: http://www.python.org/dev/peps/pep-0370/ + + +Use the "--user" option +~~~~~~~~~~~~~~~~~~~~~~~ +With Python 2.6 came the User scheme for installation, which means that all +python distributions support an alternative install location that is specific to a user [2]_ [3]_. +The Default location for each OS is explained in the python documentation +for the ``site.USER_BASE`` variable. This mode of installation can be turned on by +specifying the ``--user`` option to ``setup.py install`` or ``easy_install``. +This approach serves the need to have a user-specific stash of packages. + +.. [2] Prior to Python2.6, Mac OS X offered a form of the User scheme. That is now subsumed into the User scheme introduced in Python 2.6. +.. [3] Prior to the User scheme, there was the Home scheme, which is still available, but requires more effort than the User scheme to get packages recognized. + +Use the "--user" option and customize "PYTHONUSERBASE" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The User scheme install location can be customized by setting the ``PYTHONUSERBASE`` environment +variable, which updates the value of ``site.USER_BASE``. To isolate packages to a specific +application, simply set the OS environment of that application to a specific value of +``PYTHONUSERBASE``, that contains just those packages. + +Use "virtualenv" +~~~~~~~~~~~~~~~~ +"virtualenv" is a 3rd-party python package that effectively "clones" a python installation, thereby +creating an isolated location to intall packages. The evolution of "virtualenv" started before the existence +of the User installation scheme. "virtualenv" provides a version of ``easy_install`` that is +scoped to the cloned python install and is used in the normal way. "virtualenv" does offer various features +that the User installation scheme alone does not provide, e.g. the ability to hide the main python site-packages. + +Please refer to the `virtualenv`_ documentation for more details. + +.. _virtualenv: http://pypi.python.org/pypi/virtualenv + + + +Package Index "API" +------------------- + +Custom package indexes (and PyPI) must follow the following rules for +EasyInstall to be able to look up and download packages: + +1. Except where stated otherwise, "pages" are HTML or XHTML, and "links" + refer to ``href`` attributes. + +2. Individual project version pages' URLs must be of the form + ``base/projectname/version``, where ``base`` is the package index's base URL. + +3. Omitting the ``/version`` part of a project page's URL (but keeping the + trailing ``/``) should result in a page that is either: + + a) The single active version of that project, as though the version had been + explicitly included, OR + + b) A page with links to all of the active version pages for that project. + +4. Individual project version pages should contain direct links to downloadable + distributions where possible. It is explicitly permitted for a project's + "long_description" to include URLs, and these should be formatted as HTML + links by the package index, as EasyInstall does no special processing to + identify what parts of a page are index-specific and which are part of the + project's supplied description. + +5. Where available, MD5 information should be added to download URLs by + appending a fragment identifier of the form ``#md5=...``, where ``...`` is + the 32-character hex MD5 digest. EasyInstall will verify that the + downloaded file's MD5 digest matches the given value. + +6. Individual project version pages should identify any "homepage" or + "download" URLs using ``rel="homepage"`` and ``rel="download"`` attributes + on the HTML elements linking to those URLs. Use of these attributes will + cause EasyInstall to always follow the provided links, unless it can be + determined by inspection that they are downloadable distributions. If the + links are not to downloadable distributions, they are retrieved, and if they + are HTML, they are scanned for download links. They are *not* scanned for + additional "homepage" or "download" links, as these are only processed for + pages that are part of a package index site. + +7. The root URL of the index, if retrieved with a trailing ``/``, must result + in a page containing links to *all* projects' active version pages. + + (Note: This requirement is a workaround for the absence of case-insensitive + ``safe_name()`` matching of project names in URL paths. If project names are + matched in this fashion (e.g. via the PyPI server, mod_rewrite, or a similar + mechanism), then it is not necessary to include this all-packages listing + page.) + +8. If a package index is accessed via a ``file://`` URL, then EasyInstall will + automatically use ``index.html`` files, if present, when trying to read a + directory with a trailing ``/`` on the URL. + + +Backward Compatibility +~~~~~~~~~~~~~~~~~~~~~~ + +Package indexes that wish to support setuptools versions prior to 0.6b4 should +also follow these rules: + +* Homepage and download links must be preceded with ``"<th>Home Page"`` or + ``"<th>Download URL"``, in addition to (or instead of) the ``rel=""`` + attributes on the actual links. These marker strings do not need to be + visible, or uncommented, however! For example, the following is a valid + homepage link that will work with any version of setuptools:: + + <li> + <strong>Home Page:</strong> + <!-- <th>Home Page --> + <a rel="homepage" href="http://sqlobject.org">http://sqlobject.org</a> + </li> + + Even though the marker string is in an HTML comment, older versions of + EasyInstall will still "see" it and know that the link that follows is the + project's home page URL. + +* The pages described by paragraph 3(b) of the preceding section *must* + contain the string ``"Index of Packages</title>"`` somewhere in their text. + This can be inside of an HTML comment, if desired, and it can be anywhere + in the page. (Note: this string MUST NOT appear on normal project pages, as + described in paragraphs 2 and 3(a)!) + +In addition, for compatibility with PyPI versions that do not use ``#md5=`` +fragment IDs, EasyInstall uses the following regular expression to match PyPI's +displayed MD5 info (broken onto two lines for readability):: + + <a href="([^"#]+)">([^<]+)</a>\n\s+\(<a href="[^?]+\?:action=show_md5 + &digest=([0-9a-f]{32})">md5</a>\) + +History +======= + +0.6c9 + * Fixed ``win32.exe`` support for .pth files, so unnecessary directory nesting + is flattened out in the resulting egg. (There was a case-sensitivity + problem that affected some distributions, notably ``pywin32``.) + + * Prevent ``--help-commands`` and other junk from showing under Python 2.5 + when running ``easy_install --help``. + + * Fixed GUI scripts sometimes not executing on Windows + + * Fixed not picking up dependency links from recursive dependencies. + + * Only make ``.py``, ``.dll`` and ``.so`` files executable when unpacking eggs + + * Changes for Jython compatibility + + * Improved error message when a requirement is also a directory name, but the + specified directory is not a source package. + + * Fixed ``--allow-hosts`` option blocking ``file:`` URLs + + * Fixed HTTP SVN detection failing when the page title included a project + name (e.g. on SourceForge-hosted SVN) + + * Fix Jython script installation to handle ``#!`` lines better when + ``sys.executable`` is a script. + + * Removed use of deprecated ``md5`` module if ``hashlib`` is available + + * Keep site directories (e.g. ``site-packages``) from being included in + ``.pth`` files. + +0.6c7 + * ``ftp:`` download URLs now work correctly. + + * The default ``--index-url`` is now ``http://pypi.python.org/simple``, to use + the Python Package Index's new simpler (and faster!) REST API. + +0.6c6 + * EasyInstall no longer aborts the installation process if a URL it wants to + retrieve can't be downloaded, unless the URL is an actual package download. + Instead, it issues a warning and tries to keep going. + + * Fixed distutils-style scripts originally built on Windows having their line + endings doubled when installed on any platform. + + * Added ``--local-snapshots-ok`` flag, to allow building eggs from projects + installed using ``setup.py develop``. + + * Fixed not HTML-decoding URLs scraped from web pages + +0.6c5 + * Fixed ``.dll`` files on Cygwin not having executable permisions when an egg + is installed unzipped. + +0.6c4 + * Added support for HTTP "Basic" authentication using ``http://user:pass@host`` + URLs. If a password-protected page contains links to the same host (and + protocol), those links will inherit the credentials used to access the + original page. + + * Removed all special support for Sourceforge mirrors, as Sourceforge's + mirror system now works well for non-browser downloads. + + * Fixed not recognizing ``win32.exe`` installers that included a custom + bitmap. + + * Fixed not allowing ``os.open()`` of paths outside the sandbox, even if they + are opened read-only (e.g. reading ``/dev/urandom`` for random numbers, as + is done by ``os.urandom()`` on some platforms). + + * Fixed a problem with ``.pth`` testing on Windows when ``sys.executable`` + has a space in it (e.g., the user installed Python to a ``Program Files`` + directory). + +0.6c3 + * You can once again use "python -m easy_install" with Python 2.4 and above. + + * Python 2.5 compatibility fixes added. + +0.6c2 + * Windows script wrappers now support quoted arguments and arguments + containing spaces. (Patch contributed by Jim Fulton.) + + * The ``ez_setup.py`` script now actually works when you put a setuptools + ``.egg`` alongside it for bootstrapping an offline machine. + + * A writable installation directory on ``sys.path`` is no longer required to + download and extract a source distribution using ``--editable``. + + * Generated scripts now use ``-x`` on the ``#!`` line when ``sys.executable`` + contains non-ASCII characters, to prevent deprecation warnings about an + unspecified encoding when the script is run. + +0.6c1 + * EasyInstall now includes setuptools version information in the + ``User-Agent`` string sent to websites it visits. + +0.6b4 + * Fix creating Python wrappers for non-Python scripts + + * Fix ``ftp://`` directory listing URLs from causing a crash when used in the + "Home page" or "Download URL" slots on PyPI. + + * Fix ``sys.path_importer_cache`` not being updated when an existing zipfile + or directory is deleted/overwritten. + + * Fix not recognizing HTML 404 pages from package indexes. + + * Allow ``file://`` URLs to be used as a package index. URLs that refer to + directories will use an internally-generated directory listing if there is + no ``index.html`` file in the directory. + + * Allow external links in a package index to be specified using + ``rel="homepage"`` or ``rel="download"``, without needing the old + PyPI-specific visible markup. + + * Suppressed warning message about possibly-misspelled project name, if an egg + or link for that project name has already been seen. + +0.6b3 + * Fix local ``--find-links`` eggs not being copied except with + ``--always-copy``. + + * Fix sometimes not detecting local packages installed outside of "site" + directories. + + * Fix mysterious errors during initial ``setuptools`` install, caused by + ``ez_setup`` trying to run ``easy_install`` twice, due to a code fallthru + after deleting the egg from which it's running. + +0.6b2 + * Don't install or update a ``site.py`` patch when installing to a + ``PYTHONPATH`` directory with ``--multi-version``, unless an + ``easy-install.pth`` file is already in use there. + + * Construct ``.pth`` file paths in such a way that installing an egg whose + name begins with ``import`` doesn't cause a syntax error. + + * Fixed a bogus warning message that wasn't updated since the 0.5 versions. + +0.6b1 + * Better ambiguity management: accept ``#egg`` name/version even if processing + what appears to be a correctly-named distutils file, and ignore ``.egg`` + files with no ``-``, since valid Python ``.egg`` files always have a version + number (but Scheme eggs often don't). + + * Support ``file://`` links to directories in ``--find-links``, so that + easy_install can build packages from local source checkouts. + + * Added automatic retry for Sourceforge mirrors. The new download process is + to first just try dl.sourceforge.net, then randomly select mirror IPs and + remove ones that fail, until something works. The removed IPs stay removed + for the remainder of the run. + + * Ignore bdist_dumb distributions when looking at download URLs. + +0.6a11 + * Process ``dependency_links.txt`` if found in a distribution, by adding the + URLs to the list for scanning. + + * Use relative paths in ``.pth`` files when eggs are being installed to the + same directory as the ``.pth`` file. This maximizes portability of the + target directory when building applications that contain eggs. + + * Added ``easy_install-N.N`` script(s) for convenience when using multiple + Python versions. + + * Added automatic handling of installation conflicts. Eggs are now shifted to + the front of sys.path, in an order consistent with where they came from, + making EasyInstall seamlessly co-operate with system package managers. + + The ``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk`` options + are now no longer necessary, and will generate warnings at the end of a + run if you use them. + + * Don't recursively traverse subdirectories given to ``--find-links``. + +0.6a10 + * Added exhaustive testing of the install directory, including a spawn test + for ``.pth`` file support, and directory writability/existence checks. This + should virtually eliminate the need to set or configure ``--site-dirs``. + + * Added ``--prefix`` option for more do-what-I-mean-ishness in the absence of + RTFM-ing. :) + + * Enhanced ``PYTHONPATH`` support so that you don't have to put any eggs on it + manually to make it work. ``--multi-version`` is no longer a silent + default; you must explicitly use it if installing to a non-PYTHONPATH, + non-"site" directory. + + * Expand ``$variables`` used in the ``--site-dirs``, ``--build-directory``, + ``--install-dir``, and ``--script-dir`` options, whether on the command line + or in configuration files. + + * Improved SourceForge mirror processing to work faster and be less affected + by transient HTML changes made by SourceForge. + + * PyPI searches now use the exact spelling of requirements specified on the + command line or in a project's ``install_requires``. Previously, a + normalized form of the name was used, which could lead to unnecessary + full-index searches when a project's name had an underscore (``_``) in it. + + * EasyInstall can now download bare ``.py`` files and wrap them in an egg, + as long as you include an ``#egg=name-version`` suffix on the URL, or if + the ``.py`` file is listed as the "Download URL" on the project's PyPI page. + This allows third parties to "package" trivial Python modules just by + linking to them (e.g. from within their own PyPI page or download links + page). + + * The ``--always-copy`` option now skips "system" and "development" eggs since + they can't be reliably copied. Note that this may cause EasyInstall to + choose an older version of a package than what you expected, or it may cause + downloading and installation of a fresh version of what's already installed. + + * The ``--find-links`` option previously scanned all supplied URLs and + directories as early as possible, but now only directories and direct + archive links are scanned immediately. URLs are not retrieved unless a + package search was already going to go online due to a package not being + available locally, or due to the use of the ``--update`` or ``-U`` option. + + * Fixed the annoying ``--help-commands`` wart. + +0.6a9 + * Fixed ``.pth`` file processing picking up nested eggs (i.e. ones inside + "baskets") when they weren't explicitly listed in the ``.pth`` file. + + * If more than one URL appears to describe the exact same distribution, prefer + the shortest one. This helps to avoid "table of contents" CGI URLs like the + ones on effbot.org. + + * Quote arguments to python.exe (including python's path) to avoid problems + when Python (or a script) is installed in a directory whose name contains + spaces on Windows. + + * 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 + * Update for changed SourceForge mirror format + + * Fixed not installing dependencies for some packages fetched via Subversion + + * Fixed dependency installation with ``--always-copy`` not using the same + dependency resolution procedure as other operations. + + * Fixed not fully removing temporary directories on Windows, if a Subversion + checkout left read-only files behind + + * Fixed some problems building extensions when Pyrex was installed, especially + with Python 2.4 and/or packages using SWIG. + +0.6a7 + * Fixed not being able to install Windows script wrappers using Python 2.3 + +0.6a6 + * Added support for "traditional" PYTHONPATH-based non-root installation, and + also the convenient ``virtual-python.py`` script, based on a contribution + by Ian Bicking. The setuptools egg now contains a hacked ``site`` module + that makes the PYTHONPATH-based approach work with .pth files, so that you + can get the full EasyInstall feature set on such installations. + + * Added ``--no-deps`` and ``--allow-hosts`` options. + + * Improved Windows ``.exe`` script wrappers so that the script can have the + same name as a module without confusing Python. + + * Changed dependency processing so that it's breadth-first, allowing a + depender's preferences to override those of a dependee, to prevent conflicts + when a lower version is acceptable to the dependee, but not the depender. + Also, ensure that currently installed/selected packages aren't given + precedence over ones desired by a package being installed, which could + cause conflict errors. + +0.6a3 + * Improved error message when trying to use old ways of running + ``easy_install``. Removed the ability to run via ``python -m`` or by + running ``easy_install.py``; ``easy_install`` is the command to run on all + supported platforms. + + * Improved wrapper script generation and runtime initialization so that a + VersionConflict doesn't occur if you later install a competing version of a + needed package as the default version of that package. + + * Fixed a problem parsing version numbers in ``#egg=`` links. + +0.6a2 + * EasyInstall can now install "console_scripts" defined by packages that use + ``setuptools`` and define appropriate entry points. On Windows, console + scripts get an ``.exe`` wrapper so you can just type their name. On other + platforms, the scripts are installed without a file extension. + + * Using ``python -m easy_install`` or running ``easy_install.py`` is now + DEPRECATED, since an ``easy_install`` wrapper is now available on all + platforms. + +0.6a1 + * EasyInstall now does MD5 validation of downloads from PyPI, or from any link + that has an "#md5=..." trailer with a 32-digit lowercase hex md5 digest. + + * EasyInstall now handles symlinks in target directories by removing the link, + rather than attempting to overwrite the link's destination. This makes it + easier to set up an alternate Python "home" directory (as described above in + the `Non-Root Installation`_ section). + + * Added support for handling MacOS platform information in ``.egg`` filenames, + based on a contribution by Kevin Dangoor. You may wish to delete and + reinstall any eggs whose filename includes "darwin" and "Power_Macintosh", + because the format for this platform information has changed so that minor + OS X upgrades (such as 10.4.1 to 10.4.2) do not cause eggs built with a + previous OS version to become obsolete. + + * easy_install's dependency processing algorithms have changed. When using + ``--always-copy``, it now ensures that dependencies are copied too. When + not using ``--always-copy``, it tries to use a single resolution loop, + rather than recursing. + + * Fixed installing extra ``.pyc`` or ``.pyo`` files for scripts with ``.py`` + extensions. + + * Added ``--site-dirs`` option to allow adding custom "site" directories. + Made ``easy-install.pth`` work in platform-specific alternate site + directories (e.g. ``~/Library/Python/2.x/site-packages`` on Mac OS X). + + * If you manually delete the current version of a package, the next run of + EasyInstall against the target directory will now remove the stray entry + from the ``easy-install.pth`` file. + + * EasyInstall now recognizes URLs with a ``#egg=project_name`` fragment ID + as pointing to the named project's source checkout. Such URLs have a lower + match precedence than any other kind of distribution, so they'll only be + used if they have a higher version number than any other available + distribution, or if you use the ``--editable`` option. The ``#egg`` + fragment can contain a version if it's formatted as ``#egg=proj-ver``, + where ``proj`` is the project name, and ``ver`` is the version number. You + *must* use the format for these values that the ``bdist_egg`` command uses; + i.e., all non-alphanumeric runs must be condensed to single underscore + characters. + + * Added the ``--editable`` option; see `Editing and Viewing Source Packages`_ + above for more info. Also, slightly changed the behavior of the + ``--build-directory`` option. + + * Fixed the setup script sandbox facility not recognizing certain paths as + valid on case-insensitive platforms. + +0.5a12 + * Fix ``python -m easy_install`` not working due to setuptools being installed + as a zipfile. Update safety scanner to check for modules that might be used + as ``python -m`` scripts. + + * Misc. fixes for win32.exe support, including changes to support Python 2.4's + changed ``bdist_wininst`` format. + +0.5a10 + * Put the ``easy_install`` module back in as a module, as it's needed for + ``python -m`` to run it! + + * Allow ``--find-links/-f`` to accept local directories or filenames as well + as URLs. + +0.5a9 + * EasyInstall now automatically detects when an "unmanaged" package or + module is going to be on ``sys.path`` ahead of a package you're installing, + thereby preventing the newer version from being imported. By default, it + will abort installation to alert you of the problem, but there are also + new options (``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk``) + available to change the default behavior. (Note: this new feature doesn't + take effect for egg files that were built with older ``setuptools`` + versions, because they lack the new metadata file required to implement it.) + + * The ``easy_install`` distutils command now uses ``DistutilsError`` as its + base error type for errors that should just issue a message to stderr and + exit the program without a traceback. + + * EasyInstall can now be given a path to a directory containing a setup + script, and it will attempt to build and install the package there. + + * EasyInstall now performs a safety analysis on module contents to determine + whether a package is likely to run in zipped form, and displays + information about what modules may be doing introspection that would break + when running as a zipfile. + + * Added the ``--always-unzip/-Z`` option, to force unzipping of packages that + would ordinarily be considered safe to unzip, and changed the meaning of + ``--zip-ok/-z`` to "always leave everything zipped". + +0.5a8 + * There is now a separate documentation page for `setuptools`_; revision + history that's not specific to EasyInstall has been moved to that page. + + .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools + +0.5a5 + * 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 + * Added ``--always-copy/-a`` option to always copy needed packages to the + installation directory, even if they're already present elsewhere on + sys.path. (In previous versions, this was the default behavior, but now + you must request it.) + + * Added ``--upgrade/-U`` option to force checking PyPI for latest available + version(s) of all packages requested by name and version, even if a matching + version is available locally. + + * Added automatic installation of dependencies declared by a distribution + being installed. These dependencies must be listed in the distribution's + ``EGG-INFO`` directory, so the distribution has to have declared its + dependencies by using setuptools. If a package has requirements it didn't + declare, you'll still have to deal with them yourself. (E.g., by asking + EasyInstall to find and install them.) + + * Added the ``--record`` option to ``easy_install`` for the benefit of tools + that run ``setup.py install --record=filename`` on behalf of another + packaging system.) + +0.5a3 + * Fixed not setting script permissions to allow execution. + + * Improved sandboxing so that setup scripts that want a temporary directory + (e.g. pychecker) can still run in the sandbox. + +0.5a2 + * Fix stupid stupid refactoring-at-the-last-minute typos. :( + +0.5a1 + * Added support for converting ``.win32.exe`` installers to eggs on the fly. + EasyInstall will now recognize such files by name and install them. + + * Fixed a problem with picking the "best" version to install (versions were + being sorted as strings, rather than as parsed values) + +0.4a4 + * Added support for the distutils "verbose/quiet" and "dry-run" options, as + well as the "optimize" flag. + + * Support downloading packages that were uploaded to PyPI (by scanning all + links on package pages, not just the homepage/download links). + +0.4a3 + * Add progress messages to the search/download process so that you can tell + what URLs it's reading to find download links. (Hopefully, this will help + people report out-of-date and broken links to package authors, and to tell + when they've asked for a package that doesn't exist.) + +0.4a2 + * Added support for installing scripts + + * Added support for setting options via distutils configuration files, and + using distutils' default options as a basis for EasyInstall's defaults. + + * Renamed ``--scan-url/-s`` to ``--find-links/-f`` to free up ``-s`` for the + script installation directory option. + + * Use ``urllib2`` instead of ``urllib``, to allow use of ``https:`` URLs if + Python includes SSL support. + +0.4a1 + * Added ``--scan-url`` and ``--index-url`` options, to scan download pages + and search PyPI for needed packages. + +0.3a4 + * Restrict ``--build-directory=DIR/-b DIR`` option to only be used with single + URL installs, to avoid running the wrong setup.py. + +0.3a3 + * Added ``--build-directory=DIR/-b DIR`` option. + + * Added "installation report" that explains how to use 'require()' when doing + a multiversion install or alternate installation directory. + + * Added SourceForge mirror auto-select (Contributed by Ian Bicking) + + * Added "sandboxing" that stops a setup script from running if it attempts to + write to the filesystem outside of the build area + + * Added more workarounds for packages with quirky ``install_data`` hacks + +0.3a2 + * Added subversion download support for ``svn:`` and ``svn+`` URLs, as well as + automatic recognition of HTTP subversion URLs (Contributed by Ian Bicking) + + * Misc. bug fixes + +0.3a1 + * Initial release. + + +Future Plans +============ + +* Additional utilities to list/remove/verify packages +* Signature checking? SSL? Ability to suppress PyPI search? +* Display byte progress meter when downloading distributions and long pages? +* Redirect stdout/stderr to log during run_setup? + diff --git a/vendor/distribute-0.6.35/docs/index.txt b/vendor/distribute-0.6.35/docs/index.txt new file mode 100644 index 00000000..5f3b945b --- /dev/null +++ b/vendor/distribute-0.6.35/docs/index.txt @@ -0,0 +1,36 @@ +Welcome to Distribute's documentation! +====================================== + +`Distribute` is a fork of the `Setuptools` project. + +Distribute is intended to replace Setuptools as the standard method for +working with Python module distributions. + +For those who may wonder why they should switch to Distribute over Setuptools, it’s quite simple: + +- Distribute is a drop-in replacement for Setuptools +- The code is actively maintained, and has over 10 commiters +- Distribute offers Python 3 support ! + +Documentation content: + +.. toctree:: + :maxdepth: 2 + + roadmap + python3 + using + setuptools + easy_install + pkg_resources + + +.. image:: http://python-distribute.org/pip_distribute.png + +Design done by Idan Gazit (http://pixane.com) - License: cc-by-3.0 + +Copy & paste:: + + curl -O http://python-distribute.org/distribute_setup.py + python distribute_setup.py + easy_install pip \ No newline at end of file diff --git a/vendor/distribute-0.6.35/docs/pkg_resources.txt b/vendor/distribute-0.6.35/docs/pkg_resources.txt new file mode 100644 index 00000000..480f9547 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/pkg_resources.txt @@ -0,0 +1,1955 @@ +============================================================= +Package Discovery and Resource Access using ``pkg_resources`` +============================================================= + +The ``pkg_resources`` module distributed with ``setuptools`` 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. + + +.. contents:: **Table of Contents** + + +-------- +Overview +-------- + +Eggs are a distribution format for Python modules, similar in concept to Java's +"jars" or Ruby's "gems". They differ from previous Python distribution formats +in that they are importable (i.e. they can be added to ``sys.path``), and they +are *discoverable*, meaning that they carry metadata that unambiguously +identifies their contents and dependencies, and thus can be *automatically* +found and added to ``sys.path`` in response to simple requests of the form, +"get me everything I need to use docutils' PDF support". + +The ``pkg_resources`` module provides runtime facilities for finding, +introspecting, activating and using eggs and other "pluggable" distribution +formats. Because these are new concepts in Python (and not that well- +established in other languages either), it helps to have a few special terms +for talking about eggs and how they can be used: + +project + A library, framework, script, plugin, application, or collection of data + or other resources, or some combination thereof. Projects are assumed to + have "relatively unique" names, e.g. names registered with PyPI. + +release + A snapshot of a project at a particular point in time, denoted by a version + identifier. + +distribution + A file or files that represent a particular release. + +importable distribution + A file or directory that, if placed on ``sys.path``, allows Python to + import any modules contained within it. + +pluggable distribution + An importable distribution whose filename unambiguously identifies its + release (i.e. project and version), and whose contents unamabiguously + specify what releases of other projects will satisfy its runtime + requirements. + +extra + An "extra" is an optional feature of a release, that may impose additional + runtime requirements. For example, if docutils PDF support required a + PDF support library to be present, docutils could define its PDF support as + an "extra", and list what other project releases need to be available in + order to provide it. + +environment + A collection of distributions potentially available for importing, but not + necessarily active. More than one distribution (i.e. release version) for + a given project may be present in an environment. + +working set + A collection of distributions actually available for importing, as on + ``sys.path``. At most one distribution (release version) of a given + project may be present in a working set, as otherwise there would be + ambiguity as to what to import. + +eggs + Eggs are pluggable distributions in one of the three formats currently + supported by ``pkg_resources``. There are built eggs, development eggs, + and egg links. Built eggs are directories or zipfiles whose name ends + with ``.egg`` and follows the egg naming conventions, and contain an + ``EGG-INFO`` subdirectory (zipped or otherwise). Development eggs are + normal directories of Python code with one or more ``ProjectName.egg-info`` + subdirectories. And egg links are ``*.egg-link`` files that contain the + name of a built or development egg, to support symbolic linking on + platforms that do not have native symbolic links. + +(For more information about these terms and concepts, see also this +`architectural overview`_ of ``pkg_resources`` and Python Eggs in general.) + +.. _architectural overview: http://mail.python.org/pipermail/distutils-sig/2005-June/004652.html + + +.. ----------------- +.. Developer's Guide +.. ----------------- + +.. This section isn't written yet. Currently planned topics include + Accessing Resources + Finding and Activating Package Distributions + get_provider() + require() + WorkingSet + iter_distributions + Running Scripts + Configuration + Namespace Packages + Extensible Applications and Frameworks + Locating entry points + Activation listeners + Metadata access + Extended Discovery and Installation + Supporting Custom PEP 302 Implementations +.. For now, please check out the extensive `API Reference`_ below. + + +------------- +API Reference +------------- + +Namespace Package Support +========================= + +A namespace package is a package that only contains other packages and modules, +with no direct contents of its own. Such packages can be split across +multiple, separately-packaged distributions. Normally, you do not need to use +the namespace package APIs directly; instead you should supply the +``namespace_packages`` argument to ``setup()`` in your project's ``setup.py``. +See the `setuptools documentation on namespace packages`_ for more information. + +However, if for some reason you need to manipulate namespace packages or +directly alter ``sys.path`` at runtime, you may find these APIs useful: + +``declare_namespace(name)`` + Declare that the dotted package name `name` is a "namespace package" whose + contained packages and modules may be spread across multiple distributions. + The named package's ``__path__`` will be extended to include the + corresponding package in all distributions on ``sys.path`` that contain a + package of that name. (More precisely, if an importer's + ``find_module(name)`` returns a loader, then it will also be searched for + the package's contents.) Whenever a Distribution's ``activate()`` method + is invoked, it checks for the presence of namespace packages and updates + their ``__path__`` contents accordingly. + +Applications that manipulate namespace packages or directly alter ``sys.path`` +at runtime may also need to use this API function: + +``fixup_namespace_packages(path_item)`` + Declare that `path_item` is a newly added item on ``sys.path`` that may + need to be used to update existing namespace packages. Ordinarily, this is + called for you when an egg is automatically added to ``sys.path``, but if + your application modifies ``sys.path`` to include locations that may + contain portions of a namespace package, you will need to call this + function to ensure they are added to the existing namespace packages. + +Although by default ``pkg_resources`` only supports namespace packages for +filesystem and zip importers, you can extend its support to other "importers" +compatible with PEP 302 using the ``register_namespace_handler()`` function. +See the section below on `Supporting Custom Importers`_ for details. + +.. _setuptools documentation on namespace packages: http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages + + +``WorkingSet`` Objects +====================== + +The ``WorkingSet`` class provides access to a collection of "active" +distributions. In general, there is only one meaningful ``WorkingSet`` +instance: the one that represents the distributions that are currently active +on ``sys.path``. This global instance is available under the name +``working_set`` in the ``pkg_resources`` module. However, specialized +tools may wish to manipulate working sets that don't correspond to +``sys.path``, and therefore may wish to create other ``WorkingSet`` instances. + +It's important to note that the global ``working_set`` object is initialized +from ``sys.path`` when ``pkg_resources`` is first imported, but is only updated +if you do all future ``sys.path`` manipulation via ``pkg_resources`` APIs. If +you manually modify ``sys.path``, you must invoke the appropriate methods on +the ``working_set`` instance to keep it in sync. Unfortunately, Python does +not provide any way to detect arbitrary changes to a list object like +``sys.path``, so ``pkg_resources`` cannot automatically update the +``working_set`` based on changes to ``sys.path``. + +``WorkingSet(entries=None)`` + Create a ``WorkingSet`` from an iterable of path entries. If `entries` + is not supplied, it defaults to the value of ``sys.path`` at the time + the constructor is called. + + Note that you will not normally construct ``WorkingSet`` instances + yourself, but instead you will implicitly or explicitly use the global + ``working_set`` instance. For the most part, the ``pkg_resources`` API + is designed so that the ``working_set`` is used by default, such that you + don't have to explicitly refer to it most of the time. + + +Basic ``WorkingSet`` Methods +---------------------------- + +The following methods of ``WorkingSet`` objects are also available as module- +level functions in ``pkg_resources`` that apply to the default ``working_set`` +instance. Thus, you can use e.g. ``pkg_resources.require()`` as an +abbreviation for ``pkg_resources.working_set.require()``: + + +``require(*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. + + For the syntax of requirement specifiers, see the section below on + `Requirements Parsing`_. + + In general, it should not be necessary for you to call this method + directly. It's intended more for use in quick-and-dirty scripting and + interactive interpreter hacking than for production use. If you're creating + an actual library or application, it's strongly recommended that you create + a "setup.py" script using ``setuptools``, and declare all your requirements + there. That way, tools like EasyInstall can automatically detect what + requirements your package has, and deal with them accordingly. + + Note that calling ``require('SomePackage')`` will not install + ``SomePackage`` if it isn't already present. If you need to do this, you + should use the ``resolve()`` method instead, which allows you to pass an + ``installer`` callback that will be invoked when a needed distribution + can't be found on the local machine. You can then have this callback + display a dialog, automatically download the needed distribution, or + whatever else is appropriate for your application. See the documentation + below on the ``resolve()`` method for more information, and also on the + ``obtain()`` method of ``Environment`` objects. + +``run_script(requires, script_name)`` + Locate distribution specified by `requires` and run its `script_name` + script. `requires` must be a string containing a requirement specifier. + (See `Requirements Parsing`_ below for the syntax.) + + The script, if found, will be executed in *the caller's globals*. That's + because this method is intended to be called from wrapper scripts that + act as a proxy for the "real" scripts in a distribution. A wrapper script + usually doesn't need to do anything but invoke this function with the + correct arguments. + + If you need more control over the script execution environment, you + probably want to use the ``run_script()`` method of a ``Distribution`` + object's `Metadata API`_ instead. + +``iter_entry_points(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. Entry points are yielded from the active + distributions in the order that the distributions appear in the working + set. (For the global ``working_set``, this should be the same as the order + that they are listed in ``sys.path``.) Note that within the entry points + advertised by an individual distribution, there is no particular ordering. + + Please see the section below on `Entry Points`_ for more information. + + +``WorkingSet`` Methods and Attributes +------------------------------------- + +These methods are used to query or manipulate the contents of a specific +working set, so they must be explicitly invoked on a particular ``WorkingSet`` +instance: + +``add_entry(entry)`` + Add a path item to the ``entries``, finding any distributions on it. You + should use this when you add additional items to ``sys.path`` and you want + the global ``working_set`` to reflect the change. This method is also + called by the ``WorkingSet()`` constructor during initialization. + + This method uses ``find_distributions(entry,True)`` to find distributions + corresponding to the path entry, and then ``add()`` them. `entry` is + always appended to the ``entries`` attribute, even if it is already + present, however. (This is because ``sys.path`` can contain the same value + more than once, and the ``entries`` attribute should be able to reflect + this.) + +``__contains__(dist)`` + True if `dist` is active in this ``WorkingSet``. Note that only one + distribution for a given project can be active in a given ``WorkingSet``. + +``__iter__()`` + 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. + +``find(req)`` + Find a distribution matching `req` (a ``Requirement`` instance). + 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. + +``resolve(requirements, env=None, installer=None)`` + 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, an ``Environment`` is created from the working set's + ``entries``. `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``. (See the ``obtain()`` method + of `Environment Objects`_, below, for more information on the `installer` + argument.) + +``add(dist, entry=None)`` + Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to ``dist.location``. 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 active in the set. If it's + successfully added, any callbacks registered with the ``subscribe()`` + method will be called. (See `Receiving Change Notifications`_, below.) + + Note: ``add()`` is automatically called for you by the ``require()`` + method, so you don't normally need to use this method directly. + +``entries`` + This attribute represents a "shadow" ``sys.path``, primarily useful for + debugging. If you are experiencing import problems, you should check + the global ``working_set`` object's ``entries`` against ``sys.path``, to + ensure that they match. If they do not, then some part of your program + is manipulating ``sys.path`` without updating the ``working_set`` + accordingly. IMPORTANT NOTE: do not directly manipulate this attribute! + Setting it equal to ``sys.path`` will not fix your problem, any more than + putting black tape over an "engine warning" light will fix your car! If + this attribute is out of sync with ``sys.path``, it's merely an *indicator* + of the problem, not the cause of it. + + +Receiving Change Notifications +------------------------------ + +Extensible applications and frameworks may need to receive notification when +a new distribution (such as a plug-in component) has been added to a working +set. This is what the ``subscribe()`` method and ``add_activation_listener()`` +function are for. + +``subscribe(callback)`` + Invoke ``callback(distribution)`` once for each active distribution that is + in the set now, or gets added later. Because the callback is invoked for + already-active distributions, you do not need to loop over the working set + yourself to deal with the existing items; just register the callback and + be prepared for the fact that it will be called immediately by this method. + + Note that callbacks *must not* allow exceptions to propagate, or they will + interfere with the operation of other callbacks and possibly result in an + inconsistent working set state. Callbacks should use a try/except block + to ignore, log, or otherwise process any errors, especially since the code + that caused the callback to be invoked is unlikely to be able to handle + the errors any better than the callback itself. + +``pkg_resources.add_activation_listener()`` is an alternate spelling of +``pkg_resources.working_set.subscribe()``. + + +Locating Plugins +---------------- + +Extensible applications will sometimes have a "plugin directory" or a set of +plugin directories, from which they want to load entry points or other +metadata. The ``find_plugins()`` method allows you to do this, by scanning an +environment for the newest version of each project that can be safely loaded +without conflicts or missing requirements. + +``find_plugins(plugin_env, full_env=None, fallback=True)`` + Scan `plugin_env` and identify which distributions could be added to this + working set without version conflicts or missing requirements. + + Example usage:: + + distributions, errors = working_set.find_plugins( + Environment(plugin_dirlist) + ) + map(working_set.add, distributions) # add plugins+libs to sys.path + print "Couldn't 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`` instance that + 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. + + 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. + + Most applications will use this method mainly on the master ``working_set`` + instance in ``pkg_resources``, and then immediately add the returned + distributions to the working set so that they are available on sys.path. + This will make it possible to find any entry points, and allow any other + metadata tracking and hooks to be activated. + + The resolution algorithm used by ``find_plugins()`` is as follows. First, + the project names of the distributions present in `plugin_env` are sorted. + Then, each project's eggs are tried in descending version order (i.e., + newest version first). + + An attempt is made to resolve each egg's dependencies. If the attempt is + successful, the egg and its dependencies are added to the output list and to + a temporary copy of the working set. The resolution process continues with + the next project name, and no older eggs for that project are tried. + + If the resolution attempt fails, however, the error is added to the error + dictionary. If the `fallback` flag is true, the next older version of the + plugin is tried, until a working version is found. If false, the resolution + process continues with the next plugin project name. + + Some applications may have stricter fallback requirements than others. For + example, an application that has a database schema or persistent objects + may not be able to safely downgrade a version of a package. Others may want + to ensure that a new plugin configuration is either 100% good or else + revert to a known-good configuration. (That is, they may wish to revert to + a known configuration if the `error_info` return value is non-empty.) + + Note that this algorithm gives precedence to satisfying the dependencies of + alphabetically prior project names in case of version conflicts. If two + projects named "AaronsPlugin" and "ZekesPlugin" both need different versions + of "TomsLibrary", then "AaronsPlugin" will win and "ZekesPlugin" will be + disabled due to version conflict. + + +``Environment`` Objects +======================= + +An "environment" is a collection of ``Distribution`` objects, usually ones +that are present and potentially importable on the current platform. +``Environment`` objects are used by ``pkg_resources`` to index available +distributions during dependency resolution. + +``Environment(search_path=None, platform=get_supported_platform(), python=PY_MAJOR)`` + Create an environment snapshot by scanning `search_path` for distributions + compatible with `platform` and `python`. `search_path` should be a + sequence of strings such as might be used on ``sys.path``. If a + `search_path` isn't 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. ``'2.4'``); + it defaults to the currently-running version. + + You may explicitly set `platform` (and/or `python`) to ``None`` if you + wish to include *all* distributions, not just those compatible with the + running platform or Python version. + + Note that `search_path` is scanned immediately for distributions, and the + resulting ``Environment`` is a snapshot of the found distributions. It + is not automatically updated if the system's state changes due to e.g. + installation or removal of distributions. + +``__getitem__(project_name)`` + Returns a list of distributions for the given project name, ordered + from newest to oldest version. (And highest to lowest format precedence + for distributions that contain the same version of the project.) If there + are no distributions for the project, returns an empty list. + +``__iter__()`` + Yield the unique project names of the distributions in this environment. + The yielded names are always in lower case. + +``add(dist)`` + Add `dist` to the environment if it matches the platform and python version + specified at creation time, and only if the distribution hasn't already + been added. (i.e., adding the same distribution more than once is a no-op.) + +``remove(dist)`` + Remove `dist` from the environment. + +``can_add(dist)`` + Is distribution `dist` acceptable for this environment? If it's not + compatible with the ``platform`` and ``python`` version values specified + when the environment was created, a false value is returned. + +``__add__(dist_or_env)`` (``+`` operator) + Add a distribution or environment to an ``Environment`` instance, returning + a *new* environment object that contains all the distributions previously + contained by both. The new environment will have a ``platform`` and + ``python`` of ``None``, meaning that it will not reject any distributions + from being added to it; it will simply accept whatever is added. If you + want the added items to be filtered for platform and Python version, or + you want to add them to the *same* environment instance, you should use + in-place addition (``+=``) instead. + +``__iadd__(dist_or_env)`` (``+=`` operator) + Add a distribution or environment to an ``Environment`` instance + *in-place*, updating the existing instance and returning it. The + ``platform`` and ``python`` filter attributes take effect, so distributions + in the source that do not have a suitable platform string or Python version + are silently ignored. + +``best_match(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. + +``obtain(requirement, installer=None)`` + 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. + +``scan(search_path=None)`` + Scan `search_path` for distributions usable on `platform` + + Any distributions found are added to the environment. `search_path` should + be a sequence of strings such as might be used on ``sys.path``. If not + supplied, ``sys.path`` is used. Only distributions conforming to + the platform/python version defined at initialization are added. This + method is a shortcut for using the ``find_distributions()`` function to + find the distributions from each item in `search_path`, and then calling + ``add()`` to add each one to the environment. + + +``Requirement`` Objects +======================= + +``Requirement`` objects express what versions of a project are suitable for +some purpose. These objects (or their string form) are used by various +``pkg_resources`` APIs in order to find distributions that a script or +distribution needs. + + +Requirements Parsing +-------------------- + +``parse_requirements(s)`` + Yield ``Requirement`` objects for a string or iterable of lines. Each + requirement must start on a new line. See below for syntax. + +``Requirement.parse(s)`` + Create a ``Requirement`` object from a string or iterable of lines. A + ``ValueError`` is raised if the string or lines do not contain a valid + requirement specifier, or if they contain more than one specifier. (To + parse multiple specifiers from a string or iterable of strings, use + ``parse_requirements()`` instead.) + + The syntax of a requirement specifier can be defined in EBNF as follows:: + + requirement ::= project_name versionspec? extras? + versionspec ::= comparison version (',' comparison version)* + comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' + extras ::= '[' extralist? ']' + extralist ::= identifier (',' identifier)* + project_name ::= identifier + identifier ::= [-A-Za-z0-9_]+ + version ::= [-A-Za-z0-9_.]+ + + Tokens can be separated by whitespace, and a requirement can be continued + over multiple lines using a backslash (``\\``). Line-end comments (using + ``#``) are also allowed. + + Some examples of valid requirement specifiers:: + + FooProject >= 1.2 + Fizzy [foo, bar] + PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1 + SomethingWhoseVersionIDontCareAbout + + The project name is the only required portion of a requirement string, and + if it's the only thing supplied, the requirement will accept any version + of that project. + + The "extras" in a requirement are used to request optional features of a + project, that may require additional project distributions in order to + function. For example, if the hypothetical "Report-O-Rama" project offered + optional PDF support, it might require an additional library in order to + provide that support. Thus, a project needing Report-O-Rama's PDF features + could use a requirement of ``Report-O-Rama[PDF]`` to request installation + or activation of both Report-O-Rama and any libraries it needs in order to + provide PDF support. For example, you could use:: + + easy_install.py Report-O-Rama[PDF] + + To install the necessary packages using the EasyInstall program, or call + ``pkg_resources.require('Report-O-Rama[PDF]')`` to add the necessary + distributions to sys.path at runtime. + + +``Requirement`` Methods and Attributes +-------------------------------------- + +``__contains__(dist_or_version)`` + Return true if `dist_or_version` fits the criteria for this requirement. + If `dist_or_version` is a ``Distribution`` object, its project name must + match the requirement's project name, and its version must meet the + requirement's version criteria. If `dist_or_version` is a string, it is + parsed using the ``parse_version()`` utility function. Otherwise, it is + assumed to be an already-parsed version. + + 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 + 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 + case-insensitively equal project names, version specifiers, and "extras". + (The order that extras and version specifiers are in is also ignored.) + Equal requirements also have equal hashes, so that requirements can be + used in sets or as dictionary keys. + +``__str__()`` + The string form of a ``Requirement`` is a string that, if passed to + ``Requirement.parse()``, would return an equal ``Requirement`` object. + +``project_name`` + The name of the required project + +``key`` + An all-lowercase version of the ``project_name``, useful for comparison + or indexing. + +``extras`` + A tuple of names of "extras" that this requirement calls for. (These will + be all-lowercase and normalized using the ``safe_extra()`` parsing utility + function, so they may not exactly equal the extras the requirement was + created with.) + +``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. + + +Entry Points +============ + +Entry points are a simple way for distributions to "advertise" Python objects +(such as functions or classes) for use by other distributions. Extensible +applications and frameworks can search for entry points with a particular name +or group, either from a specific distribution or from all active distributions +on sys.path, and then inspect or load the advertised objects at will. + +Entry points belong to "groups" which are named with a dotted name similar to +a Python package or module name. For example, the ``setuptools`` package uses +an entry point named ``distutils.commands`` in order to find commands defined +by distutils extensions. ``setuptools`` treats the names of entry points +defined in that group as the acceptable commands for a setup script. + +In a similar way, other packages can define their own entry point groups, +either using dynamic names within the group (like ``distutils.commands``), or +possibly using predefined names within the group. For example, a blogging +framework that offers various pre- or post-publishing hooks might define an +entry point group and look for entry points named "pre_process" and +"post_process" within that group. + +To advertise an entry point, a project needs to use ``setuptools`` and provide +an ``entry_points`` argument to ``setup()`` in its setup script, so that the +entry points will be included in the distribution's metadata. For more +details, see the ``setuptools`` documentation. (XXX link here to setuptools) + +Each project distribution can advertise at most one entry point of a given +name within the same entry point group. For example, a distutils extension +could advertise two different ``distutils.commands`` entry points, as long as +they had different names. However, there is nothing that prevents *different* +projects from advertising entry points of the same name in the same group. In +some cases, this is a desirable thing, since the application or framework that +uses the entry points may be calling them as hooks, or in some other way +combining them. It is up to the application or framework to decide what to do +if multiple distributions advertise an entry point; some possibilities include +using both entry points, displaying an error message, using the first one found +in sys.path order, etc. + + +Convenience API +--------------- + +In the following functions, the `dist` argument can be a ``Distribution`` +instance, a ``Requirement`` instance, or a string specifying a requirement +(i.e. project name, version, etc.). If the argument is a string or +``Requirement``, the specified distribution is located (and added to sys.path +if not already present). An error will be raised if a matching distribution is +not available. + +The `group` argument should be a string containing a dotted identifier, +identifying an entry point group. If you are defining an entry point group, +you should include some portion of your package's name in the group name so as +to avoid collision with other packages' entry point groups. + +``load_entry_point(dist, group, name)`` + Load the named entry point from the specified distribution, or raise + ``ImportError``. + +``get_entry_info(dist, group, name)`` + Return an ``EntryPoint`` object for the given `group` and `name` from + the specified distribution. Returns ``None`` if the distribution has not + advertised a matching entry point. + +``get_entry_map(dist, group=None)`` + Return the distribution's entry point map for `group`, or the full entry + map for the distribution. This function always returns a dictionary, + even if the distribution advertises no entry points. If `group` is given, + the dictionary maps entry point names to the corresponding ``EntryPoint`` + object. If `group` is None, the dictionary maps group names to + dictionaries that then map entry point names to the corresponding + ``EntryPoint`` instance in that group. + +``iter_entry_points(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 on sys.path, otherwise only ones matching + both `group` and `name` are yielded. Entry points are yielded from + the active distributions in the order that the distributions appear on + sys.path. (Within entry points for a particular distribution, however, + there is no particular ordering.) + + (This API is actually a method of the global ``working_set`` object; see + the section above on `Basic WorkingSet Methods`_ for more information.) + + +Creating and Parsing +-------------------- + +``EntryPoint(name, module_name, attrs=(), extras=(), dist=None)`` + Create an ``EntryPoint`` instance. `name` is the entry point name. The + `module_name` is the (dotted) name of the module containing the advertised + object. `attrs` is an optional tuple of names to look up from the + module to obtain the advertised object. For example, an `attrs` of + ``("foo","bar")`` and a `module_name` of ``"baz"`` would mean that the + advertised object could be obtained by the following code:: + + import baz + advertised_object = baz.foo.bar + + The `extras` are an optional tuple of "extra feature" names that the + distribution needs in order to provide this entry point. When the + entry point is loaded, these extra features are looked up in the `dist` + argument to find out what other distributions may need to be activated + on sys.path; see the ``load()`` method for more details. The `extras` + argument is only meaningful if `dist` is specified. `dist` must be + a ``Distribution`` instance. + +``EntryPoint.parse(src, dist=None)`` (classmethod) + 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, as is the whitespace shown between + some of the items. The `dist` argument is passed through to the + ``EntryPoint()`` constructor, along with the other values parsed from + `src`. + +``EntryPoint.parse_group(group, lines, dist=None)`` (classmethod) + Parse `lines` (a string or sequence of lines) to create a dictionary + mapping entry point names to ``EntryPoint`` objects. ``ValueError`` is + raised if entry point names are duplicated, if `group` is not a valid + entry point group name, or if there are any syntax errors. (Note: the + `group` parameter is used only for validation and to create more + informative error messages.) If `dist` is provided, it will be used to + set the ``dist`` attribute of the created ``EntryPoint`` objects. + +``EntryPoint.parse_map(data, dist=None)`` (classmethod) + Parse `data` into a dictionary mapping group names to dictionaries mapping + entry point names to ``EntryPoint`` objects. If `data` is a dictionary, + then the keys are used as group names and the values are passed to + ``parse_group()`` as the `lines` argument. If `data` is a string or + sequence of lines, it is first split into .ini-style sections (using + the ``split_sections()`` utility function) and the section names are used + as group names. In either case, the `dist` argument is passed through to + ``parse_group()`` so that the entry points will be linked to the specified + distribution. + + +``EntryPoint`` Objects +---------------------- + +For simple introspection, ``EntryPoint`` objects have attributes that +correspond exactly to the constructor argument names: ``name``, +``module_name``, ``attrs``, ``extras``, and ``dist`` are all available. In +addition, the following methods are provided: + +``load(require=True, env=None, installer=None)`` + Load the entry point, returning the advertised Python object, or raise + ``ImportError`` if it cannot be obtained. If `require` is a true value, + then ``require(env, installer)`` is called before attempting the import. + +``require(env=None, installer=None)`` + Ensure that any "extras" needed by the entry point are available on + sys.path. ``UnknownExtra`` is raised if the ``EntryPoint`` has ``extras``, + but no ``dist``, or if the named extras are not defined by the + distribution. If `env` is supplied, it must be an ``Environment``, and it + will be used to search for needed distributions if they are not already + present on sys.path. If `installer` is supplied, it must be a callable + taking a ``Requirement`` instance and returning a matching importable + ``Distribution`` instance or None. + +``__str__()`` + The string form of an ``EntryPoint`` is a string that could be passed to + ``EntryPoint.parse()`` to produce an equivalent ``EntryPoint``. + + +``Distribution`` Objects +======================== + +``Distribution`` objects represent collections of Python code that may or may +not be importable, and may or may not have metadata and resources associated +with them. Their metadata may include information such as what other projects +the distribution depends on, what entry points the distribution advertises, and +so on. + + +Getting or Creating Distributions +--------------------------------- + +Most commonly, you'll obtain ``Distribution`` objects from a ``WorkingSet`` or +an ``Environment``. (See the sections above on `WorkingSet Objects`_ and +`Environment Objects`_, which are containers for active distributions and +available distributions, respectively.) You can also obtain ``Distribution`` +objects from one of these high-level APIs: + +``find_distributions(path_item, only=False)`` + Yield distributions accessible via `path_item`. If `only` is true, yield + only distributions whose ``location`` is equal to `path_item`. In other + words, if `only` is true, this yields any distributions that would be + importable if `path_item` were on ``sys.path``. If `only` is false, this + also yields distributions that are "in" or "under" `path_item`, but would + not be importable unless their locations were also added to ``sys.path``. + +``get_distribution(dist_spec)`` + Return a ``Distribution`` object for a given ``Requirement`` or string. + If `dist_spec` is already a ``Distribution`` instance, it is returned. + If it is a ``Requirement`` object or a string that can be parsed into one, + it is used to locate and activate a matching distribution, which is then + returned. + +However, if you're creating specialized tools for working with distributions, +or creating a new distribution format, you may also need to create +``Distribution`` objects directly, using one of the three constructors below. + +These constructors all take an optional `metadata` argument, which is used to +access any resources or metadata associated with the distribution. `metadata` +must be an object that implements the ``IResourceProvider`` interface, or None. +If it is None, an ``EmptyProvider`` is used instead. ``Distribution`` objects +implement both the `IResourceProvider`_ and `IMetadataProvider Methods`_ by +delegating them to the `metadata` object. + +``Distribution.from_location(location, basename, metadata=None, **kw)`` (classmethod) + Create a distribution for `location`, which must be a string such as a + URL, filename, or other string that might be used on ``sys.path``. + `basename` is a string naming the distribution, like ``Foo-1.2-py2.4.egg``. + If `basename` ends with ``.egg``, then the project's name, version, python + version and platform are extracted from the filename and used to set those + properties of the created distribution. Any additional keyword arguments + are forwarded to the ``Distribution()`` constructor. + +``Distribution.from_filename(filename, metadata=None**kw)`` (classmethod) + Create a distribution by parsing a local filename. This is a shorter way + of saying ``Distribution.from_location(normalize_path(filename), + os.path.basename(filename), metadata)``. In other words, it creates a + distribution whose location is the normalize form of the filename, parsing + name and version information from the base portion of the filename. Any + additional keyword arguments are forwarded to the ``Distribution()`` + constructor. + +``Distribution(location,metadata,project_name,version,py_version,platform,precedence)`` + Create a distribution by setting its properties. All arguments are + optional and default to None, except for `py_version` (which defaults to + the current Python version) and `precedence` (which defaults to + ``EGG_DIST``; for more details see ``precedence`` under `Distribution + Attributes`_ below). Note that it's usually easier to use the + ``from_filename()`` or ``from_location()`` constructors than to specify + all these arguments individually. + + +``Distribution`` Attributes +--------------------------- + +location + A string indicating the distribution's location. For an importable + distribution, this is the string that would be added to ``sys.path`` to + make it actively importable. For non-importable distributions, this is + simply a filename, URL, or other way of locating the distribution. + +project_name + A string, naming the project that this distribution is for. Project names + are defined by a project's setup script, and they are used to identify + projects on PyPI. When a ``Distribution`` is constructed, the + `project_name` argument is passed through the ``safe_name()`` utility + function to filter out any unacceptable characters. + +key + ``dist.key`` is short for ``dist.project_name.lower()``. It's used for + case-insensitive comparison and indexing of distributions by project name. + +extras + A list of strings, giving the names of extra features defined by the + project's dependency list (the ``extras_require`` argument specified in + the project's setup script). + +version + A string denoting what release of the project this distribution contains. + When a ``Distribution`` is constructed, the `version` argument is passed + through the ``safe_version()`` utility function to filter out any + unacceptable characters. If no `version` is specified at construction + time, then attempting to access this attribute later will cause the + ``Distribution`` to try to discover its version by reading its ``PKG-INFO`` + metadata file. If ``PKG-INFO`` is unavailable or can't be parsed, + ``ValueError`` is raised. + +parsed_version + The ``parsed_version`` is a tuple 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 + more information on the ``parse_version()`` function.) Note that accessing + ``parsed_version`` may result in a ``ValueError`` if the ``Distribution`` + was constructed without a `version` and without `metadata` capable of + supplying the missing version info. + +py_version + The major/minor Python version the distribution supports, as a string. + For example, "2.3" or "2.4". The default is the current version of Python. + +platform + A string representing the platform the distribution is intended for, or + ``None`` if the distribution is "pure Python" and therefore cross-platform. + See `Platform Utilities`_ below for more information on platform strings. + +precedence + A distribution's ``precedence`` is used to determine the relative order of + two distributions that have the same ``project_name`` and + ``parsed_version``. The default precedence is ``pkg_resources.EGG_DIST``, + which is the highest (i.e. most preferred) precedence. The full list + of predefined precedences, from most preferred to least preferred, is: + ``EGG_DIST``, ``BINARY_DIST``, ``SOURCE_DIST``, ``CHECKOUT_DIST``, and + ``DEVELOP_DIST``. Normally, precedences other than ``EGG_DIST`` are used + only by the ``setuptools.package_index`` module, when sorting distributions + found in a package index to determine their suitability for installation. + "System" and "Development" eggs (i.e., ones that use the ``.egg-info`` + format), however, are automatically given a precedence of ``DEVELOP_DIST``. + + + +``Distribution`` Methods +------------------------ + +``activate(path=None)`` + Ensure distribution is importable on `path`. If `path` is None, + ``sys.path`` is used instead. This ensures that the distribution's + ``location`` is in the `path` list, and it also performs any necessary + namespace package fixups or declarations. (That is, if the distribution + contains namespace packages, this method ensures that they are declared, + and that the distribution's contents for those namespace packages are + merged with the contents provided by any other active distributions. See + the section above on `Namespace Package Support`_ for more information.) + + ``pkg_resources`` adds a notification callback to the global ``working_set`` + that ensures this method is called whenever a distribution is added to it. + Therefore, you should not normally need to explicitly call this method. + (Note that this means that namespace packages on ``sys.path`` are always + imported as soon as ``pkg_resources`` is, which is another reason why + namespace packages should not contain any code or import statements.) + +``as_requirement()`` + Return a ``Requirement`` instance that matches this distribution's project + name and version. + +``requires(extras=())`` + List the ``Requirement`` objects that specify this distribution's + dependencies. If `extras` is specified, it should be a sequence of names + of "extras" defined by the distribution, and the list returned will then + include any dependencies needed to support the named "extras". + +``clone(**kw)`` + Create a copy of the distribution. Any supplied keyword arguments override + the corresponding argument to the ``Distribution()`` constructor, allowing + you to change some of the copied distribution's attributes. + +``egg_name()`` + Return what this distribution's standard filename should be, not including + the ".egg" extension. For example, a distribution for project "Foo" + version 1.2 that runs on Python 2.3 for Windows would have an ``egg_name()`` + of ``Foo-1.2-py2.3-win32``. Any dashes in the name or version are + converted to underscores. (``Distribution.from_location()`` will convert + them back when parsing a ".egg" file name.) + +``__cmp__(other)``, ``__hash__()`` + Distribution objects are hashed and compared on the basis of their parsed + version and precedence, followed by their key (lowercase project name), + location, Python version, and platform. + +The following methods are used to access ``EntryPoint`` objects advertised +by the distribution. See the section above on `Entry Points`_ for more +detailed information about these operations: + +``get_entry_info(group, name)`` + Return the ``EntryPoint`` object for `group` and `name`, or None if no + such point is advertised by this distribution. + +``get_entry_map(group=None)`` + Return the entry point map for `group`. If `group` is None, return + a dictionary mapping group names to entry point maps for all groups. + (An entry point map is a dictionary of entry point names to ``EntryPoint`` + objects.) + +``load_entry_point(group, name)`` + Short for ``get_entry_info(group, name).load()``. Returns the object + advertised by the named entry point, or raises ``ImportError`` if + the entry point isn't advertised by this distribution, or there is some + other import problem. + +In addition to the above methods, ``Distribution`` objects also implement all +of the `IResourceProvider`_ and `IMetadataProvider Methods`_ (which are +documented in later sections): + +* ``has_metadata(name)`` +* ``metadata_isdir(name)`` +* ``metadata_listdir(name)`` +* ``get_metadata(name)`` +* ``get_metadata_lines(name)`` +* ``run_script(script_name, namespace)`` +* ``get_resource_filename(manager, resource_name)`` +* ``get_resource_stream(manager, resource_name)`` +* ``get_resource_string(manager, resource_name)`` +* ``has_resource(resource_name)`` +* ``resource_isdir(resource_name)`` +* ``resource_listdir(resource_name)`` + +If the distribution was created with a `metadata` argument, these resource and +metadata access methods are all delegated to that `metadata` provider. +Otherwise, they are delegated to an ``EmptyProvider``, so that the distribution +will appear to have no resources or metadata. This delegation approach is used +so that supporting custom importers or new distribution formats can be done +simply by creating an appropriate `IResourceProvider`_ implementation; see the +section below on `Supporting Custom Importers`_ for more details. + + +``ResourceManager`` API +======================= + +The ``ResourceManager`` class provides uniform access to package resources, +whether those resources exist as files and directories or are compressed in +an archive of some kind. + +Normally, you do not need to create or explicitly manage ``ResourceManager`` +instances, as the ``pkg_resources`` module creates a global instance for you, +and makes most of its methods available as top-level names in the +``pkg_resources`` module namespace. So, for example, this code actually +calls the ``resource_string()`` method of the global ``ResourceManager``:: + + import pkg_resources + my_data = pkg_resources.resource_string(__name__, "foo.dat") + +Thus, you can use the APIs below without needing an explicit +``ResourceManager`` instance; just import and use them as needed. + + +Basic Resource Access +--------------------- + +In the following methods, the `package_or_requirement` argument may be either +a Python package/module name (e.g. ``foo.bar``) or a ``Requirement`` instance. +If it is a package or module name, the named module or package must be +importable (i.e., be in a distribution or directory on ``sys.path``), and the +`resource_name` argument is interpreted relative to the named package. (Note +that if a module name is used, then the resource name is relative to the +package immediately containing the named module. Also, you should not use use +a namespace package name, because a namespace package can be spread across +multiple distributions, and is therefore ambiguous as to which distribution +should be searched for the resource.) + +If it is a ``Requirement``, then the requirement is automatically resolved +(searching the current ``Environment`` if necessary) and a matching +distribution is added to the ``WorkingSet`` and ``sys.path`` if one was not +already present. (Unless the ``Requirement`` can't be satisfied, in which +case an exception is raised.) The `resource_name` argument is then interpreted +relative to the root of the identified distribution; i.e. its first path +segment will be treated as a peer of the top-level modules or packages in the +distribution. + +Note that resource names must be ``/``-separated paths and cannot be absolute +(i.e. no leading ``/``) or contain relative names like ``".."``. Do *not* use +``os.path`` routines to manipulate resource paths, as they are *not* filesystem +paths. + +``resource_exists(package_or_requirement, resource_name)`` + Does the named resource exist? Return ``True`` or ``False`` accordingly. + +``resource_stream(package_or_requirement, resource_name)`` + Return a readable file-like object for the specified resource; it may be + an actual file, a ``StringIO``, or some similar object. The stream is + in "binary mode", in the sense that whatever bytes are in the resource + will be read as-is. + +``resource_string(package_or_requirement, resource_name)`` + Return the specified resource as a string. The resource is read in + binary fashion, such that the returned string contains exactly the bytes + that are stored in the resource. + +``resource_isdir(package_or_requirement, resource_name)`` + Is the named resource a directory? Return ``True`` or ``False`` + accordingly. + +``resource_listdir(package_or_requirement, resource_name)`` + List the contents of the named resource directory, just like ``os.listdir`` + except that it works even if the resource is in a zipfile. + +Note that only ``resource_exists()`` and ``resource_isdir()`` are insensitive +as to the resource type. You cannot use ``resource_listdir()`` on a file +resource, and you can't use ``resource_string()`` or ``resource_stream()`` on +directory resources. Using an inappropriate method for the resource type may +result in an exception or undefined behavior, depending on the platform and +distribution format involved. + + +Resource Extraction +------------------- + +``resource_filename(package_or_requirement, resource_name)`` + Sometimes, it is not sufficient to access a resource in string or stream + form, and a true filesystem filename is needed. In such cases, you can + use this method (or module-level function) to obtain a filename for a + resource. If the resource is in an archive distribution (such as a zipped + egg), it will be extracted to a cache directory, and the filename within + the cache will be returned. If the named resource is a directory, then + all resources within that directory (including subdirectories) are also + extracted. If the named resource is a C extension or "eager resource" + (see the ``setuptools`` documentation for details), then all C extensions + and eager resources are extracted at the same time. + + Archived resources are extracted to a cache location that can be managed by + the following two methods: + +``set_extraction_path(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 resource provider. 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. (On + Windows, for example, you can't unlink .pyd or .dll files that are still + in use.) + + Note that you may not change the extraction path for a given resource + manager once resources have been extracted, unless you first call + ``cleanup_resources()``. + +``cleanup_resources(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. + + +"Provider" Interface +-------------------- + +If you are implementing an ``IResourceProvider`` and/or ``IMetadataProvider`` +for a new distribution archive format, you may need to use the following +``IResourceManager`` methods to co-ordinate extraction of resources to the +filesystem. If you're not implementing an archive format, however, you have +no need to use these methods. Unlike the other methods listed above, they are +*not* available as top-level functions tied to the global ``ResourceManager``; +you must therefore have an explicit ``ResourceManager`` instance to use them. + +``get_cache_path(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. + +``extraction_error()`` + Raise an ``ExtractionError`` describing the active exception as interfering + with the extraction process. You should call this if you encounter any + OS errors extracting the file to the cache path; it will format the + operating system exception for you, and add other information to the + ``ExtractionError`` instance that may be needed by programs that want to + wrap or handle extraction errors themselves. + +``postprocess(tempname, filename)`` + Perform any platform-specific postprocessing of `tempname`. + 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. + + +Metadata API +============ + +The metadata API is used to access metadata resources bundled in a pluggable +distribution. Metadata resources are virtual files or directories containing +information about the distribution, such as might be used by an extensible +application or framework to connect "plugins". Like other kinds of resources, +metadata resource names are ``/``-separated and should not contain ``..`` or +begin with a ``/``. You should not use ``os.path`` routines to manipulate +resource paths. + +The metadata API is provided by objects implementing the ``IMetadataProvider`` +or ``IResourceProvider`` interfaces. ``Distribution`` objects implement this +interface, as do objects returned by the ``get_provider()`` function: + +``get_provider(package_or_requirement)`` + If a package name is supplied, return an ``IResourceProvider`` for the + package. If a ``Requirement`` is supplied, resolve it by returning a + ``Distribution`` from the current working set (searching the current + ``Environment`` if necessary and adding the newly found ``Distribution`` + to the working set). If the named package can't be imported, or the + ``Requirement`` can't be satisfied, an exception is raised. + + NOTE: if you use a package name rather than a ``Requirement``, the object + you get back may not be a pluggable distribution, depending on the method + by which the package was installed. In particular, "development" packages + and "single-version externally-managed" packages do not have any way to + map from a package name to the corresponding project's metadata. Do not + write code that passes a package name to ``get_provider()`` and then tries + to retrieve project metadata from the returned object. It may appear to + work when the named package is in an ``.egg`` file or directory, but + it will fail in other installation scenarios. If you want project + metadata, you need to ask for a *project*, not a package. + + +``IMetadataProvider`` Methods +----------------------------- + +The methods provided by objects (such as ``Distribution`` instances) that +implement the ``IMetadataProvider`` or ``IResourceProvider`` interfaces are: + +``has_metadata(name)`` + Does the named metadata resource exist? + +``metadata_isdir(name)`` + Is the named metadata resource a directory? + +``metadata_listdir(name)`` + List of metadata names in the directory (like ``os.listdir()``) + +``get_metadata(name)`` + Return the named metadata resource as a string. The data is read in binary + mode; i.e., the exact bytes of the resource file are returned. + +``get_metadata_lines(name)`` + Yield named metadata resource as list of non-blank non-comment lines. This + is short for calling ``yield_lines(provider.get_metadata(name))``. See the + section on `yield_lines()`_ below for more information on the syntax it + recognizes. + +``run_script(script_name, namespace)`` + Execute the named script in the supplied namespace dictionary. Raises + ``ResolutionError`` if there is no script by that name in the ``scripts`` + metadata directory. `namespace` should be a Python dictionary, usually + a module dictionary if the script is being run as a module. + + +Exceptions +========== + +``pkg_resources`` provides a simple exception hierarchy for problems that may +occur when processing requests to locate and activate packages:: + + ResolutionError + DistributionNotFound + VersionConflict + UnknownExtra + + ExtractionError + +``ResolutionError`` + This class is used as a base class for the other three exceptions, so that + you can catch all of them with a single "except" clause. It is also raised + directly for miscellaneous requirement-resolution problems like trying to + run a script that doesn't exist in the distribution it was requested from. + +``DistributionNotFound`` + A distribution needed to fulfill a requirement could not be found. + +``VersionConflict`` + The requested version of a project conflicts with an already-activated + version of the same project. + +``UnknownExtra`` + One of the "extras" requested was not recognized by the distribution it + was requested from. + +``ExtractionError`` + A problem occurred extracting a resource to the Python Egg cache. The + following attributes are available on 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 + + +Supporting Custom Importers +=========================== + +By default, ``pkg_resources`` supports normal filesystem imports, and +``zipimport`` importers. If you wish to use the ``pkg_resources`` features +with other (PEP 302-compatible) importers or module loaders, you may need to +register various handlers and support functions using these APIs: + +``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, when passed a + path item, the importer instance, and an `only` flag, yields + ``Distribution`` instances found under that path item. (The `only` flag, + if true, means the finder should yield only ``Distribution`` objects whose + ``location`` is equal to the path item provided.) + + See the source of the ``pkg_resources.find_on_path`` function for an + example finder function. + +``register_loader_type(loader_type, provider_factory)`` + Register `provider_factory` to make ``IResourceProvider`` objects for + `loader_type`. `loader_type` is the type or class of a PEP 302 + ``module.__loader__``, and `provider_factory` is a function that, when + passed a module object, returns an `IResourceProvider`_ for that module, + allowing it to be used with the `ResourceManager API`_. + +``register_namespace_handler(importer_type, namespace_handler)`` + Register `namespace_handler` to declare namespace packages for the given + `importer_type`. `importer_type` is the type or class of a PEP 302 + "importer" (sys.path item handler), and `namespace_handler` is a callable + with a signature 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 relevant importer object has + already agreed that it can handle the relevant path item. The handler + should only return a subpath if the module ``__path__`` does not already + contain an equivalent subpath. Otherwise, it should return None. + + For an example namespace handler, see the source of the + ``pkg_resources.file_ns_handler`` function, which is used for both zipfile + importing and regular importing. + + +IResourceProvider +----------------- + +``IResourceProvider`` is an abstract class that documents what methods are +required of objects returned by a `provider_factory` registered with +``register_loader_type()``. ``IResourceProvider`` is a subclass of +``IMetadataProvider``, so objects that implement this interface must also +implement all of the `IMetadataProvider Methods`_ as well as the methods +shown here. The `manager` argument to the methods below must be an object +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 + extraction with `manager`, if the resource must be unpacked to the + filesystem. + +``get_resource_stream(manager, resource_name)`` + Return a readable file-like object for `resource_name`. + +``get_resource_string(manager, resource_name)`` + Return a string containing the contents of `resource_name`. + +``has_resource(resource_name)`` + Does the package contain the named resource? + +``resource_isdir(resource_name)`` + Is the named resource a directory? Return a false value if the resource + does not exist or is not a directory. + +``resource_listdir(resource_name)`` + Return a list of the contents of the resource directory, ala + ``os.listdir()``. Requesting the contents of a non-existent directory may + raise an exception. + +Note, by the way, that your provider classes need not (and should not) subclass +``IResourceProvider`` or ``IMetadataProvider``! These classes exist solely +for documentation purposes and do not provide any useful implementation code. +You may instead wish to subclass one of the `built-in resource providers`_. + + +Built-in Resource Providers +--------------------------- + +``pkg_resources`` includes several provider classes that are automatically used +where appropriate. Their inheritance tree looks like this:: + + NullProvider + EggProvider + DefaultProvider + PathMetadata + ZipProvider + EggMetadata + EmptyProvider + FileMetadata + + +``NullProvider`` + This provider class is just an abstract base that provides for common + provider behaviors (such as running scripts), given a definition for just + a few abstract methods. + +``EggProvider`` + This provider class adds in some egg-specific features that are common + to zipped and unzipped eggs. + +``DefaultProvider`` + This provider class is used for unpacked eggs and "plain old Python" + filesystem modules. + +``ZipProvider`` + This provider class is used for all zipped modules, whether they are eggs + or not. + +``EmptyProvider`` + This provider class always returns answers consistent with a provider that + has no metadata or resources. ``Distribution`` objects created without + a ``metadata`` argument use an instance of this provider class instead. + Since all ``EmptyProvider`` instances are equivalent, there is no need + to have more than one instance. ``pkg_resources`` therefore creates a + global instance of this class under the name ``empty_provider``, and you + may use it if you have need of an ``EmptyProvider`` instance. + +``PathMetadata(path, egg_info)`` + Create an ``IResourceProvider`` for a filesystem-based distribution, where + `path` is the filesystem location of the importable modules, and `egg_info` + is the filesystem location of the distribution's metadata directory. + `egg_info` should usually be the ``EGG-INFO`` subdirectory of `path` for an + "unpacked egg", and a ``ProjectName.egg-info`` subdirectory of `path` for + a "development egg". However, other uses are possible for custom purposes. + +``EggMetadata(zipimporter)`` + Create an ``IResourceProvider`` for a zipfile-based distribution. The + `zipimporter` should be a ``zipimport.zipimporter`` instance, and may + represent a "basket" (a zipfile containing multiple ".egg" subdirectories) + a specific egg *within* a basket, or a zipfile egg (where the zipfile + itself is a ".egg"). It can also be a combination, such as a zipfile egg + that also contains other eggs. + +``FileMetadata(path_to_pkg_info)`` + Create an ``IResourceProvider`` that provides exactly one metadata + resource: ``PKG-INFO``. The supplied path should be a distutils PKG-INFO + file. This is basically the same as an ``EmptyProvider``, except that + requests for ``PKG-INFO`` will be answered using the contents of the + designated file. (This provider is used to wrap ``.egg-info`` files + installed by vendor-supplied system packages.) + + +Utility Functions +================= + +In addition to its high-level APIs, ``pkg_resources`` also includes several +generally-useful utility routines. These routines are used to implement the +high-level APIs, but can also be quite useful by themselves. + + +Parsing Utilities +----------------- + +``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". + +.. _yield_lines(): + +``yield_lines(strs)`` + Yield non-empty/non-comment lines from a string/unicode or a possibly- + nested sequence thereof. If `strs` is an instance of ``basestring``, it + is split into lines, and each non-blank, non-comment line is yielded after + stripping leading and trailing whitespace. (Lines whose first non-blank + 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 + 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. + (Note that between each string in a sequence of strings there is assumed to + be an implicit line break, so lines cannot bridge two strings in a + sequence.) + + This routine is used extensively by ``pkg_resources`` to parse metadata + and file formats of various kinds, and most other ``pkg_resources`` + parsing functions that yield multiple values will use it to break up their + input. However, this routine is idempotent, so calling ``yield_lines()`` + on the output of another call to ``yield_lines()`` is completely harmless. + +``split_sections(strs)`` + Split a string (or possibly-nested iterable thereof), yielding ``(section, + content)`` pairs found using an ``.ini``-like syntax. Each ``section`` is + a whitespace-stripped version of the section name ("``[section]``") + and each ``content`` is a list of stripped lines excluding blank lines and + comment-only lines. If there are any non-blank, non-comment lines before + the first section header, they're yielded in a first ``section`` of + ``None``. + + This routine uses ``yield_lines()`` as its front end, so you can pass in + anything that ``yield_lines()`` accepts, such as an open text file, string, + or sequence of strings. ``ValueError`` is raised if a malformed section + header is found (i.e. a line starting with ``[`` but not ending with + ``]``). + + Note that this simplistic parser assumes that any line whose first nonblank + character is ``[`` is a section heading, so it can't support .ini format + variations that allow ``[`` as the first nonblank character on other lines. + +``safe_name(name)`` + Return a "safe" form of a project's name, suitable for use in a + ``Requirement`` string, as a distribution name, or a PyPI project name. + All non-alphanumeric runs are condensed to single "-" characters, such that + a name like "The $$$ Tree" becomes "The-Tree". Note that if you are + generating a filename from this value you should combine it with a call to + ``to_filename()`` so all dashes ("-") are replaced by underscores ("_"). + 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. + +``safe_extra(extra)`` + Return a "safe" form of an extra's name, suitable for use in a requirement + string or a setup script's ``extras_require`` keyword. This routine is + similar to ``safe_name()`` except that non-alphanumeric runs are replaced + by a single underbar (``_``), and the result is lowercased. + +``to_filename(name_or_version)`` + Escape a name or version string so it can be used in a dash-separated + filename (or ``#egg=name-version`` tag) without ambiguity. You + should only pass in values that were returned by ``safe_name()`` or + ``safe_version()``. + + +Platform Utilities +------------------ + +``get_build_platform()`` + Return this platform's identifier string. For Windows, the return value + is ``"win32"``, and for Mac OS X it is a string of the form + ``"macosx-10.4-ppc"``. All other platforms return the same uname-based + string that the ``distutils.util.get_platform()`` function returns. + This string is the minimum platform version required by distributions built + on the local machine. (Backward compatibility note: setuptools versions + prior to 0.6b1 called this function ``get_platform()``, and the function is + still available under that name for backward compatibility reasons.) + +``get_supported_platform()`` (New in 0.6b1) + This is the similar to ``get_build_platform()``, but is the maximum + platform version that the local machine supports. You will usually want + to use this value as the ``provided`` argument to the + ``compatible_platforms()`` function. + +``compatible_platforms(provided, required)`` + Return true if a distribution built on the `provided` platform may be used + on the `required` platform. If either platform value is ``None``, it is + considered a wildcard, and the platforms are therefore compatible. + Likewise, if the platform strings are equal, they're also considered + compatible, and ``True`` is returned. Currently, the only non-equal + platform strings that are considered compatible are Mac OS X platform + strings with the same hardware type (e.g. ``ppc``) and major version + (e.g. ``10``) with the `provided` platform's minor version being less than + or equal to the `required` platform's minor version. + +``get_default_cache()`` + Determine the default cache location for extracting resources from zipped + eggs. This routine returns the ``PYTHON_EGG_CACHE`` environment variable, + if set. Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of + the user's "Application Data" directory. On all other systems, it returns + ``os.path.expanduser("~/.python-eggs")`` if ``PYTHON_EGG_CACHE`` is not + set. + + +PEP 302 Utilities +----------------- + +``get_importer(path_item)`` + Retrieve a PEP 302 "importer" for the given path item (which need not + actually be on ``sys.path``). This routine simulates the PEP 302 protocol + for obtaining an "importer" object. It first checks for an importer for + the path item in ``sys.path_importer_cache``, and if not found it calls + each of the ``sys.path_hooks`` and caches the result if a good importer is + found. If no importer is found, this routine returns an ``ImpWrapper`` + instance that wraps the builtin import machinery as a PEP 302-compliant + "importer" object. This ``ImpWrapper`` is *not* cached; instead a new + instance is returned each time. + + (Note: When run under Python 2.5, this function is simply an alias for + ``pkgutil.get_importer()``, and instead of ``pkg_resources.ImpWrapper`` + instances, it may return ``pkgutil.ImpImporter`` instances.) + + +File/Path Utilities +------------------- + +``ensure_directory(path)`` + Ensure that the parent directory (``os.path.dirname``) of `path` actually + exists, using ``os.makedirs()`` if necessary. + +``normalize_path(path)`` + Return a "normalized" version of `path`, such that two paths represent + the same filesystem location if they have equal ``normalized_path()`` + values. Specifically, this is a shortcut for calling ``os.path.realpath`` + and ``os.path.normcase`` on `path`. Unfortunately, on certain platforms + (notably Cygwin and Mac OS X) the ``normcase`` function does not accurately + reflect the platform's case-sensitivity, so there is always the possibility + of two apparently-different paths being equal on such platforms. + +History +------- + +0.6c9 + * Fix ``resource_listdir('')`` always returning an empty list for zipped eggs. + +0.6c7 + * Fix package precedence problem where single-version eggs installed in + ``site-packages`` would take precedence over ``.egg`` files (or directories) + installed in ``site-packages``. + +0.6c6 + * Fix extracted C extensions not having executable permissions under Cygwin. + + * Allow ``.egg-link`` files to contain relative paths. + + * Fix cache dir defaults on Windows when multiple environment vars are needed + to construct a path. + +0.6c4 + * Fix "dev" versions being considered newer than release candidates. + +0.6c3 + * Python 2.5 compatibility fixes. + +0.6c2 + * Fix a problem with eggs specified directly on ``PYTHONPATH`` on + case-insensitive filesystems possibly not showing up in the default + working set, due to differing normalizations of ``sys.path`` entries. + +0.6b3 + * Fixed a duplicate path insertion problem on case-insensitive filesystems. + +0.6b1 + * Split ``get_platform()`` into ``get_supported_platform()`` and + ``get_build_platform()`` to work around a Mac versioning problem that caused + the behavior of ``compatible_platforms()`` to be platform specific. + + * Fix entry point parsing when a standalone module name has whitespace + between it and the extras. + +0.6a11 + * Added ``ExtractionError`` and ``ResourceManager.extraction_error()`` so that + cache permission problems get a more user-friendly explanation of the + problem, and so that programs can catch and handle extraction errors if they + need to. + +0.6a10 + * Added the ``extras`` attribute to ``Distribution``, the ``find_plugins()`` + method to ``WorkingSet``, and the ``__add__()`` and ``__iadd__()`` methods + to ``Environment``. + + * ``safe_name()`` now allows dots in project names. + + * There is a new ``to_filename()`` function that escapes project names and + versions for safe use in constructing egg filenames from a Distribution + object's metadata. + + * Added ``Distribution.clone()`` method, and keyword argument support to other + ``Distribution`` constructors. + + * Added the ``DEVELOP_DIST`` precedence, and automatically assign it to + eggs using ``.egg-info`` format. + +0.6a9 + * Don't raise an error when an invalid (unfinished) distribution is found + unless absolutely necessary. Warn about skipping invalid/unfinished eggs + when building an Environment. + + * Added support for ``.egg-info`` files or directories with version/platform + information embedded in the filename, so that system packagers have the + option of including ``PKG-INFO`` files to indicate the presence of a + system-installed egg, without needing to use ``.egg`` directories, zipfiles, + or ``.pth`` manipulation. + + * Changed ``parse_version()`` to remove dashes before pre-release tags, so + that ``0.2-rc1`` is considered an *older* version than ``0.2``, and is equal + to ``0.2rc1``. The idea that a dash *always* meant a post-release version + was highly non-intuitive to setuptools users and Python developers, who + seem to want to use ``-rc`` version numbers a lot. + +0.6a8 + * Fixed a problem with ``WorkingSet.resolve()`` that prevented version + conflicts from being detected at runtime. + + * Improved runtime conflict warning message to identify a line in the user's + program, rather than flagging the ``warn()`` call in ``pkg_resources``. + + * Avoid giving runtime conflict warnings for namespace packages, even if they + were declared by a different package than the one currently being activated. + + * Fix path insertion algorithm for case-insensitive filesystems. + + * Fixed a problem with nested namespace packages (e.g. ``peak.util``) not + being set as an attribute of their parent package. + +0.6a6 + * Activated distributions are now inserted in ``sys.path`` (and the working + set) just before the directory that contains them, instead of at the end. + This allows e.g. eggs in ``site-packages`` to override unmanaged modules in + the same location, and allows eggs found earlier on ``sys.path`` to override + ones found later. + + * When a distribution is activated, it now checks whether any contained + non-namespace modules have already been imported and issues a warning if + a conflicting module has already been imported. + + * Changed dependency processing so that it's breadth-first, allowing a + depender's preferences to override those of a dependee, to prevent conflicts + when a lower version is acceptable to the dependee, but not the depender. + + * Fixed a problem extracting zipped files on Windows, when the egg in question + has had changed contents but still has the same version number. + +0.6a4 + * Fix a bug in ``WorkingSet.resolve()`` that was introduced in 0.6a3. + +0.6a3 + * Added ``safe_extra()`` parsing utility routine, and use it for Requirement, + EntryPoint, and Distribution objects' extras handling. + +0.6a1 + * Enhanced performance of ``require()`` and related operations when all + requirements are already in the working set, and enhanced performance of + directory scanning for distributions. + + * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than + ``zipimport``, and the previously-broken "eager resource" support. + + * Fixed ``pkg_resources.resource_exists()`` not working correctly, along with + some other resource API bugs. + + * Many API changes and enhancements: + + * Added ``EntryPoint``, ``get_entry_map``, ``load_entry_point``, and + ``get_entry_info`` APIs for dynamic plugin discovery. + + * ``list_resources`` is now ``resource_listdir`` (and it actually works) + + * Resource API functions like ``resource_string()`` that accepted a package + name and resource name, will now also accept a ``Requirement`` object in + place of the package name (to allow access to non-package data files in + an egg). + + * ``get_provider()`` will now accept a ``Requirement`` instance or a module + name. If it is given a ``Requirement``, it will return a corresponding + ``Distribution`` (by calling ``require()`` if a suitable distribution + isn't already in the working set), rather than returning a metadata and + resource provider for a specific module. (The difference is in how + resource paths are interpreted; supplying a module name means resources + path will be module-relative, rather than relative to the distribution's + root.) + + * ``Distribution`` objects now implement the ``IResourceProvider`` and + ``IMetadataProvider`` interfaces, so you don't need to reference the (no + longer available) ``metadata`` attribute to get at these interfaces. + + * ``Distribution`` and ``Requirement`` both have a ``project_name`` + attribute for the project name they refer to. (Previously these were + ``name`` and ``distname`` attributes.) + + * The ``path`` attribute of ``Distribution`` objects is now ``location``, + because it isn't necessarily a filesystem path (and hasn't been for some + time now). The ``location`` of ``Distribution`` objects in the filesystem + should always be normalized using ``pkg_resources.normalize_path()``; all + of the setuptools and EasyInstall code that generates distributions from + the filesystem (including ``Distribution.from_filename()``) ensure this + invariant, but if you use a more generic API like ``Distribution()`` or + ``Distribution.from_location()`` you should take care that you don't + create a distribution with an un-normalized filesystem path. + + * ``Distribution`` objects now have an ``as_requirement()`` method that + returns a ``Requirement`` for the distribution's project name and version. + + * Distribution objects no longer have an ``installed_on()`` method, and the + ``install_on()`` method is now ``activate()`` (but may go away altogether + soon). The ``depends()`` method has also been renamed to ``requires()``, + and ``InvalidOption`` is now ``UnknownExtra``. + + * ``find_distributions()`` now takes an additional argument called ``only``, + that tells it to only yield distributions whose location is the passed-in + path. (It defaults to False, so that the default behavior is unchanged.) + + * ``AvailableDistributions`` is now called ``Environment``, and the + ``get()``, ``__len__()``, and ``__contains__()`` methods were removed, + because they weren't particularly useful. ``__getitem__()`` no longer + raises ``KeyError``; it just returns an empty list if there are no + distributions for the named project. + + * The ``resolve()`` method of ``Environment`` is now a method of + ``WorkingSet`` instead, and the ``best_match()`` method now uses a working + set instead of a path list as its second argument. + + * There is a new ``pkg_resources.add_activation_listener()`` API that lets + you register a callback for notifications about distributions added to + ``sys.path`` (including the distributions already on it). This is + basically a hook for extensible applications and frameworks to be able to + search for plugin metadata in distributions added at runtime. + +0.5a13 + * Fixed a bug in resource extraction from nested packages in a zipped egg. + +0.5a12 + * Updated extraction/cache mechanism for zipped resources to avoid inter- + process and inter-thread races during extraction. The default cache + location can now be set via the ``PYTHON_EGGS_CACHE`` environment variable, + and the default Windows cache is now a ``Python-Eggs`` subdirectory of the + current user's "Application Data" directory, if the ``PYTHON_EGGS_CACHE`` + variable isn't set. + +0.5a10 + * Fix a problem with ``pkg_resources`` being confused by non-existent eggs on + ``sys.path`` (e.g. if a user deletes an egg without removing it from the + ``easy-install.pth`` file). + + * Fix a problem with "basket" support in ``pkg_resources``, where egg-finding + never actually went inside ``.egg`` files. + + * Made ``pkg_resources`` import the module you request resources from, if it's + not already imported. + +0.5a4 + * ``pkg_resources.AvailableDistributions.resolve()`` and related methods now + accept an ``installer`` argument: a callable taking one argument, a + ``Requirement`` instance. The callable must return a ``Distribution`` + object, or ``None`` if no distribution is found. This feature is used by + EasyInstall to resolve dependencies by recursively invoking itself. + +0.4a4 + * Fix problems with ``resource_listdir()``, ``resource_isdir()`` and resource + directory extraction for zipped eggs. + +0.4a3 + * Fixed scripts not being able to see a ``__file__`` variable in ``__main__`` + + * Fixed a problem with ``resource_isdir()`` implementation that was introduced + in 0.4a2. + +0.4a1 + * Fixed a bug in requirements processing for exact versions (i.e. ``==`` and + ``!=``) when only one condition was included. + + * Added ``safe_name()`` and ``safe_version()`` APIs to clean up handling of + arbitrary distribution names and versions found on PyPI. + +0.3a4 + * ``pkg_resources`` now supports resource directories, not just the resources + in them. In particular, there are ``resource_listdir()`` and + ``resource_isdir()`` APIs. + + * ``pkg_resources`` now supports "egg baskets" -- .egg zipfiles which contain + multiple distributions in subdirectories whose names end with ``.egg``. + Having such a "basket" in a directory on ``sys.path`` is equivalent to + having the individual eggs in that directory, but the contained eggs can + be individually added (or not) to ``sys.path``. Currently, however, there + is no automated way to create baskets. + + * Namespace package manipulation is now protected by the Python import lock. + +0.3a1 + * Initial release. + diff --git a/vendor/distribute-0.6.35/docs/python3.txt b/vendor/distribute-0.6.35/docs/python3.txt new file mode 100644 index 00000000..2f6cde4a --- /dev/null +++ b/vendor/distribute-0.6.35/docs/python3.txt @@ -0,0 +1,121 @@ +===================================================== +Supporting both Python 2 and Python 3 with Distribute +===================================================== + +Starting with version 0.6.2, Distribute supports Python 3. Installing and +using distribute for Python 3 code works exactly the same as for Python 2 +code, but Distribute 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. + + +Distribute as help during porting +================================= + +Distribute 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 +setup.py so that you can run the unit tests with ``python setup.py test``. + +See :ref:`test` for more information on this. + +Once you have the tests running under Python 2, you can add the use_2to3 +keyword parameters to setup(), and start running the tests under Python 3. +The test command will now first run the build command during which the code +will be converted with 2to3, and the tests will then be run from the build +directory, as opposed from the source directory as is normally done. + +Distribute will convert all Python files, and also all doctests in Python +files. However, if you have doctests located in separate text files, these +will not automatically be converted. By adding them to the +``convert_2to3_doctests`` keyword parameter Distrubute will convert them as +well. + +By default, the conversion uses all fixers in the ``lib2to3.fixers`` package. +To use additional fixers, the parameter ``use_2to3_fixers`` can be set +to a list of names of packages containing fixers. To exclude fixers, the +parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be +skipped. + +A typical setup.py can look something like this:: + + from setuptools import setup + + setup( + name='your.module', + version = '1.0', + 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'], + ) + +Differential conversion +----------------------- + +Note that a file will only be copied and converted during the build process +if the source file has been changed. If you add a file to the doctests +that should be converted, it will not be converted the next time you run +the tests, since it hasn't been modified. You need to remove it from the +build directory. Also if you run the build, install or test commands before +adding the use_2to3 parameter, you will have to remove the build directory +before you run the test command, as the files otherwise will seem updated, +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 +"out of sync" with the source directory. + +Distributing Python 3 modules +============================= + +You can distribute your modules with Python 3 support in different ways. A +normal source distribution will work, but can be slow in installing, as the +2to3 process will be run during the install. But you can also distribute +the module in binary format, such as a binary egg. That egg will contain the +already converted code, and hence no 2to3 conversion is needed during install. + +Advanced features +================= + +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 setuptools +===================================== + +Setuptools do not know about the new keyword parameters to support Python 3. +As a result it will warn about the unknown keyword parameters if you use +setuptools instead of Distribute under Python 2. This is not an error, and +install process will continue as normal, but if you want to get rid of that +error this is easy. Simply conditionally add the new parameters into an extra +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 you have to +use Distribute. diff --git a/vendor/distribute-0.6.35/docs/roadmap.txt b/vendor/distribute-0.6.35/docs/roadmap.txt new file mode 100644 index 00000000..ea5070ea --- /dev/null +++ b/vendor/distribute-0.6.35/docs/roadmap.txt @@ -0,0 +1,86 @@ +======= +Roadmap +======= + +Distribute has two branches: + +- 0.6.x : provides a Setuptools-0.6cX compatible version +- 0.7.x : will provide a refactoring + +0.6.x +===== + +Not "much" is going to happen here, we want this branch to be helpful +to the community *today* by addressing the 40-or-so bugs +that were found in Setuptools and never fixed. This is eventually +happen soon because its development is +fast : there are up to 5 commiters that are working on it very often +(and the number grows weekly.) + +The biggest issue with this branch is that it is providing the same +packages and modules setuptools does, and this +requires some bootstrapping work where we make sure once Distribute is +installed, all Distribution that requires Setuptools +will continue to work. This is done by faking the metadata of +Setuptools 0.6c9. That's the only way we found to do this. + +There's one major thing though: thanks to the work of Lennart, Alex, +Martin, this branch supports Python 3, +which is great to have to speed up Py3 adoption. + +The goal of the 0.6.x is to remove as much bugs as we can, and try if +possible to remove the patches done +on Distutils. We will support 0.6.x maintenance for years and we will +promote its usage everywhere instead of +Setuptools. + +Some new commands are added there, when they are helpful and don't +interact with the rest. I am thinking +about "upload_docs" that let you upload documentation to PyPI. The +goal is to move it to Distutils +at some point, if the documentation feature of PyPI stays and starts to be used. + +0.7.x +===== + +We've started to refactor Distribute with this roadmap in mind (and +no, as someone said, it's not vaporware, +we've done a lot already) + +- 0.7.x can be installed and used with 0.6.x + +- easy_install is going to be deprecated ! use Pip ! + +- the version system will be deprecated, in favor of the one in Distutils + +- no more Distutils monkey-patch that happens once you use the code + (things like 'from distutils import cmd; cmd.Command = CustomCommand') + +- no more custom site.py (that is: if something misses in Python's + site.py we'll add it there instead of patching it) + +- no more namespaced packages system, if PEP 382 (namespaces package + support) makes it to 2.7 + +- The code is splitted in many packages and might be distributed under + several distributions. + + - distribute.resources: that's the old pkg_resources, but + reorganized in clean, pep-8 modules. This package will + only contain the query APIs and will focus on being PEP 376 + compatible. We will promote its usage and see if Pip wants + to use it as a basis. + It will probably shrink a lot though, once the stdlib provides PEP 376 support. + + - distribute.entrypoints: that's the old pkg_resources entry points + system, but on its own. it uses distribute.resources + + - distribute.index: that's package_index and a few other things. + everything required to interact with PyPI. We will promote + its usage and see if Pip wants to use it as a basis. + + - distribute.core (might be renamed to main): that's everything + else, and uses the other packages. + +Goal: A first release before (or when) Python 2.7 / 3.2 is out. + diff --git a/vendor/distribute-0.6.35/docs/setuptools.txt b/vendor/distribute-0.6.35/docs/setuptools.txt new file mode 100644 index 00000000..fe8bb3f6 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/setuptools.txt @@ -0,0 +1,3230 @@ +================================================== +Building and Distributing Packages with Distribute +================================================== + +``Distribute`` is a collection of enhancements to the Python ``distutils`` +(for Python 2.3.5 and up on most platforms; 64-bit platforms require a minimum +of Python 2.4) that allow you to more easily build and distribute Python +packages, especially ones that have dependencies on other packages. + +Packages built and distributed using ``setuptools`` look to the user like +ordinary Python packages based on the ``distutils``. Your users don't need to +install or even know about setuptools in order to use them, and you don't +have to include the entire setuptools package in your distributions. By +including just a single `bootstrap module`_ (an 8K .py file), your package will +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: http://nightly.ziade.org/distribute_setup.py + +Feature Highlights: + +* Automatically find/download/install/upgrade dependencies at build time using + the `EasyInstall tool <http://peak.telecommunity.com/DevCenter/EasyInstall>`_, + which supports downloading via HTTP, FTP, Subversion, and SourceForge, and + automatically scans web pages linked from PyPI to find download links. (It's + the closest thing to CPAN currently available for Python.) + +* Create `Python Eggs <http://peak.telecommunity.com/DevCenter/PythonEggs>`_ - + a single-file importable distribution format + +* Include data files inside your package directories, where your code can + actually use them. (Python 2.4 distutils also supports this feature, but + setuptools provides the feature for Python 2.3 packages also, and supports + accessing data files in zipped packages too.) + +* Automatically include all packages in your source tree, without listing them + individually in setup.py + +* Automatically include all relevant files in your source distributions, + without needing to create a ``MANIFEST.in`` file, and without having to force + regeneration of the ``MANIFEST`` file when your source tree changes. + +* Automatically generate wrapper scripts or Windows (console and GUI) .exe + files for any number of "main" functions in your project. (Note: this is not + a py2exe replacement; the .exe files rely on the local Python installation.) + +* Transparent Pyrex support, so that your setup.py can list ``.pyx`` files and + still work even when the end-user doesn't have Pyrex installed (as long as + you include the Pyrex-generated C in your source distribution) + +* Command aliases - create project-specific, per-user, or site-wide shortcut + names for commonly used commands and options + +* PyPI upload support - upload your source distributions and eggs to PyPI + +* Deploy your project in "development mode", such that it's available on + ``sys.path``, yet can still be edited directly from its source checkout. + +* Easily extend the distutils with new commands or ``setup()`` arguments, and + distribute/reuse your extensions for multiple projects, without copying code. + +* Create extensible applications and frameworks that automatically discover + extensions, using simple "entry points" declared in a project's setup script. + +In addition to the PyPI downloads, the development version of ``setuptools`` +is available from the `Python SVN sandbox`_, and in-development versions of the +`0.6 branch`_ are available as well. + +.. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 + +.. _Python SVN sandbox: http://svn.python.org/projects/sandbox/trunk/setuptools/#egg=setuptools-dev + +.. contents:: **Table of Contents** + +.. _distribute_setup.py: `bootstrap module`_ + + +----------------- +Developer's Guide +----------------- + + +Installing ``setuptools`` +========================= + +Please follow the `EasyInstall Installation Instructions`_ to install the +current stable version of setuptools. In particular, be sure to read the +section on `Custom Installation Locations`_ if you are installing anywhere +other than Python's ``site-packages`` directory. + +.. _EasyInstall Installation Instructions: http://peak.telecommunity.com/DevCenter/EasyInstall#installation-instructions + +.. _Custom Installation Locations: http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations + +If you want the current in-development version of setuptools, you should first +install a stable version, and then run:: + + distribute_setup.py setuptools==dev + +This will download and install the latest development (i.e. unstable) version +of setuptools from the Python Subversion sandbox. + + +Basic Use +========= + +For basic use of setuptools, just import things from setuptools instead of +the distutils. Here's a minimal setup script using setuptools:: + + from setuptools import setup, find_packages + setup( + name = "HelloWorld", + version = "0.1", + packages = find_packages(), + ) + +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 +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. + +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 +project. And maybe your project will have grown by then to include a few +dependencies, and perhaps some data files and scripts:: + + from setuptools import setup, find_packages + setup( + name = "HelloWorld", + version = "0.1", + packages = find_packages(), + scripts = ['say_hello.py'], + + # Project uses reStructuredText, so ensure that the docutils get + # installed or upgraded on the target machine + install_requires = ['docutils>=0.3'], + + package_data = { + # If any package contains *.txt or *.rst files, include them: + '': ['*.txt', '*.rst'], + # And include any *.msg files found in the 'hello' package, too: + 'hello': ['*.msg'], + }, + + # metadata for upload to PyPI + author = "Me", + author_email = "me@example.com", + description = "This is an Example Package", + license = "PSF", + keywords = "hello world example examples", + url = "http://example.com/HelloWorld/", # project home page, if any + + # could also include long_description, download_url, classifiers, etc. + ) + +In the sections that follow, we'll explain what most of these ``setup()`` +arguments do (except for the metadata ones), and the various ways you might use +them in your own project(s). + + +Specifying Your Project's Version +--------------------------------- + +Setuptools can work well with most versioning schemes; there are, however, a +few special things to watch out for, in order to ensure that setuptools and +EasyInstall can always tell what version of your package is newer than another +version. Knowing these things will also help you correctly specify what +versions of other projects your project depends on. + +A version consists of an alternating series of release numbers and pre-release +or post-release tags. A release number is a series of digits punctuated by +dots, such as ``2.4`` or ``0.5``. Each series of digits is treated +numerically, so releases ``2.1`` and ``2.1.0`` are different ways to spell the +same release number, denoting the first subrelease of release 2. But ``2.10`` +is the *tenth* subrelease of release 2, and so is a different and newer release +from ``2.1`` or ``2.1.0``. Leading zeros within a series of digits are also +ignored, so ``2.01`` is the same as ``2.1``, and different from ``2.0.1``. + +Following a release number, you can have either a pre-release or post-release +tag. Pre-release tags make a version be considered *older* than the version +they are appended to. So, revision ``2.4`` is *newer* than revision ``2.4c1``, +which in turn is newer than ``2.4b1`` or ``2.4a1``. Postrelease tags make +a version be considered *newer* than the version they are appended to. So, +revisions like ``2.4-1`` and ``2.4pl3`` are newer than ``2.4``, but are *older* +than ``2.4.1`` (which has a higher release number). + +A pre-release tag is a series of letters that are alphabetically before +"final". Some examples of prerelease tags would include ``alpha``, ``beta``, +``a``, ``c``, ``dev``, and so on. You do not have to place a dot or dash +before the prerelease tag if it's immediately after a number, but it's okay to +do so if you prefer. Thus, ``2.4c1`` and ``2.4.c1`` and ``2.4-c1`` all +represent release candidate 1 of version ``2.4``, and are treated as identical +by setuptools. + +In addition, there are three special prerelease tags that are treated as if +they were the letter ``c``: ``pre``, ``preview``, and ``rc``. So, version +``2.4rc1``, ``2.4pre1`` and ``2.4preview1`` are all the exact same version as +``2.4c1``, and are treated as identical by setuptools. + +A post-release tag is either a series of letters that are alphabetically +greater than or equal to "final", or a dash (``-``). Post-release tags are +generally used to separate patch numbers, port numbers, build numbers, revision +numbers, or date stamps from the release number. For example, the version +``2.4-r1263`` might denote Subversion revision 1263 of a post-release patch of +version ``2.4``. Or you might use ``2.4-20051127`` to denote a date-stamped +post-release. + +Notice that after each pre or post-release tag, you are free to place another +release number, followed again by more pre- or post-release tags. For example, +``0.6a9.dev-r41475`` could denote Subversion revision 41475 of the in- +development version of the ninth alpha of release 0.6. Notice that ``dev`` is +a pre-release tag, so this version is a *lower* version number than ``0.6a9``, +which would be the actual ninth alpha of release 0.6. But the ``-r41475`` is +a post-release tag, so this version is *newer* than ``0.6a9.dev``. + +For the most part, setuptools' interpretation of version numbers is intuitive, +but here are a few tips that will keep you out of trouble in the corner cases: + +* Don't stick adjoining pre-release tags together without a dot or number + between them. Version ``1.9adev`` is the ``adev`` prerelease of ``1.9``, + *not* a development pre-release of ``1.9a``. Use ``.dev`` instead, as in + ``1.9a.dev``, or separate the prerelease tags with a number, as in + ``1.9a0dev``. ``1.9a.dev``, ``1.9a0dev``, and even ``1.9.a.dev`` are + identical versions from setuptools' point of view, so you can use whatever + scheme you prefer. + +* If you want to be certain that your chosen numbering scheme works the way + you think it will, you can use the ``pkg_resources.parse_version()`` function + to compare different version numbers:: + + >>> from pkg_resources import parse_version + >>> parse_version('1.9.a.dev') == parse_version('1.9a0dev') + True + >>> parse_version('2.1-rc2') < parse_version('2.1') + True + >>> parse_version('0.6a9dev-r41475') < parse_version('0.6a9') + True + +Once you've decided on a version numbering scheme for your project, you can +have setuptools automatically tag your in-development releases with various +pre- or post-release tags. See the following sections for more details: + +* `Tagging and "Daily Build" or "Snapshot" Releases`_ +* `Managing "Continuous Releases" Using Subversion`_ +* The `egg_info`_ command + + +New and Changed ``setup()`` Keywords +==================================== + +The following keyword arguments to ``setup()`` are added or changed by +``setuptools``. All of them are optional; you do not have to supply them +unless you need the associated ``setuptools`` feature. + +``include_package_data`` + If set to ``True``, this tells ``setuptools`` to automatically include any + data files it finds inside your package directories, that are either under + CVS or Subversion control, or which are specified by your ``MANIFEST.in`` + file. For more information, see the section below on `Including Data + Files`_. + +``exclude_package_data`` + A dictionary mapping package names to lists of glob patterns that should + be *excluded* from your package directories. You can use this to trim back + any excess files included by ``include_package_data``. For a complete + description and examples, see the section below on `Including Data Files`_. + +``package_data`` + A dictionary mapping package names to lists of glob patterns. For a + complete description and examples, see the section below on `Including + Data Files`_. You do not need to use this option if you are using + ``include_package_data``, unless you need to add e.g. files that are + generated by your setup script and build process. (And are therefore not + in source control or are files that you don't want to include in your + source distribution.) + +``zip_safe`` + 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. + +``install_requires`` + A string or list of strings specifying what other distributions need to + be installed when this one is. See the section below on `Declaring + Dependencies`_ for details and examples of the format of this argument. + +``entry_points`` + A dictionary mapping entry point group names to strings or lists of strings + defining the entry points. Entry points are used to support dynamic + discovery of services or plugins provided by a project. See `Dynamic + Discovery of Services and Plugins`_ for details and examples of the format + of this argument. In addition, this keyword is used to support `Automatic + Script Creation`_. + +``extras_require`` + A dictionary mapping names of "extras" (optional features of your project) + to strings or lists of strings specifying what other distributions must be + installed to support those features. See the section below on `Declaring + Dependencies`_ for details and examples of the format of this argument. + +``setup_requires`` + A string or list of strings specifying what other distributions need to + be present in order for the *setup script* to run. ``setuptools`` will + attempt to obtain these (even going so far as to download them using + ``EasyInstall``) before processing the rest of the setup script or commands. + This argument is needed if you are using distutils extensions as part of + your build process; for example, extensions that process setup() arguments + and turn them into EGG-INFO metadata files. + + (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 + 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``.) + +``dependency_links`` + A list of strings naming URLs to be searched when satisfying dependencies. + These links will be used if needed to install packages specified by + ``setup_requires`` or ``tests_require``. They will also be written into + the egg's metadata for use by tools like EasyInstall to use when installing + an ``.egg`` file. + +``namespace_packages`` + A list of strings naming the project's "namespace packages". A namespace + package is a package that may be split across multiple project + distributions. For example, Zope 3's ``zope`` package is a namespace + package, because subpackages like ``zope.interface`` and ``zope.publisher`` + may be distributed separately. The egg runtime system can automatically + merge such subpackages into a single parent package at runtime, as long + as you declare them in each project that contains any subpackages of the + namespace package, and as long as the namespace package's ``__init__.py`` + does not contain any code other than a namespace declaration. See the + section below on `Namespace Packages`_ for more information. + +``test_suite`` + A string naming a ``unittest.TestCase`` subclass (or a package or module + containing one or more of them, or a method of such a subclass), or naming + a function that can be called with no arguments and returns a + ``unittest.TestSuite``. If the named suite is a module, and the module + has an ``additional_tests()`` function, it is called and the results are + added to the tests to be run. If the named suite is a package, any + submodules and subpackages are recursively added to the overall test suite. + + Specifying this argument enables use of the `test`_ command to run the + specified test suite, e.g. via ``setup.py test``. See the section on the + `test`_ command below for more details. + +``tests_require`` + If your project's tests need one or more additional packages besides those + needed to install it, you can use this option to specify them. It should + be a string or list of strings specifying what other distributions need to + be present for the package's tests to run. When you run the ``test`` + command, ``setuptools`` will attempt to obtain these (even going + so far as to download them using ``EasyInstall``). Note that these + required projects will *not* be installed on the system where the tests + are run, but only downloaded to the project's setup directory if they're + not already installed locally. + +.. _test_loader: + +``test_loader`` + If you would like to use a different way of finding tests to run than what + setuptools normally uses, you can specify a module name and class name in + this argument. The named class must be instantiable with no arguments, and + its instances must support the ``loadTestsFromNames()`` method as defined + in the Python ``unittest`` module's ``TestLoader`` class. Setuptools will + pass only one test "name" in the `names` argument: the value supplied for + the ``test_suite`` argument. The loader you specify may interpret this + string in any way it likes, as there are no restrictions on what may be + contained in a ``test_suite`` string. + + The module name and class name must be separated by a ``:``. The default + value of this argument is ``"setuptools.command.test:ScanningLoader"``. If + you want to use the default ``unittest`` behavior, you can specify + ``"unittest:TestLoader"`` as your ``test_loader`` argument instead. This + will prevent automatic scanning of submodules and subpackages. + + The module and class you specify here may be contained in another package, + as long as you use the ``tests_require`` option to ensure that the package + containing the loader class is available when the ``test`` command is run. + +``eager_resources`` + A list of strings naming resources that should be extracted together, if + any of them is needed, or if any C extensions included in the project are + imported. This argument is only useful if the project will be installed as + a zipfile, and there is a need to have all of the listed resources be + extracted to the filesystem *as a unit*. Resources listed here + should be '/'-separated paths, relative to the source root, so to list a + resource ``foo.png`` in package ``bar.baz``, you would include the string + ``bar/baz/foo.png`` in this argument. + + If you only need to obtain resources one at a time, or you don't have any C + extensions that access other files in the project (such as data files or + shared libraries), you probably do NOT need this argument and shouldn't + mess with it. For more details on how this argument works, see the section + below on `Automatic Resource Extraction`_. + +``use_2to3`` + Convert the source code from Python 2 to Python 3 with 2to3 during the + build process. See :doc:`python3` for more details. + +``convert_2to3_doctests`` + List of doctest source files that need to be converted with 2to3. + See :doc:`python3` for more details. + +``use_2to3_fixers`` + A list of modules to search for additional fixers to be used during + the 2to3 conversion. See :doc:`python3` for more details. + + +Using ``find_packages()`` +------------------------- + +For simple projects, it's usually easy enough to manually add packages to +the ``packages`` argument of ``setup()``. However, for very large projects +(Twisted, PEAK, Zope, Chandler, etc.), it can be a big burden to keep the +package list updated. That's what ``setuptools.find_packages()`` is for. + +``find_packages()`` takes a source directory, and a list of package names or +patterns to exclude. If omitted, the source directory defaults to the same +directory as the setup script. Some projects use a ``src`` or ``lib`` +directory as the root of their source tree, and those projects would of course +use ``"src"`` or ``"lib"`` as the first argument to ``find_packages()``. (And +such projects also need something like ``package_dir = {'':'src'}`` in their +``setup()`` arguments, but that's just a normal distutils thing.) + +Anyway, ``find_packages()`` walks the target directory, and finds Python +packages by looking for ``__init__.py`` files. It then filters the list of +packages using the exclusion patterns. + +Exclusion patterns are package names, optionally including wildcards. For +example, ``find_packages(exclude=["*.tests"])`` will exclude all packages whose +last name part is ``tests``. Or, ``find_packages(exclude=["*.tests", +"*.tests.*"])`` will also exclude any subpackages of packages named ``tests``, +but it still won't exclude a top-level ``tests`` package or the children +thereof. In fact, if you really want no ``tests`` packages at all, you'll need +something like this:: + + find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]) + +in order to cover all the bases. Really, the exclusion patterns are intended +to cover simpler use cases than this, like excluding a single, specified +package and its subpackages. + +Regardless of the target directory or exclusions, the ``find_packages()`` +function returns a list of package names suitable for use as the ``packages`` +argument to ``setup()``, and so is usually the easiest way to set that +argument in your setup script. Especially since it frees you from having to +remember to modify your setup script whenever your project grows additional +top-level packages or subpackages. + + +Automatic Script Creation +========================= + +Packaging and installing scripts can be a bit awkward with the distutils. For +one thing, there's no easy way to have a script's filename match local +conventions on both Windows and POSIX platforms. For another, you often have +to create a separate file just for the "main" script, when your actual "main" +is a function in a module somewhere. And even in Python 2.4, using the ``-m`` +option only works for actual ``.py`` files that aren't installed in a package. + +``setuptools`` fixes all of these problems by automatically generating scripts +for you with the correct extension, and on Windows it will even create an +``.exe`` file so that users don't have to change their ``PATHEXT`` settings. +The way to use this feature is to define "entry points" in your setup script +that indicate what function the generated script should import and run. For +example, to create two console scripts called ``foo`` and ``bar``, and a GUI +script called ``baz``, you might do something like this:: + + setup( + # other arguments here... + entry_points = { + 'console_scripts': [ + 'foo = my_package.some_module:main_func', + 'bar = other_module:some_func', + ], + 'gui_scripts': [ + 'baz = my_package_gui.start_func', + ] + } + ) + +When this project is installed on non-Windows platforms (using "setup.py +install", "setup.py develop", or by using EasyInstall), a set of ``foo``, +``bar``, and ``baz`` scripts will be installed that import ``main_func`` and +``some_func`` from the specified modules. The functions you specify are called +with no arguments, and their return value is passed to ``sys.exit()``, so you +can return an errorlevel or message to print to stderr. + +On Windows, a set of ``foo.exe``, ``bar.exe``, and ``baz.exe`` launchers are +created, alongside a set of ``foo.py``, ``bar.py``, and ``baz.pyw`` files. The +``.exe`` wrappers find and execute the right version of Python to run the +``.py`` or ``.pyw`` file. + +You may define as many "console script" and "gui script" entry points as you +like, and each one can optionally specify "extras" that it depends on, that +will be added to ``sys.path`` when the script is run. For more information on +"extras", see the section below on `Declaring Extras`_. For more information +on "entry points" in general, see the section below on `Dynamic Discovery of +Services and Plugins`_. + + +"Eggsecutable" Scripts +---------------------- + +Occasionally, there are situations where it's desirable to make an ``.egg`` +file directly executable. You can do this by including an entry point such +as the following:: + + setup( + # other arguments here... + entry_points = { + 'setuptools.installation': [ + 'eggsecutable = my_package.some_module:main_func', + ] + } + ) + +Any eggs built from the above setup script will include a short excecutable +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 +``.egg`` file. For the executable prelude to run, the appropriate version of +Python must be available via the ``PATH`` environment variable, under its +"long" name. That is, if the egg is built for Python 2.3, there must be a +``python2.3`` executable present in a directory on ``PATH``. + +This feature is primarily intended to support distribute_setup the installation of +setuptools itself on non-Windows platforms, but may also be useful for other +projects as well. + +IMPORTANT NOTE: Eggs with an "eggsecutable" header cannot be renamed, or +invoked via symlinks. They *must* be invoked using their original filename, in +order to ensure that, once running, ``pkg_resources`` will know what project +and version is in use. The header script will check this and exit with an +error if the ``.egg`` file has been renamed or is invoked via a symlink that +changes its base name. + + +Declaring Dependencies +====================== + +``setuptools`` supports automatically installing dependencies when a package is +installed, and including information about dependencies in Python Eggs (so that +package management tools like EasyInstall can use the information). + +``setuptools`` and ``pkg_resources`` use a common syntax for specifying a +project's required dependencies. This syntax consists of a project's PyPI +name, optionally followed by a comma-separated list of "extras" in square +brackets, optionally followed by a comma-separated list of version +specifiers. A version specifier is one of the operators ``<``, ``>``, ``<=``, +``>=``, ``==`` or ``!=``, followed by a version identifier. Tokens may be +separated by whitespace, but any whitespace or nonstandard characters within a +project name or version identifier must be replaced with ``-``. + +Version specifiers for a given project are internally sorted into ascending +version order, and used to establish what ranges of versions are acceptable. +Adjacent redundant conditions are also consolidated (e.g. ``">1, >2"`` becomes +``">1"``, and ``"<2,<3"`` becomes ``"<3"``). ``"!="`` versions are excised from +the ranges they fall within. A project's version 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.) + +Here are some example requirement specifiers:: + + docutils >= 0.3 + + # comment lines and \ continuations are allowed in requirement strings + BazSpam ==1.1, ==1.2, ==1.3, ==1.4, ==1.5, \ + ==1.6, ==1.7 # and so are line-end comments + + PEAK[FastCGI, reST]>=0.5a4 + + setuptools==0.5a7 + +The simplest way to include requirement specifiers is to use the +``install_requires`` argument to ``setup()``. It takes a string or list of +strings containing requirement specifiers. If you include more than one +requirement in a string, each requirement must begin on a new line. + +This has three effects: + +1. When your project is installed, either by using EasyInstall, ``setup.py + install``, or ``setup.py develop``, all of the dependencies not already + installed will be located (via PyPI), downloaded, built (if necessary), + and installed. + +2. Any scripts in your project will be installed with wrappers that verify + the availability of the specified dependencies at runtime, and ensure that + the correct versions are added to ``sys.path`` (e.g. if multiple versions + have been installed). + +3. Python Egg distributions will include a metadata file listing the + dependencies. + +Note, by the way, that if you declare your dependencies in ``setup.py``, you do +*not* need to use the ``require()`` function in your scripts or modules, as +long as you either install the project or use ``setup.py develop`` to do +development work on it. (See `"Development Mode"`_ below for more details on +using ``setup.py develop``.) + + +Dependencies that aren't in PyPI +-------------------------------- + +If your project depends on packages that aren't registered in PyPI, you may +still be able to depend on them, as long as they are available for download +as: + +- an egg, in the standard distutils ``sdist`` format, +- a single ``.py`` file, or +- a VCS repository (Subversion, Mercurial, or Git). + +You just need to add some URLs to the ``dependency_links`` argument to +``setup()``. + +The URLs must be either: + +1. direct download URLs, +2. the URLs of web pages that contain direct download links, or +3. the repository's URL + +In general, it's better to link to web pages, because it is usually less +complex to update a web page than to release a new version of your project. +You can also use a SourceForge ``showfiles.php`` link in the case where a +package you depend on is distributed via SourceForge. + +If you depend on a package that's distributed as a single ``.py`` file, you +must include an ``"#egg=project-version"`` suffix to the URL, to give a project +name and version number. (Be sure to escape any dashes in the name or version +by replacing them with underscores.) EasyInstall will recognize this suffix +and automatically create a trivial ``setup.py`` to wrap the single ``.py`` file +as an egg. + +In the case of a VCS checkout, you should also append ``#egg=project-version`` +in order to identify for what package that checkout should be used. You can +append ``@REV`` to the URL's path (before the fragment) to specify a revision. +Additionally, you can also force the VCS being used by prepending the URL with +a certain prefix. Currently available are: + +- ``svn+URL`` for Subversion, +- ``git+URL`` for Git, and +- ``hg+URL`` for Mercurial + +A more complete example would be: + + ``vcs+proto://host/path@revision#egg=project-version`` + +Be careful with the version. It should match the one inside the project files. +If you want do disregard the version, you have to omit it both in the +``requires`` and in the URL's fragment. + +This will do a checkout (or a clone, in Git and Mercurial parlance) to a +temporary folder and run ``setup.py bdist_egg``. + +The ``dependency_links`` option takes the form of a list of URL strings. For +example, the below will cause EasyInstall to search the specified page for +eggs or source distributions, if the package's dependencies aren't already +installed:: + + setup( + ... + dependency_links = [ + "http://peak.telecommunity.com/snapshots/" + ], + ) + + +.. _Declaring Extras: + + +Declaring "Extras" (optional features with their own dependencies) +------------------------------------------------------------------ + +Sometimes a project has "recommended" dependencies, that are not required for +all uses of the project. For example, a project might offer optional PDF +output if ReportLab is installed, and reStructuredText support if docutils is +installed. These optional features are called "extras", and setuptools allows +you to define their requirements as well. In this way, other projects that +require these optional features can force the additional requirements to be +installed, by naming the desired extras in their ``install_requires``. + +For example, let's say that Project A offers optional PDF and reST support:: + + setup( + name="Project-A", + ... + extras_require = { + 'PDF': ["ReportLab>=1.2", "RXP"], + 'reST': ["docutils>=0.3"], + } + ) + +As you can see, the ``extras_require`` argument takes a dictionary mapping +names of "extra" features, to strings or lists of strings describing those +features' requirements. These requirements will *not* be automatically +installed unless another package depends on them (directly or indirectly) by +including the desired "extras" in square brackets after the associated project +name. (Or if the extras were listed in a requirement spec on the EasyInstall +command line.) + +Extras can be used by a project's `entry points`_ to specify dynamic +dependencies. For example, if Project A includes a "rst2pdf" script, it might +declare it like this, so that the "PDF" requirements are only resolved if the +"rst2pdf" script is run:: + + setup( + name="Project-A", + ... + entry_points = { + 'console_scripts': + ['rst2pdf = project_a.tools.pdfgen [PDF]'], + ['rst2html = project_a.tools.htmlgen'], + # more script entry points ... + } + ) + +Projects can also use another project's extras when specifying dependencies. +For example, if project B needs "project A" with PDF support installed, it +might declare the dependency like this:: + + setup( + name="Project-B", + install_requires = ["Project-A[PDF]"], + ... + ) + +This will cause ReportLab to be installed along with project A, if project B is +installed -- even if project A was already installed. In this way, a project +can encapsulate groups of optional "downstream dependencies" under a feature +name, so that packages that depend on it don't have to know what the downstream +dependencies are. If a later version of Project A builds in PDF support and +no longer needs ReportLab, or if it ends up needing other dependencies besides +ReportLab in order to provide PDF support, Project B's setup information does +not need to change, but the right packages will still be installed if needed. + +Note, by the way, that if a project ends up not needing any other packages to +support a feature, it should keep an empty requirements list for that feature +in its ``extras_require`` argument, so that packages depending on that feature +don't break (due to an invalid feature name). For example, if Project A above +builds in PDF support and no longer needs ReportLab, it could change its +setup to this:: + + setup( + name="Project-A", + ... + extras_require = { + 'PDF': [], + 'reST': ["docutils>=0.3"], + } + ) + +so that Package B doesn't have to remove the ``[PDF]`` from its requirement +specifier. + + +Including Data Files +==================== + +The distutils have traditionally allowed installation of "data files", which +are placed in a platform-specific location. However, the most common use case +for data files distributed with a package is for use *by* the package, usually +by including the data files in the package directory. + +Setuptools offers three ways to specify data files to be included in your +packages. First, you can simply use the ``include_package_data`` keyword, +e.g.:: + + from setuptools import setup, find_packages + setup( + ... + include_package_data = True + ) + +This tells setuptools to install any data files it finds in your packages. +The data files must be under CVS or Subversion control, or else they must be +specified via the distutils' ``MANIFEST.in`` file. (They can also be tracked +by another revision control system, using an appropriate plugin. See the +section below on `Adding Support for Other Revision Control Systems`_ for +information on how to write such plugins.) + +If the data files are not under version control, or are not in a supported +version control system, or if you want finer-grained control over what files +are included (for example, if you have documentation files in your package +directories and want to exclude them from installation), then you can also use +the ``package_data`` keyword, e.g.:: + + from setuptools import setup, find_packages + setup( + ... + package_data = { + # If any package contains *.txt or *.rst files, include them: + '': ['*.txt', '*.rst'], + # And include any *.msg files found in the 'hello' package, too: + 'hello': ['*.msg'], + } + ) + +The ``package_data`` argument is a dictionary that maps from package names to +lists of glob patterns. The globs may include subdirectory names, if the data +files are contained in a subdirectory of the package. For example, if the +package tree looks like this:: + + setup.py + src/ + mypkg/ + __init__.py + mypkg.txt + data/ + somefile.dat + otherdata.dat + +The setuptools setup file might look like this:: + + from setuptools import setup, find_packages + setup( + ... + packages = find_packages('src'), # include all packages under src + package_dir = {'':'src'}, # tell distutils packages are under src + + package_data = { + # If any package contains *.txt files, include them: + '': ['*.txt'], + # And include any *.dat files found in the 'data' subdirectory + # of the 'mypkg' package, also: + 'mypkg': ['data/*.dat'], + } + ) + +Notice that if you list patterns in ``package_data`` under the empty string, +these patterns are used to find files in every package, even ones that also +have their own patterns listed. Thus, in the above example, the ``mypkg.txt`` +file gets included even though it's not listed in the patterns for ``mypkg``. + +Also notice that if you use paths, you *must* use a forward slash (``/``) as +the path separator, even if you are on Windows. Setuptools automatically +converts slashes to appropriate platform-specific separators at build time. + +(Note: although the ``package_data`` argument was previously only available in +``setuptools``, it was also added to the Python ``distutils`` package as of +Python 2.4; there is `some documentation for the feature`__ available on the +python.org website. If using the setuptools-specific ``include_package_data`` +argument, files specified by ``package_data`` will *not* be automatically +added to the manifest unless they are tracked by a supported version control +system, or are listed in the MANIFEST.in file.) + +__ http://docs.python.org/dist/node11.html + +Sometimes, the ``include_package_data`` or ``package_data`` options alone +aren't sufficient to precisely define what files you want included. For +example, you may want to include package README files in your revision control +system and source distributions, but exclude them from being installed. So, +setuptools offers an ``exclude_package_data`` option as well, that allows you +to do things like this:: + + from setuptools import setup, find_packages + setup( + ... + packages = find_packages('src'), # include all packages under src + package_dir = {'':'src'}, # tell distutils packages are under src + + include_package_data = True, # include everything in source control + + # ...but exclude README.txt from all packages + exclude_package_data = { '': ['README.txt'] }, + ) + +The ``exclude_package_data`` option is a dictionary mapping package names to +lists of wildcard patterns, just like the ``package_data`` option. And, just +as with that option, a key of ``''`` will apply the given pattern(s) to all +packages. However, any files that match these patterns will be *excluded* +from installation, even if they were listed in ``package_data`` or were +included as a result of using ``include_package_data``. + +In summary, the three options allow you to: + +``include_package_data`` + Accept all data files and directories matched by ``MANIFEST.in`` or found + in source control. + +``package_data`` + Specify additional patterns to match files and directories that may or may + not be matched by ``MANIFEST.in`` or found in source control. + +``exclude_package_data`` + Specify patterns for data files and directories that should *not* be + included when a package is installed, even if they would otherwise have + been included due to the use of the preceding options. + +NOTE: Due to the way the distutils build process works, a data file that you +include in your project and then stop including may be "orphaned" in your +project's build directories, requiring you to run ``setup.py clean --all`` to +fully remove them. This may also be important for your users and contributors +if they track intermediate revisions of your project using Subversion; be sure +to let them know when you make changes that remove files from inclusion so they +can run ``setup.py clean --all``. + + +Accessing Data Files at Runtime +------------------------------- + +Typically, existing programs manipulate a package's ``__file__`` attribute in +order to find the location of data files. However, this manipulation isn't +compatible with PEP 302-based import hooks, including importing from zip files +and Python Eggs. It is strongly recommended that, if you are using data files, +you should use the `Resource Management API`_ of ``pkg_resources`` to access +them. The ``pkg_resources`` module is distributed as part of setuptools, so if +you're using setuptools to distribute your package, there is no reason not to +use its resource management API. See also `Accessing Package Resources`_ for +a quick example of converting code that uses ``__file__`` to use +``pkg_resources`` instead. + +.. _Resource Management API: http://peak.telecommunity.com/DevCenter/PythonEggs#resource-management +.. _Accessing Package Resources: http://peak.telecommunity.com/DevCenter/PythonEggs#accessing-package-resources + + +Non-Package Data Files +---------------------- + +The ``distutils`` normally install general "data files" to a platform-specific +location (e.g. ``/usr/share``). This feature intended to be used for things +like documentation, example configuration files, and the like. ``setuptools`` +does not install these data files in a separate location, however. They are +bundled inside the egg file or directory, alongside the Python modules and +packages. The data files can also be accessed using the `Resource Management +API`_, by specifying a ``Requirement`` instead of a package name:: + + from pkg_resources import Requirement, resource_filename + filename = resource_filename(Requirement.parse("MyProject"),"sample.conf") + +The above code will obtain the filename of the "sample.conf" file in the data +root of the "MyProject" distribution. + +Note, by the way, that this encapsulation of data files means that you can't +actually install data files to some arbitrary location on a user's machine; +this is a feature, not a bug. You can always include a script in your +distribution that extracts and copies your the documentation or data files to +a user-specified location, at their discretion. If you put related data files +in a single directory, you can use ``resource_filename()`` with the directory +name to get a filesystem directory that then can be copied with the ``shutil`` +module. (Even if your package is installed as a zipfile, calling +``resource_filename()`` on a directory will return an actual filesystem +directory, whose contents will be that entire subtree of your distribution.) + +(Of course, if you're writing a new package, you can just as easily place your +data files or directories inside one of your packages, rather than using the +distutils' approach. However, if you're updating an existing application, it +may be simpler not to change the way it currently specifies these data files.) + + +Automatic Resource Extraction +----------------------------- + +If you are using tools that expect your resources to be "real" files, or your +project includes non-extension native libraries or other files that your C +extensions expect to be able to access, you may need to list those files in +the ``eager_resources`` argument to ``setup()``, so that the files will be +extracted together, whenever a C extension in the project is imported. + +This is especially important if your project includes shared libraries *other* +than distutils-built C extensions, and those shared libraries use file +extensions other than ``.dll``, ``.so``, or ``.dylib``, which are the +extensions that setuptools 0.6a8 and higher automatically detects as shared +libraries and adds to the ``native_libs.txt`` file for you. Any shared +libraries whose names do not end with one of those extensions should be listed +as ``eager_resources``, because they need to be present in the filesystem when +he C extensions that link to them are used. + +The ``pkg_resources`` runtime for compressed packages will automatically +extract *all* C extensions and ``eager_resources`` at the same time, whenever +*any* C extension or eager resource is requested via the ``resource_filename()`` +API. (C extensions are imported using ``resource_filename()`` internally.) +This ensures that C extensions will see all of the "real" files that they +expect to see. + +Note also that you can list directory resource names in ``eager_resources`` as +well, in which case the directory's contents (including subdirectories) will be +extracted whenever any C extension or eager resource is requested. + +Please note that if you're not sure whether you need to use this argument, you +don't! It's really intended to support projects with lots of non-Python +dependencies and as a last resort for crufty projects that can't otherwise +handle being compressed. If your package is pure Python, Python plus data +files, or Python plus C, you really don't need this. You've got to be using +either C or an external program that needs "real" files in your project before +there's any possibility of ``eager_resources`` being relevant to your project. + + +Extensible Applications and Frameworks +====================================== + + +.. _Entry Points: + +Dynamic Discovery of Services and Plugins +----------------------------------------- + +``setuptools`` supports creating libraries that "plug in" to extensible +applications and frameworks, by letting you register "entry points" in your +project that can be imported by the application or framework. + +For example, suppose that a blogging tool wants to support plugins +that provide translation for various file types to the blog's output format. +The framework might define an "entry point group" called ``blogtool.parsers``, +and then allow plugins to register entry points for the file extensions they +support. + +This would allow people to create distributions that contain one or more +parsers for different file types, and then the blogging tool would be able to +find the parsers at runtime by looking up an entry point for the file +extension (or mime type, or however it wants to). + +Note that if the blogging tool includes parsers for certain file formats, it +can register these as entry points in its own setup script, which means it +doesn't have to special-case its built-in formats. They can just be treated +the same as any other plugin's entry points would be. + +If you're creating a project that plugs in to an existing application or +framework, you'll need to know what entry points or entry point groups are +defined by that application or framework. Then, you can register entry points +in your setup script. Here are a few examples of ways you might register an +``.rst`` file parser entry point in the ``blogtool.parsers`` entry point group, +for our hypothetical blogging tool:: + + setup( + # ... + entry_points = {'blogtool.parsers': '.rst = some_module:SomeClass'} + ) + + setup( + # ... + entry_points = {'blogtool.parsers': ['.rst = some_module:a_func']} + ) + + setup( + # ... + entry_points = """ + [blogtool.parsers] + .rst = some.nested.module:SomeClass.some_classmethod [reST] + """, + extras_require = dict(reST = "Docutils>=0.3.5") + ) + +The ``entry_points`` argument to ``setup()`` accepts either a string with +``.ini``-style sections, or a dictionary mapping entry point group names to +either strings or lists of strings containing entry point specifiers. An +entry point specifier consists of a name and value, separated by an ``=`` +sign. The value consists of a dotted module name, optionally followed by a +``:`` and a dotted identifier naming an object within the module. It can +also include a bracketed list of "extras" that are required for the entry +point to be used. When the invoking application or framework requests loading +of an entry point, any requirements implied by the associated extras will be +passed to ``pkg_resources.require()``, so that an appropriate error message +can be displayed if the needed package(s) are missing. (Of course, the +invoking app or framework can ignore such errors if it wants to make an entry +point optional if a requirement isn't installed.) + + +Defining Additional Metadata +---------------------------- + +Some extensible applications and frameworks may need to define their own kinds +of metadata to include in eggs, which they can then access using the +``pkg_resources`` metadata APIs. Ordinarily, this is done by having plugin +developers include additional files in their ``ProjectName.egg-info`` +directory. However, since it can be tedious to create such files by hand, you +may want to create a distutils extension that will create the necessary files +from arguments to ``setup()``, in much the same way that ``setuptools`` does +for many of the ``setup()`` arguments it adds. See the section below on +`Creating distutils Extensions`_ for more details, especially the subsection on +`Adding new EGG-INFO Files`_. + + +"Development Mode" +================== + +Under normal circumstances, the ``distutils`` assume that you are going to +build a distribution of your project, not use it in its "raw" or "unbuilt" +form. If you were to use the ``distutils`` that way, you would have to rebuild +and reinstall your project every time you made a change to it during +development. + +Another problem that sometimes comes up with the ``distutils`` is that you may +need to do development on two related projects at the same time. You may need +to put both projects' packages in the same directory to run them, but need to +keep them separate for revision control purposes. How can you do this? + +Setuptools allows you to deploy your projects for use in a common directory or +staging area, but without copying any files. Thus, you can edit each project's +code in its checkout directory, and only need to run build commands when you +change a project's C extensions or similarly compiled files. You can even +deploy a project into another project's checkout directory, if that's your +preferred way of working (as opposed to using a common independent staging area +or the site-packages directory). + +To do this, use the ``setup.py develop`` command. It works very similarly to +``setup.py install`` or the EasyInstall tool, except that it doesn't actually +install anything. Instead, it creates a special ``.egg-link`` file in the +deployment directory, that links to your project's source code. And, if your +deployment directory is Python's ``site-packages`` directory, it will also +update the ``easy-install.pth`` file to include your project's source code, +thereby making it available on ``sys.path`` for all programs using that Python +installation. + +If you have enabled the ``use_2to3`` flag, then of course the ``.egg-link`` +will not link directly to your source code when run under Python 3, since +that source code would be made for Python 2 and not work under Python 3. +Instead the ``setup.py develop`` will build Python 3 code under the ``build`` +directory, and link there. This means that after doing code changes you will +have to run ``setup.py build`` before these changes are picked up by your +Python 3 installation. + +In addition, the ``develop`` command creates wrapper scripts in the target +script directory that will run your in-development scripts after ensuring that +all your ``install_requires`` packages are available on ``sys.path``. + +You can deploy the same project to multiple staging areas, e.g. if you have +multiple projects on the same machine that are sharing the same project you're +doing development work. + +When you're done with a given development task, you can remove the project +source from a staging area using ``setup.py develop --uninstall``, specifying +the desired staging area if it's not the default. + +There are several options to control the precise behavior of the ``develop`` +command; see the section on the `develop`_ command below for more details. + +Note that you can also apply setuptools commands to non-setuptools projects, +using commands like this:: + + python -c "import setuptools; execfile('setup.py')" develop + +That is, you can simply list the normal setup commands and options following +the quoted part. + + +Distributing a ``setuptools``-based project +=========================================== + +Using ``setuptools``... Without bundling it! +--------------------------------------------- + +Your users might not have ``setuptools`` installed on their machines, or even +if they do, it might not be the right version. Fixing this is easy; just +download `distribute_setup.py`_, and put it in the same directory as your ``setup.py`` +script. (Be sure to add it to your revision control system, too.) Then add +these two lines to the very top of your setup script, before the script imports +anything from setuptools: + +.. code-block:: python + + import distribute_setup + distribute_setup.use_setuptools() + +That's it. The ``distribute_setup`` module will automatically download a matching +version of ``setuptools`` from PyPI, if it isn't present on the target system. +Whenever you install an updated version of setuptools, you should also update +your projects' ``distribute_setup.py`` files, so that a matching version gets installed +on the target machine(s). + +By the way, setuptools supports the new PyPI "upload" command, so you can use +``setup.py sdist upload`` or ``setup.py bdist_egg upload`` to upload your +source or egg distributions respectively. Your project's current version must +be registered with PyPI first, of course; you can use ``setup.py register`` to +do that. Or you can do it all in one step, e.g. ``setup.py register sdist +bdist_egg upload`` will register the package, build source and egg +distributions, and then upload them both to PyPI, where they'll be easily +found by other projects that depend on them. + +(By the way, if you need to distribute a specific version of ``setuptools``, +you can specify the exact version and base download URL as parameters to the +``use_setuptools()`` function. See the function's docstring for details.) + + +What Your Users Should Know +--------------------------- + +In general, a setuptools-based project looks just like any distutils-based +project -- as long as your users have an internet connection and are installing +to ``site-packages``, that is. But for some users, these conditions don't +apply, and they may become frustrated if this is their first encounter with +a setuptools-based project. To keep these users happy, you should review the +following topics in your project's installation instructions, if they are +relevant to your project and your target audience isn't already familiar with +setuptools and ``easy_install``. + +Network Access + If your project is using ``distribute_setup``, you should inform users of the + need to either have network access, or to preinstall the correct version of + setuptools using the `EasyInstall installation instructions`_. Those + instructions also have tips for dealing with firewalls as well as how to + manually download and install setuptools. + +Custom Installation Locations + You should inform your users that if they are installing your project to + somewhere other than the main ``site-packages`` directory, they should + first install setuptools using the instructions for `Custom Installation + Locations`_, before installing your project. + +Your Project's Dependencies + If your project depends on other projects that may need to be downloaded + from PyPI or elsewhere, you should list them in your installation + instructions, or tell users how to find out what they are. While most + users will not need this information, any users who don't have unrestricted + internet access may have to find, download, and install the other projects + manually. (Note, however, that they must still install those projects + using ``easy_install``, or your project will not know they are installed, + and your setup script will try to download them again.) + + If you want to be especially friendly to users with limited network access, + you may wish to build eggs for your project and its dependencies, making + them all available for download from your site, or at least create a page + with links to all of the needed eggs. In this way, users with limited + network access can manually download all the eggs to a single directory, + then use the ``-f`` option of ``easy_install`` to specify the directory + to find eggs in. Users who have full network access can just use ``-f`` + with the URL of your download page, and ``easy_install`` will find all the + needed eggs using your links directly. This is also useful when your + target audience isn't able to compile packages (e.g. most Windows users) + and your package or some of its dependencies include C code. + +Subversion or CVS Users and Co-Developers + Users and co-developers who are tracking your in-development code using + CVS, Subversion, or some other revision control system should probably read + this manual's sections regarding such development. Alternately, you may + wish to create a quick-reference guide containing the tips from this manual + that apply to your particular situation. For example, if you recommend + that people use ``setup.py develop`` when tracking your in-development + code, you should let them know that this needs to be run after every update + or commit. + + Similarly, if you remove modules or data files from your project, you + should remind them to run ``setup.py clean --all`` and delete any obsolete + ``.pyc`` or ``.pyo``. (This tip applies to the distutils in general, not + just setuptools, but not everybody knows about them; be kind to your users + by spelling out your project's best practices rather than leaving them + guessing.) + +Creating System Packages + Some users want to manage all Python packages using a single package + manager, and sometimes that package manager isn't ``easy_install``! + Setuptools currently supports ``bdist_rpm``, ``bdist_wininst``, and + ``bdist_dumb`` formats for system packaging. If a user has a locally- + installed "bdist" packaging tool that internally uses the distutils + ``install`` command, it should be able to work with ``setuptools``. Some + examples of "bdist" formats that this should work with include the + ``bdist_nsi`` and ``bdist_msi`` formats for Windows. + + However, packaging tools that build binary distributions by running + ``setup.py install`` on the command line or as a subprocess will require + modification to work with setuptools. They should use the + ``--single-version-externally-managed`` option to the ``install`` command, + combined with the standard ``--root`` or ``--record`` options. + See the `install command`_ documentation below for more details. The + ``bdist_deb`` command is an example of a command that currently requires + this kind of patching to work with setuptools. + + If you or your users have a problem building a usable system package for + your project, please report the problem via the mailing list so that + either the "bdist" tool in question or setuptools can be modified to + resolve the issue. + + + +Managing Multiple Projects +-------------------------- + +If you're managing several projects that need to use ``distribute_setup``, and you +are using Subversion as your revision control system, you can use the +"svn:externals" property to share a single copy of ``distribute_setup`` between +projects, so that it will always be up-to-date whenever you check out or update +an individual project, without having to manually update each project to use +a new version. + +However, because Subversion only supports using directories as externals, you +have to turn ``distribute_setup.py`` into ``distribute_setup/__init__.py`` in order +to do this, then create "externals" definitions that map the ``distribute_setup`` +directory into each project. Also, if any of your projects use +``find_packages()`` on their setup directory, you will need to exclude the +resulting ``distribute_setup`` package, to keep it from being included in your +distributions, e.g.:: + + setup( + ... + packages = find_packages(exclude=['distribute_setup']), + ) + +Of course, the ``distribute_setup`` package will still be included in your +packages' source distributions, as it needs to be. + +For your convenience, you may use the following external definition, which will +track the latest version of setuptools:: + + ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup + +You can set this by executing this command in your project directory:: + + svn propedit svn:externals . + +And then adding the line shown above to the file that comes up for editing. + + +Setting the ``zip_safe`` flag +----------------------------- + +For maximum performance, Python packages are best installed as zip files. +Not all packages, however, are capable of running in compressed form, because +they may expect to be able to access either source code or data files as +normal operating system files. So, ``setuptools`` can install your project +as a zipfile or a directory, and its default choice is determined by the +project's ``zip_safe`` flag. + +You can pass a True or False value for the ``zip_safe`` argument to the +``setup()`` function, or you can omit it. If you omit it, the ``bdist_egg`` +command will analyze your project's contents to see if it can detect any +conditions that would prevent it from working in a zipfile. It will output +notices to the console about any such conditions that it finds. + +Currently, this analysis is extremely conservative: it will consider the +project unsafe if it contains any C extensions or datafiles whatsoever. This +does *not* mean that the project can't or won't work as a zipfile! It just +means that the ``bdist_egg`` authors aren't yet comfortable asserting that +the project *will* work. If the project contains no C or data files, and does +no ``__file__`` or ``__path__`` introspection or source code manipulation, then +there is an extremely solid chance the project will work when installed as a +zipfile. (And if the project uses ``pkg_resources`` for all its data file +access, then C extensions and other data files shouldn't be a problem at all. +See the `Accessing Data Files at Runtime`_ section above for more information.) + +However, if ``bdist_egg`` can't be *sure* that your package will work, but +you've checked over all the warnings it issued, and you are either satisfied it +*will* work (or if you want to try it for yourself), then you should set +``zip_safe`` to ``True`` in your ``setup()`` call. If it turns out that it +doesn't work, you can always change it to ``False``, which will force +``setuptools`` to install your project as a directory rather than as a zipfile. + +Of course, the end-user can still override either decision, if they are using +EasyInstall to install your package. And, if you want to override for testing +purposes, you can just run ``setup.py easy_install --zip-ok .`` or ``setup.py +easy_install --always-unzip .`` in your project directory. to install the +package as a zipfile or directory, respectively. + +In the future, as we gain more experience with different packages and become +more satisfied with the robustness of the ``pkg_resources`` runtime, the +"zip safety" analysis may become less conservative. However, we strongly +recommend that you determine for yourself whether your project functions +correctly when installed as a zipfile, correct any problems if you can, and +then make an explicit declaration of ``True`` or ``False`` for the ``zip_safe`` +flag, so that it will not be necessary for ``bdist_egg`` or ``EasyInstall`` to +try to guess whether your project can work as a zipfile. + + +Namespace Packages +------------------ + +Sometimes, a large package is more useful if distributed as a collection of +smaller eggs. However, Python does not normally allow the contents of a +package to be retrieved from more than one location. "Namespace packages" +are a solution for this problem. When you declare a package to be a namespace +package, it means that the package has no meaningful contents in its +``__init__.py``, and that it is merely a container for modules and subpackages. + +The ``pkg_resources`` runtime will then automatically ensure that the contents +of namespace packages that are spread over multiple eggs or directories are +combined into a single "virtual" package. + +The ``namespace_packages`` argument to ``setup()`` lets you declare your +project's namespace packages, so that they will be included in your project's +metadata. The argument should list the namespace packages that the egg +participates in. For example, the ZopeInterface project might do this:: + + setup( + # ... + namespace_packages = ['zope'] + ) + +because it contains a ``zope.interface`` package that lives in the ``zope`` +namespace package. Similarly, a project for a standalone ``zope.publisher`` +would also declare the ``zope`` namespace package. When these projects are +installed and used, Python will see them both as part of a "virtual" ``zope`` +package, even though they will be installed in different locations. + +Namespace packages don't have to be top-level packages. For example, Zope 3's +``zope.app`` package is a namespace package, and in the future PEAK's +``peak.util`` package will be too. + +Note, by the way, that your project's source tree must include the namespace +packages' ``__init__.py`` files (and the ``__init__.py`` of any parent +packages), in a normal Python package layout. These ``__init__.py`` files +*must* contain the line:: + + __import__('pkg_resources').declare_namespace(__name__) + +This code ensures that the namespace package machinery is operating and that +the current package is registered as a namespace package. + +You must NOT include any other code and data in a namespace package's +``__init__.py``. Even though it may appear to work during development, or when +projects are installed as ``.egg`` files, it will not work when the projects +are installed using "system" packaging tools -- in such cases the +``__init__.py`` files will not be installed, let alone executed. + +You must include the ``declare_namespace()`` line in the ``__init__.py`` of +*every* project that has contents for the namespace package in question, in +order to ensure that the namespace will be declared regardless of which +project's copy of ``__init__.py`` is loaded first. If the first loaded +``__init__.py`` doesn't declare it, it will never *be* declared, because no +other copies will ever be loaded!) + + +TRANSITIONAL NOTE +~~~~~~~~~~~~~~~~~ + +Setuptools 0.6a automatically calls ``declare_namespace()`` for you at runtime, +but the 0.7a versions will *not*. This is because the automatic declaration +feature has some negative side effects, such as needing to import all namespace +packages during the initialization of the ``pkg_resources`` runtime, and also +the need for ``pkg_resources`` to be explicitly imported before any namespace +packages work at all. Beginning with the 0.7a releases, you'll be responsible +for including your own declaration lines, and the automatic declaration feature +will be dropped to get rid of the negative side effects. + +During the remainder of the 0.6 development cycle, therefore, setuptools will +warn you about missing ``declare_namespace()`` calls in your ``__init__.py`` +files, and you should correct these as soon as possible before setuptools 0.7a1 +is released. Namespace packages without declaration lines will not work +correctly once a user has upgraded to setuptools 0.7a1, so it's important that +you make this change now in order to avoid having your code break in the field. +Our apologies for the inconvenience, and thank you for your patience. + + + +Tagging and "Daily Build" or "Snapshot" Releases +------------------------------------------------ + +When a set of related projects are under development, it may be important to +track finer-grained version increments than you would normally use for e.g. +"stable" releases. While stable releases might be measured in dotted numbers +with alpha/beta/etc. status codes, development versions of a project often +need to be tracked by revision or build number or even build date. This is +especially true when projects in development need to refer to one another, and +therefore may literally need an up-to-the-minute version of something! + +To support these scenarios, ``setuptools`` allows you to "tag" your source and +egg distributions by adding one or more of the following to the project's +"official" version identifier: + +* A manually-specified pre-release tag, such as "build" or "dev", or a + manually-specified post-release tag, such as a build or revision number + (``--tag-build=STRING, -bSTRING``) + +* A "last-modified revision number" string generated automatically from + Subversion's metadata (assuming your project is being built from a Subversion + "working copy") (``--tag-svn-revision, -r``) + +* An 8-character representation of the build date (``--tag-date, -d``), as + a postrelease tag + +You can add these tags by adding ``egg_info`` and the desired options to +the command line ahead of the ``sdist`` or ``bdist`` commands that you want +to generate a daily build or snapshot for. See the section below on the +`egg_info`_ command for more details. + +(Also, before you release your project, be sure to see the section above on +`Specifying Your Project's Version`_ for more information about how pre- and +post-release tags affect how setuptools and EasyInstall interpret version +numbers. This is important in order to make sure that dependency processing +tools will know which versions of your project are newer than others.) + +Finally, if you are creating builds frequently, and either building them in a +downloadable location or are copying them to a distribution server, you should +probably also check out the `rotate`_ command, which lets you automatically +delete all but the N most-recently-modified distributions matching a glob +pattern. So, you can use a command line like:: + + setup.py egg_info -rbDEV bdist_egg rotate -m.egg -k3 + +to build an egg whose version info includes 'DEV-rNNNN' (where NNNN is the +most recent Subversion revision that affected the source tree), and then +delete any egg files from the distribution directory except for the three +that were built most recently. + +If you have to manage automated builds for multiple packages, each with +different tagging and rotation policies, you may also want to check out the +`alias`_ command, which would let each package define an alias like ``daily`` +that would perform the necessary tag, build, and rotate commands. Then, a +simpler script or cron job could just run ``setup.py daily`` in each project +directory. (And, you could also define sitewide or per-user default versions +of the ``daily`` alias, so that projects that didn't define their own would +use the appropriate defaults.) + + +Generating Source Distributions +------------------------------- + +``setuptools`` enhances the distutils' default algorithm for source file +selection, so that all files managed by CVS or Subversion in your project tree +are included in any source distribution you build. This is a big improvement +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. +(And, if you already have one, you might consider deleting it the next time +you would otherwise have to change it.) + +(NOTE: other revision control systems besides CVS and Subversion can be +supported using plugins; see the section below on `Adding Support for Other +Revision Control Systems`_ for information on how to write such plugins.) + +If you need to include automatically generated files, or files that are kept in +an unsupported revision control system, you'll need to create a ``MANIFEST.in`` +file to specify any files that the default file location algorithm doesn't +catch. See the distutils documentation for more information on the format of +the ``MANIFEST.in`` file. + +But, be sure to ignore any part of the distutils documentation that deals with +``MANIFEST`` or how it's generated from ``MANIFEST.in``; setuptools shields you +from these issues and doesn't work the same way in any case. Unlike the +distutils, setuptools regenerates the source distribution manifest file +every time you build a source distribution, and it builds it inside the +project's ``.egg-info`` directory, out of the way of your main project +directory. You therefore need not worry about whether it is up-to-date or not. + +Indeed, because setuptools' approach to determining the contents of a source +distribution is so much simpler, its ``sdist`` command omits nearly all of +the options that the distutils' more complex ``sdist`` process requires. For +all practical purposes, you'll probably use only the ``--formats`` option, if +you use any option at all. + +(By the way, if you're using some other revision control system, you might +consider creating and publishing a `revision control plugin for setuptools`_.) + + +.. _revision control plugin for setuptools: `Adding Support for Other Revision Control Systems`_ + + +Making your package available for EasyInstall +--------------------------------------------- + +If you use the ``register`` command (``setup.py register``) to register your +package with PyPI, that's most of the battle right there. (See the +`docs for the register command`_ for more details.) + +.. _docs for the register command: http://docs.python.org/dist/package-index.html + +If you also use the `upload`_ command to upload actual distributions of your +package, that's even better, because EasyInstall will be able to find and +download them directly from your project's PyPI page. + +However, there may be reasons why you don't want to upload distributions to +PyPI, and just want your existing distributions (or perhaps a Subversion +checkout) to be used instead. + +So here's what you need to do before running the ``register`` command. There +are three ``setup()`` arguments that affect EasyInstall: + +``url`` and ``download_url`` + These become links on your project's PyPI page. EasyInstall will examine + them to see if they link to a package ("primary links"), or whether they are + HTML pages. If they're HTML pages, EasyInstall scans all HREF's on the + page for primary links + +``long_description`` + EasyInstall will check any URLs contained in this argument to see if they + are primary links. + +A URL is considered a "primary link" if it is a link to a .tar.gz, .tgz, .zip, +.egg, .egg.zip, .tar.bz2, or .exe file, or if it has an ``#egg=project`` or +``#egg=project-version`` fragment identifier attached to it. EasyInstall +attempts to determine a project name and optional version number from the text +of a primary link *without* downloading it. When it has found all the primary +links, EasyInstall will select the best match based on requested version, +platform compatibility, and other criteria. + +So, if your ``url`` or ``download_url`` point either directly to a downloadable +source distribution, or to HTML page(s) that have direct links to such, then +EasyInstall will be able to locate downloads automatically. If you want to +make Subversion checkouts available, then you should create links with either +``#egg=project`` or ``#egg=project-version`` added to the URL. You should +replace ``project`` and ``version`` with the values they would have in an egg +filename. (Be sure to actually generate an egg and then use the initial part +of the filename, rather than trying to guess what the escaped form of the +project name and version number will be.) + +Note that Subversion checkout links are of lower precedence than other kinds +of distributions, so EasyInstall will not select a Subversion checkout for +downloading unless it has a version included in the ``#egg=`` suffix, and +it's a higher version than EasyInstall has seen in any other links for your +project. + +As a result, it's a common practice to use mark checkout URLs with a version of +"dev" (i.e., ``#egg=projectname-dev``), so that users can do something like +this:: + + easy_install --editable projectname==dev + +in order to check out the in-development version of ``projectname``. + + +Managing "Continuous Releases" Using Subversion +----------------------------------------------- + +If you expect your users to track in-development versions of your project via +Subversion, there are a few additional steps you should take to ensure that +things work smoothly with EasyInstall. First, you should add the following +to your project's ``setup.cfg`` file: + +.. code-block:: ini + + [egg_info] + tag_build = .dev + tag_svn_revision = 1 + +This will tell ``setuptools`` to generate package version numbers like +``1.0a1.dev-r1263``, which will be considered to be an *older* release than +``1.0a1``. Thus, when you actually release ``1.0a1``, the entire egg +infrastructure (including ``setuptools``, ``pkg_resources`` and EasyInstall) +will know that ``1.0a1`` supersedes any interim snapshots from Subversion, and +handle upgrades accordingly. + +(Note: the project version number you specify in ``setup.py`` should always be +the *next* version of your software, not the last released version. +Alternately, you can leave out the ``tag_build=.dev``, and always use the +*last* release as a version number, so that your post-1.0 builds are labelled +``1.0-r1263``, indicating a post-1.0 patchlevel. Most projects so far, +however, seem to prefer to think of their project as being a future version +still under development, rather than a past version being patched. It is of +course possible for a single project to have both situations, using +post-release numbering on release branches, and pre-release numbering on the +trunk. But you don't have to make things this complex if you don't want to.) + +Commonly, projects releasing code from Subversion will include a PyPI link to +their checkout URL (as described in the previous section) with an +``#egg=projectname-dev`` suffix. This allows users to request EasyInstall +to download ``projectname==dev`` in order to get the latest in-development +code. Note that if your project depends on such in-progress code, you may wish +to specify your ``install_requires`` (or other requirements) to include +``==dev``, e.g.: + +.. code-block:: python + + install_requires = ["OtherProject>=0.2a1.dev-r143,==dev"] + +The above example says, "I really want at least this particular development +revision number, but feel free to follow and use an ``#egg=OtherProject-dev`` +link if you find one". This avoids the need to have actual source or binary +distribution snapshots of in-development code available, just to be able to +depend on the latest and greatest a project has to offer. + +A final note for Subversion development: if you are using SVN revision tags +as described in this section, it's a good idea to run ``setup.py develop`` +after each Subversion checkin or update, because your project's version number +will be changing, and your script wrappers need to be updated accordingly. + +Also, if the project's requirements have changed, the ``develop`` command will +take care of fetching the updated dependencies, building changed extensions, +etc. Be sure to also remind any of your users who check out your project +from Subversion that they need to run ``setup.py develop`` after every update +in order to keep their checkout completely in sync. + + +Making "Official" (Non-Snapshot) Releases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you make an official release, creating source or binary distributions, +you will need to override the tag settings from ``setup.cfg``, so that you +don't end up registering versions like ``foobar-0.7a1.dev-r34832``. This is +easy to do if you are developing on the trunk and using tags or branches for +your releases - just make the change to ``setup.cfg`` after branching or +tagging the release, so the trunk will still produce development snapshots. + +Alternately, if you are not branching for releases, you can override the +default version options on the command line, using something like:: + + python setup.py egg_info -RDb "" sdist bdist_egg register upload + +The first part of this command (``egg_info -RDb ""``) will override the +configured tag information, before creating source and binary eggs, registering +the project with PyPI, and uploading the files. Thus, these commands will use +the plain version from your ``setup.py``, without adding the Subversion +revision number or build designation string. + +Of course, if you will be doing this a lot, you may wish to create a personal +alias for this operation, e.g.:: + + python setup.py alias -u release egg_info -RDb "" + +You can then use it like this:: + + python setup.py release sdist bdist_egg register upload + +Or of course you can create more elaborate aliases that do all of the above. +See the sections below on the `egg_info`_ and `alias`_ commands for more ideas. + + + +Distributing Extensions compiled with Pyrex +------------------------------------------- + +``setuptools`` includes transparent support for building Pyrex extensions, as +long as you define your extensions using ``setuptools.Extension``, *not* +``distutils.Extension``. You must also not import anything from Pyrex in +your setup script. + +If you follow these rules, you can safely list ``.pyx`` files as the source +of your ``Extension`` objects in the setup script. ``setuptools`` will detect +at build time whether Pyrex is installed or not. If it is, then ``setuptools`` +will use it. If not, then ``setuptools`` will silently change the +``Extension`` objects to refer to the ``.c`` counterparts of the ``.pyx`` +files, so that the normal distutils C compilation process will occur. + +Of course, for this to work, your source distributions must include the C +code generated by Pyrex, as well as your original ``.pyx`` files. This means +that you will probably want to include current ``.c`` files in your revision +control system, rebuilding them whenever you check changes in for the ``.pyx`` +source files. This will ensure that people tracking your project in CVS or +Subversion will be able to build it even if they don't have Pyrex installed, +and that your source releases will be similarly usable with or without Pyrex. + + +----------------- +Command Reference +----------------- + +.. _alias: + +``alias`` - Define shortcuts for commonly used commands +======================================================= + +Sometimes, you need to use the same commands over and over, but you can't +necessarily set them as defaults. For example, if you produce both development +snapshot releases and "stable" releases of a project, you may want to put +the distributions in different places, or use different ``egg_info`` tagging +options, etc. In these cases, it doesn't make sense to set the options in +a distutils configuration file, because the values of the options changed based +on what you're trying to do. + +Setuptools therefore allows you to define "aliases" - shortcut names for +an arbitrary string of commands and options, using ``setup.py alias aliasname +expansion``, where aliasname is the name of the new alias, and the remainder of +the command line supplies its expansion. For example, this command defines +a sitewide alias called "daily", that sets various ``egg_info`` tagging +options:: + + setup.py alias --global-config daily egg_info --tag-svn-revision \ + --tag-build=development + +Once the alias is defined, it can then be used with other setup commands, +e.g.:: + + setup.py daily bdist_egg # generate a daily-build .egg file + setup.py daily sdist # generate a daily-build source distro + setup.py daily sdist bdist_egg # generate both + +The above commands are interpreted as if the word ``daily`` were replaced with +``egg_info --tag-svn-revision --tag-build=development``. + +Note that setuptools will expand each alias *at most once* in a given command +line. This serves two purposes. First, if you accidentally create an alias +loop, it will have no effect; you'll instead get an error message about an +unknown command. Second, it allows you to define an alias for a command, that +uses that command. For example, this (project-local) alias:: + + setup.py alias bdist_egg bdist_egg rotate -k1 -m.egg + +redefines the ``bdist_egg`` command so that it always runs the ``rotate`` +command afterwards to delete all but the newest egg file. It doesn't loop +indefinitely on ``bdist_egg`` because the alias is only expanded once when +used. + +You can remove a defined alias with the ``--remove`` (or ``-r``) option, e.g.:: + + setup.py alias --global-config --remove daily + +would delete the "daily" alias we defined above. + +Aliases can be defined on a project-specific, per-user, or sitewide basis. The +default is to define or remove a project-specific alias, but you can use any of +the `configuration file options`_ (listed under the `saveopts`_ command, below) +to determine which distutils configuration file an aliases will be added to +(or removed from). + +Note that if you omit the "expansion" argument to the ``alias`` command, +you'll get output showing that alias' current definition (and what +configuration file it's defined in). If you omit the alias name as well, +you'll get a listing of all current aliases along with their configuration +file locations. + + +``bdist_egg`` - Create a Python Egg for the project +=================================================== + +This command generates a Python Egg (``.egg`` file) for the project. Python +Eggs are the preferred binary distribution format for EasyInstall, because they +are cross-platform (for "pure" packages), directly importable, and contain +project metadata including scripts and information about the project's +dependencies. They can be simply downloaded and added to ``sys.path`` +directly, or they can be placed in a directory on ``sys.path`` and then +automatically discovered by the egg runtime system. + +This command runs the `egg_info`_ command (if it hasn't already run) to update +the project's metadata (``.egg-info``) directory. If you have added any extra +metadata files to the ``.egg-info`` directory, those files will be included in +the new egg file's metadata directory, for use by the egg runtime system or by +any applications or frameworks that use that metadata. + +You won't usually need to specify any special options for this command; just +use ``bdist_egg`` and you're done. But there are a few options that may +be occasionally useful: + +``--dist-dir=DIR, -d DIR`` + Set the directory where the ``.egg`` file will be placed. If you don't + supply this, then the ``--dist-dir`` setting of the ``bdist`` command + will be used, which is usually a directory named ``dist`` in the project + directory. + +``--plat-name=PLATFORM, -p PLATFORM`` + Set the platform name string that will be embedded in the egg's filename + (assuming the egg contains C extensions). This can be used to override + the distutils default platform name with something more meaningful. Keep + in mind, however, that the egg runtime system expects to see eggs with + distutils platform names, so it may ignore or reject eggs with non-standard + platform names. Similarly, the EasyInstall program may ignore them when + searching web pages for download links. However, if you are + cross-compiling or doing some other unusual things, you might find a use + for this option. + +``--exclude-source-files`` + Don't include any modules' ``.py`` files in the egg, just compiled Python, + C, and data files. (Note that this doesn't affect any ``.py`` files in the + EGG-INFO directory or its subdirectories, since for example there may be + scripts with a ``.py`` extension which must still be retained.) We don't + recommend that you use this option except for packages that are being + bundled for proprietary end-user applications, or for "embedded" scenarios + where space is at an absolute premium. On the other hand, if your package + is going to be installed and used in compressed form, you might as well + exclude the source because Python's ``traceback`` module doesn't currently + understand how to display zipped source code anyway, or how to deal with + files that are in a different place from where their code was compiled. + +There are also some options you will probably never need, but which are there +because they were copied from similar ``bdist`` commands used as an example for +creating this one. They may be useful for testing and debugging, however, +which is why we kept them: + +``--keep-temp, -k`` + Keep the contents of the ``--bdist-dir`` tree around after creating the + ``.egg`` file. + +``--bdist-dir=DIR, -b DIR`` + Set the temporary directory for creating the distribution. The entire + contents of this directory are zipped to create the ``.egg`` file, after + running various installation commands to copy the package's modules, data, + and extensions here. + +``--skip-build`` + Skip doing any "build" commands; just go straight to the + install-and-compress phases. + + +.. _develop: + +``develop`` - Deploy the project source in "Development Mode" +============================================================= + +This command allows you to deploy your project's source for use in one or more +"staging areas" where it will be available for importing. This deployment is +done in such a way that changes to the project source are immediately available +in the staging area(s), without needing to run a build or install step after +each change. + +The ``develop`` command works by creating an ``.egg-link`` file (named for the +project) in the given staging area. If the staging area is Python's +``site-packages`` directory, it also updates an ``easy-install.pth`` file so +that the project is on ``sys.path`` by default for all programs run using that +Python installation. + +The ``develop`` command also installs wrapper scripts in the staging area (or +a separate directory, as specified) that will ensure the project's dependencies +are available on ``sys.path`` before running the project's source scripts. +And, it ensures that any missing project dependencies are available in the +staging area, by downloading and installing them if necessary. + +Last, but not least, the ``develop`` command invokes the ``build_ext -i`` +command to ensure any C extensions in the project have been built and are +up-to-date, and the ``egg_info`` command to ensure the project's metadata is +updated (so that the runtime and wrappers know what the project's dependencies +are). If you make any changes to the project's setup script or C extensions, +you should rerun the ``develop`` command against all relevant staging areas to +keep the project's scripts, metadata and extensions up-to-date. Most other +kinds of changes to your project should not require any build operations or +rerunning ``develop``, but keep in mind that even minor changes to the setup +script (e.g. changing an entry point definition) require you to re-run the +``develop`` or ``test`` commands to keep the distribution updated. + +Here are some of the options that the ``develop`` command accepts. Note that +they affect the project's dependencies as well as the project itself, so if you +have dependencies that need to be installed and you use ``--exclude-scripts`` +(for example), the dependencies' scripts will not be installed either! For +this reason, you may want to use EasyInstall to install the project's +dependencies before using the ``develop`` command, if you need finer control +over the installation options for dependencies. + +``--uninstall, -u`` + Un-deploy the current project. You may use the ``--install-dir`` or ``-d`` + option to designate the staging area. The created ``.egg-link`` file will + be removed, if present and it is still pointing to the project directory. + The project directory will be removed from ``easy-install.pth`` if the + staging area is Python's ``site-packages`` directory. + + Note that this option currently does *not* uninstall script wrappers! You + must uninstall them yourself, or overwrite them by using EasyInstall to + activate a different version of the package. You can also avoid installing + script wrappers in the first place, if you use the ``--exclude-scripts`` + (aka ``-x``) option when you run ``develop`` to deploy the project. + +``--multi-version, -m`` + "Multi-version" mode. Specifying this option prevents ``develop`` from + adding an ``easy-install.pth`` entry for the project(s) being deployed, and + if an entry for any version of a project already exists, the entry will be + removed upon successful deployment. In multi-version mode, no specific + version of the package is available for importing, unless you use + ``pkg_resources.require()`` to put it on ``sys.path``, or you are running + a wrapper script generated by ``setuptools`` or EasyInstall. (In which + case the wrapper script calls ``require()`` for you.) + + Note that if you install to a directory other than ``site-packages``, + this option is automatically in effect, because ``.pth`` files can only be + used in ``site-packages`` (at least in Python 2.3 and 2.4). So, if you use + the ``--install-dir`` or ``-d`` option (or they are set via configuration + file(s)) your project and its dependencies will be deployed in multi- + version mode. + +``--install-dir=DIR, -d DIR`` + Set the installation directory (staging area). If this option is not + directly specified on the command line or in a distutils configuration + file, the distutils default installation location is used. Normally, this + will be the ``site-packages`` directory, but if you are using distutils + configuration files, setting things like ``prefix`` or ``install_lib``, + then those settings are taken into account when computing the default + staging area. + +``--script-dir=DIR, -s DIR`` + Set the script installation directory. If you don't supply this option + (via the command line or a configuration file), but you *have* supplied + an ``--install-dir`` (via command line or config file), then this option + defaults to the same directory, so that the scripts will be able to find + their associated package installation. Otherwise, this setting defaults + to the location where the distutils would normally install scripts, taking + any distutils configuration file settings into account. + +``--exclude-scripts, -x`` + Don't deploy script wrappers. This is useful if you don't want to disturb + existing versions of the scripts in the staging area. + +``--always-copy, -a`` + Copy all needed distributions to the staging area, even if they + are already present in another directory on ``sys.path``. By default, if + a requirement can be met using a distribution that is already available in + a directory on ``sys.path``, it will not be copied to the staging area. + +``--egg-path=DIR`` + Force the generated ``.egg-link`` file to use a specified relative path + to the source directory. This can be useful in circumstances where your + installation directory is being shared by code running under multiple + platforms (e.g. Mac and Windows) which have different absolute locations + for the code under development, but the same *relative* locations with + respect to the installation directory. If you use this option when + installing, you must supply the same relative path when uninstalling. + +In addition to the above options, the ``develop`` command also accepts all of +the same options accepted by ``easy_install``. If you've configured any +``easy_install`` settings in your ``setup.cfg`` (or other distutils config +files), the ``develop`` command will use them as defaults, unless you override +them in a ``[develop]`` section or on the command line. + + +``easy_install`` - Find and install packages +============================================ + +This command runs the `EasyInstall tool +<http://peak.telecommunity.com/DevCenter/EasyInstall>`_ for you. It is exactly +equivalent to running the ``easy_install`` command. All command line arguments +following this command are consumed and not processed further by the distutils, +so this must be the last command listed on the command line. Please see +the EasyInstall documentation for the options reference and usage examples. +Normally, there is no reason to use this command via the command line, as you +can just use ``easy_install`` directly. It's only listed here so that you know +it's a distutils command, which means that you can: + +* create command aliases that use it, +* create distutils extensions that invoke it as a subcommand, and +* configure options for it in your ``setup.cfg`` or other distutils config + files. + + +.. _egg_info: + +``egg_info`` - Create egg metadata and set build tags +===================================================== + +This command performs two operations: it updates a project's ``.egg-info`` +metadata directory (used by the ``bdist_egg``, ``develop``, and ``test`` +commands), and it allows you to temporarily change a project's version string, +to support "daily builds" or "snapshot" releases. It is run automatically by +the ``sdist``, ``bdist_egg``, ``develop``, ``register``, and ``test`` commands +in order to update the project's metadata, but you can also specify it +explicitly in order to temporarily change the project's version string while +executing other commands. (It also generates the``.egg-info/SOURCES.txt`` +manifest file, which is used when you are building source distributions.) + +In addition to writing the core egg metadata defined by ``setuptools`` and +required by ``pkg_resources``, this command can be extended to write other +metadata files as well, by defining entry points in the ``egg_info.writers`` +group. See the section on `Adding new EGG-INFO Files`_ below for more details. +Note that using additional metadata writers may require you to include a +``setup_requires`` argument to ``setup()`` in order to ensure that the desired +writers are available on ``sys.path``. + + +Release Tagging Options +----------------------- + +The following options can be used to modify the project's version string for +all remaining commands on the setup command line. The options are processed +in the order shown, so if you use more than one, the requested tags will be +added in the following order: + +``--tag-build=NAME, -b NAME`` + Append NAME to the project's version string. Due to the way setuptools + processes "pre-release" version suffixes beginning with the letters "a" + through "e" (like "alpha", "beta", and "candidate"), you will usually want + to use a tag like ".build" or ".dev", as this will cause the version number + to be considered *lower* than the project's default version. (If you + want to make the version number *higher* than the default version, you can + always leave off --tag-build and then use one or both of the following + options.) + + If you have a default build tag set in your ``setup.cfg``, you can suppress + it on the command line using ``-b ""`` or ``--tag-build=""`` as an argument + to the ``egg_info`` command. + +``--tag-svn-revision, -r`` + If the current directory is a Subversion checkout (i.e. has a ``.svn`` + subdirectory, this appends a string of the form "-rNNNN" to the project's + version string, where NNNN is the revision number of the most recent + modification to the current directory, as obtained from the ``svn info`` + command. + + If the current directory is not a Subversion checkout, the command will + look for a ``PKG-INFO`` file instead, and try to find the revision number + from that, by looking for a "-rNNNN" string at the end of the version + number. (This is so that building a package from a source distribution of + a Subversion snapshot will produce a binary with the correct version + number.) + + If there is no ``PKG-INFO`` file, or the version number contained therein + does not end with ``-r`` and a number, then ``-r0`` is used. + +``--no-svn-revision, -R`` + Don't include the Subversion revision in the version number. This option + is included so you can override a default setting put in ``setup.cfg``. + +``--tag-date, -d`` + Add a date stamp of the form "-YYYYMMDD" (e.g. "-20050528") to the + project's version number. + +``--no-date, -D`` + Don't include a date stamp in the version number. This option is included + so you can override a default setting in ``setup.cfg``. + + +(Note: Because these options modify the version number used for source and +binary distributions of your project, you should first make sure that you know +how the resulting version numbers will be interpreted by automated tools +like EasyInstall. See the section above on `Specifying Your Project's +Version`_ for an explanation of pre- and post-release tags, as well as tips on +how to choose and verify a versioning scheme for your your project.) + +For advanced uses, there is one other option that can be set, to change the +location of the project's ``.egg-info`` directory. Commands that need to find +the project's source directory or metadata should get it from this setting: + + +Other ``egg_info`` Options +-------------------------- + +``--egg-base=SOURCEDIR, -e SOURCEDIR`` + Specify the directory that should contain the .egg-info directory. This + should normally be the root of your project's source tree (which is not + necessarily the same as your project directory; some projects use a ``src`` + or ``lib`` subdirectory as the source root). You should not normally need + to specify this directory, as it is normally determined from the + ``package_dir`` argument to the ``setup()`` function, if any. If there is + no ``package_dir`` set, this option defaults to the current directory. + + +``egg_info`` Examples +--------------------- + +Creating a dated "nightly build" snapshot egg:: + + python setup.py egg_info --tag-date --tag-build=DEV bdist_egg + +Creating and uploading a release with no version tags, even if some default +tags are specified in ``setup.cfg``:: + + python setup.py egg_info -RDb "" sdist bdist_egg register upload + +(Notice that ``egg_info`` must always appear on the command line *before* any +commands that you want the version changes to apply to.) + + +.. _install command: + +``install`` - Run ``easy_install`` or old-style installation +============================================================ + +The setuptools ``install`` command is basically a shortcut to run the +``easy_install`` command on the current project. However, for convenience +in creating "system packages" of setuptools-based projects, you can also +use this option: + +``--single-version-externally-managed`` + This boolean option tells the ``install`` command to perform an "old style" + installation, with the addition of an ``.egg-info`` directory so that the + installed project will still have its metadata available and operate + normally. If you use this option, you *must* also specify the ``--root`` + or ``--record`` options (or both), because otherwise you will have no way + to identify and remove the installed files. + +This option is automatically in effect when ``install`` is invoked by another +distutils command, so that commands like ``bdist_wininst`` and ``bdist_rpm`` +will create system packages of eggs. It is also automatically in effect if +you specify the ``--root`` option. + + +``install_egg_info`` - Install an ``.egg-info`` directory in ``site-packages`` +============================================================================== + +Setuptools runs this command as part of ``install`` operations that use the +``--single-version-externally-managed`` options. You should not invoke it +directly; it is documented here for completeness and so that distutils +extensions such as system package builders can make use of it. This command +has only one option: + +``--install-dir=DIR, -d DIR`` + The parent directory where the ``.egg-info`` directory will be placed. + Defaults to the same as the ``--install-dir`` option specified for the + ``install_lib`` command, which is usually the system ``site-packages`` + directory. + +This command assumes that the ``egg_info`` command has been given valid options +via the command line or ``setup.cfg``, as it will invoke the ``egg_info`` +command and use its options to locate the project's source ``.egg-info`` +directory. + + +.. _rotate: + +``rotate`` - Delete outdated distribution files +=============================================== + +As you develop new versions of your project, your distribution (``dist``) +directory will gradually fill up with older source and/or binary distribution +files. The ``rotate`` command lets you automatically clean these up, keeping +only the N most-recently modified files matching a given pattern. + +``--match=PATTERNLIST, -m PATTERNLIST`` + Comma-separated list of glob patterns to match. This option is *required*. + The project name and ``-*`` is prepended to the supplied patterns, in order + to match only distributions belonging to the current project (in case you + have a shared distribution directory for multiple projects). Typically, + you will use a glob pattern like ``.zip`` or ``.egg`` to match files of + the specified type. Note that each supplied pattern is treated as a + distinct group of files for purposes of selecting files to delete. + +``--keep=COUNT, -k COUNT`` + Number of matching distributions to keep. For each group of files + identified by a pattern specified with the ``--match`` option, delete all + but the COUNT most-recently-modified files in that group. This option is + *required*. + +``--dist-dir=DIR, -d DIR`` + Directory where the distributions are. This defaults to the value of the + ``bdist`` command's ``--dist-dir`` option, which will usually be the + project's ``dist`` subdirectory. + +**Example 1**: Delete all .tar.gz files from the distribution directory, except +for the 3 most recently modified ones:: + + setup.py rotate --match=.tar.gz --keep=3 + +**Example 2**: Delete all Python 2.3 or Python 2.4 eggs from the distribution +directory, except the most recently modified one for each Python version:: + + setup.py rotate --match=-py2.3*.egg,-py2.4*.egg --keep=1 + + +.. _saveopts: + +``saveopts`` - Save used options to a configuration file +======================================================== + +Finding and editing ``distutils`` configuration files can be a pain, especially +since you also have to translate the configuration options from command-line +form to the proper configuration file format. You can avoid these hassles by +using the ``saveopts`` command. Just add it to the command line to save the +options you used. For example, this command builds the project using +the ``mingw32`` C compiler, then saves the --compiler setting as the default +for future builds (even those run implicitly by the ``install`` command):: + + setup.py build --compiler=mingw32 saveopts + +The ``saveopts`` command saves all options for every commmand 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 +to the site-wide (global) distutils configuration:: + + setup.py build --compiler=mingw32 saveopts -g + +Note that it doesn't matter where you place the ``saveopts`` command on the +command line; it will still save all the options specified for all commands. +For example, this is another valid way to spell the last example:: + + setup.py saveopts -g build --compiler=mingw32 + +Note, however, that all of the commands specified are always run, regardless of +where ``saveopts`` is placed on the command line. + + +Configuration File Options +-------------------------- + +Normally, settings such as options and aliases are saved to the project's +local ``setup.cfg`` file. But you can override this and save them to the +global or per-user configuration files, or to a manually-specified filename. + +``--global-config, -g`` + Save settings to the global ``distutils.cfg`` file inside the ``distutils`` + package directory. You must have write access to that directory to use + this option. You also can't combine this option with ``-u`` or ``-f``. + +``--user-config, -u`` + Save settings to the current user's ``~/.pydistutils.cfg`` (POSIX) or + ``$HOME/pydistutils.cfg`` (Windows) file. You can't combine this option + with ``-g`` or ``-f``. + +``--filename=FILENAME, -f FILENAME`` + Save settings to the specified configuration file to use. You can't + combine this option with ``-g`` or ``-u``. Note that if you specify a + non-standard filename, the ``distutils`` and ``setuptools`` will not + use the file's contents. This option is mainly included for use in + testing. + +These options are used by other ``setuptools`` commands that modify +configuration files, such as the `alias`_ and `setopt`_ commands. + + +.. _setopt: + +``setopt`` - Set a distutils or setuptools option in a config file +================================================================== + +This command is mainly for use by scripts, but it can also be used as a quick +and dirty way to change a distutils configuration option without having to +remember what file the options are in and then open an editor. + +**Example 1**. Set the default C compiler to ``mingw32`` (using long option +names):: + + setup.py setopt --command=build --option=compiler --set-value=mingw32 + +**Example 2**. Remove any setting for the distutils default package +installation directory (short option names):: + + setup.py setopt -c install -o install_lib -r + + +Options for the ``setopt`` command: + +``--command=COMMAND, -c COMMAND`` + Command to set the option for. This option is required. + +``--option=OPTION, -o OPTION`` + The name of the option to set. This option is required. + +``--set-value=VALUE, -s VALUE`` + The value to set the option to. Not needed if ``-r`` or ``--remove`` is + set. + +``--remove, -r`` + Remove (unset) the option, instead of setting it. + +In addition to the above options, you may use any of the `configuration file +options`_ (listed under the `saveopts`_ command, above) to determine which +distutils configuration file the option will be added to (or removed from). + + +.. _test: + +``test`` - Build package and run a unittest suite +================================================= + +When doing test-driven development, or running automated builds that need +testing before they are deployed for downloading or use, it's often useful +to be able to run a project's unit tests without actually deploying the project +anywhere, even using the ``develop`` command. The ``test`` command runs a +project's unit tests without actually deploying it, by temporarily putting the +project's source on ``sys.path``, after first running ``build_ext -i`` and +``egg_info`` to ensure that any C extensions and project metadata are +up-to-date. + +To use this command, your project's tests must be wrapped in a ``unittest`` +test suite by either a function, a ``TestCase`` class or method, or a module +or package containing ``TestCase`` classes. If the named suite is a module, +and the module has an ``additional_tests()`` function, it is called and the +result (which must be a ``unittest.TestSuite``) is added to the tests to be +run. If the named suite is a package, any submodules and subpackages are +recursively added to the overall test suite. (Note: if your project specifies +a ``test_loader``, the rules for processing the chosen ``test_suite`` may +differ; see the `test_loader`_ documentation for more details.) + +Note that many test systems including ``doctest`` support wrapping their +non-``unittest`` tests in ``TestSuite`` objects. So, if you are using a test +package that does not support this, we suggest you encourage its developers to +implement test suite support, as this is a convenient and standard way to +aggregate a collection of tests to be run under a common test harness. + +By default, tests will be run in the "verbose" mode of the ``unittest`` +package's text test runner, but you can get the "quiet" mode (just dots) if +you supply the ``-q`` or ``--quiet`` option, either as a global option to +the setup script (e.g. ``setup.py -q test``) or as an option for the ``test`` +command itself (e.g. ``setup.py test -q``). There is one other option +available: + +``--test-suite=NAME, -s NAME`` + Specify the test suite (or module, class, or method) to be run + (e.g. ``some_module.test_suite``). The default for this option can be + set by giving a ``test_suite`` argument to the ``setup()`` function, e.g.:: + + setup( + # ... + test_suite = "my_package.tests.test_all" + ) + + If you did not set a ``test_suite`` in your ``setup()`` call, and do not + provide a ``--test-suite`` option, an error will occur. + + +.. _upload: + +``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. + +``--repository=URL, -r URL`` + The URL of the repository to upload to. Defaults to + http://pypi.python.org/pypi (i.e., the main PyPI installation). + +.. _upload_docs: + +``upload_docs`` - Upload package documentation to PyPI +====================================================== + +PyPI now supports uploading project documentation to the dedicated URL +http://packages.python.org/<project>/. + +The ``upload_docs`` command will create the necessary zip file out of a +documentation directory and will post to the repository. + +Note that to upload the documentation of a project, the corresponding version +must already be registered with PyPI, using the distutils ``register`` +command -- just like the ``upload`` command. + +Assuming there is an ``Example`` project with documentation in the +subdirectory ``docs``, e.g.:: + + Example/ + |-- example.py + |-- setup.cfg + |-- setup.py + |-- docs + | |-- build + | | `-- html + | | | |-- index.html + | | | `-- tips_tricks.html + | |-- conf.py + | |-- index.txt + | `-- tips_tricks.txt + +You can simply pass the documentation directory path to the ``upload_docs`` +command:: + + python setup.py upload_docs --upload-dir=docs/build/html + +If no ``--upload-dir`` is given, ``upload_docs`` will attempt to run the +``build_sphinx`` command to generate uploadable documentation. +For the command to become available, `Sphinx <http://sphinx.pocoo.org/>`_ +must be installed in the same environment as distribute. + +As with other ``setuptools``-based commands, you can define useful +defaults in the ``setup.cfg`` of your Python project, e.g.: + +.. code-block:: ini + + [upload_docs] + upload-dir = docs/build/html + +The ``upload_docs`` command has the following options: + +``--upload-dir`` + The directory to be uploaded to the repository. + +``--show-response`` + Display the full response text from server; this is useful for debugging + PyPI problems. + +``--repository=URL, -r URL`` + The URL of the repository to upload to. Defaults to + http://pypi.python.org/pypi (i.e., the main PyPI installation). + + +-------------------------------- +Extending and Reusing Distribute +-------------------------------- + +Creating ``distutils`` Extensions +================================= + +It can be hard to add new commands or setup arguments to the distutils. But +the ``setuptools`` package makes it a bit easier, by allowing you to distribute +a distutils extension as a separate project, and then have projects that need +the extension just refer to it in their ``setup_requires`` argument. + +With ``setuptools``, your distutils extension projects can hook in new +commands and ``setup()`` arguments just by defining "entry points". These +are mappings from command or argument names to a specification of where to +import a handler from. (See the section on `Dynamic Discovery of Services and +Plugins`_ above for some more background on entry points.) + + +Adding Commands +--------------- + +You can add new ``setup`` commands by defining entry points in the +``distutils.commands`` group. For example, if you wanted to add a ``foo`` +command, you might add something like this to your distutils extension +project's setup script:: + + setup( + # ... + entry_points = { + "distutils.commands": [ + "foo = mypackage.some_module:foo", + ], + }, + ) + +(Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is +a ``setuptools.Command`` subclass.) + +Once a project containing such entry points has been activated on ``sys.path``, +(e.g. by running "install" or "develop" with a site-packages installation +directory) the command(s) will be available to any ``setuptools``-based setup +scripts. It is not necessary to use the ``--command-packages`` option or +to monkeypatch the ``distutils.command`` package to install your commands; +``setuptools`` automatically adds a wrapper to the distutils to search for +entry points in the active distributions on ``sys.path``. In fact, this is +how setuptools' own commands are installed: the setuptools project's setup +script defines entry points for them! + + +Adding ``setup()`` Arguments +---------------------------- + +Sometimes, your commands may need additional arguments to the ``setup()`` +call. You can enable this by defining entry points in the +``distutils.setup_keywords`` group. For example, if you wanted a ``setup()`` +argument called ``bar_baz``, you might add something like this to your +distutils extension project's setup script:: + + setup( + # ... + entry_points = { + "distutils.commands": [ + "foo = mypackage.some_module:foo", + ], + "distutils.setup_keywords": [ + "bar_baz = mypackage.some_module:validate_bar_baz", + ], + }, + ) + +The idea here is that the entry point defines a function that will be called +to validate the ``setup()`` argument, if it's supplied. The ``Distribution`` +object will have the initial value of the attribute set to ``None``, and the +validation function will only be called if the ``setup()`` call sets it to +a non-None value. Here's an example validation function:: + + 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) + ) + +Your function should accept three arguments: the ``Distribution`` object, +the attribute name, and the attribute value. It should raise a +``DistutilsSetupError`` (from the ``distutils.errors`` module) if the argument +is invalid. Remember, your function will only be called with non-None values, +and the default value of arguments defined this way is always None. So, your +commands should always be prepared for the possibility that the attribute will +be ``None`` when they access it later. + +If more than one active distribution defines an entry point for the same +``setup()`` argument, *all* of them will be called. This allows multiple +distutils extensions to define a common argument, as long as they agree on +what values of that argument are valid. + +Also note that as with commands, it is not necessary to subclass or monkeypatch +the distutils ``Distribution`` class in order to add your arguments; it is +sufficient to define the entry points in your extension, as long as any setup +script using your extension lists your project in its ``setup_requires`` +argument. + + +Adding new EGG-INFO Files +------------------------- + +Some extensible applications or frameworks may want to allow third parties to +develop plugins with application or framework-specific metadata included in +the plugins' EGG-INFO directory, for easy access via the ``pkg_resources`` +metadata API. The easiest way to allow this is to create a distutils extension +to be used from the plugin projects' setup scripts (via ``setup_requires``) +that defines a new setup keyword, and then uses that data to write an EGG-INFO +file when the ``egg_info`` command is run. + +The ``egg_info`` command looks for extension points in an ``egg_info.writers`` +group, and calls them to write the files. Here's a simple example of a +distutils extension defining a setup argument ``foo_bar``, which is a list of +lines that will be written to ``foo_bar.txt`` in the EGG-INFO directory of any +project that uses the argument:: + + setup( + # ... + entry_points = { + "distutils.setup_keywords": [ + "foo_bar = setuptools.dist:assert_string_list", + ], + "egg_info.writers": [ + "foo_bar.txt = setuptools.command.egg_info:write_arg", + ], + }, + ) + +This simple example makes use of two utility functions defined by setuptools +for its own use: a routine to validate that a setup keyword is a sequence of +strings, and another one that looks up a setup argument and writes it to +a file. Here's what the writer utility looks like:: + + def write_arg(cmd, basename, filename): + argname = os.path.splitext(basename)[0] + value = getattr(cmd.distribution, argname, None) + if value is not None: + value = '\n'.join(value)+'\n' + cmd.write_or_delete_file(argname, filename, value) + +As you can see, ``egg_info.writers`` entry points must be a function taking +three arguments: a ``egg_info`` command instance, the basename of the file to +write (e.g. ``foo_bar.txt``), and the actual full filename that should be +written to. + +In general, writer functions should honor the command object's ``dry_run`` +setting when writing files, and use the ``distutils.log`` object to do any +console output. The easiest way to conform to this requirement is to use +the ``cmd`` object's ``write_file()``, ``delete_file()``, and +``write_or_delete_file()`` methods exclusively for your file operations. See +those methods' docstrings for more details. + + +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 +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 +are under revision control. + +For example, if you were going to create a plugin for a revision control system +called "foobar", you would write a function something like this: + +.. code-block:: python + + def find_files_for_foobar(dirname): + # loop to yield paths that start with `dirname` + +And you would register it in a setup script using something like this:: + + entry_points = { + "setuptools.file_finders": [ + "foobar = my_foobar_module:find_files_for_foobar" + ] + } + +Then, anyone who wants to use your plugin can simply install it, and their +local setuptools installation will be able to find the necessary files. + +It is not necessary to distribute source control plugins with projects that +simply use the other source control system, or to specify the plugins in +``setup_requires``. When you create a source distribution with the ``sdist`` +command, setuptools automatically records what files were found in the +``SOURCES.txt`` file. That way, recipients of source distributions don't need +to have revision control at all. However, if someone is working on a package +by checking out with that system, they will need the same plugin(s) that the +original author is using. + +A few important points for writing revision control file finders: + +* Your finder function MUST return relative paths, created by appending to the + passed-in directory name. Absolute paths are NOT allowed, nor are relative + paths that reference a parent directory of the passed-in directory. + +* Your finder function MUST accept an empty string as the directory name, + meaning the current directory. You MUST NOT convert this to a dot; just + yield relative paths. So, yielding a subdirectory named ``some/dir`` under + the current directory should NOT be rendered as ``./some/dir`` or + ``/somewhere/some/dir``, but *always* as simply ``some/dir`` + +* Your finder function SHOULD NOT raise any errors, and SHOULD deal gracefully + with the absence of needed programs (i.e., ones belonging to the revision + control system itself. It *may*, however, use ``distutils.log.warn()`` to + inform the user of the missing program(s). + + +Subclassing ``Command`` +----------------------- + +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 <setuptools?action=subscribe>`_ to see when new documentation is +added or updated. + +XXX + + +Reusing ``setuptools`` Code +=========================== + +``distribute_setup`` +-------------------- + +XXX + + +``setuptools.archive_util`` +--------------------------- + +XXX + + +``setuptools.sandbox`` +---------------------- + +XXX + + +``setuptools.package_index`` +---------------------------- + +XXX + +History +======= + +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`_ above 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. + +Mailing List and Bug Tracker +============================ + +Please use the `distutils-sig mailing list`_ for questions and discussion about +setuptools, and the `setuptools bug tracker`_ ONLY for issues you have +confirmed via the list are actual bugs, and which you have reduced to a minimal +set of steps to reproduce. + +.. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ +.. _setuptools bug tracker: http://bugs.python.org/setuptools/ + diff --git a/vendor/distribute-0.6.35/docs/using.txt b/vendor/distribute-0.6.35/docs/using.txt new file mode 100644 index 00000000..192f1dc2 --- /dev/null +++ b/vendor/distribute-0.6.35/docs/using.txt @@ -0,0 +1,21 @@ +================================ +Using Distribute in your project +================================ + +To use Distribute in your project, the recommended way is to ship +`distribute_setup.py` alongside your `setup.py` script and call +it at the very begining of `setup.py` like this:: + + from distribute_setup import use_setuptools + use_setuptools() + +Another way is to add ``Distribute`` in the ``install_requires`` option:: + + from setuptools import setup + + setup(... + install_requires=['distribute'] + ) + + +XXX to be finished diff --git a/vendor/distribute-0.6.35/easy_install.py b/vendor/distribute-0.6.35/easy_install.py new file mode 100644 index 00000000..d87e9840 --- /dev/null +++ b/vendor/distribute-0.6.35/easy_install.py @@ -0,0 +1,5 @@ +"""Run the EasyInstall command""" + +if __name__ == '__main__': + from setuptools.command.easy_install import main + main() diff --git a/vendor/distribute-0.6.35/launcher.c b/vendor/distribute-0.6.35/launcher.c new file mode 100644 index 00000000..ea4c80b5 --- /dev/null +++ b/vendor/distribute-0.6.35/launcher.c @@ -0,0 +1,327 @@ +/* Setuptools Script Launcher for Windows + + This is a stub executable for Windows that functions somewhat like + Effbot's "exemaker", in that it runs a script with the same name but + a .py extension, using information from a #! line. It differs in that + it spawns the actual Python executable, rather than attempting to + hook into the Python DLL. This means that the script will run with + sys.executable set to the Python executable, where exemaker ends up with + sys.executable pointing to itself. (Which means it won't work if you try + to run another Python process using sys.executable.) + + To build/rebuild with mingw32, do this in the setuptools project directory: + + gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c + gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c + + It links to msvcrt.dll, but this shouldn't be a problem since it doesn't + actually run Python in the same process. Note that using 'exec' instead + of 'spawn' doesn't work, because on Windows this leads to the Python + executable running in the *background*, attached to the same console + window, meaning you get a command prompt back *before* Python even finishes + starting. So, we have to use spawnv() and wait for Python to exit before + continuing. :( +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <windows.h> +#include <tchar.h> +#include <fcntl.h> + +int child_pid=0; + +int fail(char *format, char *data) { + /* Print error message to stderr and return 2 */ + fprintf(stderr, format, data); + return 2; +} + +char *quoted(char *data) { + int i, ln = strlen(data), nb; + + /* We allocate twice as much space as needed to deal with worse-case + of having to escape everything. */ + char *result = calloc(ln*2+3, sizeof(char)); + char *presult = result; + + *presult++ = '"'; + for (nb=0, i=0; i < ln; i++) + { + if (data[i] == '\\') + nb += 1; + else if (data[i] == '"') + { + for (; nb > 0; nb--) + *presult++ = '\\'; + *presult++ = '\\'; + } + else + nb = 0; + *presult++ = data[i]; + } + + for (; nb > 0; nb--) /* Deal w trailing slashes */ + *presult++ = '\\'; + + *presult++ = '"'; + *presult++ = 0; + return result; +} + + + + + + + + + + +char *loadable_exe(char *exename) { + /* HINSTANCE hPython; DLL handle for python executable */ + char *result; + + /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hPython) return NULL; */ + + /* Return the absolute filename for spawnv */ + result = calloc(MAX_PATH, sizeof(char)); + strncpy(result, exename, MAX_PATH); + /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH); + + FreeLibrary(hPython); */ + return result; +} + + +char *find_exe(char *exename, char *script) { + char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; + char path[_MAX_PATH], c, *result; + + /* convert slashes to backslashes for uniform search below */ + result = exename; + while (c = *result++) if (c=='/') result[-1] = '\\'; + + _splitpath(exename, drive, dir, fname, ext); + if (drive[0] || dir[0]=='\\') { + return loadable_exe(exename); /* absolute path, use directly */ + } + /* Use the script's parent directory, which should be the Python home + (This should only be used for bdist_wininst-installed scripts, because + easy_install-ed scripts use the absolute path to python[w].exe + */ + _splitpath(script, drive, dir, fname, ext); + result = dir + strlen(dir) -1; + if (*result == '\\') result--; + while (*result != '\\' && result>=dir) *result-- = 0; + _makepath(path, drive, dir, exename, NULL); + return loadable_exe(path); +} + + +char **parse_argv(char *cmdline, int *argc) +{ + /* Parse a command line in-place using MS C rules */ + + char **result = calloc(strlen(cmdline), sizeof(char *)); + char *output = cmdline; + char c; + int nb = 0; + int iq = 0; + *argc = 0; + + result[0] = output; + while (isspace(*cmdline)) cmdline++; /* skip leading spaces */ + + do { + c = *cmdline++; + if (!c || (isspace(c) && !iq)) { + while (nb) {*output++ = '\\'; nb--; } + *output++ = 0; + result[++*argc] = output; + if (!c) return result; + while (isspace(*cmdline)) cmdline++; /* skip leading spaces */ + if (!*cmdline) return result; /* avoid empty arg if trailing ws */ + continue; + } + if (c == '\\') + ++nb; /* count \'s */ + else { + if (c == '"') { + if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */ + nb = nb >> 1; /* cut \'s in half */ + } + while (nb) {*output++ = '\\'; nb--; } + if (c) *output++ = c; + } + } while (1); +} + +void pass_control_to_child(DWORD control_type) { + /* + * distribute-issue207 + * passes the control event to child process (Python) + */ + if (!child_pid) { + return; + } + GenerateConsoleCtrlEvent(child_pid,0); +} + +BOOL control_handler(DWORD control_type) { + /* + * distribute-issue207 + * control event handler callback function + */ + switch (control_type) { + case CTRL_C_EVENT: + pass_control_to_child(0); + break; + } + return TRUE; +} + +int create_and_wait_for_subprocess(char* command) { + /* + * distribute-issue207 + * launches child process (Python) + */ + DWORD return_value = 0; + LPSTR commandline = command; + STARTUPINFOA s_info; + PROCESS_INFORMATION p_info; + ZeroMemory(&p_info, sizeof(p_info)); + ZeroMemory(&s_info, sizeof(s_info)); + s_info.cb = sizeof(STARTUPINFO); + // set-up control handler callback funciotn + SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE); + if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) { + fprintf(stderr, "failed to create process.\n"); + return 0; + } + child_pid = p_info.dwProcessId; + // wait for Python to exit + WaitForSingleObject(p_info.hProcess, INFINITE); + if (!GetExitCodeProcess(p_info.hProcess, &return_value)) { + fprintf(stderr, "failed to get exit code from process.\n"); + return 0; + } + return return_value; +} + +char* join_executable_and_args(char *executable, char **args, int argc) +{ + /* + * distribute-issue207 + * CreateProcess needs a long string of the executable and command-line arguments, + * so we need to convert it from the args that was built + */ + int len,counter; + char* cmdline; + + len=strlen(executable)+2; + for (counter=1; counter<argc; counter++) { + len+=strlen(args[counter])+1; + } + + cmdline = (char*)calloc(len, sizeof(char)); + sprintf(cmdline, "%s", executable); + len=strlen(executable); + for (counter=1; counter<argc; counter++) { + sprintf(cmdline+len, " %s", args[counter]); + len+=strlen(args[counter])+1; + } + return cmdline; +} + +int run(int argc, char **argv, int is_gui) { + + char python[256]; /* python executable's filename*/ + char *pyopt; /* Python option */ + char script[256]; /* the script's filename */ + + int scriptf; /* file descriptor for script file */ + + char **newargs, **newargsp, **parsedargs; /* argument array for exec */ + char *ptr, *end; /* working pointers for string manipulation */ + char *cmdline; + int i, parsedargc; /* loop counter */ + + /* compute script name from our .exe name*/ + GetModuleFileNameA(NULL, script, sizeof(script)); + end = script + strlen(script); + while( end>script && *end != '.') + *end-- = '\0'; + *end-- = '\0'; + strcat(script, (GUI ? "-script.pyw" : "-script.py")); + + /* figure out the target python executable */ + + scriptf = open(script, O_RDONLY); + if (scriptf == -1) { + return fail("Cannot open %s\n", script); + } + end = python + read(scriptf, python, sizeof(python)); + close(scriptf); + + ptr = python-1; + while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;} + + *ptr-- = '\0'; + + if (strncmp(python, "#!", 2)) { + /* default to python.exe if no #! header */ + strcpy(python, "#!python.exe"); + } + + parsedargs = parse_argv(python+2, &parsedargc); + + /* Using spawnv() can fail strangely if you e.g. find the Cygwin + Python, so we'll make sure Windows can find and load it */ + + ptr = find_exe(parsedargs[0], script); + if (!ptr) { + return fail("Cannot find Python executable %s\n", parsedargs[0]); + } + + /* printf("Python executable: %s\n", ptr); */ + + /* Argument array needs to be + parsedargc + argc, plus 1 for null sentinel */ + + newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *)); + newargsp = newargs; + + *newargsp++ = quoted(ptr); + for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]); + + *newargsp++ = quoted(script); + for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]); + + *newargsp++ = NULL; + + /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */ + + if (is_gui) { + /* Use exec, we don't need to wait for the GUI to finish */ + execv(ptr, (const char * const *)(newargs)); + return fail("Could not exec %s", ptr); /* shouldn't get here! */ + } + + /* + * distribute-issue207: using CreateProcessA instead of spawnv + */ + cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc); + return create_and_wait_for_subprocess(cmdline); +} + +int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) { + return run(__argc, __argv, GUI); +} + +int main(int argc, char** argv) { + return run(argc, argv, GUI); +} + diff --git a/vendor/distribute-0.6.35/pkg_resources.py b/vendor/distribute-0.6.35/pkg_resources.py new file mode 100644 index 00000000..69601480 --- /dev/null +++ b/vendor/distribute-0.6.35/pkg_resources.py @@ -0,0 +1,2827 @@ +"""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, os, zipimport, time, re, imp, types +from urlparse import urlparse, urlunparse + +try: + frozenset +except NameError: + from sets import ImmutableSet as frozenset + +# 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 + +# This marker is used to simplify the process that checks is the +# setuptools package was installed by the Setuptools project +# or by the Distribute project, in case Setuptools creates +# a distribution with the same version. +# +# The bootstrapping script for instance, will check if this +# attribute is present to decide wether to reinstall the package +_distribute = True + +def _bypass_ensure_directory(name, mode=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): + g = globals() + for name, val in kw.iteritems(): + g[name] = val + _state_vars[name] = vartype + +def __getstate__(): + state = {} + g = globals() + for k, v in _state_vars.iteritems(): + state[k] = g['_sget_'+v](g[k]) + return state + +def __setstate__(state): + g = globals() + for k, v in state.iteritems(): + 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', + + # 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: + from distutils.util import get_platform + except ImportError: + from sysconfig 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) + + + 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): + """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. 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 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, replacement=True): + """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``. + """ + + 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 _override_setuptools(req) and replacement: + req = Requirement.parse('distribute') + + 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: + if env is None: + env = Environment(self.entries) + dist = best[req.key] = env.best_match(req, self, 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__([]) + 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: + 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: + 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, (entries, keys, by_key, callbacks)): + 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. ``'2.4'``); + 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.cached_files[target_path] = 1 + return target_path + + + + + + + + + + + + + + + + + + + + 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) | 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 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 StringIO(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 in 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() + + + + +class ZipProvider(EggProvider): + """Resource support for zips and eggs""" + + eagers = None + + def __init__(self, module): + EggProvider.__init__(self,module) + self.zipinfo = zipimport._zip_directory_cache[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) + + 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 + + zip_stat = self.zipinfo[zip_path] + t,d,size = zip_stat[5], zip_stat[6], zip_stat[3] + date_time = ( + (d>>9)+1980, (d>>5)&0xF, d&0x1F, # ymd + (t&0xFFFF)>>11, (t>>5)&0x3F, (t&0x1F) * 2, 0, 0, -1 # hms, etc. + ) + timestamp = time.mktime(date_time) + + try: + if not WRITE_SUPPORT: + raise IOError('"os.rename" and "os.unlink" are not supported ' + 'on this platform') + + real_path = manager.get_cache_path( + self.egg_name, self._parts(zip_path) + ) + + if os.path.isfile(real_path): + stat = os.stat(real_path) + if stat.st_size==size and stat.st_mtime==timestamp: + # size and stamp match, don't bother extracting + 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): + stat = os.stat(real_path) + + if stat.st_size==size and stat.st_mtime==timestamp: + # size and stamp match, somebody did it just ahead of + # us, so we're done + 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 _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 = zipimport._zip_directory_cache[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() + + +class ImpWrapper: + """PEP 302 Importer that wraps Python's "normal" import algorithm""" + + def __init__(self, path=None): + self.path = path + + def find_module(self, fullname, path=None): + subname = fullname.split(".")[-1] + if subname != fullname and self.path is None: + return None + if self.path is None: + path = None + else: + path = [self.path] + try: + file, filename, etc = imp.find_module(subname, path) + except ImportError: + return None + return ImpLoader(file, filename, etc) + + +class ImpLoader: + """PEP 302 Loader that wraps Python's "normal" import algorithm""" + + def __init__(self, file, filename, etc): + self.file = file + self.filename = filename + self.etc = etc + + def load_module(self, fullname): + try: + mod = imp.load_module(fullname, self.file, self.filename, self.etc) + finally: + if self.file: self.file.close() + # Note: we don't set __loader__ because we want the module to look + # normal; i.e. this is just a wrapper for standard import machinery + return mod + + + + +def get_importer(path_item): + """Retrieve a PEP 302 "importer" for the given path item + + If there is no importer, this returns a wrapper around the builtin import + machinery. The returned importer is only cached if it was created by a + path hook. + """ + try: + importer = sys.path_importer_cache[path_item] + except KeyError: + for hook in sys.path_hooks: + try: + importer = hook(path_item) + except ImportError: + pass + else: + break + else: + importer = None + + sys.path_importer_cache.setdefault(path_item,importer) + if importer is None: + try: + importer = ImpWrapper(path_item) + except ImportError: + pass + return importer + +try: + from pkgutil import get_importer, ImpImporter +except ImportError: + pass # Python 2.3 or 2.4, use our own implementation +else: + ImpWrapper = ImpImporter # Python 2.5, use pkgutil's implementation + del ImpLoader, ImpImporter + + + + + + +_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_in_zip(importer, path_item, only=False): + 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_in_zip(zipimport.zipimporter(subpath), subpath): + yield dist + +register_finder(zipimport.zipimporter, find_in_zip) + +def StringIO(*args, **kw): + """Thunk to load the real StringIO on demand""" + global StringIO + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + return StringIO(*args,**kw) + +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(ImpWrapper,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] = 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); module.__path__ = path + 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(ImpWrapper,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<name>[^-]+)" + r"( -(?P<ver>[^-]+) (-py(?P<pyver>[^-]+) (-(?P<plat>.+))? )? )?", + 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) + 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) + + parse = classmethod(parse) + + + + + + + + + #@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 + + parse_group = classmethod(parse_group) + + #@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 + + parse_map = classmethod(parse_map) + + +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 + ) + from_location = classmethod(from_location) + + + 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 + key = property(key) + + #@property + def parsed_version(self): + try: + return self._parsed_version + except AttributeError: + self._parsed_version = pv = parse_version(self.version) + return pv + + parsed_version = property(parsed_version) + + #@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 + ) + version = property(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: extra = safe_extra(extra) + dm.setdefault(extra,[]).extend(parse_requirements(reqs)) + return dm + _dep_map = property(_dep_map) + + 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) + map(declare_namespace, self._get_metadata('namespace_packages.txt')) + + + 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 + ) + from_filename = classmethod(from_filename) + + 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 self.project_name == 'setuptools': + try: + version = self.version + except ValueError: + version = '' + if '0.7' in version: + raise ValueError( + "A 0.7-series setuptools cannot be installed " + "with distribute. Found one at %s" % str(self.location)) + + if not loc: + return + + if path is sys.path: + self.check_version_conflict() + + nloc = _normalize_cached(loc) + bdir = os.path.dirname(nloc) + npath= map(_normalize_cached, path) + + bp = None + 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 + path.insert(p, loc) + npath.insert(p, nloc) + break + else: + 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=='distribute': + 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] + extras = property(extras) + + +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 = parse_requirements(distvers).next() + 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 = lines.next(); 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, replacement=True): + reqs = list(parse_requirements(s)) + if reqs: + if len(reqs) == 1: + founded_req = reqs[0] + # if asked for setuptools distribution + # and if distribute is installed, we want to give + # distribute instead + if _override_setuptools(founded_req) and replacement: + distribute = list(parse_requirements('distribute')) + if len(distribute) == 1: + return distribute[0] + return founded_req + else: + return founded_req + + raise ValueError("Expected only one requirement", s) + raise ValueError("No requirements found", s) + + parse = staticmethod(parse) + +state_machine = { + # =>< + '<' : '--T', + '<=': 'T-T', + '>' : 'F+F', + '>=': 'T+F', + '==': 'T..', + '!=': 'F++', +} + + +def _override_setuptools(req): + """Return True when distribute wants to override a setuptools dependency. + + We want to override when the requirement is setuptools and the version is + a variant of 0.6. + + """ + if req.project_name == 'setuptools': + if not len(req.specs): + # Just setuptools: ok + return True + for comparator, version in req.specs: + if comparator in ['==', '>=', '>']: + if '0.7' in version: + # We want some setuptools not from the 0.6 series. + return False + return True + return False + + +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 +_declare_state('object', working_set = WorkingSet()) + +try: + # Does the main program list any requirements? + from __main__ import __requires__ +except ImportError: + pass # No: just use the default working set based on sys.path +else: + # Yes: ensure the requirements are met, by prefixing sys.path if necessary + try: + working_set.require(__requires__) + except VersionConflict: # try it without defaults already on sys.path + working_set = WorkingSet([]) # by starting with an empty path + for dist in working_set.resolve( + parse_requirements(__requires__), Environment() + ): + working_set.add(dist) + for entry in sys.path: # add any missing entries from sys.path + if entry not in working_set.entries: + working_set.add_entry(entry) + sys.path[:] = working_set.entries # then copy back to sys.path + +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=[]; map(working_set.add_entry,sys.path) # match order + diff --git a/vendor/distribute-0.6.35/release.py b/vendor/distribute-0.6.35/release.py new file mode 100644 index 00000000..98370304 --- /dev/null +++ b/vendor/distribute-0.6.35/release.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python + +""" +Script to fully automate the release process. Requires Python 2.6+ +with sphinx installed and the 'hg' command on the path. +""" + +from __future__ import print_function + +import subprocess +import shutil +import os +import sys +import urllib2 +import getpass +import collections + +try: + import keyring +except Exception: + pass + +VERSION = '0.6.35' + +def get_next_version(): + digits = map(int, VERSION.split('.')) + digits[-1] += 1 + return '.'.join(map(str, digits)) + +NEXT_VERSION = get_next_version() + +files_with_versions = ('docs/conf.py', 'setup.py', 'release.py', + 'README.txt', 'distribute_setup.py') + +def get_repo_name(): + """ + Get the repo name from the hgrc default path. + """ + default = subprocess.check_output('hg paths default').strip() + parts = default.split('/') + if parts[-1] == '': + parts.pop() + return '/'.join(parts[-2:]) + +def get_mercurial_creds(system='https://bitbucket.org', username=None): + """ + Return named tuple of username,password in much the same way that + Mercurial would (from the keyring). + """ + # todo: consider getting this from .hgrc + username = username or getpass.getuser() + keyring_username = '@@'.join((username, system)) + system = '@'.join((keyring_username, 'Mercurial')) + password = ( + keyring.get_password(system, keyring_username) + if 'keyring' in globals() + else None + ) + if not password: + password = getpass.getpass() + Credential = collections.namedtuple('Credential', 'username password') + return Credential(username, password) + +def add_milestone_and_version(version=NEXT_VERSION): + auth = 'Basic ' + ':'.join(get_mercurial_creds()).encode('base64').strip() + headers = { + 'Authorization': auth, + } + base = 'https://api.bitbucket.org' + for type in 'milestones', 'versions': + url = (base + '/1.0/repositories/{repo}/issues/{type}' + .format(repo = get_repo_name(), type=type)) + req = urllib2.Request(url = url, headers = headers, + data='name='+version) + try: + urllib2.urlopen(req) + except urllib2.HTTPError as e: + print(e.fp.read()) + +def bump_versions(): + list(map(bump_version, files_with_versions)) + +def bump_version(filename): + with open(filename, 'rb') as f: + lines = [line.replace(VERSION, NEXT_VERSION) for line in f] + with open(filename, 'wb') as f: + f.writelines(lines) + +def do_release(): + assert all(map(os.path.exists, files_with_versions)), ( + "Expected file(s) missing") + + assert has_sphinx(), "You must have Sphinx installed to release" + + res = raw_input('Have you read through the SCM changelog and ' + 'confirmed the changelog is current for releasing {VERSION}? ' + .format(**globals())) + if not res.lower().startswith('y'): + print("Please do that") + raise SystemExit(1) + + print("Travis-CI tests: http://travis-ci.org/#!/jaraco/distribute") + res = raw_input('Have you or has someone verified that the tests ' + 'pass on this revision? ') + if not res.lower().startswith('y'): + print("Please do that") + raise SystemExit(2) + + subprocess.check_call(['hg', 'tag', VERSION]) + + subprocess.check_call(['hg', 'update', VERSION]) + + has_docs = build_docs() + if os.path.isdir('./dist'): + shutil.rmtree('./dist') + cmd = [sys.executable, 'setup.py', '-q', 'egg_info', '-RD', '-b', '', + 'sdist', 'register', 'upload'] + if has_docs: + cmd.append('upload_docs') + subprocess.check_call(cmd) + upload_bootstrap_script() + + # update to the tip for the next operation + subprocess.check_call(['hg', 'update']) + + # we just tagged the current version, bump for the next release. + bump_versions() + subprocess.check_call(['hg', 'ci', '-m', + 'Bumped to {NEXT_VERSION} in preparation for next ' + 'release.'.format(**globals())]) + + # push the changes + subprocess.check_call(['hg', 'push']) + + add_milestone_and_version() + +def has_sphinx(): + try: + devnull = open(os.path.devnull, 'wb') + subprocess.Popen(['sphinx-build', '--version'], stdout=devnull, + stderr=subprocess.STDOUT).wait() + except Exception: + return False + return True + +def build_docs(): + if not os.path.isdir('docs'): + return + if os.path.isdir('docs/build'): + shutil.rmtree('docs/build') + subprocess.check_call([ + 'sphinx-build', + '-b', 'html', + '-d', 'build/doctrees', + '.', + 'build/html', + ], + cwd='docs') + return True + +def upload_bootstrap_script(): + scp_command = 'pscp' if sys.platform.startswith('win') else 'scp' + try: + subprocess.check_call([scp_command, 'distribute_setup.py', + 'pypi@ziade.org:python-distribute.org/']) + except: + print("Unable to upload bootstrap script. Ask Tarek to do it.") + +if __name__ == '__main__': + do_release() diff --git a/vendor/distribute-0.6.35/setup.cfg b/vendor/distribute-0.6.35/setup.cfg new file mode 100644 index 00000000..319f9412 --- /dev/null +++ b/vendor/distribute-0.6.35/setup.cfg @@ -0,0 +1,21 @@ +[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 + diff --git a/vendor/distribute-0.6.35/setup.py b/vendor/distribute-0.6.35/setup.py new file mode 100644 index 00000000..cecb9e9f --- /dev/null +++ b/vendor/distribute-0.6.35/setup.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python +"""Distutils setup file, used to install or test 'setuptools'""" +import sys +import os +import textwrap +import re + +# Allow to run setup.py from another directory. +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +src_root = None +if sys.version_info >= (3,): + tmp_src = os.path.join("build", "src") + from distutils.filelist import FileList + from distutils import dir_util, file_util, util, log + log.set_verbosity(1) + fl = FileList() + manifest_file = open("MANIFEST.in") + for line in manifest_file: + fl.process_template_line(line) + manifest_file.close() + dir_util.create_tree(tmp_src, fl.files) + outfiles_2to3 = [] + dist_script = os.path.join("build", "src", "distribute_setup.py") + for f in fl.files: + outf, copied = file_util.copy_file(f, os.path.join(tmp_src, f), update=1) + if copied and outf.endswith(".py") and outf != dist_script: + outfiles_2to3.append(outf) + if copied and outf.endswith('api_tests.txt'): + # XXX support this in distutils as well + from lib2to3.main import main + main('lib2to3.fixes', ['-wd', os.path.join(tmp_src, 'tests', 'api_tests.txt')]) + + util.run_2to3(outfiles_2to3) + + # arrange setup to use the copy + sys.path.insert(0, os.path.abspath(tmp_src)) + src_root = tmp_src + +from distutils.util import convert_path + +d = {} +init_path = convert_path('setuptools/command/__init__.py') +init_file = open(init_path) +exec(init_file.read(), d) +init_file.close() + +SETUP_COMMANDS = d['__all__'] +VERSION = "0.6.35" + +from setuptools import setup, find_packages +from setuptools.command.build_py import build_py as _build_py +from setuptools.command.test import test as _test + +scripts = [] + +console_scripts = ["easy_install = setuptools.command.easy_install:main"] +if os.environ.get("DISTRIBUTE_DISABLE_VERSIONED_EASY_INSTALL_SCRIPT") is None: + console_scripts.append("easy_install-%s = setuptools.command.easy_install:main" % sys.version[:3]) + +# 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""" + lastdir = None + 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) + + # avoid a bootstrapping issue with easy_install -U (when the + # previous version doesn't have convert_2to3_doctests) + if not hasattr(self.distribution, 'convert_2to3_doctests'): + continue + + if copied and srcfile in self.distribution.convert_2to3_doctests: + self.__doctests_2to3.append(outf) + +class test(_test): + """Specific test class to avoid rewriting the entry_points.txt""" + def run(self): + entry_points = os.path.join('distribute.egg-info', 'entry_points.txt') + + if not os.path.exists(entry_points): + _test.run(self) + return # even though _test.run will raise SystemExit + + f = open(entry_points) + + # running the test + try: + ep_content = f.read() + finally: + f.close() + + try: + _test.run(self) + finally: + # restoring the file + f = open(entry_points, 'w') + try: + f.write(ep_content) + finally: + f.close() + + +# if we are installing Distribute using "python setup.py install" +# we need to get setuptools out of the way +def _easy_install_marker(): + return (len(sys.argv) == 5 and sys.argv[2] == 'bdist_egg' and + sys.argv[3] == '--dist-dir' and 'egg-dist-tmp-' in sys.argv[-1]) + +def _buildout_marker(): + command = os.environ.get('_') + if command: + return 'buildout' in os.path.basename(command) + +def _being_installed(): + if os.environ.get('DONT_PATCH_SETUPTOOLS') is not None: + return False + if _buildout_marker(): + # Installed by buildout, don't mess with a global setuptools. + return False + # easy_install marker + if "--help" in sys.argv[1:] or "-h" in sys.argv[1:]: # Don't bother doing anything if they're just asking for help + return False + return 'install' in sys.argv[1:] or _easy_install_marker() + +if _being_installed(): + from distribute_setup import _before_install + _before_install() + +# return contents of reStructureText file with linked issue references +def _linkified(rst_path): + bitroot = 'http://bitbucket.org/tarek/distribute' + revision = re.compile(r'\b(issue\s+#?\d+)\b', re.M | re.I) + + rst_file = open(rst_path) + rst_content = rst_file.read() + rst_file.close() + + anchors = revision.findall(rst_content) # ['Issue #43', ...] + anchors = sorted(set(anchors)) + rst_content = revision.sub(r'`\1`_', rst_content) + rst_content += "\n" + for x in anchors: + issue = re.findall(r'\d+', x)[0] + rst_content += '.. _`%s`: %s/issue/%s\n' % (x, bitroot, issue) + rst_content += "\n" + return rst_content + +readme_file = open('README.txt') +long_description = readme_file.read() + _linkified('CHANGES.txt') +readme_file.close() + +dist = setup( + name="distribute", + version=VERSION, + description="Easily download, build, install, upgrade, and uninstall " + "Python packages", + author="The fellowship of the packaging", + author_email="distutils-sig@python.org", + license="PSF or ZPL", + long_description = long_description, + keywords = "CPAN PyPI distutils eggs package management", + url = "http://packages.python.org/distribute", + test_suite = 'setuptools.tests', + src_root = src_root, + packages = find_packages(), + package_data = {'setuptools':['*.exe']}, + + py_modules = ['pkg_resources', 'easy_install', 'site'], + + zip_safe = (sys.version>="2.5"), # <2.5 needs unzipped for -m to work + + cmdclass = {'test': test}, + entry_points = { + + "distutils.commands" : [ + "%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals() + for cmd in SETUP_COMMANDS + ], + + "distutils.setup_keywords": [ + "eager_resources = setuptools.dist:assert_string_list", + "namespace_packages = setuptools.dist:check_nsp", + "extras_require = setuptools.dist:check_extras", + "install_requires = setuptools.dist:check_requirements", + "tests_require = setuptools.dist:check_requirements", + "entry_points = setuptools.dist:check_entry_points", + "test_suite = setuptools.dist:check_test_suite", + "zip_safe = setuptools.dist:assert_bool", + "package_data = setuptools.dist:check_package_data", + "exclude_package_data = setuptools.dist:check_package_data", + "include_package_data = setuptools.dist:assert_bool", + "packages = setuptools.dist:check_packages", + "dependency_links = setuptools.dist:assert_string_list", + "test_loader = setuptools.dist:check_importable", + "use_2to3 = setuptools.dist:assert_bool", + "convert_2to3_doctests = setuptools.dist:assert_string_list", + "use_2to3_fixers = setuptools.dist:assert_string_list", + "use_2to3_exclude_fixers = setuptools.dist:assert_string_list", + ], + + "egg_info.writers": [ + "PKG-INFO = setuptools.command.egg_info:write_pkg_info", + "requires.txt = setuptools.command.egg_info:write_requirements", + "entry_points.txt = setuptools.command.egg_info:write_entries", + "eager_resources.txt = setuptools.command.egg_info:overwrite_arg", + "namespace_packages.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", + "dependency_links.txt = setuptools.command.egg_info:overwrite_arg", + ], + + "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(""" + Development Status :: 5 - Production/Stable + Intended Audience :: Developers + License :: OSI Approved :: Python Software Foundation License + License :: OSI Approved :: Zope Public License + Operating System :: OS Independent + Programming Language :: Python :: 2.4 + Programming Language :: Python :: 2.5 + 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 + Topic :: Software Development :: Libraries :: Python Modules + Topic :: System :: Archiving :: Packaging + Topic :: System :: Systems Administration + Topic :: Utilities + """).strip().splitlines(), + scripts = scripts, +) + +if _being_installed(): + from distribute_setup import _after_install + _after_install(dist) diff --git a/vendor/distribute-0.6.35/setuptools/__init__.py b/vendor/distribute-0.6.35/setuptools/__init__.py new file mode 100644 index 00000000..9de373f9 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/__init__.py @@ -0,0 +1,104 @@ +"""Extensions to the 'distutils' for large or complex distributions""" +from setuptools.extension import Extension, Library +from setuptools.dist import Distribution, Feature, _get_unpatched +import distutils.core, setuptools.command +from setuptools.depends import Require +from distutils.core import Command as _Command +from distutils.util import convert_path +import os +import sys + +__version__ = '0.6' +__all__ = [ + 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', + 'find_packages' +] + +# This marker is used to simplify the process that checks is the +# setuptools package was installed by the Setuptools project +# or by the Distribute project, in case Setuptools creates +# a distribution with the same version. +# +# The distribute_setup script for instance, will check if this +# attribute is present to decide whether to reinstall the package +# or not. +_distribute = True + +bootstrap_install_from = None + +# If we run 2to3 on .py files, should we also convert docstrings? +# Default: yes; assume that we can detect doctests reliably +run_2to3_on_doctests = True +# Standard package names for fixer packages +lib2to3_fixer_packages = ['lib2to3.fixes'] + +def find_packages(where='.', exclude=()): + """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). + """ + out = [] + stack=[(convert_path(where), '')] + while stack: + where,prefix = stack.pop(0) + for name in os.listdir(where): + fn = os.path.join(where,name) + if ('.' not in name and os.path.isdir(fn) and + os.path.isfile(os.path.join(fn,'__init__.py')) + ): + out.append(prefix+name); stack.append((fn,prefix+name+'.')) + for pat in list(exclude)+['ez_setup', 'distribute_setup']: + from fnmatch import fnmatchcase + out = [item for item in out if not fnmatchcase(item,pat)] + return out + +setup = distutils.core.setup + +_Command = _get_unpatched(_Command) + +class Command(_Command): + __doc__ = _Command.__doc__ + + 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) + + 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 + return cmd + +import distutils.core +distutils.core.Command = Command # we can't patch distutils.cmd, alas + +def findall(dir = os.curdir): + """Find all files under 'dir' and return the list of full filenames + (relative to 'dir'). + """ + 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 + +import distutils.filelist +distutils.filelist.findall = findall # fix findall bug in distutils. + +# sys.dont_write_bytecode was introduced in Python 2.6. +if ((hasattr(sys, "dont_write_bytecode") and sys.dont_write_bytecode) or + (not hasattr(sys, "dont_write_bytecode") and os.environ.get("PYTHONDONTWRITEBYTECODE"))): + _dont_write_bytecode = True +else: + _dont_write_bytecode = False diff --git a/vendor/distribute-0.6.35/setuptools/archive_util.py b/vendor/distribute-0.6.35/setuptools/archive_util.py new file mode 100644 index 00000000..e22b25c0 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/archive_util.py @@ -0,0 +1,214 @@ +"""Utilities for extracting common archive formats""" + + +__all__ = [ + "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", + "UnrecognizedFormat", "extraction_drivers", "unpack_directory", +] + +import zipfile, tarfile, os, shutil +from pkg_resources import ensure_directory +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""" + return dst + + + + + + + + + + + + + + + + + + + + + + + +def unpack_archive(filename, extract_dir, progress_filter=default_filter, + drivers=None +): + """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` + + `progress_filter` is a function taking two arguments: a source path + internal to the archive ('/'-separated), and a filesystem path where it + will be extracted. The callback must return the desired extract path + (which may be the same as the one passed in), or else ``None`` to skip + that file or directory. The callback can thus be used to report on the + progress of the extraction, as well as to filter the items extracted or + alter their extraction paths. + + `drivers`, if supplied, must be a non-empty sequence of functions with the + same signature as this function (minus the `drivers` argument), that raise + ``UnrecognizedFormat`` if they do not support extracting the designated + archive type. The `drivers` are tried in sequence until one is found that + does not raise an error, or until all are exhausted (in which case + ``UnrecognizedFormat`` is raised). If you do not supply a sequence of + drivers, the module's ``extraction_drivers`` constant will be used, which + means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that + order. + """ + for driver in drivers or extraction_drivers: + try: + driver(filename, extract_dir, progress_filter) + except UnrecognizedFormat: + continue + else: + return + else: + raise UnrecognizedFormat( + "Not a recognized archive type: %s" % filename + ) + + + + + + + +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,)) + + paths = {filename:('',extract_dir)} + for base, dirs, files in os.walk(filename): + src,dst = paths[base] + for d in dirs: + 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) + if not target: + continue # skip non-files + ensure_directory(target) + 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` + + Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined + by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation + of the `progress_filter` argument. + """ + + if not zipfile.is_zipfile(filename): + raise UnrecognizedFormat("%s is not a zip file" % (filename,)) + + z = zipfile.ZipFile(filename) + try: + for info in z.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + target = progress_filter(name, target) + if not target: + continue + if name.endswith('/'): + # directory + ensure_directory(target) + else: + # file + ensure_directory(target) + data = z.read(info.filename) + f = open(target,'wb') + try: + 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): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + + Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined + by ``tarfile.open()``). See ``unpack_archive()`` for an explanation + of the `progress_filter` argument. + """ + + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise UnrecognizedFormat( + "%s is not a compressed or uncompressed tar file" % (filename,) + ) + + try: + tarobj.chown = lambda *args: None # don't do any chowning! + 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: + prelim_dst = os.path.join(extract_dir, *name.split('/')) + final_dst = progress_filter(name, prelim_dst) + # If progress_filter returns None, then we do not extract + # this file + # TODO: Do we really need to limit to just these file types? + # tarobj.extract() will handle all files on all platforms, + # turning file types that aren't allowed on that platform into + # regular files. + if final_dst and (member.isfile() or member.isdir() or + member.islnk() or member.issym()): + tarobj.extract(member, extract_dir) + if final_dst != prelim_dst: + shutil.move(prelim_dst, final_dst) + return True + finally: + tarobj.close() + + + + +extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/cli-32.exe b/vendor/distribute-0.6.35/setuptools/cli-32.exe new file mode 100755 index 0000000000000000000000000000000000000000..9b7717b78bbf71f105ccde26746a0f6e3a4d12db GIT binary patch literal 69632 zcmeFae|%KM)jxhWyGb@=lU*Qz009<=iUtu~qKQjzA=wa=z{bdiRT8iQu3Ks`+za?f zAn|5tZZ5adR$Kd2S}FKE__Td$Kb0T0f?0wI;4gkuM4>h+)rm_rlr&i&=6>I2?&b&D zKHum2*XN%vymIf%+%q$0&YW{*=FFMdvir9QW<d}v_|tVk*pD~;^YG{Y{AkDL^of5+ z7hX<zYtnwxg108!7kp%`b4|^6AFg@uJI;q5eDu-piq3DXbk<0ZIv;t|S-hyi`JL~s zSUEi{ZCFmc=+6$!+qLuDjXnK;6Mpns&wnERU%P(O^F984wdZ$uH;lcv=Xnk{wI{~Y z|EuQ|fA8=4CEoWw@=%b<_&UZuuOKWiS%i}#&Xx6lYZnqssiqV`IEIvJBejhXa^SC> z;vOTMAP9*R#lQZy;4>M-LYi6d)N??}N16G1;6;hTw9A4pm52Vt!($SBK;{4KUt`zT z`lKCkpz^Q&O&3>g5b?3>2p)tNwUs(~$UmnbET3Mp;z9921Q6kEpN#k0_#5)igQ}(* zV8Y>Cd~l#*DzkG45P}{-Xr5lPa`kr~5`^dNln{p#@E-EdBM5VcMF0Qb|3wPuVvd#m z*q&rTkefX|wk-*P!?sYul9t8l1=VYnFW9tFQ<KBfa8kNl;m?g!s%Ny~apsW8$7X_c zT_@cisIfqxHF>hO-lQz<RTjrKJ*<|+kk=e(vMS!Ly30$YMBUpPy}9o4Wa+ws#l4%x z>QZlLsh_z~f?4X7SN003w+j`!PPQg3Es2^@P?OM@RHA!h1y!+)zoksW<C&6>382W= znlxE$Th>})5~?3K+TyPanGRaOZGQIeRy@(NEHzfi{2V?5kku`VwO{9my}Dk1!3KHQ zQ8!|a;CfvNH$n^g)jdz+)s$4J9(Wc3_3dctoLRR>mex7?(k4?wvvg4lH==kSUg$J> zK}YyBZ=KK2Zm<zj8FjUFf<0W1&vggr>r!#Uzsyw0{+=obMk&au`Akh#Ps35^a_%9m zA@O_2U6;R9Ow%+f$Q`LkX%&Q0BuRe@3H~9KYu*MQdj^f<f$lzCmk(z}ll?4;U_jNV zam!q9RkL?cUH$7@5j{%1i>|HktCCf1tsLy)+(^jcWA}p})GC|nD7sHcRc6=^Ci&Dp zrL0#ei?Q$WrrM&ZC6vsTBN_;UI!#F>jo#FTW^tAMV6%^v8tGz^TpJU_d+Tab<81IA zf|I4JZf~zivb&lKys=hqs$hS*S@FhB)b`4?y@Hs@`?`{i1tMmo9kvmVAfq5Y+vH7c zOr96rb`9V~Fzz5An5i{cn5Ua5hnlL)Y81yuO$NR%feIYoy4mQedAhCxdKod$4#7D` z2seu<A;G6-3hf@DMc$ZW5hQC!V1EH%z}4(AD7VC4>1x($FZ}9PzX}!qYMHCMQuFTi z`xL2{JscMyQ*iP~kD%1<)-xR_O7mU-tL*mq{r-^2@7E=(U(dAR!?J1+Z%lCaM;?LQ z45s9AXhkOlP~FiMAQ#eg>B3GzPS3RRqI!Ku(K9WGAaioC4w<77)!WNE7NR%Up%uVX zpO+gcsC8(i32M)#Y}IR1EiVzfWqBIT61$bSC5N`aWZHPXvYb_8v;%hPncxwWTEYH% z7<d7S0314?2zYU7=O!1*(r511EUw^T0Q*=y2S)k((Pcy7=ebe8m}J`c*0O4~<$)?L zi9s-E{e`TAA(Hqs1WXO@!V`!q-o`)D@KK?KpC*Y5fdCmq03OxW3<yjs1co4@DRueN z#dH!BO``;NWc}Z?0~A8qqNaJKd647S!Koj6gcn{|^@33lx_cLU?Dwd+GZ2vbbSW!d zUoZ=B?DQ4%e4yiQj)?bZ2>Xq{g1XQ)CO*yFO(b?t%ZDAM9(UVXN0YVTs5q?d@-Q*6 z?sA$G4JDvn00c8ol8^nxP+j0L+d&IbwA!a%c;SUzns*y`<HtU>3aUw+p?DkO2>97O zS4o^5igznII@KR+2bnt_A*QX`riPyfPUaTHTjwFE-DRep+p5Nx2PiAa;8yg4`;4~U zqIkDa$2X{D+w_@@%t_yq<W`IB-BwVwEwJ%?yh4_QFRrsnQV~8DY^U-Ao5rf%Mt$b9 z?DNa<Tt#l<%f?UT>jnA1Za@iQRwe3YU+v^L1m6Un>^WqJj?kq#{^?s^>AH^{Koij* zRimC>R_%K00d@z3y#DoP5kK03E*5ia^v6B`Jn(M`*@B&2DDCGHG2C=3(s@_2T4i;A zXn&^J-6}cRok(vJMga%Nmfz0~P2j3nKB9NLg+yo=$;M&DKPgq#3ib<X6eP8~$mWsO zSFjt$BQD2uahx3M6Gy4XBUcjDBl1TRBOfK1ZO=S^(;Ok1_{y^wD!S+7Y?f{$&@lv> zp&p4`PL$gxM%t6i7R><M&jCF-bz(Mq9+(WpY-${{vh#X@bY7ZL!R|=|*Tpoi!v~FE zt6;xN7X-z7zM_)7g)j2q>^5&NghXdx97y4L_92RBfq1e7)QXn<f@6-*vZL8ONAQO- zNRuS*7a&j3BzJ3Vvf8?nz7TKx&<XIs&R26u!$}iD7Qd25-`L~Vd`Jw9T~giRI{6Bf z8%^9n@QN)#jyUB*mio&yUT*w6)K?7%2OuidLy=gbY6(-@)hqI66C<A`sg`6Sk=5NQ zT2NPlax1dWt-rhm88*JX%+*}o!v13lMz_KlP-%jg$i6!XOp`}-vD1W3i>hOMqOpm$ z&)r!wxxQ~X>RvxqeLI&EJ>n>5pJLixztASsAxm_a-0Flz&4PNUt}+TBtrg3t9VItA zeC!nfLtE8jSR#0Ucx`gC6N;X)4Cdf1$7nmTkXM*hzucy8*7e*78p;d$F;GW#BX9PQ zyk%DTat2DR9U0Ff6Os@A3-EFp(EOU0RJn~h^d3U66AT~jma+=Gz2Zo=JX@ggXc((R zK*i{bvAX(b%bWfG)cbO5>Vh0g_@wxVtGTH-#|rH>s{RV;%$jt$uo1li`gW|mPC!>( zmakZ9ZtZzr{>Uuaa!)iS%WWpP!z6WsjoUF<qn87(WAex5NJoO0bm><pc$fkAIl-ZV zWi5DG;wYeQTV?pDz2S!fgs(z<UlnsQdRonhsT*?~QYwnEhr@_QZ)k$LG4<Ce=3<&~ zivcP9Rec|D(u49RW^v>o7$EMDqbBKZsL=61^|F?pHY!*g)nACc;aS9uROxf05YhOE zY~2r38~7@t<u(i2DgNRQdSBlrHOYKj?$lj})KO4zFA648y?CzSq&TgiTb$5y2#hF* zHhM#q9#%$2v+6&lr7=S32q76Ei|ZsW)zwVp+FZ>FXi0TQ-Dre8yq@%P9Ba<X7*cd8 zLzf)rYZ}e1%!w|+G%e0|<>eKwvl#EHFx$0?wQ8Bo{f3lWQ00&wizebFh6<`OC?QK) zP6=6Jpr9(75}eW^N^pv$1ywoH?1HMP(rm~LRDb>iF{!k~-Lk&BZuXs0p8E}PtX%6b z+n@Xg8WBnW5+S{uU3Wd<;V4lgYjiZ_KGf!ofqjGyS_dLiLgN@JPgkmXQQ~4g<vRo9 zF@+M%CDBn$NwaPd(`GFdQ)W$<tWc{_v$n}pl0QNEll!W89q<;%scpGlYk@awT`ia$ z)q)o6*PH+jrPdlvQN0=N7Sxo584Ln<yS>&LFB&M0;rX2Fy#4vInP}ugYwZmfhJ{?I zw?LY@ZVL2gFO{6b?lmAfG<>B(Hs?y#0?E046=V~o6Is{sx~Nj3sS(RIVooELW5lLX zjGf7%lC09G(5UJP`lrlbOOb{-k=h!)2`d!ouc65Sh-W04O;bBUB%2+DMAJ~`rNU5- ztC>$TIY+2vSv~KMJG!4lb;^-)Fo;@~K`Dr+W#E%|1UTcPqvy=HX1U!AGH_kd#)rn7 zsup(|sbnePQcK4M(jTNZq4xah#nuuVY5Ip){%zpd602IeT1i(+gUUjSn(j_pGj5I` zj!@IKj>Ujbx<*Q7$EO1>NiDIs6Ss}Q$5ARW4Sct<;v1+O3sSp1YZ9akxpYkeDltWe zsaBNivCzlX>Z(H)0}c5CT4B@5I@u}`2XCjm|JUdd)25M{x6>E0k`&a;BnsK04z-R< z6>6E)zRyxBw_EFI5s-{!r2OETuP_OwcFBb-2l`AJfd;B+%h3P;&jD~1%^FZz81)25 zvvcSRPRLY2l}#GYvPNSLN&k$&m_3il0{RX!glHKGL+_mPD_*8}+i4`OAhf;hzBcc9 z6u7y~dtokcW1}!jL2v41=he;)$*Q-#F)Pa9D%eA4Mj(L3V-dkC=gPf8t#X9VN|=Uq z{5uM$l&@N9B<+dbu)gk5NH{8Pa>&gVIbwnOx%bZUUa73f_Z7mk?kxXGx}(Y0hw$}x zmiI}MntVFKjyu5$sj|1%Qc&Alb0~V3eXmEi@13tlOAzWqs4qGTp|247Dta42y$JP2 zry8|I?M)7pl5yv7$>EuU1$jYLZ_NcTC9t;d73_OcawE~dbNnk`W6-sgdS(vBH;`7( zbRtmSMyd7s^3MffJ%)Di!)0+|vo*JqzO=FfpoE^+2%cn*-7E+}QkeR2ba5OoSo|>x z<fS2hW^g8=7=ovwbi@;>s^f7`D((pND6fASAl?jF+21h|23ioX^8m-zuXaXL)g%;< zfVx^OZpm8H**^)OS%j-OYKJU1)b#LCz?|SPwweq5FmmC`n0pA~m>|8`b@_&R8^&v< zqyW434zy<ZM;;+qiU-@lSq){*4L-00@#AR!eh<F1S#pXA;2{9Wh5M=4fH*El0rnQk zAhl@=LI2WPhEiS4VBf5u;~&WMY6dj3m8DbDXnNo}TU0PUACn||!|NcVGJYn)O<u<@ zY2qZ;+OU4zP6W>TH5D&RLpC+0)Se0J;s!l$Hzh`MDX~+L&MCF$6{%hR!h*27r>2s% z;Zs49_%}rE)^BGKM6q=E9bQV3{$9M$U-8s<VLwL%eOXX@UP>(Rwu|XhX6+fs4X;71 zJrn&!a1ENje+AKC8QC9#8z?SPd=bU_C$yNfqX`Z{nyT<7qTRE`0$1wxUZ^*;oj!|J ze3(KXTG+=UG56&?4gzv^Ye9*F%!O1FW&cfoYRE)@Y`YO}K@<t>`|+r%`&r9PXmqEa z6}T~hVTbRe=RL#e`63TL&7T{=5Pp`4?(?%g^mOppWHcuedF8`7JBiz?`&CpidL{u= z+GQ^E3vl`Mt#K(}H=t3ZokAJG8PwVDi~!4&-7g5M3KGeDD&_B(g;)K4ijd`6y5W^n zj1H>`8nfv07<s>lcltVq>u5nEL(u+AL@7HTwa6>aqvdSXU7!+J(i+NUj}m{fEf7JT z;9yle!9)5MjKw~}>LT1+YYmNKZY;<GdghFFkFfK3Vwukh1!3nbw1Z7Xh(lRfCPA^E zf*d>{g;^*8wf>RbVCrNayNI=FU`G~m?##x+r{_8F((`Oo)|9{Vt^%*fwdVy1hNIii z4=jL3bh_%jpjy=wrR<!qoc(tm+JQB|N~U_x4S~-h_<TI#ECdzI-a%iru;*rDzOoBn z;_3jl6;=Tow2x&GO$fb>>;xgu>~wcZ7SabS!s8yqmt(f1Ct84IPl?S2l1mFKDz#bR zQl!Xt34bJWx8$r~Dd4|=k_?KD)Jif!2^dwCq$Ns87Dm2kntGSA$*Rm&s<V`83zj7b zKn=>(^FTBKOP>Bwsn#lpH$W%ZP!*Lcj`1^lCba4*oBjn5T$LrzntGL02p~`Q9GeFQ zw8xPtN1t!mkg5)EOwdjCz0FY@jBMpT#?ZwuTEuk8oRZX{CmDQ58gV415lvpJUS?x^ zNEyx6$rNW3Hh<QSO!qvS2Nu9i^?mU+d9ziJreRDnB}H?a%zBwseTUT|UlB4&BiXwk zr<{M2WLMvL=`OZ{3Pe*jzgrDc4yStkg$)UVb{uanMn9XOdn?sin)+(mE=Yi~=Vf{x zI7iR$e*Wy_&o}v#@#k^=Z064+c(N%yx{h^G9xDSL#whM;_R&9f3QJ}T=5+^N0-zuc zQ^UVTKwiG)E3yC_872tbC0OWJ`<Vw!ANT{U&xfq`X`!!nM*0%@YJU%3#3!i7_)`A| zLznur&cB>EWT~H^9_sew)Y-!igBq@*?)U8tRR}eWRJ1d|K+)Ry^Hn?>pZOBchLiS& ziNL2wK0pA1vi&e#_N}Q%YdSQ|Icv%K;r4@v><8<XeC!eAcDt(^OO0+<v;AO0WCM~y z$&r{PpoE`BHh0ASz2Cqppyz~NyA{wHQ4ZwYhL^I3lWq?u=^jqZJ)JzAh}p3Y*-($n zoZ{UwGmE#&%qm`2S}JBDW)D}AkxC<YYsWnUVN1td17TB#3*mYWQzt<7at1ynbYvl1 zcjYE&8kR&xKdYO2-F?ad!p5#$hH2g?-O{t2k~%&^iW;Wix0{FA4<6Hst;ZD}?|2iR zls(k4jtGKO?DbzSmcH7xU-Du(4LW|z3#9PS0(mJ<@KWZBi|eig#p1dvtHrFkE9>py zhmdZxM?k3KJ_2*EmPQrD6CtTaZ*>&llYzgZ<K}^|vtts%P3Bp*OXKUFFwK-k7xiZa zf#O;FFoT@s;sCdCfES3!WL<~@{Fwk&*c;xZ_apX(x9I&{4F2?%><tI#y}{l<+cmS6 z*c*O>x3Y)0K?{>``RscS`IJ3J5M(dU0<(vko5I9-0dcabk>F{2i1XMkXzC_&kx^|! zv%O&#wD>g;PXeN&4CND}#8%j!V$h5BhQ}e}a;(Ds)ZfwV_6D>~kl7s30p?kPKWk~J zJ^VuqXLX01ZQ*UG3b_P>`wgOb3V3&F+q>|Qo2r!U=MhxG&*N!_i5l`9roKu-&W;xl z?Fkc^W`Mr-@Uuu9(oYJagP)~ggP&9`5AtPQN_>TA46ZQ%9VlmjEtLaQx4q$a7OZvq zq|_ZxLpdm6N>ur?Elk9uMs#cjjLbmw4}cTe`gm@{-f#oTrZ)eaK7O+bafW^0yk1|B zOmbS7nv7i|QVTxTgP|152@FjW+rlKSR7rGX)4bkB4%o)wDACAhVAYX_id3>T7;S)! z&8?PN+;59Bjph;i+FuhCjoKh){51E_iP(@vbef4{s7)PzMR3Qqf%f{?qcrX9cpJ%b zY>oY?tEk)F@ClxBY^8nct33T-`}b#JoRwpbh>yv!N5!df?7Q~x^Z3@yd#TPq8%PM^ zgYn)#+oOxsI|guOpJ5^u2GiXFTeFePDcV-4VPefyN>bEn1eK&g!gTxx5tu6+k5L75 zrl9hKo`_IKsJ;kP)nv8OBDYyP-bF+jUU%hTX{EtVhzrp`0cWjENeX}0A0S5Ci7%V( zQaNANw^jkr&nBconz_=3x+M*cesUOHpzI+|RnJ6+83j{zS2y*E6&s24X<n}q-ikn6 zD0QxrAxAo|!ss}k&Wph|9snyaRa%mbNm8K`U7#OV4-m)0`dj~59ZDCShS1Qy#4dcm z3N>#9fu|ebfk52>lJbY8Y%uW<pydSAF_D)EAotDE@OYn~k&u4kk%|s8O{q9NsM{26 zKT@MPGFxkJ*bB7)_HIz9&uMJfi;Qi2*uDX<*Yr75Bs$>{KsIpzOL=SfPbg|eWB6UX z+QP^21TP33UcjK!kij0lhe~d<bVr<GmO+{B2&O#t*XH#`EhIcY#YARaFD06PikZ~O zL7;K&)0;<cw76T>4(~Z5pA>pN7;Icz7`A~Uustm$xX#MFuZ3FM5Ox?Va}C_X_0YAf zp|+*ANJ*18(wcNh<@C|HQVBP2PNL7^%_^7CpWf?(y?z^*T8_++FBd4=IfKO14>l#4 zIW-&87e)_g-b=ZyC2_<+2Zd)=_HaRc5d4*_zFk)^L-gxhc2)jtHO=ruXU|`S^dyhR z{kGJV%k|QUSad2^Sc3v=D6DAm{JMPDd<pg+2CPw$e1Mb;D83Y3sB&T5?GbN-0Tc|D zVszEb(X8F3{zz^#b$5a|-1y=&x(~2|%17<o?d>QocRO{e!3H*Iw9Y4Y8W-e>kdv+X z2XV1Y=Ti{%03U$(M@=KnVC(SR$ZW+T*$7#r5tS988Ac&&x>16BfK(RHrb@+C;pR=> zQaRz`!^XZOT_d9VLP?sp3p(~$L`r-m><3s&a4joME#QfwQ{O`$jq<g!E_SgCNFJcv zLO|LR&6fG>O$XcY9zbEFm)J3Y1>zI8js3WagsU?S@gx<5jp_rWF9dO<zJ~(L0;!T; z;AsJs&-j|mjeJyYXcke)(*RQWe7Na&$46-IKbgrI3K2U1#)eta1zkVdvhCQ79^s7} zJi=A{1*T$06Mrw^uN!|kH(|PXU(iP@&6UudFyPkqYToByZ1J?iOkr#*g*+iACdLxR z+CaeFW^c#<WA3Cmu#&e8Ppy&0ljw|Ak42EJdaEaKn6kmz>d6sWJ=YCu^<0l=ek)d$ z*tAyDC|`Yqa$x`D%~b`pZ`&J&5x04dQ`tH(PrkOqqFLP7<2uLz`!*)1eQn-$;;iTc zgb(`+^9R0W^Q&d;nvL(PDJD6Q5OQkUI7T-O!AM?i73!Af)b*nzFV6>h22R7xr`?BY zPU_zFf<nr_aeFjL<so@xyAakleFvLrDmHF((Jx=_6U&>-kbrx3Tcy-;J#!W)1;L!9 zO6_VZ?f-l_G4g4Wd8V=5g^aM2pfgJ>LGpOgN^EeTxyeA@-f$Ex(o3wUx=8k(hsmye z<Bwct)k{=D9^WrZqUA*@?Ib4EEwt1{Yg$Vz^{^NwhPs!)s@hV@t-j6wK%eCU6E!A- z`HNuOxeJ!LIBqkQ+1C+a<yeA5rFfz#a?C7Q5VQ_rb>+r5N$&tg(P0GFmITd<)!kLI zeJd?sbl%~5=1kOt_3?15iD?NQXA~@@*h2~Z<`*mz{jP3ozK&-H&~bd*HEvq<A|5xb znpKaZf2oNaJAGJA4=fg^V#?6(e&g+xUpRx2MyLoa(8A{s!j3$f_*X8ah$-QzkP$6B z15XH;5}t-YTzzWiDEthGsIr}uiejvH_-bR-)@Nc!TD4WXz+c-*i>%rjKFnV)H1pSQ zNHm{&ifcsGYthOqZM-HEG@~(1P_!<9sPlV`Syfw@kR5Fin%g+C#JZRoAWhF)0_ueX z^^Bf*A3_>O9Np(b1ZD#pI@cOXV3%PO3IwSHJ#zs*0iqNy$Tw|=Ph}+Cd{M3E5z*N7 zS%3#4nyd77Wd8$Yuj=?e=s*qy;$rz}dFu=&bK=N3^5vUrE^4KJlP?cnpB_qE0-9Ui zI)`snEs4cIGL#;09~sv?B_cP&bk2S;hGt_@(tb|{wvv(7!nXD&6&p#mxK)8+D@=!x zzFe`gClQ2Uk-dtyG6VgLP08R(w|j&YI&>~1y*S6Atj=+0_{(jFGY9YOTfM!m*L})L zrb{tw_Qbghjz8EFSV1!>82HLMS14Giqm9e3U!wlCs=R;4lebpBkY(5w)>>V8wEI!1 zCbfEXsI)HX3GE37NmQD;&|-eaWy@#pe+rxz+OTh7#E(+ki%ks6DtmYovcOKFEoMqZ zulj(Eb^*#R$XENsW!ii}vpk?K*pi_YZ-E0wC#2mQg8?~1eUHsV7obv8xOt;z^E}lX zQ_rAQ>Fv5&X#N}(l06g!e;frrN8wIZ!cicnBebpsh*N8$M?u;8f``_AryV{9g<GMm zF!Kx2oBe1KNfnvg?doD{$aJrsN$K)oD@^<By%}hP*H*B^CXNUi6gj0HVILUD*hEoE zZC^*J1=2-S=|}1J6h|9Nt!UkMkn<0u9ttXK_J(^Ah!^_?3*%EqHd1(Bz_+NIteo#s zRk1)=mu@IXybmn9ZX)*Lb4UcX(4K+YNHjx@V2c~Zs$=Ah7gq*U2$^&F&XyO-ABqmU z;Q#BgTE13Ryrfig5qTz}plJnOoA|%PEb@)gXd8<+5*um#sG&s1|F*;fMu{O?a1D*d z??F*uPa@ncN^)TXdeJNug)D3g25D~e_p{GXQ2-+(x;w@1V^)}w0|Rz*EKFcGhXwTx z;1nH(oQWWCpv4ao=7~3wkJxfU+l*pPs;X1ZTuM5I9mkShNeZx^A+;ss2yP>6<|6`s zpQ`gP<^Gro!ai@vyiBQWcNda>NNuIs6ZtfOJA#;73$nywRp|EEWYO+pPry9P9cRqC z_q?oUY@Eu$R7;ZK98rvFd5S(WiG2lr3K;$**-7)FKaY$4fMZJ{$I8U+NTAkm?lQa+ zOKj?qx{u7RvvrpfB+rXhNUT@@X|7af=f*ICPpgDS)=GF91$^w;Vv-Y^yA5{A5?e#_ z<950IE2YF1O_mqhobns`GGvrjSuk!JUT6jv^X`yR{EReLAbN|RZ3Kst#!UprMkkW3 z)`My@{H!-di+7tBa6M-N<C^2fT^RLWB640K_bE)Zuq|>96fLI4VB$q?OYLs%aAVhG zRKf|NSzap07pvn0^`jZyKcm`!>*QSczs70#l3Hr(j>zII1&giHa38yyFr$gX1Q0zs zrl8g;Wpqaps6TFre}X9(hV$B9hMAa95^ZpS-`e9H@sgh{<ds0}7@kGgh5$oZO_&IY zW?0<W6KDhWO4x7k0b6Y*Hj&Cjmyn>owuFr0v;MIFBZEnrpjrM=ijb1e=NkG9xh;!n zP*!~YW-F2VayFjCOah*_at?>2xy40QuTaMmclZxdZuBH3H6!Is7L%A(sh_H3$H5FR zg9qeRYkglZ6Z5un9C8`o<x3$*37g@k2ETt={eZzVQ0@B6*Qr=NGaFT4!^IXnLw!>X z9)T+)ItTm0<4IJcEVd6rU1$PJ#0bkbD_Pwq)CJ%OZ6-&!V1j5-+oF$#vRDcP2peqf ztCF3)4nAlT;NnURDh~}~0iqU!r(l9KjT57iH8>4INTVxRALV6F4djBvMN^g8(d0_@ z34QAC4H!?M%g?iJK(?URsd3uJ_w_ZSY4U7A8tG$`=_B9Z8O}tE%>n)P0S_p&I!3Jy zq96<`F5Ugky6K_zC9ab_7u{alxMq(uk?An28?C6Mf9!jRWA=s}>vw^N{kPbqz6j3{ zcaLOtb(e5GA@{Yff23b=-6OZ!<xjD@NW0nY#5K@n>+gU{T0n?_14(UOhES0<>u=#Q zYGKuR_g_RfbXzMc*zITew9fq(=|Ml-0^&++1^P}sgTw^|g>~pF(dB2qBvS?~N8uWj zuX-J{s_-FbG@-+bAo02l7?1%a(1Pq~98OF!U{q`tp^b(UuLT&YwKRlAI+9n}zif_L zwOu(tPuRA~z8NW-=Q-%%q{j?;c<AAy$8vhC(O#<q^nB^Kijpvtlb6B;__Xwb96wcK zt}D6liL=uSqtGl&G}IIF$D5VKUG8Jzh}>h?zgY{MX&8q~!{RQuTY1f1NA4j^G~nb| z8&k`=F8vq2MW^@tMQ%gEos<lWJ1Myn{i-f@n2+Qhzc(b5vrW7#>WVlz;DM}e@W6_0 zRDx~4RraY7cr`$S3ehRF=O(B^AqHHym=%tvm)X_a5})|freeIyh#yy>2t&Z+3vgtq zP`th58}5x&JhwzWf-ZInzU|N5pL;@_SiT)Q7QdvgRZLlYK`HCpPc<S5rvtpP2YS4{ zh+4#SwiF1Hl0}uIN8yLSeu|`><hKS)xN<J%qk!vdrTdZyM<?5QC!3E&a%fb5dvt(5 zt?W2odBYcnJA9(U!R;;Lm?q)Q7I9=KVOc?~&Aw$jD#eL{)}%X2;A*2r;M?TMA0y6+ znu%JAZBPuo?kj5_Z*nw_D)HoJNep|D+dZ%YLYu+I$pIfH8{C*}YyHL<1<K~lLPaB@ zM*8d~Yhyak+NpZUo#=)p>z!|ilj<%{7qfWI?AD~|C2?r@3im_Pw{^qOZ}2r*jkbg) zcT4~s8Yc|(7~=jkR`RDAbq+S`z3}2L>uOq@(Quz>yflIDm5%^psLBx{HaugdcpXGl z5E$L+`DY$AAq(F|$NYxV9fp$llq~)Mo8|SKrv}n7O^ds+k!b(;E*fq#u36OWd}%Vq zgS21MGjlgR$M2$N-t+V<d=Af5TQiUFSK6!mHU3%tN_?8XuG_|6H*dx3xu+7F@lw6Q z&X@VyvU5M)8dj5sDIRXeK+%>cAZ)__9rSVM%ai5^ZHc?_OrbSe;;#`R2ILD6g)iQA zG;q5&Ej5ib+s+t(Fw`xB_y<4~zI+S*>0=Lqw0M&X34l%ln3$Vjf>ic3tGA;qH}Ap( zN}Mb+i#S?lX`-!^3)Fs#1<RWKBlwf7K`r}-Q<w%+wKHe}ZZ2Ib$*%OV+|$rt&Gvmq z)QGalLi@>^Y>|%~sS$0H14j*Bp`j4-8vy6N{TgL#$}lxLJd30rZOeE>4^l&$GOS2j zDD_~}<swvnAsa$IxZ1|%c9>z1_vz~_dS(#KdyVpuN&YJ6<Z5ngNTj&|Jlbozn!;ZI zv^7i#PFSp_Yump>f_?81`(CsA$of&a5sy!MI*q=EocFTeyIh+WVS5SAsAoXSbv7;B zi!7+khnfk{#~m?l!Ys;lwgTx$g}$yF_*{uh6)d%g*sC}WfW8_8;5#ZD=+n6bltWb8 z>ZNMBBPKDuZb8y`N7L3sDmFTt=0};7<fJ4N)VMW?$Q8A=Ht>KzO+6U(8&qrypGP^r z0LHGPH}bIh45erd>6FWST)W>XUmdgFR<|G>wVc3aSJW<F8M7YMrlXD%b)P#M9Z@q} z|L3^hsX0V;J6hN;IztP4DCK-o%I|c-IQX++w5Hg>z3}F(5y#7$R}123b$t+<-B#Gb ze*OW5F}0O_2H=)Z8oPwSi?0#@0#A5%9(UEd9gB&vSa7XDS7JI~H|9(tjsSh{65w|b zkTNf*a%f}&=xTuWkH}ySA^Lq)I*$tWL(j*j-%vR4psOH_v+F%99mc;2_dB_-Pnyt{ zNI{SS(y;*r<yZBJ-ng?~be7!rl{8`~hzOAAS-G#5T=zQRDLD8sdYJOUn=VEh_G)Xt z1D$-qIfP&1t^}3b?*PMUH@rq+{Z7Ydz7M^L>B@E>!%qej?0*)GwKx2Lki)8^c}8I; zf;FGj>+CD&#fCM2tk*kucm=}teQhwmY~+-~S{Esrm-%2|Be@`va3P5csaBMY)mY<6 zRCsbO*`c1WC~Iv6i<x~(3{}+Ceu3iOK}eInY)Wr{Tl67B?0ZWfEJr*31K}aX%t0|~ z*?AQ6?V~fWIM9B#n>tB4AHAum!~{8;YTrAX{5(Li_NKb0@zGlB9*@#Y^W3p@pJNtK zQi2mq(h2k%Y>b!*%eC$B?K)r6p|%0Fwjx?73G89aE<;I5kxeUdXv%Xa=l)gdt#ei> zGv;_acVlPc5_=CI9s3}bbqmbnEgpAdT{p_!M4JUOAp}~{gjf1dRGro8nJ-;di!5ve za-c}1!iuAMu)`QC%g|I$kfw_6F32Muv4@wSTw3<`+ph11et-~U1ecHy9Qzx-mbL5b zhuCT+-?ej$l(M=kh#5GOAiWAEmPHnOLnU>CGXX7n@=KD5GvTxLh7u&c(g@rj4(ioQ zFUV5_cyC(SewzJZ(%DXvMVf7>(m8!ya6m$at0logQl{j#^blk#pi~Dd)IyR9{k`sz zHE>)19ND@PNit3L@ShQZbch(74e=|o>^z6|sYTYE?fh-qc^+@Lf`jQ|iM5VZ>VhK2 zD#hkKj$}`i@h^p>vuo3u7Gz~NHa3o?4;{t_lBQZ{tSr(njg8x~=-a0-%A&&t&>qPp zc>wYMB0?zR38X@QuV0!$B3SH!?BD*5&n?mG$ll_tziKqMf{B!iC1MM~Fxis-SUZN; zcJ?IFTI9l)-~<LQ+t63ckG>1EB~k*g8kmw9>+&tHQWEB6E#h|zOUHwjL3PVZNJBz( zL6&sCx@Er+8;uxND_7y)r0=C%YyoP(B5TXb*8qGl2=J+g0Q9|79y>Icz7Ijl*o<`4 zQ;d>5>XyTZ-ApX%V?PFfy5&uT`P4kO&BtV(bR0<(lXzjxh_MiYnDb}{|Ad&DT-b>1 zQgL*_vxJp|_4J!?E7R{_MF0x~v`ugbwvtmq{pQ#<aD_NrO$G|7KmklNfq)8@^}?rm zo@FpOnUXPchd-6n=4UamdjMv?_>2jJ%p;bAhm^HaKdpX`noILFA4Q0I0};Y$AksV- z(UuLM^@M>|ifWDn%1^+FdKl!jKi<OeK+)9TL@E*$4WdJ6gy9WA1`0xrhLitmXu&qx z2KQnZ2JQg*F26d%-6Kw|RPtGbxDq4YIM_?TQCJHHXvlk(`UFE>fMj27!zrd_8f!On zd*F@RfwA@$%+AzKW2`M%gL&E}jJ4S;i;~x@jt{supQ7BYY#nkSJA0Cp1FfC3lGSP< zdCfCAeK%x1%jGQs&|0pSr1Qq4%dh7(09wtf0~PhtXv3r(bx0u7&1mfR(?|WZejFdH zYF!NS6}{o0_z7$xdfYu4$Nku&7$(RLl@(lpPZ+4CqBP0^EvFxcZp5Mic2rE%zXz=1 z1NZ;8s(b%M)t656SH10js#?!%07~5HKVGk%NljKeLD6w=0lf|+TS>^l&o<ud%tiue zt!^2h$S6=Giy++u2`}z6qLsdbs6-S?N7J_=lbpus*6{}j5<2%;>f9}#>H60w2R4{V z=%br3j<l65-PYm3BzvB+DFejIF^H*-Ct~WSlr2R4AhlA*Sc*82MA@{abqg(}idwha zgLqL}Nsv@16zij0sKFC_NFf34*S$~}0yv?J0Js&vrj)EE1I-TN9EA0CtC<M{+<?6& z6FFE4TF?UYfGdj6BPBt+H;o6duR<#Y!-}it5nbS>O-{^k6d@un4AQPG7AF6VjUzh3 z3fZ_5q~;XN%OI-$m1KhRS{BZZvqL07@cDh3D7w%Bt8f&?&j-Nr0i0ykGq)jq8TAjj zNN+|(ydG=F!P1WdhQ5TX!Db?U3T<VOHQU}mlOVMu2Ly&bOsB%sl4(XvFk&-}*x!LC zzRfaX=Z%=hh@CcK#YXIi5i2!fe=uT83#m7$k{2lf6#Fv<E@N2U6okSUizW<Ag>_@x zt7IDqxWA(+jgHzy8Igwm71T|uk#|ZZ>%>$);O4R}X4LCkuh`%REWuVs=HG!rCLoue z<xsh-1p6l>1iS~=Mv>G)VH<nc2%`tT$)nre2Am2bw!NVmD5!bFkiq6pxY`ZAOz)jG z^q+n@xSK~vm=JlMN2q7@({dp}ATP<(PLd&Ulw3%Ff|w>35|F^pVdm^0vD`^tc91Bw zB~r%Xg&wTU35w@6q<Lpt?CcFRkQy?Kk%DH!e?$U11TKJEH!?8?W`YI)$CL>?&dcMH zPsB7tdnYBbcEmB}^2*qYU<-8Z%Anf^*)s~f69s@(clPVb(thqf4hqM)d*-#=oor-5 zN#lsS&r|do?k4+EGJ6W?WKc2mGt5|+Dmt_>##)b|<SMIHWGbY2&U(A*WyXOdm{FEQ zC7c?L)LN~yE`Yk_+wDGfA31}QY90Y6>rg_YH`Z8nxz&4xj-tAbHdf(MgUiAkl!P-0 zYcljT7CP!#u6biP>5ViWn}&k~@?j^mgCpPDMQfl=S_8qHoMGSR?VaMa)zx-^&0*7# zA6)ZQ|H`PGoX7o4Y^Om8yPCGZ?kA<uEDz@2Hi4|ie5V7R&$pl{@bF1vWBI4a_!RvF z3p)5WjDm;yZil_$dq`6kTIKdWB^|pYC`@kuQa%F5b{imI%zlx3!%t(+w4m3>cV4tH zg@?&+K8*}Vd*S&&HfX5aH((A5V6TK09+mcnIw~D!$Y$dn02~lon3Wrw@4kxjXPd@X z(m^)%IeaB(9fhkw%H$(X)JnT8kHa2I{utxPA7hjnf#0=y0!OmB=XLxvcKndF#VNuK zzoMd?-2u%z<q#N)28-)ZYg3uE(Hb2ErHY#wth~A>2CBpHDKRBZCwLpi`*hg@I9qGj z9Lur8Y^CiE?l$Aj{;CmLS4<%jp{$Rt`2r8SydKRAnc4R|Xtf+O*&AjW3F{~U6oK?@ zg_#K-#^FQ#Ra%GG8|EM!TmuF6#|%t7DqeF!Dk@oFJ|_j(Da|;<{_ck)CmBJy&*WeM zV6eZ}npk-K9LOWT0|6CWA6$ZRf>#qr4PCvXzXaT=VR**>z$nAdo`#FO2RP1Jmk*Nw z`OAOdHn)b%ugsh}M+n}BLUND57H#H5&<Hu))oq}$&?o|S#O|OEaBy^+!1>lTi0VxS z47T&J@v;?!0uUMf(Y1p>iShP0oF*YS6(v=&zZP<s=xw2{xP!|X_lIJRd{q}GhOi2U zq|E$^%ERHLlW+(K`1IQ=^vq|WyD(?P8q&;CiQ_<fF%ywK@Bq<$Vw~>Ms34J?-Pniy zYn?(95u%eNbUqMv<;wUOr#9F;j1x|@0_|n{5GPIJ?y)~fb7A$v+`ni=7CC0ASzpOM zMm0FHUt|fmV{1$Ib1$aY+61-D+y*0(9jw;N)_g=20hdwQJnT}`czEjl@l^5F$khZi z?pbycmh8YzI=w}!*29SLTN(W975;%vaDh7mWX9!9#&`_Vtdkvv^wY7W9|8<y<|XVT zXiNtZLs>Y&kKHpmXpcD(qhb16AU`{B1kf~XL0vH-#gJKS|Gv{E0Ah~>kOr9ub|1(? zu1MJMETxr;e}8+IM>t52N^FO<uC=Q;6vGeSwOQPKH5a*#_3vi{MUVdp3b&JJ`#e~A zp_g08j^Bn84oR{;wT7XX{*&&;n|B;GJ>tivOd?M50HHav%#r$heq`!PTuhJ(ky%wx znq`0bka~#wrSz9#<j17Bbe8#ueczmn3cr2dV@a-)l{j;d74BX)POY_Jztw%YCPiIh zHNWq^S~F~}+&tBNx&{k)zEbKhi{8AvP+!p612N>jFFU|4f=|9+9dvk!!Qo}Vy9J&v zm~IeI5F#nCn?PE_v12hh`esUlw>W+A@h?`;)vbDRB5Y#Mak<?TpT7+CkujV|j1yEQ z*Gayg!<#<DeG9urL%eE?9GJmP1>S7lIk3h^VtLO7)HaH9$nhxM9x|i^_LEtHz?K8H zCHPeU*+!FPaVIH|mVTv)Ls#HOnkyQX8P&gZhlrk~b)|Z&qM$%bSI>O=tWA#C%pbVl zsQKdC%{KEP_mQ>Mf&$5cv(v_I#W0W_V^93(ELo)GtBI10-28x32iaxhtI(<+BA_l@ zjw^{UVkirj!w+7*Y_*4J-K?esQ85fU^gLm{?0&B{=i5hZ>ZYag3Y_3j3;E~q^m(rN zFF?qBYU9UhRWEkLHmxZ9KK8<-l(v!;B>mCq!fpNWdWtVBgmKaM-azr$g+J<#hbcb2 zQ0tFBN%0AVPxZ&QP&~cxhZIjn`AvxH>sDab^Hf0Dv;uAlXk@v53ii-|QnDPw;RDP1 z2PN>w&U}!2=PY`7=uwPE+?0T?Y8nySU*NOAOX%XayKzI7Rc^MqTWc<$>E<$PwL7vl zkv@aYRV{iRmBEf(L_fBKoWW9JhC5+zj{7g1!4N24P2Ide%v4)K34z>*I2nId{H@51 zNX2XwI3Rx96sN&4<9HB)caTurL67Kief?7P6hC<gr=M1<niRcXZIPK>oF%g)F}D<p z?@jObo1yv#EeldG@J0XoAfdN|9??+;sm(j+5gm4rTD^lF@vTfBOF|nIZ#(Wwf(;a$ zaRy{9@U~0I7!^K#9d1l;ZNPG2FSI6LFyD}`TE$^#9Q-@3TBLF6B5={4lzGdM4tvs~ z6-wFhws|YIq8Lh<Zg3M$C#q?jp)!ek%*P7K&ee`l%gzyFRW4PEhr`+PT=Xn^6gC4K zUWofwWX4OGsIOm9p)YO^M8|-#I4etDJUHGeu;RZ^7w~V_B8Dx&eyoz<M61kO;c8~* zu!~?w9C5?~&|#1Tb}qR#x|B!Z>l38TtwK&i|C2wHp80$`=KgRZxh1|83=+DI7LEpU z+MkZ75t9D;+IEU#B?EX`7JhA8n6@+qky$=iyPii8wwi1r&?<JS@HmBNv$qPinL(sg zp+28`z1<{laG0eW)ss=^O#IOpF|%+Iz0wOO(<`}9@ch&yC9)zukEeSEf}5(bZs2=$ zF!uCYE)!Wk)?Bb((HT|@FBlWEh&`W2N6ab|P4oOr#+FBbuA^#7!Y0+{A<Mi<wg!wx z{$ffYonXaM@C~Dcis)QFyB8VMGevc?3j^Y<AyWmL3uwU7xVO+>;bR-8gID;3XJGm@ z;$6<k7|_g@$Ws4`&M{(_h{LZV<OKN!EW>sUm{$XkcE}~w&)(ut6clJyeBPL}z=fc~ z)$CW2)xTrQx{b`q;B>2)Lc;2`T9lFC?z-8NB?n!s*8BU(xK^!%CfKv|WOx@?o01w6 z;9O*Dnqc4C0{{4Q@)|)KM(W9QHWb#vGFwxU?zJ_VN>Bl+YdDL;p}37fda>@R6SrDj zO_6?qk}R!rb$*nXZc%IK02;Um#3@>4rASF7(Mt=XpYRW4b)|!%KoFPl5P}ZfgrnWA zqtS$tId!v_ikAu7>#=Evc^h5&fXz))UH)W@2c6M0S2J97yuJKxxZV>TaK0QdpI4r+ zbS@fnRJurQK_7~XIgVDKaL=q1abEbWSV*_f0eA|#k>*`!WLi@anrAdl$GWP&rO`B& z6bCVv=*jrB*jCcv#{i7%$*l<jQH(M;I?|DdmQ+80;>@yB&`tf9Q{XZ^y27PkJXy=Z zr7y!QV9efw5Cnfk<M`F^Vln3KJLsIXk~bBd3sZ42`Uma?X55{kE{2bO%vVvN)poIA zn4;0f*kM~CYQ1ai-PrHP!f5SWH5U0SL9^K5Wq&(7NKON+GXVF98{^r{eU*MH;3%v< zMggTe=?u2Q&tqeONq(5|`6On-JJtX(<1)a!mm%VnuCwGnAx(!78qQ9ltu2uth}EJ~ z3^SA*+aL|YC6PPn1FnhUC142@t_KkLM;Tf9-51A@q_(Xpm?)-uJgZ<WzihnzuI9aj z+Tg{J+g5QR=J8eHUKMYbei}X^pvo;i_EQKD=BT}hO{&0RJ%(9y7of-zK`xoSY&Y6Y zPFEPYVe|Plic?#nOW_MI!Uiursb}t{q)zuGdqWLqhzo3nk!QzMdUWTudVHvh-G*u) z_(0nR+v_gm;GRUN&tJ)2%;j<&|3IFc{R?ptFlcY^W{{3D!9ckmS$C3O8PH209p~9e z{+)46hwW6pr75qBalxsmd~M;Uo<G8%g2TLRVp_OGOzAnklROim%W*LjTATSMp)d8i zq?n$01YuXFVYH+7VIIfK5^&7~=k0QNJ6)Y{)=ECO2qi~T!<Qu70ft+hQacsyD&2Eh z$)gIYm-V-T#1f9ncGd-ZsbN4M-OSzlH^QZh4o%c#v(xy>SA+%#t45qVibcobs<d`G z8Lb*8HLy&#A1pRm<aQ4X(?*Mrm~dr5;s#L07+Ct}&~$fIPXx<g_)IsM<OuD1E;JIP zFQIX<m1_87#b2t4U*QzLzzG+p7}qy3bxtpG-qvtl%y|*ygcCeoxJWJ``j$3Fr&@9& zE!v#EfzVe2q273it5<Xp_B|vUcD2-6hx?M0;l8@g0TO`&6BM{Tb@1gNkDGBGrXD<{ zZ(cW!?SnyV$lX95L_r<g4TQ^pvS<VSq5UL^odruW?BVBt8}1^?c!k!atFYU8J7m|6 zno=t({A}vWl-I^qpo}&FCJTWD5LEdld;g6%oC}fbHuu%_(^vu3K6&6~qC@ZS+Oe^Y z^SVGVzPaA<9fTV(kD%7T9ggIg!(2B6W(>kwnXSB{61P-pWf|oaN|g=9D?O8B6&W+& zf@Kd^Q<gF-T&NBxrsymEO5xw^VLD(y;zmbG+*j>emf=m!D*ruiR>va5jb+odu0$K5 z>_D<XS%HCw2zL_}pYU}em$yOBrt5?{+He2n6+zsciM@h4=%$S~{Wye>k=iUxMJGED z#`Us27u7QeS@G^vTY6R?{fOF1Z}W-hJcO4bg|1Zt%!!T@XHR^7;!NsMsjKIb+6gFJ z`G+r#o=?puYSP_+TW_tgy8*i{WnnHpjJq!<!*v!RD?+xO4{$K?13^8ep2FQ|sHggn zLy)hlgG>puw8bJ3brEJ6z%Xm^y}t7Dpd&bNhQe@xIIN(!70Pw!FFI8*1Ir^oPjih? z*Vy2Wf%V~iIWy%eeb9M-UpHNwxlUX9dj~E(Ew#x{;PTQpxz_<Us#yX&;$NX|r$`1O z(U(>{#l;Lak%6UJNEUkLSZI@TKf#GE)Q8ow)pdmZaE}hNNia)a1AcJ8q{(K3%;3~2 z4ufVW3HwQu;RLw=nQqh{%hn&u(jS}3GUI@lu`TvjR;ZuTu<klZ);0YErab8M&((`+ zg#52&U{9I89>sTE{}jU$h(x!z1owe1<?JWrbZaEtAF8g-vEEybn<6vV%ba;^RfnwD zeF-+wT=%iJfZWRS(4JOz9`{R~46o3a{{+sUDX^b?D-~0~e_{ZsMaC9@{`M3=jj1hN zV*$5U`}cOBc@>pv;R?utTu7RpT!=+%)4+xJ5GI|5nW+#w8wl(m-4EN8l#cxv+>8|^ zFFYU47vgvpcJ?ZWNy$Ql>8Yv2@S`2{;eU_(8>HzWTXjJq_kP8NxK{Q{azDV#!w!Tx zo<IR?_M2F0%wTu$*D_qJ8ikMg69mSlAkA=k<=2m35wM#GvjoYQETZ&uvcZlcG&<fy zZ$s|^6}VkhKz{@}_8}?m=4%iC2ob(4<YZ_<3>12pC<J>MJa`j0E!)W-_vfHdoZ|Co zVmt<p9pDmRok%{<d45JN|3rBVdN-&=y`@;7CaA4+?bdmAXAUULK1Bssj3BoSC4)KX z#-UOSY)SA!hO_a2*D;y!s2lW5>Jp<&=hw^pbPCGUrFQljHR*6h|H2G2cFaxN1?koy zU4YX46;LDbV*i9<)fk*`;Ne_lMWdg^zz4RdJ&#SB@M|a`?wvf%&n%bli5yN&f*si| zY%1W)pR{`L0LCID!L}7$MtNx@VVeygF=%vD^f8XfHxYpMus_ZSGyUvm<k$g%PDF34 zd&|#MiZd6=>hEv150Mt;#Is`~dKmdfu@Q(3B6H{{EmE;j9zDtRF{Z<qz`Ea9H#OAm zI=O_L#2st1*`EQ%9c_)G*-FGgLrfy)z&+dn1$L3HEKDW#JaQvCRy{)(;4zKnp8WKU znBo3#tt0mmnA`l93Re0Xt~K~fs(%fb7KEtmSdGWGk7k&UM2F*$Q?Ad3i!3p-s!5TX zGceVS4y+k5Oq1vH90!fnm1<w^<KT$i$d|aA=8>ZoaE!LqR7@;{F(Z9GZmq`Z!X7?_ z4;5PWt?EelU#ot)s2ncW7~Z-MnItiC#d5cN<*s$+&|UYd_gLKbSf#nN*HtH9ajqSs z9y=A)79?1DPEA_6zql_&ngRqSjfrM!cef9Gd2T=Xq2MD{8P-Vw3%u6U3ak2n1-?(_ zvM%L*3$3W|yw?iHDWFB$8bfNWipigtl&UU!81^FEYZz0jVv(zs&|Tokd#c?Zu1ioq zG{e}%b0NF?G*V8xKfnnR_~}1paX)62+y^<%SDkA|t8bk8qUZD^5%?}JTck;Z)UDC6 z+CA+&{bd7N`o!^l3}~Vht2*C8R|N7B)%jLsp%p}ik2Kbo*p7lW{lMN(he|LYYqk?= z0MJ(2EJFT;cv|svFSJU_n?SC{GJ9X75dk9Nb#=9N0X}=jI9X3cflta99_G|7-d~)O z6}^!IIY8DSPyq|#f1rk)`dn+^c&A`i)~h5b#WUc8-KoRscM0EjY~+(~!vLhFZ3IK9 zd9Ol*gMvp8A|Kh!rM5rP+@Ycz3l#pHXNi}c;<NH7&aE0B<z0=`rAE0(?JF%Z07@No zj~5A2ioD#?$5Z4D@W@z6iUY&rX`X~pa!`*f2NJL%5t|c^U~@H-_&xWCwqW>$a;-E2 z`!9dPT7%}}I5E#b-H8Od&LV%un!%-Gr${Y=)rZoRLTVqk55Bo$1A?%4PzA7fU~g_F z?yCKEa|YZhsG0#aN%{<@qv!^#4RRvoau~UGa_Q^NFmw3e;W<$8*PO*rO0bb3wuLM~ z!O5-H4!R%k49dg49f};GuX7AkL(Pr;OkQZ!aUs?wi=Ie`sU;4~nbp?*9oTYQbO|Yj zsa$=`fkkK3Y;G>X?P8bJmPeYo7&puyF@^wmWA`f_tKzZXc<S9!SIDAX<%_P!XLj@B zwjgzB92tzLRx<W%N4IG|5!OHpEQVYE`XcpM?mLkV8}?)7$fYq|ZoGhvOI_R6i<jcS z8<wgzPj4qheU`R5h5$tpX>m7SdIM`~Or#UZRYY54Q%Wt$9IJLW0#;>?MPBjqVhoV; zlvjUF4AWFn)O4gT($I{)YFt=^^H>`!oW~%OpZA=c<g=<Rg9}M4y*VNH+QWgBhfRGi zw;U>MbmVipdhBZ|txH|hiz7Gl-50fu1-<G-rObf^u>JdsfmnA7^c<bQ#?Hkh`%`X& zpnD>hEl`3n`SM-sl0tU{$X>q8;$CKziVOvJ*|~NsiDL{`z;g|^jWpc#q%X!qC(03M zxWSLlZKDPbQF4o{C{2O3TVzo;Tb0K#Q+MRPZ7SpU_}jn#0-))j1kTv#mPOivTd{%4 zwd^vrs!Pkhs#H0kAt`^ALkU=wdn}|<?y=(O4p^nirUl7RBO^(TBwJ+Nxi-75b|k5h zcZMj4F<SAqV)dP<lYet)i@v5k8aUEO?iX|iw{7)m#kb*3Wo3a0m)0T$mM3LyuTp$l ztYa2Phvi;AUUrRk(xJ?6gtx##lX6e5w$#<DN{&dMWg&(SB*=ZdN!9d|2KI0rHCgJV z&;1`j9QUGu5v7ktl(#W%h)MnQP9Gdm7V;5=fB6QnF`|IpxXvBgcD)s)lERf>H0@Ok zd<H5k>(Xo&)yIjH<fjb!-h-z#KD2?XN&VV6$sz+Gkd<raw`opOcj`;h&IO#TZxdPZ z4UKOf^6_zt7ANb%A!PMB6thyC)r+a_PzKM~!4*K66)MS`NUBDTjFvy@#0U-Ute7uf zcKR!8Q{}hyQ(wqsF+G|Fwv&(PuI^Kx(>R^R72o@q7*tqP_msu4DSfH$NyFrp4ESca z&(tvY8ELaRo(ldKFz*BAed&QH)<n4IZZKyja^4!xnR3my_iH+lBa=N3j}`R{>WObi zr6kZ4mAk2^_c#=jTI7)Pb@8vtc#dR|Lv=vq$X9UtlDd^Mp1N^c@su*c`5m0>#_B^g z__4HDE$DAcI__gtf6xHp!>kegjI_-+C4a%TVwXPUZMe}J1*6cAa~bsJ(Rtyc(3@pl z>V20j>abi)d@jcM58}QFlbUL5W;c+zSiRfgzS}A-g)DIis=Z!)hXlM=+n5h-RH`ma zS=v~v;IGdvxzw@?82KlqMyEk~46v<yOf;Y;jp?%^hm;B+fKIx{5}zr=P>)spH;eMP z1r@6QMvB4SfPFD2q<+r4+o}MdoB)(^YaFj?gELe6BH+qKaB1xn`V9{$m9rkC=F1ef zI>@BGDH|J$Y1ROcv_S?<d4eWg+N%bt3)}gu=+qY}cR-QBh@7enQx*&-p@%M%I?X3Y zu90*b#JWpO*B&=1vte8w>mE-7Ey#_@7N0Fh$?|oSL~2#BYI7}vOiqR)E5=?NGR8tB zo9#LX!w3C~UyLygaZH?3TcUGuAE7MX;b)`aN#j?~u$HOh!12ph>16TexK~N0Yr$$0 zQ4*NBBpbu-F#K*pgcc8*vT-7a4<7tn>k(SfZK0C!lLFY}rHi`J(fDD6Hr&lI2_KBw zIU?-E0~`g~PO#CPh@y=O!{I&!fGvKu<$0>2w%5<MrH3w#$w&}=7sdP8p9siU7w<nm z7HgP0V51s5tATq6U^`U8GvTeJ?8)cP8F&^*4sH$ZfN=pAhupw^0%Wjqt;H*DSR92) zSmFSV9R~r5)i(By+i>@aHq*FuCCT`a0drf^lAMII$FC}TrlR=9?Kj|AcNJH!)?GD8 zGcXACoS;pG>)CXa2#jX15nrq7-$8KnNJkOs!EF#uaX8(|YnYI}g=4|!23pCy`#Bm+ zu5a5R_-ayjak8b(-mnc3_GdD^dsf4^S(>4Rvw;EZn?5y3pP8&^PDJ(0cFcq*^K!rg zj;D&&2Ao~+Aw|zThwtikPAy&lwkN~0kQ4U{*tg6D-IZ`LqD^6HA8zUkKMWaeN>zEQ zUCsEV5!xIHQ)Rf>zD?eM%bzlvd@~ytcQuy%gRa5}CD4^f(R=I%BR+Qe0&k3Xr>aq% zxo?=uuv6r5AF*$F0R;m#>_IwK-fl1@W}@(?GOouf(m5j0aoGJbfP8H95E#uuBc{(6 zO2nl~<uD#<R8TqYIU~Bna~ozv!$V*xGQiD;x7G)Hcb88MQ&*}2$Y;3u5aDhFn98eG zHDV-lq+kybNC^{j*|%omyL^D!FW|yNu+Tu6z+p(Ct=_J*YYILNW0ib>iZa=^zJrJ! zrt)=OE;sbff`iGd1Zk3epUZW0mD~qXM~aGMj!c5GhuUX!a~$wqou{#!>#z=9<>r*M zhl5lPFEk;Jr+6c7W$`KeJL}0A3hd^1P|FN#aF(@z*Jpq7@>f{Q-+=FGdecY)%f|cc zGu3pZ*q+~!jt{P*!~$St@aJpbF4d4i-Vxxq@G(#)&Ru2TE+?|!HYCnTsz!v6Um#u+ zayf5k;Zj80WsbE4>NE6J=Uvq_Vou$aVfZBjPOVlU&0{bIjvN|+`U6ym4);i$d^=;5 zl8bYIT6h}LePA9c*N~FIZl25WB?uFzmAl2h^-i8fRp;`Sz#?IPaskTjaN>(07!Y}T z_yihOKusz``e2g?5BUYk|BWV<sL$}PMqk?ZjhHiMm5gSMl6kWdLTL}IQnEZAnYTG1 z{#vCtJf3>aGkw&)J^%ameT#-(PJzMp-Otkqk0I^5i`wVG7v7+a1fqSTAta}zmvz0G zx@VTr7Bs@Nhak;w^QPeHA8LcS)x_n+c%lX7R-*;Gq4sKCb9MXu!NqA<)M%YBV3und zm75#k7f1Tkh|eFSvvP64J%eA}Y4}N8$ar_EExD~ets##x|1$v=ZRR}$=>Bl?8&R9F zQDAUBQkEKmZM5DHXx_)eK!fOAU>S|F((fPWdq`dBGx`|@J}I1-@(Uz|-~|$yYs;4p zP?{jEmJe_k@#ausbpe-9{QN{BY_##ctTY6b8PU7q(mR~2x6xbUa>4bz2NqY(fpz&~ z`Pw;$y}p<7XM+^%Ed*sJ-=(*y9FbhkM9Ut)EP;M^t@7vm$eSa`Xt;h4;IzueuG={F z10ye6$BTnul#1btR}AEB0~>IYSP%d>`?7EV&KS~9!zzz440i|7ui|Lg{IWE7+whCZ z)KvSy1-Dw{k4)lgK9*042BW)b?k=8zn>I!fS&f@*rpKrhIO3j<j$%<18K=x81eJW6 zTlCvZ2}7DOR00qFGel2PsdSr+HHNlbMTU6WMzUWH6hv+MFXV)Mv1Oo5V_E$G0Jku* z6vU}9$Bo9!y0$TPG$x%lrq##3J%t*Bjo;+%;v_WYRvM}QG8u{34L#pZW3H4M=Qgy; z4AXN#)p>CYa}tJS=W%I(d7$=x*1&c6${V<YYBJ_Kv^_{aDPhI*?saU_#qFYe-cp7* zaEDzbL{>@c9gbx?z6Nun0fXOb!4DLW2?jT7!vVdMd7mSsy0j9#AYc`<OR=%Mewcl) zqq}(6c#G6Yzj=gC%)Pi!Z8eU|8o!G%uoX>n7Jfz1V#o+Oa$pxNgM1P&ZKGe0q5Vt; z{T>De{Ep9{SFnG`FI1SoV!yv;`?4NUv<25GG?N}eUQ6SI=uy5WdR3axIDxfYo55#f z=$Hy{zTtU+)%=V&0UMrH30oH#_yI6Dt^aZu`1`P<V*%h~TnbLB@K(v*WN);3=HaG< zi8zlM9Xk-U-i=>`D9ez(AQa4vSswQ(d-w?WD1RbdWu9S@^0W<fuOWO+C(!Tf!6t|w zvcT1GuR(;#LXO+d@#`?XYd@x6py}O>#d!;f7~MyHKW3`fomqFMwlS$ssm(wclZ-Ml zco}CgC+;sJqd>|)8F06MC$|i@?O<NeI5BEzT$-fkSH;M6zl&V=L%t>aM`u8w|M)-G zY{}k&C@4A<7#l(>)FZiX%a;>2mT4Q}D8!p#ps?hdD4-b`aNy5woXCn$rg|iF(-Or* z<&Gxr5S$Z;rVp)Uz;75EX%I}1WCSkzuFwB74z$v-#fQP>gTI)PF*uK}@Y5#v#e(q- zv;xYns31@J;EK=5mWtkkA9g2~GSR9O5=b<&e-jv<A#I72lmJqr=Qd5I>o&ZO`T1F* z)q~$P>Xwg!H8OG|rEYIVt;wT!Gj<R>+&1hDzeeF0`x|x<i;zbNZB6mtMRMXd36pSm zT=6>9ybGut4j5HA<QI~G1rJG*<#oWq5kqns?kDz!r;xCz$k@>6LHRXzXvKF~3kA#> z*N<cxL|Z+KP3`P9;Z2-$i4OO%RQ%>k07)rr0?`QeM);(V{^%-zWxioH3Is2A8P{OY z&rP5%nx=k&n$<j_NkxSLz<umat4FW^cfVnr1@H0NsA};>{49~Z;U#2omu1_Z`cDM# zdqI$#p*cIY(f2ntdE@&rggz`XDRJ~iv9~9q$}UK8s4a=mhl^!&tdGtA<m)YfCl&nn z0XT>Iv~ctd55RaIPOhk+pOdmwR78^uL<kU+bsFP7?5}>~Of~Yd-(n&PQ)r+gz`F)p zD4nDedGBQ4NFx0x)j(H~UY_VAW$nFywFF-SPC`Dn*J*D!ix$Gy32p}HKI%7q0W$Xc zKy&oLpVU0Y2?}cCt3goU0@t2oS9ixg<la;$$J*EDqnnIQ9mV!f0#$n9w)E$=WKNYf zP8An9x?R(+*w#zHAbVAO8I8q}h2Q>=>rO<_3s4Z~<DoU;BL3)gAPyXJ&{4P`0K}0l zu&onO9WFrX1lBztj_aO+>`d!LWl{XdE%m9vD)GWHsX;2})g`77EkFAmAfYFLnGHXX zMP90Z;z_OA%61qR_zZ%L`tiVxkQjqNQW`WINYtgN2;xVtI5yYR#-;)ZoG<!kZW86? zgMz-J5u#^E`(+UJPI5fLE~}r*I^3ROK$tYCl1G5inM1^!9Kd*DA}@r??>oe_kl!}E zx%@H&xcp{;DU!MTW(~@(ljPUI<<~YSzghkA`zz|=S@n7++-%m*94fmfi0)sL-9_Zz zdu<<M7hQZrv)qNB4y|BsZR0&$NmZghNP1Bd8i$LhGHCx9KCaYUuvi5<N@hQBc~o+B zlW=h4!QR>QBWwdLK^HU6c(6C|HVx_X+~~y##MBNjwGC{W#ex8!U-rv_2%f`c-ZdNn z9?9$?rikGy4pF`PTjGc|ZRLf5?jQa1Kk5GANJPi;?guAc+xMgTsHL#!e$z#UrUT@l zUk@R~%`0pr>eJU*SrvcV*kb;6urmJ6U|#;tVukd+o!!o(PBxvtbJ+F#J(W%1?`dol zf6rj){5_K;@pm@s`){fypLO&1EcON7@?np@&ci<8NyY3ef0wdT{Jns^!QVdC!r%9? zKl1ky_Iv(b%6`S)%h^u;Ucr9G-$C{x{$9;g{$9gm{ubF2{Jnv#<?oH`+jtWSd+Weu ztcp_iHc;?h9&DuGJRT%Ra5jqvNhz~idGKipUeANiQg9p(l6Mz#@Zj?lOyt2`6ug41 zZ+-7>3Vz9V!KV#efyp~X%u|!xiTo-B=z%u@f>W~iIkp9KxdKxDz*E-2p~c5j{A@R+ ze65g8IL3$jHsg7=7^OJeiA&-sqLGr}PFxyK`IeEA<xX54Pw^Qk+3v&@@s!y{iqoAK zjHgWFDeH3Fd8>JfpN*xIerzz?;102n$7F12!BK4-+x8-#XDTy{`TiJ0`8+d<8<uH$ zYQayceV`uCA1hksE|SRi^oyqS#$j_yFgG+Wk}knT(}63p=2J2J=k_i}_Y6IjgGr7* zevSYq;Alr@zR;8~tQm*>4w>w~vgF|EL2M5m)sYTw!=@zusnulPX~|jp1&$gXcJ`mP z;O1ORfv%Z3kBC=BlG@*<S9f32CNH8!o8Il8I3L3uZSGTi4t;{pdTGi#3{&2@Xx0QY zD>`N%YF#vB%8Q>2M2l5EUB#JHTgXQ<&Ltfiz($y3&ZU~;WOy>}!x5+X8-w^|UyI)h z|Jje<jDDJr0nJZv$M6!|mo`A>G3+D2_E!)YO6LLp&HHjJ<m}aR$PA{&1$PN|nxy}y zy>9`CvP%DcVFnoyoiWicZ{synv$-?F%)lU^SfZmKNQz1_3Wz}Pj+a(+aIghNHrwvI z)@oYoZkM&K%<dot-bze2t^603)k{N##VW2O-|so^3=F7k|8MvE{@?%qHTrPQd+yig zJm)#jdCpWc>V)X5Am{k7bNq-}K@lAn>>LWmfzeqKrvk?tcuF?xoD*Uv5Zd25tmb%= zyC$ga;(j0`j*qMgMqeSBuh2n=bmrpzU~=EJ+yf6v|2??YQ~K{9{WsmU!QKjgdC>pq zwEF`0m)OR&xcO6WzJdwUF5g51W!WX7U5jx+umUGVxG0^T2K9XIFXiSdi<dZMi<e|J zPXSBY_oV1xyh@6vP;sZIc+w9~b&h)|VXKYX>S=h5D(h~R7UQ<8L~;-h@GQ8`hIe?X zQ^_CZX?$+Y!Jh{K`v7C9c|)Psr(#A>)%0MbTQMWpT`zGru+)!srH*mg6_$kxa@PmD z8-l3}Pj`jdDu%&(s#HQe;tJo2E?=Z!MnNV5lz>Qp0w4o$fOeF}lkl5!l?nHqgDJoi zV79<)f!PYP6=oaEHkj=&+hO8Z^uCU2X*H_ONm?cCzUJ_BQl%FGascZAnD>j9Ksi0t zIM6QE-seK|GO$I^9R9G?yc$PQrVd{xjO*@%{y+ZkR0r~Hx*xf8Ui=U(y%koZ<?oYA zVxLT=J~@Z7AOr>8+6H?hEH*&ZbjjG`6*DC6Z&~Yo$6D{N0ZCKYd||r#>f2!VcdQpG z0zz&L2!|S=hQ2=gR^tASdRD$E4O2BB2GV{IW!MJT1$Y+l65tKM0l+B$+Il$JdN|BT zn2|6eU`D`Hz=W{qZ^B_hK=n5=m@=4Bm{6)8*f(MuwIaQCfb6$6ZaBc-#wa&hAfPYU zH)<Qu4`LY6tw-PaCmYP4hi^Td4ADZMK}59Y!RH9Tv=9TqnGx_Z$S!OX)A15#hY&Fk zQ|uV1xd!JzA!DbXBjsuEobuid`l&j(1LPHn$a7~I!G?f?MA8)WTwl9z2jXOSk1@6V zzW1p`rdTzYUoPd3AnkC*N|)>MB621Y?<y8CZ~#p&B|_c5$e<f8v_1(}B`5q1rpOiZ z)O$W?Zp1X`#i6T52yp10?FuMz=ya3-m|6#annQ<!s?A~oD|;pI!w!}JPQyL>y$kI^ zk%D$p-F!Sye%P%LK}&nBKQYQrQ3(aW^P9Xk2_w2v6UMXj-N|Q|#w|ZbFB~<2)?d$j z=zl^0#`AiPvJiP*;=6cE*hc8Pizt$02)qy@p}%`(xU3;AlH_B&1MwlPj*Ea7oCsq> zu*aPRMaw|}%qZNam<Qo(Is$iFw_-biJ5}<{xNQlh0<H;n4&KHHVbX^&35eRK52Nh| z+({94*%5HH3)>(}k9RiDk^4?crt<^4@N3brkvTr-b1W7eUt*4r`W!Rin6Yy^zEF#Z zoNZ$Ab|I0uZ-e^|`UApcj%fr1<7e1~o$&0`(-(B!KTIJ>amNLI3NDIGWSfYg)yeI1 z^B}a|g3~X1=P4xK=K^%nJNuR;qluK9*R+Gmg>+SRA%&7aknyC&rvsMZJE(l{9Ap;^ zK2OM$bufSE0fVP7(&vuO_VqUlK=)?552DdQbbI5y^&`Pr+5lAw5@*DY1SR%v6PZ!j zpM4Ayf^m`?c=THJ2XUYs>;w%5j&2goidzr}2g{jsu>7h2VEG_I1|BTiyJC7%{HlSC z5SC2@0U=5VM|?oGL`Vqp{X8Wd?r-~&syhjE*ZIdG&dfNHmsNm$;uF4=VroN5zg}oY z`p}O<LIzM$C=~`hjnr@_RoGZb7DoG&wM@ji+`X^85V93yX;2z&ScVA`h?6FSy@N9> zY-RI?2;s11h(W+~5)a1cZJEk{^Lr9bsQr*u`X2P6_bY-xfru~Kd2AhdI0U5UfAD|| zHtY20#iULCFXG1synB&{XO}3@V2-ol%^=vsXE3hu&;%~MepA)iDdJ~H&(CM#^X-pd zf&oFKjp4XV+FC+g@m2Ev8g>;SsY82Ecycq7_g8rA6X$vC<K_tw=pgq2*;V5Hbcq2s zALiR}5uSUr_uU11HJ*zXUv@yKiF9{?ZY^~3(eCx*rr=3RGe2(1>RWMZ!4v*sCEk;# zYYXdN#Jz<Z#d`}0FUo|Ogipw_1QzcrRP1c=i3n_}Q5Rgb%J%e!A6K?cN@c)PzjMPq z^TJJYWzG<Gm7y+W?&}X?KzRH4EJy^RTe8Y{Y30iB`E%_HGBPt3;)X(Jqo3Iy0qJsL zwX_INl@l*O0m_naKCS{m7nyU4P`j<Ch{sHP1J%1q+evMU$P)&y{WOr4sWgHQ2O%H4 z{t*6-+lW^#T2iV;0*&LbboZ;zqUb>zZY2IQ?q%l5?7{-zNrb^Dz~k8WAA~<VppIr5 z-n+&a4yhV7!`tAxe5<pMJ2^7g3#o_6P6-^rSOq(B%N@v**e~VNm}Q*&J`*fB6q)3@ ztO9d0F#@c3aC53cEo<?5`vT@9Bd5{u1G>URYj?ZCIS9d>16U}jWr0&VgR*#miUU*x z%<%q2a9{Txk-ri?`$Dahm&xBc;%-)Xhv5<z^5fN2M_kQWu1iDVzDDA1R=R5snUf<* zhN93iT<k2q*(o(2UOgJ0QuY`yv{FaT!RtFprq39fnZs$Z@Gis!KlxuWBP1W<%!jJ( z!G!MIxEpu3cLzDG?xtYAZyA^!5M5i-7qy%WrvK^*f)a-i7ZM|b8aNDk4rd0*9i3h| zTp;JM0LV;I58R86MS})c8p)lPT+Hm~(SbNq@J9N>sCsxoV|CZ<d~7?rkg_R+9x8W+ z=Byot0S8q-&tQ&YVD!*ML1fgwVZX8-!~S~vm9}l5ef_j?;C@90575Ta$KemNg2F}O zPXZtZ(6tBosr?G24tlmL?6vnRtPI!PulUmNBB|4WM!-Qp4PYN&4`4R{H15A)ze1UL zI;qm(fJnd;Ko?E?e{8?9^$E(C?N@BDUT44ZAj(2J8id%o3-*J6R)Bwxan1b-h5mW_ z6_&0)tuCtmr}itpv=flUEI=w?5g;3o58wg62B2^L4f_?!%+t9Ye|H1+0gjT3e=qs3 z>{l3dK>LgIG~rF0z7VUHx9^}AxZGDjon3Gd(=W)`&wVA>IsAex0Y~E?Eq;rjc|p*$ zS4nZO5#fiY38iGmrb7nG1ZXBq+;NB}32DNIAV99(aAeeD$3gl8!qbJ9!L!dG`8!6j zF)AyEsH{4;`?egzgi?ICvE{f6rnu#x^K+t-d+j(<5db@m=&o?$j${8r4BPx1nSgOr zpMbptu7t^iBiKTa@E_jD{uD|1if|1ffO*K6?H5?Hh|4B5G#HS(-TcViGX5swEK45i z?8Nid7cUbfiTh9VZ1!}ipHGMbjc%e1gsVxvhuDd8aKCP39Crmb=|96#wSzv``4QF~ zEKWsfV0@F586KlTe?*A=u>vX}5INZSQTHjuu}YR;S{ek?APz=CVKO_;H57<~n0si) z(VwLbonud?RnKpoXQzO8{w<uP%2(sEE~HzTD94ud#EOSXTx5d<4jR?i@Iobg7l*+b z9Bj%|@CxHd(soUEZ9^bDRtX)+bX?E2uB}2Uk`b>1J4cCu@Y=-Q0SG3Z?~CfNA(-bq zOc%W6d+}WQ=LgU&v}GtoOiu-o4DL%o8^%LUXuVSVK91nz5AC0a4xF2o*Oy({r9;xq zH3$uIC|O}<QHqtu#X<ZqkBj27>%R`Hq>zK9v*YFr*oChjpiZA8`V%43?te@>nwET= zx*{i9?w~oXH7}@VZt~3($om>=7LrTwZB&Gl;>NVc8aTI_u4dycvWtyl4|)!a=Wxzr zK3E*)sm*v0uWd=k)!j<F%gvm(nWcxON=wI+TN&cL^pd%3PtC+#s(sQTay+l+wqP9V zeOkcituQ=~AaHo381EB12c_h-d1WbifA>mK@-E=H6m+sDv~qYKtmcq@`39$e;)oai zP6vWY63FR#stS86c1bQRef>gnf4UoAlH#d_bgJh(-iv3C`i1%)39N@4UJ$P*(QuVt zA=!w@M|j0dUN-YOrErJ$LHl|K3oE)yQ3z`#=`R7D>%T82GAAO16tRSYu`4*j`7iH} z@io#lF6c{Ysc_D5!VQ$TN@%~oYbQtoK7tG1pjVKXH`v3`ZV<O>2~Q0}c)vid=c2Es zI#zL?G9JjsES5P9*mEUe+Or37@O@MFQ-p;eY?*2_lF7kqg#P`X3K^4#&Il&$D+>Ag z7&p}kMjWIKj-;sy*`tq9x;nh1SV}uP*`r8KL_IW1uhK<Ooe)HEha)bk5t*}_s*y_d zBZ+AUkDSTtCw%k>5&=GEH-|`44{nu|Fi>M96!mo4<kfT|#G`wY`k0Q-UPEz-Pb6h7 zAxsNgtK3bpaTlheZ5O#W;GTgACA3jOP<aB%mAMV?ZVS>1z}f;=W6yXcXbqxvg^5VS zU3vyvpz6ipkhGwRQ=<GZd{9l?^)~M&Xb{4)PRJmHN?*q!e2Et%gWLl;CyNEGy@H2o zYnwtOIG{cUbwi!bbu*eLV}7!CHaDU(eM-{#tm<%9k*;?(Jp;@3vr6qRxv|$<o9-Hj zY&3cQqxP#1yrsmt%X7?qc2w=zKE4jCPmoE2(uI1Ez0|DIYYA8l#$jw7+Ia>RkuLeF z@b0BRe91LOiun&rLy9#!2X~<ENRK_r6-G!}SSrB+CLWTXUmb8ts_RaOHg3s~C^(I+ z5fqFxdN^<x&tR}XSids)C|)|NEIo-Ak>uq|sEhSE$OKwJv8;UH86l!jezCh$2y!kU z4WPtlqch_>m{TGY%QqyRq@@6xT4KSS7ACxjNz$4z-F$Jw!m=yu=sKl3!QhinxJ?*B z*&F~tVf2Ze+?tM!<{3n#6KSXdgTj)FPV8x$k0V*Tu$CnM5j;>Ng+$s)&*54$f4W*~ zAZdhi!nb$Rtc4B}C@~I94u#$5$vlb&mqt)V!&4{(ERe>e)eqiFD>Iw0#~MMOrqYuT z*TSzW6e|yJfkFsj7CMa$85CzSf?y%_C3OM}SYX{IVKC+v=1r5gA4X&+AL2=FtVFfW z32Q%w2h_}0JBV2&_L<d5eMVa$_M`PcMzU^lN$s#h{c1CsKe|LRsXo_Gzv}_GV($bs zdo)3DQ5Hu&IPXbT;2kG#pX%SE+3?m;VIRP3yx>%rro^Ac^nw#T>NE#V8`I&maS5CX zm)r2Cz>Ytwm*UTcB6zHT+r~n;ZCnGljT?)q_qvd#|GB4~9^?rQtpCNQ;gzLrC<e(R z;)Yh;V^H;gCpiyKK8%`>(eo)N&vD#cx*ex)p7-2mH&!MK=JWiZ$>-^^{LPq~=t9C| z$pS8_tii1~9AipOOg@g6lq9DoWB=Rgakh9$TM^)gT?pt+F&}g4FMjB*Ra7QJ+qKvd z=irwtlfVJ7=bytIn4EadK5s62nM=$8np^zMhAYL*!9P6ZL3t%CQPPA*RcvEiB5Lcr zF!5r9{5&gR7gLucBBAvt6WV0|h8FVCH+%_hFhC|~s_?j{r<~+?d}C<|By)fSJ2y5z zhS=;(l|RDv_P8*zdZMtnSM)Ez*y<G>f^<uLwA2WY8yMI!!40&4T2d|vKHA1>Mq@#; zkLX6bFe4acMJu<;_lAltdbmI~aYkpdf|r4clS0|;yOY6v^u8L%U1bz1+ulQGp$t!` zy@3)1a#0h+60%BpZ#Fr@`7>pu3aa9o6N@vOn~@DBjh`yoD^f*RV%gmZi9Jt}gNCr> z%wqiT;UG?S5^-9`2w>dsrJV<DU`T$Ly%VsbNTiIrUHl4;t)y6tZUvJPF(#a{EFJm< zhMDwAIPfV#Jz5Fq^mZ`>nAtX_sw<jWFpHKZY;10}3u$CEH>@7&>Ep5(t<Hhe#CD-T zY-6Agxw~FU5A!)sP)lKG^udZ9<ZS~FxsjIJFTkbE3l*XWGvFo;^cfLD8KUI4r&Nz7 zTu1&xmQ)&9I|{-0L>~jcHE%*&RBCZPWUeQ!8)#1^EQGJaXhR_a&C0mS_51?6@H_;! zJ?%5{u=4yapN-N=3DUn&7>Wda>I(+IO7FPhnH3-_ytqV~R54PJqEGSeqF=Mz{dpR( za{5UWzwq;&NTd!G+HxPV_j3y)39W+rF9>UjkVmGBy~PC82dS8;ehyy*tsta6ZrxJ| z19!0Z`g_WVpGK;tq2QC6(^Gbo9QH~hn|H$EQv)rkhxXJpZ-X23O1t-oTtoFW)l<Jr zokqI_zk2G9ip(GD6R$u$^<Y6(;ivFPQ*}pu;*VXLs-@NQ+w&yz=F$OMT4xa}u(0Vv zYLjs!=U7M>3XH|QiS2w}`QGG9wN0{qwLLUd(>_PU=ZwFV0=(Ss5T8sN!_x3q;$FOS zuabBc6T;3_h4MG!G=D5k262oX{Z(<F=+D;#2Y(se09zew_0dh(mp2DFk82M_H}QQz zJ9c&!2VeZqQ@fB(nY%V$KD^UWK+UQkJr>SEfj9<>DcyDyaZ+D&aiHw>{r9pi4-C(y zZ*v8U63)My#!!;^z124fM-ezMa;g~F8w-XnNju{#j>H++VH_@x6Hf6OupJ{efGj77 zD4L>h+Sdt>WB-k#P{`dW0&@q_k-KZIh)&m#_4Z>AdQ%nY`;hTms5FN9evg%=Hz|_~ z#i(|Ot2)iByiR*s8lE?R0A)R&N-D@pF%D=s?|?%*{BWR}*V!3Gp)hg`&{&>k7tW#* zG?GdOf~m@*ULArO6CeXQK(!%d;@siGkhEdAKmimKzzaD7C<21&rG5vA+wSa(Z|TLe z(1Db4@vKh`Q}(zBiKvk2tmMQ(c!?XmWSKW~rVDr3`q*$0^Y1f(yCE;!wdza>B=4Zb z7o?o$BRmC|c?MJ4WL*j(-D%7V+DG!rm~VE_J%h&qbD~zzW=GycvGtN!CTC!0P(X?e z6M$Ykbpnlcv=7$cNb{);BeDCKCoF`Ur!k{)ex&yXaH%^>Kf~Z6Ar)NtUEk*EPs!lq zO<sNpd6<vM%g@7PckG-WU^8JVC0W7&q-G;|II_ZGb4tGXca-mZ1@vqNFKBimF>|B* zzEv=B4{(DtPvUJBX-^0X5`Bt#R8cW+0TCKp+(b`LRVRMSpQ^G4mA}t7R`rX<1%v3r zt6#9$(1=dK`=+Tha)XgV(`!w(<{OZ-Kh}3*ECJUds`?_LEc&qgULLg+BcJuYC(3IQ z@u)}vZvn!FAJC2HlQ<D9@5C5<o1~gIf4spaiYos=qRNog940e2K+Jl=1vJ<J6gfc5 zde>ewESv&q+9vTOB2vjCFW-%1A(7d{mP$OO%Q7Vd^jox)cuNzKwdcA@13AxMZI~92 zzrmOP5aH>+BmWLC;O^`p5j^^;B8YrE1XPm<H%s21FMlIBon!@~sVxpCY%0=)?Tx4k zQNEAB;z>N6(fl%ssKu+w^fqs|R5a^%QGgvs_A;UG4+!3xfo%hJlh`Slox^#Esp8gC zBFRFZ!E_uh+)9B?<CKeDyLu3z!~l^9fLGiQAe;g~M`R>a{6KfpBRI9oXkLkcG#6;c zN7WD;QAA33T?P{YS1>>32c!rq5I$YVqF8v=quOz>i!^^SH()yjgu`Txx4{uYr=I!1 za!Mw8D$1P_LK2pC5H^aume48j$9yO{14%$24k-G>RVbQ-hD8*;9IEvKvFx|5>!4^7 z!o;PPE)@L%Q1mUmBEKL;_TE8^vm^!9hQWk=!7F1}T7&UHSUR?|2yZ;Jk~6W<7@`KL zc!?od!qLNoV@OFn`2M-*+DCqQN2jC9WP%A&#aQ$~EA{vEsgj05AMFUJE*$Eopg#1} zPYxk^t+qY*;%TC#y1#)>nc{kAQwITc4C8dVDHNiOwNjhg#5pgf+47`#69p&8q`V&J z8N^;>USHu(;B@Z*ymN**&(zD4ignW1?(~j^I>3&Ag%tNRh{1*14yf)3p=o2!UdX{W zC^JIy1$dAt9eIFKPRX<4E<30}raiZ`1!9{vywzmU))<!rG1aZ@JE%(Lkm3023={Mi zL_3*FopUL5-Z;|;Mv@K}wAk4JE!-|Rkd@fd$PI(?P@O5WUB3BI;8F+xY(x)d_>$m1 zsf-lkI|soln|V=kV7=B=Le`vef`C3s`qE^2lDI>-3tdX8O*7Wd!}HFwt95TdvUw32 zE(4iB9W<#HLQ7OeG6EDbxb)dNqguBQuRFIQ15(GDmnVg!0wpdSgA);vb^LtqY*x<C zFf7fNOM@?dT0J8eYSFeB5XVaK<ZfcX*z=^mxDWW_%FAzn2dQuk-&Z-1G<HDJW+<y9 zwb5Fr6alkUIQT3ObB4_>)L<-9i=(+0rKJgbeD3MO`M>$b7~fx%v#kWT8Qn(84jLxc zOA=dfmFnV$!wy|MKK9^Ttc(-c%IK84liNClmQp`$m@dquwnTk+?Cd)PGrrI&8EDhQ zw&onPA-Rt4a>X*3LJdoU6oZH+GD*b8v14>Wf%17;r>6;j+S66;F_;pN39|Jr@abQP z1#a+3wsfugghkkmxj_zA7P?UAoG2Jk=0I#wBUU(Yj-ntu&L-N3JBbZWxLvppU6hdl zHD-H{Ur5l5kn%U#sua;D_!#*shva+TuRSa42Myoh&VEVW5%O1#o92h}{lOO4D}(=X z;E)EG<d6GS9d!GOanR}ZRrh<ABF~>SNY@oT4Vn#Oh4I0wr*$r@^Q$<`9tSF+3KUa{ z=QN0FD0TG7)#5&X7|FyQ;g6Lc;^+E=ZN2?Yr+eyZKUbvnJM9U3yYtGG4G?&}s67Jd z%uDX`o$l67?J;dVWNpjNazR05&f(+9;7^bd<dl_tiTb;o2cQZTVz{1Z9gzJs02O@~ z{W*U#G^u_?lDl>MU^tzDQy(~;^gg_JiCE@o5ST^Lr~N1zz#$9kI>$GHG!f~y`HW9~ z0ytzF`ZBO@#)*API7A6S?@yr_2x>%6dx9`~-p3WO_fqE069z%?5*o?R@OHNh$C5!u zOL<oo;384w{BuxoHB3mMw3M7+gxP&kRsn*Qxb#2Zs;Qpouf18g1tBUU1vv~~VHl(P zk$c!cLt&cdA{INmOTUVfUzH>!RT2@x=Ln8e4#5z!^X8QSp<`=r2VVxa6U${t1+UG@ zH+O;}qG=mdWg8b<)7V~-cm?{Xlk%h)xZer&Mf)!{;vU~n_h(ls=R=nn?%uXFm!U^Q z59erMjhI&^%Zsj<igWpkb*#i*ooD}X0lJ@{7*7HM71Kh<!>9+bN~n9JFrLK=M?B$H zW|hH8^~^!Rumh#rF2ec`FpK1s2?HjQw8{ZRW$J(_9=YVb3vtpUp0Ao20`(GnJ{@PR zsE~Q&Ht<Fo5?g_Sx%z|wAz{YMEBtJaylU2f@f0wg0>=0Qx=OF$wTf1(ITUz&7^nsc zIe|hBrH~Q+kO+mvgF;OR!@U^+yCj9(6WXck(>ZtwLrwDXU(xacPT3LpmLgbj?Op!s z733Bg1U+=P0(^mU$;(M^B=QCAJp}n;SoO!HNS7(h8RC*bGmT4m8A_*s$t87AJ5`BW zSEuFfMr4gGV^xslCVBbu_^{yN<_bxC92%Eh!9(~YyisvubsY4PhdIOI$fsTshIgUx z!1k)nM5uWaxAoPDxB?$oZvO!>mfA$n-W(q*-d9fIAtclp#=lxG>F)`xO74WBn-K4K zb7q^f5A)cL_mMlXY@?4(pQH{~FlQ;k$D=%?9AwiB3_R~(PpDXX8`TkVKvh8~J1*rX zwowP5j`Gb^L!z9C%Wy|kzw$$C`@}cjiw|rB@G>p7n(fk!gOGXgfIH-S``KKtHi4zY z@j}%g`QF3ww<_rqyRiO3;~M|k;Jqi#e9$SCoc7wf2F$p4(ESy2L)Q1L8sw2zqz)Jl z2Z_`FH6ecTY3~gePd}CyG>_3jS5B~+VN*3Zv+X$JtYcKR<#9fZ1H^kr1<-iDOJ{hz z69vd{C%0f7Y6HujF2y{B(G9jTE*D;rZ}wmSpnaO%qUpI&dkB}&9;%hpAfd`xLsZ^+ zjEVsm70cZ}JuGm@jFc4eS7giGmoPF;;TyL8ynK0Ozxa3?jzAR6FHs;o&sBQ`FKdjf zP6}qJ_IKCdlByyvjGfujFe*nlccKDPM{J-#Axryp2g*V=Q0Dsw%EaaF()KX^uh1B> zyi!7grJV)~SuVjc-V<7%&}TxJcM=VrP%-dkHhORzArpT0K5Jvq9ghoABJo{AXc!Hl zNRPalA0WNZhlbFAV6SYshhw48E5K^a_tQc@co8}S`V$yG?U2)t|AgbPR;rqF5ysuV zO1?P*7AS;jUIY_N0eVpjT)<Z10)C31ARk1%2an;y4a~ivD=ETFZ=szax?10*BVe>p z#4-@ly26P(!cVY21xeFO#-ZJJY)E<!Oj4%zfH+1Qfi8v}iUR^4Bc>)}sS#53?!j$w zx-d)p5-3J6;*@O&@Q-h6umR*K)*(?b!u!b6cQpJFtd**39c#rPX(khqOR4%9R4S}T z7ZMdNh)TBNtfeCJN<(5JA!lr&`M#Bzr|T0t72dFhM3NQcDl$8(6PxUU9I{=sN%oO( z`-@qffvom%E==iz&Vd(eIa?^_3^64(@lscEr;DCTlT5CA4XM<;jXy4aMiM_YiJu_c zOht~w*`N>xTY$3i2TEA7&BUyNt~Kw_3$-#{hLky^{B1*GJCd={aTBETBk~mV4onna z5?};C;TCMp9j4NDM(MYDNBYpYcd!rpd&6O&YSAs~R?Ml_kT4!=dzF|5=34gj{6;gc z!umf2$4aBD#Du|S7cs0HP`rGz4Sm><*aBzHdmAi>$9X5f0$<KM!b&CQ<yH;~P57ne z{qoInF#=_Z{2G7@VcXn**W~)kK(B-DO^yT_422Jc!7F(;lqI*pCM`=wb%Qu}aw~Mp zgHgvz`j)osR{H&AUT6<)L3W(?>D>xGRE(t%cAiD!_96L{n}oN}O=3gufUSXxL}-Qy zF!()I;^-5W6ZNm-261&_Bd}pBcyBc3PGP7~GOIvO?nA_yu?K-?Cu8gc@#D)J?KGMx zI$|O2H6rRfhO0%8#5)gH#93??ZbP{;1PT6nxMm)$Ni2fF7R+#v4hjD>0eX0>1!s+5 zdLSAdNZ{(;9^pkeHE<+_>)nZk04rH?r_I}!mH-->kYzuIU6$?><l4uBx2#6tO+QZr zd(bZfj|OC58FU>AB5ko(`NO+9A$Xii>8eQn(dGCtsUjH~lwHW`LM@j47cer=Lc#pq zdBM0el8$V4g4|&fSHQXCP+=0vR%Ub~0-p@u<`1D`=N~{(Bn{MoXXU^I_rIlv<>n@^ zFm7^UFDyKUmC7J&$G}2j7@T#Wn+(EqF>!pqcp<S91yG>?Z_`YCm9t@>l`5RLuGciS z!5PvwS>cuR1p_frF}A^6%O_ZAc=5O3EgKkP@D(h6!JscGB!}S#@#hg>)(3g9uTbm@ zl3>2jIOq$vV6Oz|<6<HPXDFu0%NW2Ygsn1DkZ<0N4~Xl$ih9<JtwnO2O<qpd<jLyd z*O+VNo6A|47A%YRu7edlwR!*ufYmCzS}xzb98U7L60c}GljP+S@R20nJP$@gqR@GT z3^og!Z-Ns&yokmy9wqdl=(nG50EG&No8jPpicwxp@6_f=81vE~+}6g>DF(Q_+zAh4 z&acD(k#Bwu1uQESzI**`&Y3|qZ$1MTEbCNGItE8j`Mq~x_@k`yU)y2v<-hNUFMoM? zJY2;x>=YeQ3}m(We#CDML4N4b@gzQGy@Ef^p(yO9r)Vm)<JbTgu~G$<C)uc)mFkLv z^1NUKSs?a4D|8JQYpf6ASXHf}m-jI=4;9^ql2B~CG+v!x1x;fRq&Q2!=wb0)h%ae3 zm9}jB7=xTt_V`}Spy@z^JZM~%Op|=Yb#|kQIEU8^LDVWvx)n8NLtUS33_Dx_p|KyG zqcH<y5bQ#v-tTcBS*c5=^puJy#dC}eru7V|tnQk`KD3gD$H&3r_=+$MSe_6PAe4pD zcT-{CtzvWd+W9E2pw7oWLbEnMdKuvip7#Q($@CIcN(cD#-{S6-;u2_sI;2ReDV+{B z(J3EEn1R+9A!Ncw<O7Kd{}=hxnv4Zij5Qleb)HRJtZB)tCS`^|k_Z7A5C6H{4K$QW z&zP_97NI}Vt2BC{_sZmK;vpw~1`<b!=SYMr`CJbn7CZ?kb)hy8U3mOsRHqKXge8bB zF6wjV(oryufJX?gqD-uGVnKzt?lRs^2f&|z5+jn2;TlF;2<x!~QZ;ardzzts)C9bL zVLsLta8+=}=v_K{aJCEYzywznZ%1?;cSSI*h+xw}^UY-_%`hQ9->#Nu8liTjzm1yD zVl+cr4#ZuEJM}jYF~yEymwhBHZ&A7s0TLwdHqazO7;Koum~ETOkOZ^`GX?c|(RiBl zJM<#GhWUfD1T3N7(HHKn5--Y1$8GdL5i5zjoMv$jkCSUKbyn6<AxQ7Pk9?6}KZ7cx zp78y!wwLc0U<<>ydQC7SIlN(D)=ACv&~M&~rMNS1YMPKk?==uLGz9|{7X%>`N}ux0 zEy&bQv2_Sb39S&t*4li6d2|R5KPDDAgo<26BaQq?iwKkVdQ%LBldgUHdlkwq7K-wl zONq2gO4~Dp!>9<IAw!`~`{av~R!|Wwqew4zTc-+DEAE|2n3xKR-7aK;?Z9dwcdu%b zmX)?OA!g|T??{11s;CC;d|)_NVzq1+h~F>Pg}&ZE$<a0$CVIS<iu4Q|NOuT$FI__e zr_j)(?c3jj+yW<8c(@)zK2cye8B!!P<}w)a#QxwO_<0VFJ&eA`(^7mK6A4jFZXNay zc||=MW+Ox)<oCV-+v`LQrO-2QI^Y9{)QK-H;OZJq*k3^veJAYC!s_7|$Cl~krd<d< z7(wTZc<Fk5*hZ=Ohhiz-X`)9TP!9_5+%v4ER5Zh5l>6E~8&7P$u;v)Fv!d=4WI9U& z;lWAs7lG7_Yd>atSz!jXvN6QjPng6CLxc#s&e`UD(|md3-RqHU$x3vBLPQtB#&-hO zsRXn>W%GNmL`cG0g-VKVo+dqp!8CS19t|KQc#Ci($4}=7Ct&rzr~nqRvvsVqjh*LQ zz$ipk=t_YSjp&iphwucilnll!BfeIeForUw927z>%YhhF#3f6nV>iY=M6u|$D`p%O zRix&KLyAcOer5(@G1>BA*CPObq(>Kgyi^j4WwP4!q+2yYlwA$>U6Bn}RmFj8l`h}A zP71D7*;g)<<#>D9Wg>5QJ4`t6(_j)YGl5LdFC)nW<zjWsl)5}&(Dgm8YM|@0GS}gt zih<snd%A9N9S-&it}N+BZ~tx|*J#&f;`Td3*%l|Wj=EqxS3_#pk+rYvAf$nN+42yx zq9^LDUrqxlB5%k7Z<wclHjZMM<aHMVIR|mE7fZ*yz%C2Oa4>`!c*TYxph7l)R+T!# zu@wsfxrR>n8in&n4;;T!Faj~`5-}Uvvp$b;$=(#hE7!)Md`LZ~^wi>cF>hL4!eXd3 zeH3C{skb8)=c69Rjl_%wcAJb#&=3=A3|JdK8&&&RALF8dc#vUs60mI(rrs8iiCozg zjTU5?TL-(Req~Jv7!1oR6A#N@si9N+SE%DLyN&{Tmn#s)`~xVN#G}<o((3gpJmcNI z!9>@ceKa@d42hJH-Bot!h5a~lt{4b(7U~VD80yB(DX~2c2Sg@k`})I3#F*L1PeDrB z_h}R1z9K1=daigSd6Fe~QZ*bgWS!IEP#!O&WZFO%bHZC-%~wWNC!WE2_b6%A0m^R^ zF%sr7=!tO5TK}x+bRNYOi?dV%)VOcD@Bm_Gco#qr2|I`sVca}S5+?LS#|a~VBO%#1 zScVknt{nT2QgWFsUTB1qNu8nO_5o?3K0}AK9{|q`5F(MNh@Q}6f#}i}AV+`~FEBRJ z(%)K(1+2QX^{J<pKZRF8L2Y5BO>Tk`vt4<?m5B#E?P#rJfzDSmTPiaTEcPnwg608? zy9OyeDd`D?4kBj@7Mn`vQQ;;GP>AWGfBL|6EGSS6r;2QUd4#RZN)1PY={5<33~@Ax z%3;{N0V;|{3truFw-0gN%|@W`I;da_aqnGBg5=fTBK`ImGaz!=Xv%D%lbRM`7aS#c zLAJCJ4~QcAoIEU~K+06o3i#o)v3h-Ikf#qT=?;2|5`~KwzPS$vbG|P<O5JIo+v37B zssjo>5=TGHj$jNzs)eWYAoMvIh-5gA;!kg$kD&*dZcrB!s~}nDx@6@?r3sP94-&fP z@VGz_%c)w2w@=Ph4TwJCJOlU2<kQ~C#sxwAt**7f(axJ)Yb93aXpAVk@E;^F=1D#c z`ZdJUpUQ;;cS)_wXyxC-LHp!Hh&!H?;K}Y9?<m$7&mscau9e8{8$n57RReBJMs;y+ z_aBndMv@Jyz+hlK0)BEOP95Z%HH7;O!a_{yjLMP1*JxnhV)i|?HJYG-M4`FnT-2~3 z@c{mE-k0n+n#Ez-QG1%O@io>_-L%e)S*(vbqlBR-5{(KB4zIzEU7?5b$C}wY*4d^0 zSf6i22eu+keIMm?oYkUtKz<4pi=p?$qcUZl6jdFQ2sj$y7+!A|+edP6Zklib=}s;^ zhmj+>=qWwvHFy$hP}j~VWE_Oj9)Go0X>+^sU5R|zyQqW#Mmg(EnFpLJJf)4)rno-! zNbi`pi7|7QevYg7X@W%D>U6h*T=b`bIT8aCL7E_>hmv&%X<5Q5Ex8D!h#4rDRZ#Uf za(cx`->~Gt<E_Oc$*3GbBY=_u_0u9eM{cCJAQ@U5wC^qy&L?#VEcht%ae@Z@fcp)R zFainm?P9TLm6#8me3xkHKf#t%Bi2`1gopTfB@#r<5KbY22N&pfE1Y9+Y%}sgVt6ng zDV%_F196`?;bmrJ+>hhzy)Cx1yIUfN;?RDKTf~qK78aq5IM&7K;Y7iW7=dd_KYU|e z_tf6#y&H>kD;-)61@4?H<YD$@WKfuNzrM%W=~V;ed-u!twqHny!ZGIPxT=9T#vCl) z`wx=MYcM5-L*5|{Bw&ZPzbO-1@5x1i2ZZ9HPdMwA1ZGIm0DfZf>J!VZD$(JtsLuU& zm<vp>qeXDdAS}T&ev<T*kIHH|$@&|a$jetDu&>nYt!UEij?-&WLJCRY5)6dE_PD(G zs`kL}f~4?xB$I}NSUHZP*jerI85a_QM?jvcgO9Je5tYJqiVp7roZuqV`^)=bp**zQ zbAAQ_EH@V^io@~uhBbYbONt`A2H1xbtME5+%_O+o<Q*q}h0frEFT{;d@cofO<p^Ym zB)k&&D~Bl!oW$eQ5<Y$LmaJHUt^y=N;JWGte;Lxd%OD12MMz>rNMc1uVns+|MMz>r zNcvetpsKv*9K9T~rY|}}zS#?MGO#N#2x(t1tOl2(lgI-S<D!DluUJ1)_xd|&EaC!J z_PCox5}YKzi9W)!+J`#7e;x{%AZGquP*r01kN9c`GKTVWz#r^s=zuIHX2CDN|6VQd z;6FHS51<}!2JkJQ4~Y0lfN6j`0R@27fC|9FfZc%C0EYpm0bc`xJ2-9#U=m<DARDk2 zPyu)lupRI$-~iwZ;7h>w0O^k$cLQJ~U<$whm=0J3$N{VcYzMpscpuOL2nK6zIA9XM z2$%=B3$PaOTfh^5X8~^jjsiXbd=Cf)%P$fz5fBZS1y~Fy0;~sA0e%PA1E>Ks0zLt> z0)ny484j2TFamA|^!^>Z(Z>DOX5%7mw{b6|+qjy=wyq%0JY(b5MRtGtJ(g$X<~y>L ze4%oMgI7A%=JLvAh1m|}^5Vi(%A(@JWsZ`PsbF+;hg(+c$l@J=e#-GB9R73hh0gqJ zWkDgO<5)(naLXznhvm5i*-HC5KBusNc{=&5yYd|ff~2{zql=i&R79h4jUC+;udv8b zz(U<xvaC3_h@V=tj`Ar^L_zIh={Rl`SHdmh3b|s=fqzrEY%U-F(9T=|=VbO<C|Pb| zfipi}v~pmZ_Ms+JaFRY;pJ0VFF)=ZOetH#WXMvSQ`+`sz7o}3A+rcVRDvAE$WJ`0F z;)l*IT8p0yA;1Ke$zaIvk3PBGqvJSk3;@5NV2L!OPpGVKSikW81LTT<Hw=mxJmkj6 zp*Ia1K4Ro3<>)bE$BmzG^Tb;wO`dY=)Z0{QjaH{OL>W!dW{Wi@))qG{J|S`XjHH>j z-!UtB_8j}%c`2!Q!E`~!oeLLbE?%-U>#k+lj^!(Ia`RT^uPP`ky1Tf9cdlNucHKR{ zT3@<hBV)TK7EqVk3v&y2M={ED2bajr<7VUUEKbX5&|(R&&0^(EaP$m2J-=jnvBSZ^ zOmXmOS@}+8pAle>%g--dMv;r11$^!*htg48Tv)8+xc=ze)LC;<QbZT}<WgqNo)PfL zCCo{Vn>oANWu8H$)%6dHD^O+?73JqH%i?n}WOA}fl&i8ZEVJOw^Nv+TJPq0W!YmBk z9EUPq>CZbq_pais;&sYg)Va9Wv5e1OH#N+j@5m}~U|<*US<4U;F#=M*xkOpwEGjB2 zhL0m_m2x=>zpAj<fiz%U#Y!-h6&~fM@@e~r-Kvc1E`}3nC#TGu6)<!7oZJ#+R!NCt z)m{1Pl-bVW+=3O#0wlGXih+vc7Uc4|S^2s5u;jy1DLm!~RoH=;%DbE^@U2`|=qwH_ z>r~}TUWuTq3QKrpe(p*KQm5(^J4&4Sys~h)a#>b>K4pfMqB7mOtZ-Eko8l91Tb5sZ zi*mWMU>R#uHp8>J3sq3U7dw~ns675N&xHK^<gDBRR(GnmhU(3xcR`_ZMUJwhC~Fxo z1%hJ$WMMi7G+1DJse83oSKS?A=gmtM+ndipp$iL^Ii~*n_Mm*IY%0nl9w|}zx--c3 z`D={i?<`<g2P3CDgfhpGRV0=c>1d*UqK<2F10u41>yBr*ZoCpc`zPY*DPEBiqiuC= zG4IUE@9rS#NtOYX3v=Q+ZNH?jfYA1B7&wHz8Di}!m)b<}y6esGDds^*A-XHuu{w8| zqdTmxjT~!>FmJFZP|I}BOxDh7);><;=nJz7!!DQ4!J3dwqhMw4@Yin_U!?3TJ_|+Y zFLrsrv}BXM*m1YhQ9^~GQ9jRyV9<fUWUF#9p)lyEziGHT3!Ej?fNQe;jZ+?NuVQU@ z&2jH2K(7@Rta23ar~`#%ZFtSFS;Z@y6tILfIE7{NX*rM>PZPF?@N*X?q9h2tIoJs1 zxa8br#f2q>%Xwv5E~{ny<jGy_F-t^xKu=s4=EKyfQ#lLP?iIzrW(8Tm$j*Y51%+!0 zV$g@aCQKw8JvuB5izo$)R#IgAu#>F8F$epNfSm*#==X4dy&8757{VPoLAvY^XYI0Y z4Y1?zv&$WKC%Wtp1laqyT=%-lTv(7L_qy)g<cbIh!HT?j^JWxCrE=L_6`YKlc(c)- z?!tPDMcHnzK=#Ust_l}oaafjfa&ly{(6vQHYl@0`tjF;F|Nf`sdjFdU`bhlO+vi%} zNuZQ|>R&l`^}n9s%ed};LEO*#7ns5(uKQmw=;5F9&mUj;|9$^+SM|RV8ZZAZkAR@E zu73~!|5-nO50belsQX`V(9iqlkAJN({hxFDXET6uioidAj`Y=SSCGj2f8y6W{Liax zcPItdZ5M4pK{N?mWt-gPoA3Q~MP-#|OZ9K=+j{?RA9(PghaY+LvETiE+v89CVf&6J zckX)X=|ArN)1RMt_POW(vgd`rzWCD1dtcf2>T9pR@#b4^*VOK>JMd0@!@)y`j~spX zy<?5X-#>BkZy%gG{ozL+pZSkZK5aVt+2`lJ`0^{E`D<^>H{X8Odj9(#+WvmwV*90k zT<*YS(SLbEbo~v_&)N|ESJ(f)I{$yU{r}m9^!om6L;7D`|D>eoRjZ;)h&91w<2OZ_ zjGvM$>+s`}lW)t;z6}=q?8zJ#2f&^f`#83B=4KbJ?y}FpZi$>z97WiYiUH!BE1V@f z$KCGCXKCCHTA9*{D=N+<o<wq1@v<D4(;aseJF!tEzuU74m=*a@`W(`wG&!V2=>Q54 zZylvU@hL9F;Zm}AXK^+>D81rbW=qX+7MJ+k(jD0a4&O&A$Y^p-E-YZaDNdi6#Zz1k z@i>I%5RSrd@aM3}_wiWLu{AARlftu254q1TaTL$FD-ZjGncbUY;&{MsR#pighdt(M zupEk<Ma)h77L(zU!Bfgw;h0vqHjbO0k~mMRnVK*Q><8qDtWg3K1m!`oP(!hOP-WB{ z4S;q)bD&kwIA|j@6<UlM4!`(0v**lD9mh?@o|nG;{G_ROv1H)BDx0}4LSE~zt5`L! zu#hsqFG)21xBj|rh~pY@Vk<%HJqD1l)WMHlJ1MZa!Oi11oJla#|Gf{qJNo&*5BBok zHpWKYUH(S{{42-VxW@s3{#ye4hwE&d5)kO$JO4UUPyfb%_!RH{=$`(8`IG-Ji|9}G zugtcta`w(=yHyP5uV-)n6EWBK|1s9a4F!Lbe%FiNe|k^<-sSvwW>5d#`QMTJ)Be?S zy6d(rz<#<{d(E5M9d2=ey?1_*3wq`kn9h+58}})Ie*XFf`j5EN#*GF9`q%U-$J)%E z{(=1}1Almwk4NlJzjyhD=3YNO<vVF*PygQWZ(G~bKQMoaAM5&Qe`Q%u|K9x>@nBE? z-swO0@K5_EZ13scyZo>3>gnHmUY0#A`g8cb`BZnG_b!L!xt{6t_Fquj)4z8;FCT>d z(@T_#_#1v1W|Qxum+{M)%D;A|GB;?3qrg!N=2E=KDU0We^AlHtcf)b-z>lZXhj?PC z`%fUUrRiC@{Pe=&6mW9#9pcK!J;=qgvl3r0ERTPbfQcTEXi`=|c0MSGHcB<QFx#2$ zm=0#`Z18Ll`i{hTvlC}wb<EBO>F^<!Nc{WwVla-u8cf033)VQteHT2-k+s@!mHVac zG{tPvIc~HxCEo$cLK%$ws915?*<c-m8j=PD9;p;k-1x#(t5CjKxdkYUKqVK`!7&fD zgqhMv;j=|YjypwhsPw7piX5Ct^vwcKvxrE9IPNXbQTYzEX|D?0DoyqC^19mdPb_~Y z82AN#5`>G9&M(Me?UkLlb{R-6)E?QfBaOjQl<vCT$Af2<BsjoPU*RaWqq@|QUs4W4 zsW3(uw7Ui;f!oQBI=IJ~T|CxU$Vy_TDsVNyGpPrN&FRRVS%8Bu;^*O<FVG#dh~Ir4 z#f^){anc}ajX8<QWd9hY!8uB9HXA{pgE*ZuHNOM_#M2cGefiE*^knZkchS-pD`E@v zMnLJG3uv!Y#*Cc_N~c<yj<#kaiaQ@X3*1B>qYz{3Wt7=>0@1ri;tH};igF9YZoWN; zGED5|bEfcgmQfPNy-j&u?ZMq~ofzrdJ<{~tY)5=fR&i=!GVzV4t>YbB?X}avX#E50 z2XPMJ%}Z&T$RTGfkSdw$bQG_%JBryE4Gs-hc`=ukQ(LFzE?emvr+*G;8{Ys!<IG{> zlM#WbIJ1f?VIvnd?zfV8eE$4`H6VGpU91H29AbB*`b*&J9XCtaha%9k4+VT<GK21q z3!0wqEXkp?r#Y7|cNAl$oeiE9pPW@Bwj+AtCP`OYq!#)ci2FP+6xzZn&L?VnnqP=# z>*<0p0_8u89mR-Kj{B6x3FY2(`1drcQA+MTC|x`kpI=zw@J--N;%M<<r#SAhfZEJ) z@<mRbM(>s$q0+ey${_#?to7kM$}|qAj6fnqS;da7+RpFkf>Jk93IXFNEvq<}j%nh! z9LYQ!D^N-t_pTT!d(Lw4do0!7*PS$TIqndZmu1Uih~DMIIT~8&m*4-}El@)W0`VhL z<WTv_tMHitMlkF_0pGo?<WKO+@0S+%xh*jJOWW%&41GJ{@E98#Tlt^ijR63*QJpRl zSoq)k(KsCf@Q+F24Uk<5hy;WH`U4<`!u16}!h{P4$b2Tb(Ki)={Q3d>ev~f7B@<do zSh_S_$Za5iE}Ichexm{8uJ?V@Y@_dZ-#1V?i!;yXp5ilsm|6N6Fez^kpe)`hm`VT; zF65CQ^8ui;Qaz|VE&!Fe%x7+bN&apC`IiGIf4UHP3*ZUg_YRm;-dzC7?~ecq_X>dO z^d5lxPXWk35{*Lb<8L!qyKqAgeFXgc-+t5Y<^S$&_V(}n{m;T*&)=WU|2$K1-Je)j z<#m7mGuq<%hZ17_uFn+zpHY9R#dU{(ZzaF(5K#WlX#>>czxhze84NlsSSs6v1#9W1 zb(==}I_K$6Mazz-M6>J<O&w&jZE!JjH^SHM{Aj0A^uFqE8RTE-XY-ja|IF}lzVLey z{@9b}p1g_s;z{Ajg<@g>f4kD(u!F@QU0QQLTKticTk=ufN1A|;qP6VA=}(%#Pg8FY zW9EM&^6uh&A^kY~s)+xh!`7SPdZh5Lep5MnmzAFH_WyFcc*E&C8&`DR##IcD;~qu+ z6rN1#Yoc@LM{8@lU}H4KQJA!5Z-+^1xeO*v;xk{_*joH7OrkF;U=D)02qw`q<6sVj z+3}@~y9wq2n8RRhfl0JNHq4PQ6JU;l+4O~tQ^MR0b2Q97=WOhiGzHAH_~u})gVFlA zjk^bC6HFRxXJB^1JPPwI@OOU>VE8aPiqfSz`H&Jv?URSTfAj~ul?>Pl*aD~klmlFV zwSXc(4qy?$4oCu607ifgpaM(*OazPrC;`I(k$?z*0uT<60@}Yvp8x~^g>Qm+8qf$h z0C)qi2e1pU9k30s6|f#q1n4X6?sMwXsi;o^`h3eR{~R{@el$jc5Rc-L>HkqXDMKEh zZoKA?#!2AMRV2o5JujYT*;7&jz5mm8d&0jKzY+CPKv@`#X@BN{b~@)EpdXDzGvH1D zjf+PBF9S{jegF(a!>9nW0d#T5A14}q8Gto_hXF4EP5{0K(B;?L0Lg%Sz<>AOKNDFA z?)8)Se*Svrx8c1uz#>2@p!fKpiAZf9q*iE0XqRYnv}M{Y+UK+{YHPHIw4-#hbROMH zx=Xsz`jz@p{fqjAhCdm`M@@;E9W_6yF6vO!=TYBBbw>3w4l|B1s*P6T?ZyJ5%lI4P zPUCaN6UIKK!KRU>X{NhPO{N3Z%T`HDWX#x@Juz>@a7y4W<U2++S+zh_qFSfgq^eXs zqY6{spdPPQsrBka^&EAYI!m3WcBwt;r_?W~UsWGcf1)0#nXH+wxl`lN<Y_82Chc@> zigvBGQoB|Auy(h0kM?zKxNe|sm~OuAPF<F6g|5GTls?7qcf+74Q`BQo&qg&w-Cz#3 zY_Yy>ZL-$Iaw?8Hh;qEGu2VOtkEoBSPpD6+KUROHzM#HQGeR>*^R(u9&9|C%jZ$mU z-lP4q_6_X-U4*Vc=hDs7FVg4g%k>`pPW>^xS3kfo+A!BpVAyZi7PTwtji{4RlZ|P{ zCB~J;Cymb-Uoo~CFBwD78h4n|O+}_nrsJklCc$*YG%9*>^t|XL(b>_((aGi_^RLWL zn7=XWEM`lhrO;Apaa*3YJZGu5d}L{|G+R0>O6$wkzga)Enq%xS565ha*&XwFEN8=B z4CDP#)qKrDO_pYbW|gKybC0GBZFHaJVa?;3U7BY#FKOP;9Ml}we4sg_`BL+p<{z3q z+J4$$TBUY^c8YeIcBb|P?YG(x-CBL6zE0n$|41+B&+9MiZ!<(25)7G!6^45ZPZ<7Y z2#XpKRUP$b^!;LEsquT`72`nDSW}E?x@oq_VcKB&ooT1(Po}?`UNP01zA+7nzB&5# zXt~*BE;l!tM_E=_-nE>w{N19qF0neSMb`D!`>l^!pS8Yd{Rn;HwO+J_#|(<OIc93i z^q6@u3u3ZkN@CW<Y>N2}>iT5N^D!^Q)W#f%c|Ydsm`gESZ2wqQY+~%n*ym$kiv1+^ zTr4`%F17`yid4m@_NhKreW4nGQB|m3t-fFVu=)x0F7-1QPy5twsq5A6s^3?Cr2bs} zow`kZN!_WIX!>dfXd*O2H4`;4nwgr}nheciO|GUu^D9jy+HxD(aKGjg&5OF%bd&U1 z`gIrqyY(;V_vvf(L54ntsfHB8T7$>1)9|w4Lql*>|EOO_ZO2S`FY1dZlQ9P4A=_AK zOfn^#mY7OS_nRIuanVuH)1sF}pNak~`f_xT`33V{^Xujsv{k3Mza`a@VR^!`)ADD_ zUo3kquUjTrwN{h0&icOfto3Var}Z|Bf=skXLri1Lr!hCij*h)Mc75!<v5&+)No}zd z=OZxYtCy<_)Vz9~dZXH_KCced+@QHdqt{GB4PBaJn$I*5+FP}Aw5i&=w0CPC)b0Qd zcv<@<aKJa(ziY?p?7C$b^HU7B8`eZU6tyGjIpYUL!DvLEFE%}7dfN1zX-xE;(eFeb zi5_kqW1eo#H9v0NY5t4(g1OT28_RK&?2DMr7-{UF*x|9a#Oh+F$7aN4$L7Tr#X4g* z#Qr{ZN9?n)FT}nY`*!T%*yFKZ#J0qKA4^OQwi>BIRpF|^sxhjGs%feeRfZ~0bxgHV zw?_A8U862cKSw_%>eeWIRBhDl#=jVsncSw5=xxz|k9J#@S*M_FN-$zh#1zHuiaim_ zxkMhxEY(`ocGW4>S=9}?aXPims+*yk1B_9HUY(169A|jaP!e@HD#SR#IL<iLXfVbD zx7}kLWU4SdWd5W1RrAM~qn+k~ma!JSWrpP+F}KAg#m<RMk6jeI6g8`keG&CI9eXCW z31d<~eOhDNs6V!fV>3pTph{BBQrT5|Rkf-!s?Sw|szueR8mKm_SD~NQs@DVWm8&b% zThv=IKAY6%)PlN2eE_rfYmE$8`+D+PAGU$;Z|wC*k40o@7RhdM#`t*%2CqL0uI z)sNMy^>^!kqkl&KHD>We{YXQa;W5J>3?~eq7=ohSiF!Y(C2FoQ)A%>zcgA*OhIy&^ z&*o3f?Wk3#CETL0L|CkrWtK8ag=LFntK~t<qn2%!?Ur4ZZ!K+>cHkk-y4-rVb&K@@ z%-(I*?bce%-4QY4VkX8+iBZMqVvI4C7+XwL%+{C(V;;ra?T9hO#>Xy<Esxz7`xUjt zc99=dp?X;L1aSW$)d{r3SE>$`MBP_CN*%5KRGqAOUGtviQ;k#`i_w{<t<pAW&ugdX zl5{(D&+E?UzSjMq)9MrTf7HLEKLZRr#E@!uz_7<~#xOW)OjM9jVKkb5Z{A^k+Wf5f zMe{qT-&d$%U&~#VQ?XxC8TN480vNBWPGc;5qq>N^2dL+(Usg}jShN?k%k_^S?L0$~ zVLj&b+lC{Cj|^WL;-fYK!-pE}(Vs^TH9u*&)0%CK1jc$I=9w5b`W^|^fG&qIS(T&O zraGefK~tjr1SRjU8>Q3e5_ILdUAlXtc1JZu^)*hw%9&(bWh^%iHO-HnX?B|pX!%zy zHI`x4B<o+TZv)r&i)o6vJGL_RGNs*!yOJ<gt2U^11HZk4G7rIw9;~@r^PJ{g?M&Sh zy1(dd(2pRdW0S}yoTav_Q`HO9i_|&leDz7qY1)#tVow0$fbO79rk|)!&?o7$^*Q<q z;Io7JlloS@!Z5|4GT2f3t!UFX45tm}3|!RkC}or-$`-XWYJHRoxUB}Y;EYP6&A1e6 z|8`@I@hEVE%rw!2#6gfD8xV3bRfT4&=0VL?Q$=)ZG-p<rm1dPW6{9ZOoMX<%y0_N6 z-n_;9pn02l7kcX@^Bd*^=A-75<}>DV<`#3Cxx*~QxQwt2w~Vt)vFI!oi_MZ?NwUnc z*nuS%SQc59TCy!JOZinJcDLnO%O1;1mVK5t(5eS42Q5b}jh2&^)0Q(>Q_oohON*to zYg9|EGHbY1VU4gxT8CSe)^XN})+tt%)rQ`fWwl#VtqZJ+tV_}7Io5pZTB|)KHO4>7 bsj9#HerbVUTHu!!_@xDYX@UROTi|~I?X2KC literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.35/setuptools/cli-64.exe b/vendor/distribute-0.6.35/setuptools/cli-64.exe new file mode 100755 index 0000000000000000000000000000000000000000..265585afc4042ce55c59d28ef1aab37f0a68ecdc GIT binary patch literal 75264 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 J@V|uu{}<nag|q+w literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.35/setuptools/cli.exe b/vendor/distribute-0.6.35/setuptools/cli.exe new file mode 100755 index 0000000000000000000000000000000000000000..9b7717b78bbf71f105ccde26746a0f6e3a4d12db GIT binary patch literal 69632 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 bsj9#HerbVUTHu!!_@xDYX@UROTi|~I?X2KC literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.35/setuptools/command/__init__.py b/vendor/distribute-0.6.35/setuptools/command/__init__.py new file mode 100644 index 00000000..b063fa19 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/__init__.py @@ -0,0 +1,21 @@ +__all__ = [ + 'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop', + 'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts', + 'sdist', 'setopt', 'test', 'upload', 'install_egg_info', 'install_scripts', + 'register', 'bdist_wininst', 'upload_docs', +] + +from setuptools.command import install_scripts +import sys + +if sys.version>='2.5': + # In Python 2.5 and above, distutils includes its own upload command + __all__.remove('upload') + +from distutils.command.bdist import bdist + +if 'egg' not in bdist.format_commands: + bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") + bdist.format_commands.append('egg') + +del bdist, sys diff --git a/vendor/distribute-0.6.35/setuptools/command/alias.py b/vendor/distribute-0.6.35/setuptools/command/alias.py new file mode 100644 index 00000000..f5368b29 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/alias.py @@ -0,0 +1,82 @@ +import distutils, os +from setuptools import Command +from distutils.util import convert_path +from distutils import log +from distutils.errors import * +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 arg.split()<>[arg]: + return repr(arg) + return arg + + +class alias(option_base): + """Define a shortcut that invokes one or more commands""" + + description = "define a shortcut to invoke one or more commands" + command_consumes_arguments = True + + user_options = [ + ('remove', 'r', 'remove (unset) the alias'), + ] + option_base.user_options + + boolean_options = option_base.boolean_options + ['remove'] + + def initialize_options(self): + option_base.initialize_options(self) + self.args = None + self.remove = None + + def finalize_options(self): + option_base.finalize_options(self) + if self.remove and len(self.args)<>1: + raise DistutilsOptionError( + "Must specify exactly one argument (the alias name) when " + "using --remove" + ) + + def run(self): + aliases = self.distribution.get_option_dict('aliases') + + if not self.args: + print "Command Aliases" + print "---------------" + for alias in aliases: + print "setup.py alias", format_alias(alias, aliases) + return + + elif len(self.args)==1: + alias, = self.args + if self.remove: + command = None + elif alias in aliases: + print "setup.py alias", format_alias(alias, aliases) + return + else: + print "No alias definition found for %r" % alias + return + else: + alias = self.args[0] + command = ' '.join(map(shquote,self.args[1:])) + + edit_config(self.filename, {'aliases': {alias:command}}, self.dry_run) + + +def format_alias(name, aliases): + source, command = aliases[name] + if source == config_file('global'): + source = '--global-config ' + elif source == config_file('user'): + source = '--user-config ' + elif source == config_file('local'): + source = '' + else: + source = '--filename=%r' % source + return source+name+' '+command + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/bdist_egg.py b/vendor/distribute-0.6.35/setuptools/command/bdist_egg.py new file mode 100644 index 00000000..17fae984 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/bdist_egg.py @@ -0,0 +1,548 @@ +"""setuptools.command.bdist_egg + +Build .egg distributions""" + +# This module should be kept compatible with Python 2.3 +import sys, os, marshal +from setuptools import Command +from distutils.dir_util import remove_tree, mkpath +try: + from distutils.sysconfig import get_python_version, get_python_lib +except ImportError: + from sysconfig import get_python_version + from distutils.sysconfig import get_python_lib + +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.extension import Library + +def strip_module(filename): + if '.' in filename: + filename = os.path.splitext(filename)[0] + if filename.endswith('module'): + 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() + +# stub __init__.py for packages distributed without one +NS_PKG_STUB = '__import__("pkg_resources").declare_namespace(__name__)' + +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()), + ('exclude-source-files', None, + "remove all .py files from the generated egg"), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ] + + boolean_options = [ + 'keep-temp', 'skip-build', 'exclude-source-files' + ] + + + + + + + + + + + + + + + + + + def initialize_options (self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = 0 + self.dist_dir = None + self.skip_build = 0 + 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 + + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'egg') + + if self.plat_name is None: + self.plat_name = get_build_platform() + + self.set_undefined_options('bdist',('dist_dir', 'dist_dir')) + + if self.egg_output is None: + + # Compute filename of the output egg + basename = Distribution( + None, None, ei_cmd.egg_name, ei_cmd.egg_version, + get_python_version(), + self.distribution.has_ext_modules() and self.plat_name + ).egg_name() + + 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_python_lib())) + old, self.distribution.data_files = self.distribution.data_files,[] + + for item in old: + 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 + ): + item = realpath[len(site_packages)+1:], item[1] + # XXX else: raise ??? + self.distribution.data_files.append(item) + + try: + log.info("installing package data to %s" % self.bdist_dir) + self.call_command('install_data', force=0, root=None) + finally: + self.distribution.data_files = old + + + def get_outputs(self): + return [self.egg_output] + + + 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('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") + + # We run install_lib before install_data, because some data hacks + # 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 + cmd = self.call_command('install_lib', warn_dir=0) + instcmd.root = old_root + + 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') + 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,'/') + + to_compile.extend(self.make_init_files()) + if to_compile: + cmd.byte_compile(to_compile) + + if self.distribution.data_files: + self.do_install_data() + + # Make the EGG-INFO directory + archive_root = self.bdist_dir + 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.copy_metadata_to(egg_info) + native_libs = os.path.join(egg_info, "native_libs.txt") + if all_outputs: + log.info("writing %s" % native_libs) + if not self.dry_run: + ensure_directory(native_libs) + libs_file = open(native_libs, 'wt') + libs_file.write('\n'.join(all_outputs)) + libs_file.write('\n') + libs_file.close() + elif os.path.isfile(native_libs): + log.info("removing %s" % native_libs) + if not self.dry_run: + os.unlink(native_libs) + + write_safety_flag( + os.path.join(archive_root,'EGG-INFO'), self.zip_safe() + ) + + 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." + ) + + if self.exclude_source_files: + self.zap_pyfiles() + + # Make the archive + make_zipfile(self.egg_output, archive_root, verbose=self.verbose, + 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)) + + + + + def zap_pyfiles(self): + log.info("Removing .py files from temporary directory") + for base,dirs,files in walk_egg(self.bdist_dir): + for name in files: + if name.endswith('.py'): + 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) + 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 make_init_files(self): + """Create missing package __init__ files""" + init_files = [] + for base,dirs,files in walk_egg(self.bdist_dir): + if base==self.bdist_dir: + # don't put an __init__ in the root + continue + for name in files: + if name.endswith('.py'): + if '__init__.py' not in files: + pkg = base[len(self.bdist_dir)+1:].replace(os.sep,'.') + if self.distribution.has_contents_for(pkg): + log.warn("Creating missing __init__.py for %s",pkg) + filename = os.path.join(base,'__init__.py') + if not self.dry_run: + f = open(filename,'w'); f.write(NS_PKG_STUB) + f.close() + init_files.append(filename) + break + else: + # not a package, don't traverse to subdirectories + dirs[:] = [] + + return init_files + + def gen_header(self): + epm = EntryPoint.parse_map(self.distribution.entry_points or '') + ep = epm.get('setuptools.installation',{}).get('eggsecutable') + if ep is None: + return 'w' # not an eggsecutable, do it the usual way. + + if not ep.attrs or ep.extras: + raise DistutilsSetupError( + "eggsecutable entry point (%r) cannot have 'extras' " + "or refer to a module" % (ep,) + ) + + pyver = sys.version[:3] + pkg = ep.module_name + full = '.'.join(ep.attrs) + base = ep.attrs[0] + basename = os.path.basename(self.egg_output) + + header = ( + "#!/bin/sh\n" + 'if [ `basename $0` = "%(basename)s" ]\n' + 'then exec python%(pyver)s -c "' + "import sys, os; sys.path.insert(0, os.path.abspath('$0')); " + "from %(pkg)s import %(base)s; sys.exit(%(full)s())" + '" "$@"\n' + 'else\n' + ' echo $0 is not the correct name for this egg file.\n' + ' echo Please rename it back to %(basename)s and try again.\n' + ' exec false\n' + 'fi\n' + + ) % locals() + + if not self.dry_run: + mkpath(os.path.dirname(self.egg_output), dry_run=self.dry_run) + f = open(self.egg_output, 'w') + f.write(header) + 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,'') + for path in self.ei_cmd.filelist.files: + if path.startswith(prefix): + target = os.path.join(target_dir, path[len(prefix):]) + ensure_directory(target) + self.copy_file(path, target) + + def get_ext_outputs(self): + """Get a list of relative paths to C extensions in the output distro""" + + all_outputs = [] + ext_outputs = [] + + 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) + for filename in dirs: + 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): + 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)): + ext_outputs.append(filename) + + return all_outputs, ext_outputs + + +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 = walker.next() + if 'EGG-INFO' in dirs: + dirs.remove('EGG-INFO') + 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)): + return flag + if not can_scan(): return False + safe = True + for base, dirs, files in walk_egg(egg_dir): + for name in files: + if name.endswith('.py') or name.endswith('.pyw'): + continue + elif name.endswith('.pyc') or name.endswith('.pyo'): + # always scan, even if we already know we're not safe + 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(): + 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() + +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) + 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] + if sys.version_info < (3, 3): + 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() + safe = True + symbols = dict.fromkeys(iter_symbols(code)) + for bad in ['__file__', '__path__']: + if bad in symbols: + log.warn("%s: module references %s", module, bad) + safe = False + if 'inspect' in symbols: + for bad in [ + 'getsource', 'getabsfile', 'getsourcefile', 'getfile' + 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', + 'getinnerframes', 'getouterframes', 'stack', 'trace' + ]: + 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 const in code.co_consts: + if isinstance(const,basestring): + yield const + 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. + return True + log.warn("Unable to analyze compiled code on this platform.") + 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 + +INSTALL_DIRECTORY_ATTRS = [ + 'install_lib', 'install_dir', 'install_data', 'install_base' +] + +def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None, + 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 + and found on the default search path). If neither tool is available, + 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) + + def visit(z, dirname, names): + for name in names: + path = os.path.normpath(os.path.join(dirname, name)) + if os.path.isfile(path): + 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)] + if not dry_run: + z = zipfile.ZipFile(zip_filename, mode, compression=compression) + for dirname, dirs, files in os.walk(base_dir): + visit(z, dirname, files) + z.close() + else: + for dirname, dirs, files in os.walk(base_dir): + visit(None, dirname, files) + return zip_filename +# diff --git a/vendor/distribute-0.6.35/setuptools/command/bdist_rpm.py b/vendor/distribute-0.6.35/setuptools/command/bdist_rpm.py new file mode 100644 index 00000000..8c48da35 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/bdist_rpm.py @@ -0,0 +1,82 @@ +# 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) + + + + + + + + + + + + + + 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 = [ + line.replace( + "Source0: %{name}-%{version}.tar", + "Source0: %{name}-%{unmangled_version}.tar" + ).replace( + "setup.py install ", + "setup.py install --single-version-externally-managed " + ).replace( + "%setup", + "%setup -n %{name}-%{unmangled_version}" + ).replace(line23,line24) + for line in spec + ] + spec.insert(spec.index(line24)+1, "%define unmangled_version "+version) + return spec + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/bdist_wininst.py b/vendor/distribute-0.6.35/setuptools/command/bdist_wininst.py new file mode 100644 index 00000000..93e6846d --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/bdist_wininst.py @@ -0,0 +1,41 @@ +from distutils.command.bdist_wininst import bdist_wininst as _bdist_wininst +import os, sys + +class bdist_wininst(_bdist_wininst): + + def create_exe(self, arcname, fullname, bitmap=None): + _bdist_wininst.create_exe(self, arcname, fullname, bitmap) + dist_files = getattr(self.distribution, 'dist_files', []) + + if self.target_version: + installer_name = os.path.join(self.dist_dir, + "%s.win32-py%s.exe" % + (fullname, self.target_version)) + pyversion = self.target_version + + # fix 2.5 bdist_wininst ignoring --target-version spec + bad = ('bdist_wininst','any',installer_name) + if bad in dist_files: + dist_files.remove(bad) + else: + installer_name = os.path.join(self.dist_dir, + "%s.win32.exe" % fullname) + pyversion = 'any' + good = ('bdist_wininst', pyversion, installer_name) + if good not in dist_files: + dist_files.append(good) + + def reinitialize_command (self, command, reinit_subcommands=0): + cmd = self.distribution.reinitialize_command( + command, reinit_subcommands) + if command in ('install', 'install_lib'): + cmd.install_lib = None # work around distutils bug + return cmd + + def run(self): + self._is_running = True + try: + _bdist_wininst.run(self) + finally: + self._is_running = False + diff --git a/vendor/distribute-0.6.35/setuptools/command/build_ext.py b/vendor/distribute-0.6.35/setuptools/command/build_ext.py new file mode 100644 index 00000000..4a94572c --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/build_ext.py @@ -0,0 +1,294 @@ +from distutils.command.build_ext import build_ext as _du_build_ext +try: + # Attempt to use Pyrex for building extensions, if available + from Pyrex.Distutils.build_ext import build_ext as _build_ext +except ImportError: + _build_ext = _du_build_ext + +import os, 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, get_config_var +get_config_var("LDSHARED") # make sure _config_vars is initialized +from distutils.sysconfig import _config_vars +from distutils import log +from distutils.errors import * + +have_rtld = False +use_stubs = False +libtype = 'shared' + +if sys.platform == "darwin": + use_stubs = True +elif os.name != 'nt': + try: + from dl import RTLD_NOW + have_rtld = True + use_stubs = True + except ImportError: + pass + +def if_dl(s): + if have_rtld: + return s + return '' + + + + + + +class build_ext(_build_ext): + def run(self): + """Build extensions in build directory, then copy if --inplace""" + old_inplace, self.inplace = self.inplace, 0 + _build_ext.run(self) + self.inplace = old_inplace + if old_inplace: + self.copy_extensions_to_source() + + def copy_extensions_to_source(self): + build_py = self.get_finalized_command('build_py') + for ext in self.extensions: + fullname = self.get_ext_fullname(ext.name) + filename = self.get_ext_filename(fullname) + 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) + + # Always copy, even if source is older than destination, to ensure + # that the right extensions for the current Python/platform are + # used. + copy_file( + src_filename, dest_filename, verbose=self.verbose, + dry_run=self.dry_run + ) + 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) + if fullname not in self.ext_map: + return filename + ext = self.ext_map[fullname] + if isinstance(ext,Library): + fn, ext = os.path.splitext(filename) + 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) + else: + return filename + + def initialize_options(self): + _build_ext.initialize_options(self) + self.shlib_compiler = None + self.shlibs = [] + self.ext_map = {} + + def finalize_options(self): + _build_ext.finalize_options(self) + self.extensions = self.extensions or [] + self.check_extensions_list(self.extensions) + self.shlibs = [ext for ext in self.extensions + if isinstance(ext,Library)] + if self.shlibs: + self.setup_shlib_compiler() + for ext in self.extensions: + ext._full_name = self.get_ext_fullname(ext.name) + for ext in self.extensions: + fullname = ext._full_name + self.ext_map[fullname] = ext + + # distutils 3.1 will also ask for module names + # 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) + filename = ext._file_name = self.get_ext_filename(fullname) + 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: + ext.runtime_library_dirs.append(os.curdir) + + def setup_shlib_compiler(self): + compiler = self.shlib_compiler = new_compiler( + compiler=self.compiler, dry_run=self.dry_run, force=self.force + ) + if sys.platform == "darwin": + 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['CCSHARED'] = " -dynamiclib" + _config_vars['SO'] = ".dylib" + customize_compiler(compiler) + finally: + _config_vars.clear() + _config_vars.update(tmp) + else: + customize_compiler(compiler) + + if self.include_dirs is not None: + 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: + compiler.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + compiler.undefine_macro(macro) + if self.libraries is not None: + compiler.set_libraries(self.libraries) + if self.library_dirs is not None: + compiler.set_library_dirs(self.library_dirs) + if self.rpath is not None: + compiler.set_runtime_library_dirs(self.rpath) + if self.link_objects is not None: + compiler.set_link_objects(self.link_objects) + + # hack so distutils' build_extension() builds a library instead + compiler.link_shared_object = link_shared_object.__get__(compiler) + + + + def get_export_symbols(self, ext): + if isinstance(ext,Library): + return ext.export_symbols + return _build_ext.get_export_symbols(self,ext) + + def build_extension(self, ext): + _compiler = self.compiler + try: + if isinstance(ext,Library): + self.compiler = self.shlib_compiler + _build_ext.build_extension(self,ext) + if ext._needs_stub: + self.write_stub( + self.get_finalized_command('build_py').build_lib, ext + ) + finally: + self.compiler = _compiler + + def links_to_dynamic(self, ext): + """Return true if 'ext' links to a dynamic lib in the same package""" + # XXX this should check to ensure the lib is actually being built + # 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 + + 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 + + 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' + if compile and os.path.exists(stub_file): + raise DistutilsError(stub_file+" already exists! Please delete.") + if not self.dry_run: + 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), + " del __bootstrap__", + " if '__loader__' in globals():", + " del __loader__", + if_dl(" old_flags = sys.getdlopenflags()"), + " old_dir = os.getcwd()", + " try:", + " os.chdir(os.path.dirname(__file__))", + if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), + " imp.load_dynamic(__name__,__file__)", + " finally:", + if_dl(" sys.setdlopenflags(old_flags)"), + " os.chdir(old_dir)", + "__bootstrap__()", + "" # 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 + if optimize > 0: + byte_compile([stub_file], optimize=optimize, + force=True, dry_run=self.dry_run) + if os.path.exists(stub_file) and not self.dry_run: + os.unlink(stub_file) + + +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 + ): self.link( + self.SHARED_LIBRARY, objects, output_libname, + output_dir, libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, extra_preargs, extra_postargs, + build_temp, target_lang + ) +else: + # 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 + ): + # 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 + + 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 + # a different prefix + basename = basename[3:] + + self.create_static_lib( + objects, basename, output_dir, debug, target_lang + ) + + diff --git a/vendor/distribute-0.6.35/setuptools/command/build_py.py b/vendor/distribute-0.6.35/setuptools/command/build_py.py new file mode 100644 index 00000000..8751acd4 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/build_py.py @@ -0,0 +1,280 @@ +import os.path, sys, fnmatch +from distutils.command.build_py import build_py as _build_py +from distutils.util import convert_path +from glob import glob + +try: + from distutils.util import Mixin2to3 as _Mixin2to3 + # add support for converting doctests that is missing in 3.1 distutils + from distutils import log + from lib2to3.refactor import RefactoringTool, get_fixers_from_package + import setuptools + class DistutilsRefactoringTool(RefactoringTool): + def log_error(self, msg, *args, **kw): + log.error(msg, *args) + + def log_message(self, msg, *args): + log.info(msg, *args) + + def log_debug(self, msg, *args): + log.debug(msg, *args) + + class Mixin2to3(_Mixin2to3): + def run_2to3(self, files, doctests = False): + # See of the distribution option has been set, otherwise check the + # setuptools default. + if self.distribution.use_2to3 is not True: + return + if not files: + return + log.info("Fixing "+" ".join(files)) + self.__build_fixer_names() + self.__exclude_fixers() + if doctests: + if setuptools.run_2to3_on_doctests: + r = DistutilsRefactoringTool(self.fixer_names) + r.refactor(files, write=True, doctests_only=True) + else: + _Mixin2to3.run_2to3(self, files) + + def __build_fixer_names(self): + if self.fixer_names: return + self.fixer_names = [] + for p in setuptools.lib2to3_fixer_packages: + self.fixer_names.extend(get_fixers_from_package(p)) + if self.distribution.use_2to3_fixers is not None: + for p in self.distribution.use_2to3_fixers: + self.fixer_names.extend(get_fixers_from_package(p)) + + def __exclude_fixers(self): + excluded_fixers = getattr(self, 'exclude_fixers', []) + if self.distribution.use_2to3_exclude_fixers is not None: + excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers) + for fixer_name in excluded_fixers: + if fixer_name in self.fixer_names: + self.fixer_names.remove(fixer_name) + +except ImportError: + class Mixin2to3: + def run_2to3(self, files, doctests=True): + # Nothing done in 2.x + pass + +class build_py(_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()'. + See 'setuptools.dist.Distribution' for more details. + + 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) + 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.__updated_files = [] + self.__doctests_2to3 = [] + + def run(self): + """Build modules, packages, and copy data files to build directory""" + if not self.py_modules and not self.packages: + return + + if self.py_modules: + self.build_modules() + + if self.packages: + self.build_packages() + self.build_package_data() + + self.run_2to3(self.__updated_files, False) + self.run_2to3(self.__updated_files, True) + self.run_2to3(self.__doctests_2to3, True) + + # 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)) + + 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) + + def build_module(self, module, module_file, package): + outfile, copied = _build_py.build_module(self, module, module_file, package) + if copied: + self.__updated_files.append(outfile) + return outfile, copied + + 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('.'))) + + # 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 find_data_files(self, package, src_dir): + """Return filenames for package's data files in 'src_dir'""" + globs = (self.package_data.get('', []) + + self.package_data.get(package, [])) + files = self.manifest_files.get(package, [])[:] + for pattern in globs: + # Each pattern has to be converted to a platform-specific path + files.extend(glob(os.path.join(src_dir, convert_path(pattern)))) + return self.exclude_data_files(package, src_dir, files) + + def build_package_data(self): + """Copy data files into build directory""" + lastdir = None + 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) + if copied and srcfile in self.distribution.convert_2to3_doctests: + self.__doctests_2to3.append(outf) + + + def analyze_manifest(self): + self.manifest_files = mf = {} + if not self.distribution.include_package_data: + return + src_dirs = {} + for package in self.packages or (): + # Locate package source directory + src_dirs[assert_relative(self.get_package_dir(package))] = package + + 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)) + prev = None + oldf = f + 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 + ] + + def check_package(self, package, package_dir): + """Check namespace packages' __init__ for declare_namespace""" + try: + return self.packages_checked[package] + except KeyError: + pass + + init_py = _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+'.'): + break + else: + return init_py + + f = open(init_py,'rbU') + if 'declare_namespace'.encode() not in f.read(): + from distutils import log + log.warn( + "WARNING: %s is a namespace package, but its __init__.py does\n" + "not declare_namespace(); setuptools 0.7 will REQUIRE this!\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) + + + def get_package_dir(self, package): + res = _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)) + ) + ) + bad = dict.fromkeys(bad) + seen = {} + return [ + f for f in files if f not in bad + and f not in seen and seen.setdefault(f,1) # ditch dupes + ] + + +def assert_relative(path): + if not os.path.isabs(path): + return path + from distutils.errors import DistutilsSetupError + raise DistutilsSetupError( +"""Error: setup script specifies an absolute path: + + %s + +setup() arguments must *always* be /-separated paths relative to the +setup.py directory, *never* absolute paths. +""" % path + ) + + + + + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/develop.py b/vendor/distribute-0.6.35/setuptools/command/develop.py new file mode 100644 index 00000000..1d500040 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/develop.py @@ -0,0 +1,167 @@ +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 import log +from distutils.errors import DistutilsError, DistutilsOptionError +import os, sys, setuptools, glob + +class develop(easy_install): + """Set up package for development""" + + description = "install package in 'development mode'" + + user_options = easy_install.user_options + [ + ("uninstall", "u", "Uninstall this source package"), + ("egg-path=", None, "Set the path to be used in the .egg-link file"), + ] + + boolean_options = easy_install.boolean_options + ['uninstall'] + + command_consumes_arguments = False # override base + + def run(self): + if self.uninstall: + self.multi_version = True + self.uninstall_link() + else: + self.install_for_development() + self.warn_deprecated_options() + + def initialize_options(self): + self.uninstall = None + self.egg_path = None + easy_install.initialize_options(self) + self.setup_path = None + 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) + ) + 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') + 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: + raise DistutilsOptionError( + "--egg-path must be a relative path from the install" + " 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 + ) + + 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): + 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 we run 2to3 we can not do this inplace: + + # Ensure metadata is up-to-date + self.reinitialize_command('build_py', inplace=0) + self.run_command('build_py') + bpy_cmd = self.get_finalized_command("build_py") + build_path = normalize_path(bpy_cmd.build_lib) + + # Build extensions + self.reinitialize_command('egg_info', egg_base=build_path) + self.run_command('egg_info') + + 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 + else: + # Without 2to3 inplace works fine: + self.run_command('egg_info') + + # 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) + setuptools.bootstrap_install_from = None + + # 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() + # 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]): + log.warn("Link points to %s: uninstall aborted", contents) + return + if not self.dry_run: + os.unlink(self.egg_link) + if not self.dry_run: + self.update_pth(self.dist) # remove any .pth link to us + if self.distribution.scripts: + # XXX should also check for entry point scripts! + log.warn("Note: you must uninstall or replace scripts manually!") + + 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) + + # create wrapper scripts in the script dir, pointing to dist.scripts + + # new-style... + self.install_wrapper_scripts(dist) + + # ...and old-style + 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() + self.install_script(dist, script_name, script_text, script_path) + diff --git a/vendor/distribute-0.6.35/setuptools/command/easy_install.py b/vendor/distribute-0.6.35/setuptools/command/easy_install.py new file mode 100644 index 00000000..0d72f758 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/easy_install.py @@ -0,0 +1,1947 @@ +#!python +"""\ +Easy Install +------------ + +A tool for doing automatic download/extract/build of distutils-based Python +packages. For detailed documentation, see the accompanying EasyInstall.txt +file, or visit the `EasyInstall home page`__. + +__ http://packages.python.org/distribute/easy_install.html + +""" +import sys +import os +import zipimport +import shutil +import tempfile +import zipfile +import re +import stat +import random +from glob import glob +from setuptools import Command, _dont_write_bytecode +from setuptools.sandbox import run_setup +from distutils import log, dir_util +from distutils.util import get_platform +from distutils.util import convert_path, subst_vars +from distutils.sysconfig import get_python_lib, get_config_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 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 + +sys_executable = os.path.normpath(sys.executable) + +__all__ = [ + 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', + 'main', 'get_exe_prefixes', +] + +import site +HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE + +import struct +def is_64bit(): + return struct.calcsize("P") == 8 + +def samefile(p1,p2): + if hasattr(os.path,'samefile') and ( + os.path.exists(p1) and os.path.exists(p2) + ): + return os.path.samefile(p1,p2) + return ( + os.path.normpath(os.path.normcase(p1)) == + os.path.normpath(os.path.normcase(p2)) + ) + +if sys.version_info <= (3,): + def _to_ascii(s): + return s + def isascii(s): + try: + unicode(s, 'ascii') + return True + except UnicodeError: + return False +else: + def _to_ascii(s): + return s.encode('ascii') + def isascii(s): + try: + s.encode('ascii') + return True + except UnicodeError: + return False + +class easy_install(Command): + """Manage a download/build/install process""" + description = "Find/get/install Python packages" + command_consumes_arguments = True + + user_options = [ + ('prefix=', None, "installation prefix"), + ("zip-ok", "z", "install package as a zipfile"), + ("multi-version", "m", "make apps have to require() a version"), + ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), + ("install-dir=", "d", "install package to DIR"), + ("script-dir=", "s", "install scripts to DIR"), + ("exclude-scripts", "x", "Don't install scripts"), + ("always-copy", "a", "Copy all needed packages to install dir"), + ("index-url=", "i", "base URL of Python Package Index"), + ("find-links=", "f", "additional URL(s) to search for packages"), + ("delete-conflicting", "D", "no longer needed; don't use this"), + ("ignore-conflicts-at-my-risk", None, + "no longer needed; don't use this"), + ("build-directory=", "b", + "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]"), + ('record=', None, + "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"), + ('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"), + ('version', None, "print version information and exit"), + ('no-find-links', None, + "Don't load find-links defined in packages being installed") + ] + boolean_options = [ + 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', + 'delete-conflicting', 'ignore-conflicts-at-my-risk', 'editable', + 'no-deps', 'local-snapshots-ok', 'version' + ] + + if HAS_USER_SITE: + user_options.append(('user', None, + "install in user site-package '%s'" % site.USER_SITE)) + boolean_options.append('user') + + + negative_opt = {'always-unzip': 'zip-ok'} + create_index = PackageIndex + + def initialize_options(self): + if HAS_USER_SITE: + whereami = os.path.abspath(__file__) + self.user = whereami.startswith(site.USER_SITE) + else: + 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 + self.find_links = None + self.build_directory = None + self.args = None + self.optimize = self.record = None + self.upgrade = self.always_copy = self.multi_version = None + 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_scripts = None + self.install_data = None + self.install_base = None + self.install_platbase = None + if HAS_USER_SITE: + self.install_userbase = site.USER_BASE + self.install_usersite = site.USER_SITE + else: + self.install_userbase = None + self.install_usersite = None + self.no_find_links = None + + # Options not specifiable via command line + self.package_index = None + self.pth_file = self.always_copy_from = None + self.delete_conflicting = None + self.ignore_conflicts_at_my_risk = None + self.site_dirs = None + self.installed_projects = {} + self.sitepy_installed = False + # 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" + # section, even if this is a "develop" or "install" command, or some + # other embedding. + self._dry_run = None + self.verbose = self.distribution.verbose + self.distribution._set_command_options( + self, self.distribution.get_option_dict('easy_install') + ) + + 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) + + def finalize_options(self): + if self.version: + print 'distribute %s' % get_distribution('distribute').version + sys.exit() + + py_version = sys.version.split()[0] + prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix') + + self.config_vars = {'dist_name': self.distribution.get_name(), + 'dist_version': self.distribution.get_version(), + 'dist_fullname': self.distribution.get_fullname(), + 'py_version': py_version, + 'py_version_short': py_version[0:3], + 'py_version_nodot': py_version[0] + py_version[2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + # Only python 3.2+ has abiflags + 'abiflags': getattr(sys, 'abiflags', ''), + } + + if HAS_USER_SITE: + 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 HAS_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.expand_basedirs() + self.expand_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: + self.script_dir = self.install_dir + + if self.no_find_links is None: + self.no_find_links = False + + # 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') + ) + # Likewise, set default script_dir from 'install_scripts.install_dir' + self.set_undefined_options('install_scripts', + ('install_dir', 'script_dir') + ) + + if self.user and self.install_purelib: + self.install_dir = self.install_purelib + self.script_dir = self.install_scripts + # default --record from the install command + self.set_undefined_options('install', ('record', 'record')) + normpath = map(normalize_path, sys.path) + 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(',') + ] + 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" + ) + else: + self.all_site_dirs.append(normalize_path(d)) + if not self.editable: self.check_site_dir() + self.index_url = self.index_url or "http://pypi.python.org/simple" + self.shadow_path = self.all_site_dirs[:] + for path_item in self.install_dir, normalize_path(self.script_dir): + if path_item not in self.shadow_path: + self.shadow_path.insert(0, path_item) + + if self.allow_hosts is not None: + hosts = [s.strip() for s in self.allow_hosts.split(',')] + else: + hosts = ['*'] + if self.package_index is None: + self.package_index = self.create_index( + self.index_url, search_path = self.shadow_path, hosts=hosts, + ) + self.local_index = Environment(self.shadow_path+sys.path) + + if self.find_links is not None: + if isinstance(self.find_links, basestring): + 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) + 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): + try: + self.optimize = int(self.optimize) + if not (0 <= self.optimize <= 2): raise ValueError + except ValueError: + raise DistutilsOptionError("--optimize must be 0, 1, or 2") + + if self.delete_conflicting and self.ignore_conflicts_at_my_risk: + raise DistutilsOptionError( + "Can't use both --delete-conflicting and " + "--ignore-conflicts-at-my-risk at the same time" + ) + if self.editable and not self.build_directory: + raise DistutilsArgError( + "Must specify a build directory (-b) when using --editable" + ) + if not self.args: + raise DistutilsArgError( + "No urls, filenames, or requirements specified (see --help)") + + self.outputs = [] + + + def _expand_attrs(self, attrs): + for attr in attrs: + val = getattr(self, attr) + if val is not None: + if os.name == 'posix' or os.name == 'nt': + val = os.path.expanduser(val) + val = subst_vars(val, self.config_vars) + setattr(self, attr, val) + + def expand_basedirs(self): + """Calls `os.path.expanduser` on install_base, install_platbase and + root.""" + self._expand_attrs(['install_base', 'install_platbase', 'root']) + + def expand_dirs(self): + """Calls `os.path.expanduser` on install dirs.""" + self._expand_attrs(['install_purelib', 'install_platlib', + 'install_lib', 'install_headers', + 'install_scripts', 'install_data',]) + + def run(self): + if self.verbose != self.distribution.verbose: + log.set_verbosity(self.verbose) + try: + for spec in self.args: + self.easy_install(spec, not self.no_deps) + if self.record: + outputs = self.outputs + if self.root: # strip any package prefix + root_len = len(self.root) + for counter in xrange(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'" % + self.record + ) + self.warn_deprecated_options() + finally: + log.set_verbosity(self.distribution.verbose) + + def pseudo_tempname(self): + """Return a pseudo-tempname base in the install directory. + This code is intentionally naive; if a malicious party can write to + the target directory you're already in deep doodoo. + """ + try: + pid = os.getpid() + except: + pid = random.randint(0,sys.maxint) + return os.path.join(self.install_dir, "test-easy-install-%s" % pid) + + def warn_deprecated_options(self): + if self.delete_conflicting or self.ignore_conflicts_at_my_risk: + log.warn( + "Note: The -D, --delete-conflicting and" + " --ignore-conflicts-at-my-risk no longer have any purpose" + " and should not be used." + ) + + def check_site_dir(self): + """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') + + # Is it a configured, PYTHONPATH, implicit, or explicit site dir? + is_site_dir = instdir in self.all_site_dirs + + if not is_site_dir: + # No? Then directly test whether it does .pth file processing + is_site_dir = self.check_pth_processing() + else: + # make sure we can write to target dir + testfile = self.pseudo_tempname()+'.write-test' + test_exists = os.path.exists(testfile) + try: + if test_exists: os.unlink(testfile) + open(testfile,'w').close() + os.unlink(testfile) + except (OSError,IOError): + self.cant_write_to_target() + + if not is_site_dir and not self.multi_version: + # Can't install non-multi to non-site dir + raise DistutilsError(self.no_default_version_msg()) + + if is_site_dir: + if self.pth_file is None: + self.pth_file = PthDistributions(pth_file, self.all_site_dirs) + else: + self.pth_file = None + + 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.install_dir = instdir + + def cant_write_to_target(self): + msg = """can't create or remove files in install directory + +The following error occurred while trying to add or remove files in the +installation directory: + + %s + +The installation directory you specified (via --install-dir, --prefix, or +the distutils default setting) was: + + %s +""" % (sys.exc_info()[1], self.install_dir,) + + 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. + +For information on other options, you may wish to consult the +documentation at: + + http://packages.python.org/distribute/easy_install.html + +Please make the appropriate changes for your system and try again. +""" + 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' + ok_exists = os.path.exists(ok_file) + try: + 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): + self.cant_write_to_target() + else: + try: + f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,)) + f.close(); 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): + # use pythonw.exe to avoid opening a console window + executable = alt + + from distutils.spawn import spawn + spawn([executable,'-E','-c','pass'],0) + + if os.path.exists(ok_file): + log.info( + "TEST PASSED: %s appears to support .pth files", + instdir + ) + return True + finally: + if f: f.close() + if os.path.exists(ok_file): os.unlink(ok_file) + if os.path.exists(pth_file): os.unlink(pth_file) + if not self.multi_version: + log.warn("TEST FAILED: %s does NOT support .pth files", instdir) + return False + + def install_egg_scripts(self, dist): + """Write all the scripts for `dist`, unless scripts are excluded""" + if not self.exclude_scripts and dist.metadata_isdir('scripts'): + for script_name in dist.metadata_listdir('scripts'): + self.install_script( + dist, script_name, + dist.get_metadata('scripts/'+script_name) + ) + self.install_wrapper_scripts(dist) + + def add_output(self, path): + 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)) + else: + self.outputs.append(path) + + def not_editable(self, spec): + if self.editable: + raise DistutilsArgError( + "Invalid argument %r: you can't use filenames or URLs " + "with --editable (except via the --find-links option)." + % (spec,) + ) + + def check_editable(self,spec): + if not self.editable: + return + + if os.path.exists(os.path.join(self.build_directory, spec.key)): + raise DistutilsArgError( + "%r already exists in %s; can't do a checkout there" % + (spec.key, self.build_directory) + ) + + + + + + + def easy_install(self, spec, deps=False): + tmpdir = tempfile.mkdtemp(prefix="easy_install-") + download = None + if not self.editable: self.install_site_py() + + try: + 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) + + elif os.path.exists(spec): + # Existing file or directory, just process it directly + self.not_editable(spec) + return self.install_item(None, spec, tmpdir, deps, True) + else: + spec = parse_requirement_arg(spec) + + self.check_editable(spec) + dist = self.package_index.fetch_distribution( + 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)" + raise DistutilsError(msg) + elif dist.precedence==DEVELOP_DIST: + # .egg-info dists don't need installing, just process deps + self.process_distribution(spec, dist, deps, "Using") + return dist + else: + return self.install_item(spec, dist.location, tmpdir, deps) + + finally: + if os.path.exists(tmpdir): + rmtree(tmpdir) + + def install_item(self, spec, download, tmpdir, deps, install_needed=False): + + # Installation is also needed if file in tmpdir or is not an egg + install_needed = install_needed or self.always_copy + install_needed = install_needed or os.path.dirname(download) == tmpdir + install_needed = install_needed or not download.endswith('.egg') + install_needed = install_needed or ( + self.always_copy_from is not None and + os.path.dirname(normalize_path(download)) == + normalize_path(self.always_copy_from) + ) + + if spec and not install_needed: + # 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: + break + else: + install_needed = True # it's not in the local index + + log.info("Processing %s", os.path.basename(download)) + + if install_needed: + dists = self.install_eggs(spec, download, tmpdir) + for dist in dists: + self.process_distribution(spec, dist, deps) + else: + dists = [self.check_conflicts(self.egg_distribution(download))] + self.process_distribution(spec, dists[0], deps, "Using") + + if spec is not None: + for dist in dists: + if dist in spec: + return dist + + + + def select_scheme(self, name): + """Sets the install directories by applying the install schemes.""" + # it's the caller's problem if they supply a bad name! + scheme = INSTALL_SCHEMES[name] + for key in SCHEME_KEYS: + attrname = 'install_' + key + if getattr(self, attrname) is None: + setattr(self, attrname, scheme[key]) + + + + + def process_distribution(self, requirement, dist, deps=True, *info): + self.update_pth(dist) + self.package_index.add(dist) + self.local_index.add(dist) + if not self.editable: + self.install_egg_scripts(dist) + self.installed_projects[dist.key] = dist + log.info(self.installation_report(requirement, dist, *info)) + if (dist.has_metadata('dependency_links.txt') and + not self.no_find_links): + self.package_index.add_find_links( + dist.get_metadata_lines('dependency_links.txt') + ) + if not deps and not self.always_copy: + return + elif requirement is not None and dist.key != requirement.key: + log.warn("Skipping dependencies for %s", dist) + return # XXX this is not the distribution we were looking for + elif requirement is None or dist not in requirement: + # if we wound up with a different version, resolve what we've got + distreq = dist.as_requirement() + requirement = requirement or distreq + requirement = Requirement( + distreq.project_name, distreq.specs, requirement.extras + ) + log.info("Processing dependencies for %s", requirement) + try: + distros = WorkingSet([]).resolve( + [requirement], self.local_index, self.easy_install + ) + except DistributionNotFound, e: + raise DistutilsError( + "Could not find required distribution %s" % e.args + ) + except VersionConflict, e: + raise DistutilsError( + "Installed distribution %s conflicts with requirement %s" + % e.args + ) + if self.always_copy or self.always_copy_from: + # Force all the relevant distros to be copied or activated + for dist in distros: + if dist.key not in self.installed_projects: + self.easy_install(dist.as_requirement()) + log.info("Finished processing dependencies for %s", requirement) + + def should_unzip(self, dist): + if self.zip_ok is not None: + return not self.zip_ok + if dist.has_metadata('not-zip-safe'): + return True + if not dist.has_metadata('zip-safe'): + return True + return True + + def maybe_move(self, spec, dist_filename, setup_base): + dst = os.path.join(self.build_directory, spec.key) + if os.path.exists(dst): + log.warn( + "%r already exists in %s; build directory %s will not be kept", + 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 + contents = os.listdir(setup_base) + 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 + ensure_directory(dst); shutil.move(setup_base, dst) + return dst + + def install_wrapper_scripts(self, dist): + if not self.exclude_scripts: + for args in get_script_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: + template_name = 'script template.py' + if dev_path: + template_name = template_name.replace('.py', ' (dev).py') + script_text = (get_script_header(script_text) + + get_template(template_name) % locals()) + self.write_script(script_name, _to_ascii(script_text), 'b') + + def write_script(self, script_name, contents, mode="t", blockers=()): + """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]) + 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) + + mask = current_umask() + if not self.dry_run: + ensure_directory(target) + f = open(target,"w"+mode) + f.write(contents) + f.close() + chmod(target, 0777-mask) + + + + + def install_eggs(self, spec, dist_filename, tmpdir): + # .egg dirs or files are already built, so just return them + if dist_filename.lower().endswith('.egg'): + return [self.install_egg(dist_filename, tmpdir)] + elif dist_filename.lower().endswith('.exe'): + return [self.install_exe(dist_filename, tmpdir)] + + # Anything else, try to extract and build + setup_base = tmpdir + if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): + unpack_archive(dist_filename, tmpdir, self.unpack_progress) + elif os.path.isdir(dist_filename): + setup_base = os.path.abspath(dist_filename) + + 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) + + # Find the setup.py file + setup_script = os.path.join(setup_base, 'setup.py') + + if not os.path.exists(setup_script): + 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) + ) + if len(setups)>1: + raise DistutilsError( + "Multiple setup scripts in %s" % os.path.abspath(dist_filename) + ) + setup_script = setups[0] + + # Now run it, and return the result + if self.editable: + log.info(self.report_editable(spec, setup_script)) + return [] + else: + return self.build_and_install(setup_script, setup_base) + + def egg_distribution(self, egg_path): + if os.path.isdir(egg_path): + 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) + + def install_egg(self, egg_path, tmpdir): + 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) + + dist = self.egg_distribution(egg_path) + self.check_conflicts(dist) + if not samefile(egg_path, destination): + 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" + 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))) + + self.add_output(destination) + return self.egg_distribution(destination) + + def install_exe(self, dist_filename, tmpdir): + # See if it's valid, get data + cfg = extract_wininst_cfg(dist_filename) + if cfg is None: + raise DistutilsError( + "%s is not a valid distutils Windows .exe" % dist_filename + ) + # 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() + ) + + # Convert the .exe to an unpacked 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 + 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.write('Metadata-Version: 1.0\n') + for k,v in cfg.items('metadata'): + if k<>'target_version': + 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)] + ) + # Build .egg file from tmpdir + bdist_egg.make_zipfile( + egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run + ) + # install the .egg + return self.install_egg(egg_path, tmpdir) + + def exe_to_egg(self, dist_filename, egg_tmp): + """Extract a bdist_wininst to the directories an egg would use""" + # Check for .pth file and set up prefix translations + prefixes = get_exe_prefixes(dist_filename) + to_compile = [] + native_libs = [] + top_level = {} + def process(src,dst): + s = src.lower() + for old,new in prefixes: + if s.startswith(old): + src = new+src[len(old):] + parts = src.split('/') + dst = os.path.join(egg_tmp, *parts) + dl = dst.lower() + if dl.endswith('.pyd') or dl.endswith('.dll'): + 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/': + 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 + parts = res.split('/') + resource = parts[-1] + 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'), + bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag + + for name in 'top_level','native_libs': + if locals()[name]: + 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.close() + + def check_conflicts(self, dist): + """Verify that there are no conflicting "old-style" packages""" + + return dist # XXX temporarily disable until new strategy is stable + from imp import find_module, get_suffixes + from glob import glob + + blockers = [] + names = dict.fromkeys(dist._get_metadata('top_level.txt')) # XXX private attr + + exts = {'.pyc':1, '.pyo':1} # get_suffixes() might leave one out + for ext,mode,typ in get_suffixes(): + exts[ext] = 1 + + for path,files in expand_paths([self.install_dir]+self.all_site_dirs): + for filename in files: + base,ext = os.path.splitext(filename) + if base in names: + if not ext: + # no extension, check for package + try: + f, filename, descr = find_module(base, [path]) + except ImportError: + continue + else: + if f: f.close() + if filename not in blockers: + blockers.append(filename) + elif ext in exts and base!='site': # XXX ugh + blockers.append(os.path.join(path,filename)) + if blockers: + self.found_conflicts(dist, blockers) + + return dist + + def found_conflicts(self, dist, blockers): + if self.delete_conflicting: + log.warn("Attempting to delete conflicting packages:") + return self.delete_blockers(blockers) + + msg = """\ +------------------------------------------------------------------------- +CONFLICT WARNING: + +The following modules or packages have the same names as modules or +packages being installed, and will be *before* the installed packages in +Python's search path. You MUST remove all of the relevant files and +directories before you will be able to use the package(s) you are +installing: + + %s + +""" % '\n '.join(blockers) + + if self.ignore_conflicts_at_my_risk: + msg += """\ +(Note: you can run EasyInstall on '%s' with the +--delete-conflicting option to attempt deletion of the above files +and/or directories.) +""" % dist.project_name + else: + msg += """\ +Note: you can attempt this installation again with EasyInstall, and use +either the --delete-conflicting (-D) option or the +--ignore-conflicts-at-my-risk option, to either delete the above files +and directories, or to ignore the conflicts, respectively. Note that if +you ignore the conflicts, the installed package(s) may not work. +""" + msg += """\ +------------------------------------------------------------------------- +""" + sys.stderr.write(msg) + sys.stderr.flush() + if not self.ignore_conflicts_at_my_risk: + raise DistutilsError("Installation aborted due to conflicts") + + 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 += """ + +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) + 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 + +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 + +See the setuptools documentation for the "develop" command for more info. +""" % 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: + v = 'v' * (self.verbose - 1) + args.insert(0,'-'+v) + elif self.verbose<2: + args.insert(0,'-q') + if self.dry_run: + args.insert(0,'-n') + log.info( + "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args) + ) + try: + run_setup(setup_script, args) + except SystemExit, v: + raise DistutilsError("Setup script exited with %s" % (v.args[0],)) + + def build_and_install(self, setup_script, setup_base): + args = ['bdist_egg', '--dist-dir'] + + dist_dir = tempfile.mkdtemp( + prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) + ) + try: + self._set_fetcher_options(os.path.dirname(setup_script)) + args.append(dist_dir) + + self.run_setup(setup_script, setup_base, args) + all_eggs = Environment([dist_dir]) + eggs = [] + for key in all_eggs: + for dist in all_eggs[key]: + 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) + return eggs + finally: + rmtree(dist_dir) + log.set_verbosity(self.verbose) # restore our log verbosity + + def _set_fetcher_options(self, base): + """ + When easy_install is about to run bdist_egg on a source dist, that + source dist might have 'setup_requires' directives, requiring + additional fetching. Ensure the fetcher options given to easy_install + are available to that command as well. + """ + # find the fetch options from easy_install and write them out + # to the setup.cfg file. + ei_opts = self.distribution.get_option_dict('easy_install').copy() + fetch_directives = ( + 'find_links', 'site_dirs', 'index_url', 'optimize', + 'site_dirs', 'allow_hosts', + ) + fetch_options = {} + for key, val in ei_opts.iteritems(): + 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) + cfg_filename = os.path.join(base, 'setup.cfg') + setopt.edit_config(cfg_filename, settings) + + + def update_pth(self,dist): + if self.pth_file is None: + return + + 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) + if d.location in self.shadow_path: + self.shadow_path.remove(d.location) + + if not self.multi_version: + if dist.location in self.pth_file.paths: + log.info( + "%s is already the active version in easy-install.pth", + dist + ) + else: + log.info("Adding %s to easy-install.pth file", dist) + self.pth_file.add(dist) # add new entry + if dist.location not in self.shadow_path: + self.shadow_path.append(dist.location) + + if not self.dry_run: + + self.pth_file.save() + if dist.key=='distribute': + # 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) + f = open(filename, 'wt') + 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 + + def unpack_and_compile(self, egg_path, destination): + to_compile = []; to_chmod = [] + + def pf(src,dst): + if dst.endswith('.py') and not src.startswith('EGG-INFO/'): + to_compile.append(dst) + to_chmod.append(dst) + elif dst.endswith('.dll') or dst.endswith('.so'): + to_chmod.append(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]) | 0555) & 07755 + chmod(f, mode) + + def byte_compile(self, to_compile): + if _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) + + byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) + if self.optimize: + byte_compile( + to_compile, optimize=self.optimize, force=1, + dry_run=self.dry_run + ) + finally: + log.set_verbosity(self.verbose) # restore original verbosity + + + + + + + + + def no_default_version_msg(self): + return """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: + + %s + +and your PYTHONPATH environment variable currently contains: + + %r + +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 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: + + http://packages.python.org/distribute/easy_install.html#custom-installation-locations + +Please make the appropriate changes for your system and try again.""" % ( + 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""" + + if self.sitepy_installed: + return # already did it, or don't need to + + sitepy = os.path.join(self.install_dir, "site.py") + source = resource_string(Requirement.parse("distribute"), "site.py") + current = "" + + if os.path.exists(sitepy): + log.debug("Checking existing site.py in %s", self.install_dir) + f = open(sitepy,'rb') + current = f.read() + # we want str, not bytes + if sys.version_info >= (3,): + current = current.decode() + + f.close() + if not current.startswith('def __boot():'): + raise DistutilsError( + "%s is not a setuptools-generated site.py; please" + " remove it." % sitepy + ) + + if current != source: + log.info("Creating %s", sitepy) + if not self.dry_run: + ensure_directory(sitepy) + f = open(sitepy,'wb') + f.write(source) + f.close() + self.byte_compile([sitepy]) + + self.sitepy_installed = True + + + + + def create_home_path(self): + """Create directories under ~.""" + if not self.user: + return + home = convert_path(os.path.expanduser("~")) + for name, path in self.config_vars.iteritems(): + if path.startswith(home) and not os.path.isdir(path): + self.debug_print("os.makedirs('%s', 0700)" % path) + os.makedirs(path, 0700) + + + + + + + + INSTALL_SCHEMES = dict( + 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', + ) + + def _expand(self, *attrs): + config_vars = self.get_finalized_command('install').config_vars + + if self.prefix: + # 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) + + from distutils.util import subst_vars + for attr in attrs: + val = getattr(self, attr) + if val is not None: + val = subst_vars(val, config_vars) + if os.name == 'posix': + val = os.path.expanduser(val) + setattr(self, attr, val) + + + + + + + + + +def get_site_dirs(): + # return a list of 'site' dirs + sitedirs = filter(None,os.environ.get('PYTHONPATH','').split(os.pathsep)) + prefixes = [sys.prefix] + if sys.exec_prefix != sys.prefix: + prefixes.append(sys.exec_prefix) + for prefix in prefixes: + if prefix: + if sys.platform in ('os2emx', 'riscos'): + 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")]) + else: + sitedirs.extend( + [prefix, os.path.join(prefix, "lib", "site-packages")] + ) + if sys.platform == 'darwin': + # for framework builds *only* we add the standard Apple + # locations. Currently only per-user, but /Library and + # /Network/Library could be added too + if 'Python.framework' in prefix: + home = os.environ.get('HOME') + if home: + sitedirs.append( + os.path.join(home, + 'Library', + 'Python', + sys.version[:3], + 'site-packages')) + for plat_specific in (0,1): + site_lib = get_python_lib(plat_specific) + if site_lib not in sitedirs: sitedirs.append(site_lib) + + if HAS_USER_SITE: + sitedirs.append(site.USER_SITE) + + sitedirs = map(normalize_path, sitedirs) + + return sitedirs + + +def expand_paths(inputs): + """Yield sys.path directories that might contain "old-style" packages""" + + seen = {} + + for dirname in inputs: + dirname = normalize_path(dirname) + if dirname in seen: + continue + + seen[dirname] = 1 + if not os.path.isdir(dirname): + continue + + files = os.listdir(dirname) + yield dirname, files + + for name in files: + if not name.endswith('.pth'): + # We only care about the .pth files + continue + 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)) + lines = list(yield_lines(f)) + f.close() + + # Yield existing non-dupe, non-import directory lines from it + for line in lines: + if not line.startswith("import"): + line = normalize_path(line.rstrip()) + if line not in seen: + seen[line] = 1 + if not os.path.isdir(line): + continue + yield line, os.listdir(line) + + +def extract_wininst_cfg(dist_filename): + """Extract configuration data from a bdist_wininst .exe + + Returns a ConfigParser.RawConfigParser, or None + """ + f = open(dist_filename,'rb') + try: + endrec = zipfile._EndRecData(f) + if endrec is None: + return None + + prepended = (endrec[9] - endrec[5]) - endrec[6] + if prepended < 12: # no wininst data here + return None + f.seek(prepended-12) + + import struct, StringIO, ConfigParser + tag, cfglen, bmlen = struct.unpack("<iii",f.read(12)) + if tag not in (0x1234567A, 0x1234567B): + return None # not a valid tag + + f.seek(prepended-(12+cfglen)) + cfg = ConfigParser.RawConfigParser({'version':'','target_version':''}) + try: + part = f.read(cfglen) + # part is in bytes, but we need to read up to the first null + # byte. + if sys.version_info >= (2,6): + null_byte = bytes([0]) + else: + null_byte = chr(0) + config = part.split(null_byte, 1)[0] + # Now the config is in bytes, but on Python 3, it must be + # unicode for the RawConfigParser, so decode it. Is this the + # right encoding? + config = config.decode('ascii') + cfg.readfp(StringIO.StringIO(config)) + except ConfigParser.Error: + return None + if not cfg.has_section('metadata') or not cfg.has_section('Setup'): + return None + return cfg + + finally: + f.close() + + + + + + + + +def get_exe_prefixes(exe_filename): + """Get exe->egg path translations for a given .exe file""" + + prefixes = [ + ('PURELIB/', ''), ('PLATLIB/pywin32_system32', ''), + ('PLATLIB/', ''), + ('SCRIPTS/', 'EGG-INFO/scripts/'), + ('DATA/LIB/site-packages', ''), + ] + z = zipfile.ZipFile(exe_filename) + try: + for info in z.infolist(): + name = info.filename + parts = name.split('/') + if len(parts)==3 and parts[2]=='PKG-INFO': + if parts[1].endswith('.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'): + contents = z.read(name) + if sys.version_info >= (3,): + contents = contents.decode() + for pth in yield_lines(contents): + pth = pth.strip().replace('\\','/') + if not pth.startswith('import'): + prefixes.append((('%s/%s/' % (parts[0],pth)), '')) + finally: + z.close() + prefixes = [(x.lower(),y) for x, y in prefixes] + prefixes.sort(); prefixes.reverse() + return prefixes + + +def parse_requirement_arg(spec): + try: + return Requirement.parse(spec) + except ValueError: + raise DistutilsError( + "Not a URL, existing file, or requirement spec: %r" % (spec,) + ) + +class PthDistributions(Environment): + """A .pth file with Distribution paths in it""" + + dirty = False + + def __init__(self, filename, sitedirs=()): + self.filename = filename; self.sitedirs=map(normalize_path, sitedirs) + self.basedir = normalize_path(os.path.dirname(self.filename)) + self._load(); Environment.__init__(self, [], None, None) + for path in yield_lines(self.paths): + map(self.add, find_distributions(path, True)) + + def _load(self): + self.paths = [] + saw_import = False + seen = dict.fromkeys(self.sitedirs) + if os.path.isfile(self.filename): + f = open(self.filename,'rt') + for line in f: + if line.startswith('import'): + saw_import = True + continue + path = line.rstrip() + self.paths.append(path) + if not path.strip() or path.strip().startswith('#'): + continue + # 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) + ) + 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 :) + continue + seen[path] = 1 + f.close() + + if self.paths and not saw_import: + self.dirty = True # ensure anything we touch has import wrappers + while self.paths and not self.paths[-1].strip(): + self.paths.pop() + + def save(self): + """Write changed .pth file back to disk""" + if not self.dirty: + return + + data = '\n'.join(map(self.make_relative,self.paths)) + if data: + 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 + + if os.path.islink(self.filename): + os.unlink(self.filename) + f = open(self.filename,'wt') + f.write(data); f.close() + + elif os.path.exists(self.filename): + log.debug("Deleting empty %s", self.filename) + os.unlink(self.filename) + + self.dirty = False + + def add(self,dist): + """Add `dist` to the distribution map""" + if (dist.location not in self.paths and ( + dist.location not in self.sitedirs or + dist.location == os.getcwd() #account for '.' being in PYTHONPATH + )): + self.paths.append(dist.location) + self.dirty = True + Environment.add(self,dist) + + def remove(self,dist): + """Remove `dist` from the distribution map""" + while dist.location in self.paths: + self.paths.remove(dist.location); self.dirty = True + Environment.remove(self,dist) + + + 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: + parts.append(os.curdir) + parts.reverse() + return sep.join(parts) + npath, last = os.path.split(npath) + parts.append(last) + 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 + + # 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()) + + 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': + chmod(arg, stat.S_IWRITE) + return func(arg) + exc = sys.exc_info() + raise exc[0], (exc[1][0], exc[1][1] + (" %s %s" % (func,arg))) + +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] + else: + path = normalize_path(path) + for p in cache: + if normalize_path(p)==path: + del cache[p] + return + +def is_python(text, filename='<string>'): + "Is this string a valid Python script?" + try: + compile(text, filename, 'exec') + except (SyntaxError, TypeError): + return False + 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 + return magic == '#!' + +def nt_quote_arg(arg): + """Quote a command line argument according to Windows parsing rules""" + + 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 + if is_python(script_text, filename): + 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 + +try: + from os import chmod as _chmod +except ImportError: + # Jython compatibility + 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: + 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 + + +def get_script_args(dist, executable=sys_executable, wininst=False): + """Yield write_script() argument tuples for a distribution's entrypoints""" + spec = str(dist.as_requirement()) + header = get_script_header("", executable, wininst) + for group in 'console_scripts', 'gui_scripts': + for name, ep in dist.get_entry_map(group).items(): + script_text = ( + "# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r\n" + "__requires__ = %(spec)r\n" + "import sys\n" + "from pkg_resources import load_entry_point\n" + "\n" + "if __name__ == '__main__':" + "\n" + " sys.exit(\n" + " load_entry_point(%(spec)r, %(group)r, %(name)r)()\n" + " )\n" + ) % locals() + if sys.platform=='win32' or wininst: + # On Windows/wininst, add a .py extension and an .exe launcher + if group=='gui_scripts': + ext, launcher = '-script.pyw', 'gui.exe' + old = ['.pyw'] + new_header = re.sub('(?i)python.exe','pythonw.exe',header) + else: + ext, launcher = '-script.py', 'cli.exe' + old = ['.py','.pyc','.pyo'] + new_header = re.sub('(?i)pythonw.exe','python.exe',header) + if is_64bit(): + launcher = launcher.replace(".", "-64.") + else: + launcher = launcher.replace(".", "-32.") + if os.path.exists(new_header[2:-1]) or sys.platform!='win32': + hdr = new_header + else: + hdr = header + yield (name+ext, hdr+script_text, 't', [name+x for x in old]) + yield ( + name+'.exe', resource_string('setuptools', launcher), + 'b' # write in binary mode + ) + else: + # On other platforms, we assume the right thing to do is to + # just write the stub with no extension. + yield (name, header+script_text) + +def rmtree(path, ignore_errors=False, onerror=auto_chmod): + """Recursively delete a directory tree. + + This code is taken from the Python 2.4 version of 'shutil', because + the 2.3 version doesn't really work right. + """ + if ignore_errors: + def onerror(*args): + pass + elif onerror is None: + def onerror(*args): + raise + names = [] + try: + names = os.listdir(path) + except os.error, err: + onerror(os.listdir, path, sys.exc_info()) + for name in names: + fullname = os.path.join(path, name) + try: + mode = os.lstat(fullname).st_mode + except os.error: + mode = 0 + if stat.S_ISDIR(mode): + rmtree(fullname, ignore_errors, onerror) + else: + try: + os.remove(fullname) + except os.error, err: + onerror(os.remove, fullname, sys.exc_info()) + try: + os.rmdir(path) + except os.error: + onerror(os.rmdir, path, sys.exc_info()) + +def current_umask(): + tmp = os.umask(022) + 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): + script = os.path.basename(script_name) + return USAGE % vars() + + 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 find_config_files(self): + files = Distribution.find_config_files(self) + if 'setup.cfg' in files: + files.remove('setup.cfg') + return files + + if argv is None: + argv = sys.argv[1:] + + with_ei_usage(lambda: + setup( + script_args = ['-q','easy_install', '-v']+argv, + script_name = sys.argv[0] or 'easy_install', + distclass=DistributionWithoutHelpCommands, **kw + ) + ) + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/egg_info.py b/vendor/distribute-0.6.35/setuptools/command/egg_info.py new file mode 100644 index 00000000..0c2ea0cc --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/egg_info.py @@ -0,0 +1,486 @@ +"""setuptools.command.egg_info + +Create a distribution's .egg-info directory and contents""" + +# This module should be kept compatible with Python 2.3 +import os, re, sys +from setuptools import Command +from distutils.errors import * +from distutils import log +from setuptools.command.sdist import sdist +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 sdist import walk_revctrl + +class egg_info(Command): + description = "create a distribution's .egg-info directory" + + user_options = [ + ('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"), + ('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]"), + ('no-date', 'D', "Don't include date stamp [default]"), + ] + + boolean_options = ['tag-date', 'tag-svn-revision'] + negative_opt = {'no-svn-revision': 'tag-svn-revision', + 'no-date': 'tag-date'} + + + + + + + + def initialize_options(self): + self.egg_name = None + self.egg_version = None + self.egg_base = None + self.egg_info = None + self.tag_build = None + self.tag_svn_revision = 0 + self.tag_date = 0 + self.broken_egg_info = False + self.vtags = None + + def save_version_info(self, filename): + from setopt import edit_config + edit_config( + filename, + {'egg_info': + {'tag_svn_revision':0, 'tag_date': 0, 'tag_build': self.tags()} + } + ) + + + + + + + + + + + + + + + + + + + + + + + def finalize_options (self): + self.egg_name = safe_name(self.distribution.get_name()) + self.vtags = self.tags() + self.egg_version = self.tagged_version() + + try: + list( + parse_requirements('%s==%s' % (self.egg_name,self.egg_version)) + ) + except ValueError: + raise DistutilsOptionError( + "Invalid distribution name or version syntax: %s-%s" % + (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.ensure_dirname('egg_base') + 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() + + # Set package version for the benefit of dumber commands + # (e.g. sdist, bdist_wininst, etc.) + # + self.distribution.metadata.version = self.egg_version + + # If we bootstrapped around the lack of a PKG-INFO, as might be the + # case in a fresh checkout, make sure that any special tags get added + # to the version info + # + pd = self.distribution._patched_dist + 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 + + + def write_or_delete_file(self, what, filename, data, force=False): + """Write `data` to `filename` or delete if empty + + If `data` is non-empty, this routine is the same as ``write_file()``. + If `data` is empty but not ``None``, this is the same as calling + ``delete_file(filename)`. If `data` is ``None``, then this is a no-op + unless `filename` exists, in which case a warning is issued about the + orphaned file (if `force` is false), or deleted (if `force` is true). + """ + if data: + self.write_file(what, filename, data) + elif os.path.exists(filename): + if data is None and not force: + log.warn( + "%s not set in setup(), but %s exists", what, filename + ) + return + else: + self.delete_file(filename) + + def write_file(self, what, filename, data): + """Write `data` to `filename` (if not a dry run) after announcing it + + `what` is used in a log message to identify what is being written + to the file. + """ + log.info("writing %s to %s", what, filename) + if sys.version_info >= (3,): + data = data.encode("utf-8") + if not self.dry_run: + f = open(filename, 'wb') + f.write(data) + f.close() + + def delete_file(self, filename): + """Delete `filename` (if not a dry run) after announcing it""" + log.info("deleting %s", filename) + if not self.dry_run: + os.unlink(filename) + + def tagged_version(self): + version = self.distribution.get_version() + # egg_info may be called more than once for a distribution, + # in which case the version string already contains all tags. + if self.vtags and version.endswith(self.vtags): + return safe_version(version) + return safe_version(version + self.vtags) + + def run(self): + 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)) + + # 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") + if os.path.exists(nl): + self.delete_file(nl) + + self.find_sources() + + 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() + if self.tag_date: + import time; version += time.strftime("-%Y%m%d") + return version + + + + + + + + + + + + + + + + + + def get_svn_revision(self): + revision = 0 + urlre = re.compile('url="([^"]+)"') + revre = re.compile('committed-rev="(\d+)"') + + for base,dirs,files in os.walk(os.curdir): + if '.svn' not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove('.svn') + f = open(os.path.join(base,'.svn','entries')) + data = f.read() + f.close() + + if data.startswith('10') or data.startswith('9') or data.startswith('8'): + data = map(str.splitlines,data.split('\n\x0c\n')) + del data[0][0] # get rid of the '8' or '9' or '10' + dirurl = data[0][3] + localrev = max([int(d[9]) for d in data if len(d)>9 and d[9]]+[0]) + elif data.startswith('<?xml'): + dirurl = urlre.search(data).group(1) # get repository URL + localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0]) + else: + log.warn("unrecognized .svn/entries format; skipping %s", base) + dirs[:] = [] + continue + if base==os.curdir: + base_url = dirurl+'/' # save the root url + elif not dirurl.startswith(base_url): + dirs[:] = [] + continue # not part of the same svn tree, skip it + revision = max(revision, localrev) + + return str(revision or get_pkg_info_revision()) + + + + + + + + def find_sources(self): + """Generate SOURCES.txt manifest file""" + 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' + if self.egg_base != os.curdir: + bei = os.path.join(self.egg_base, bei) + if os.path.exists(bei): + log.warn( + "-"*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, + bei, self.egg_info + ) + self.broken_egg_info = self.egg_info + 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 + 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) + + + + + + + + +class manifest_maker(sdist): + + template = "MANIFEST.in" + + def initialize_options (self): + self.use_defaults = 1 + self.prune = 1 + self.manifest_only = 1 + self.force_manifest = 1 + + def finalize_options(self): + pass + + 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.filelist.findall() + self.add_defaults() + if os.path.exists(self.template): + self.read_template() + self.prune_file_list() + self.filelist.sort() + self.filelist.remove_duplicates() + self.write_manifest() + + 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 + 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) + + def warn(self, msg): # suppress missing-file warnings from sdist + if not msg.startswith("standard file not found:"): + sdist.warn(self, msg) + + def add_defaults(self): + sdist.add_defaults(self) + self.filelist.append(self.template) + self.filelist.append(self.manifest) + rcfiles = list(walk_revctrl()) + if rcfiles: + self.filelist.extend(rcfiles) + elif os.path.exists(self.manifest): + self.read_manifest() + ei_cmd = self.get_finalized_command('egg_info') + self.filelist.include_pattern("*", prefix=ei_cmd.egg_info) + + 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) + + +def write_file (filename, contents): + """Create a file with the specified name and write 'contents' (a + 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() + + + + + + + + + + + + + +def write_pkg_info(cmd, basename, filename): + log.info("writing %s", filename) + if not cmd.dry_run: + metadata = cmd.distribution.metadata + metadata.version, oldver = cmd.egg_version, metadata.version + metadata.name, oldname = cmd.egg_name, metadata.name + try: + # write unescaped data to PKG-INFO, so older pkg_resources + # can still parse it + metadata.write_pkg_info(cmd.egg_info) + finally: + metadata.name, metadata.version = oldname, oldver + + safe = getattr(cmd.distribution,'zip_safe',None) + import bdist_egg; bdist_egg.write_safety_flag(cmd.egg_info, safe) + +def warn_depends_obsolete(cmd, basename, filename): + if os.path.exists(filename): + log.warn( + "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" + "Use the install_requires/extras_require setup() args instead." + ) + + +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)) + +def write_toplevel_names(cmd, basename, filename): + pkgs = dict.fromkeys( + [k.split('.',1)[0] + for k in cmd.distribution.iter_distribution_names() + ] + ) + cmd.write_file("top-level names", filename, '\n'.join(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' + 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: + data = ep + elif ep is not None: + data = [] + for section, contents in ep.items(): + if not isinstance(contents,basestring): + contents = EntryPoint.parse_group(section, contents) + contents = '\n'.join(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 + # + 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() + return 0 + + + +# diff --git a/vendor/distribute-0.6.35/setuptools/command/install.py b/vendor/distribute-0.6.35/setuptools/command/install.py new file mode 100644 index 00000000..247c4f25 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/install.py @@ -0,0 +1,124 @@ +import setuptools, sys, glob +from distutils.command.install import install as _install +from distutils.errors import DistutilsArgError + +class install(_install): + """Use easy_install to install the package, w/dependencies""" + + user_options = _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"), + ] + boolean_options = _install.boolean_options + [ + 'old-and-unmanageable', 'single-version-externally-managed', + ] + new_commands = [ + ('install_egg_info', lambda self: True), + ('install_scripts', lambda self: True), + ] + _nc = dict(new_commands) + + def initialize_options(self): + _install.initialize_options(self) + self.old_and_unmanageable = None + self.single_version_externally_managed = None + self.no_compile = None # make DISTUTILS_DEBUG work right! + + def finalize_options(self): + _install.finalize_options(self) + if self.root: + self.single_version_externally_managed = True + elif self.single_version_externally_managed: + if not self.root and not self.record: + raise DistutilsArgError( + "You must specify --record or --root when building system" + " packages" + ) + + 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) + + # Ignore extra_path when installing an egg (or being run by another + # command without --root or --single-version-externally-managed + self.path_file = None + self.extra_dirs = '' + + + 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) + + # 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) + else: + self.do_egg_install() + + + + + + + def do_egg_install(self): + + easy_install = self.distribution.get_command_class('easy_install') + + cmd = easy_install( + self.distribution, args="x", root=self.root, record=self.record, + ) + cmd.ensure_finalized() # finalize before bdist_egg munges install cmd + cmd.always_copy_from = '.' # make sure local-dir eggs get installed + + # pick up setup-dir .egg files only: no .egg-info + cmd.package_index.scan(glob.glob('*.egg')) + + self.run_command('bdist_egg') + args = [self.distribution.get_command_obj('bdist_egg').egg_output] + + if setuptools.bootstrap_install_from: + # Bootstrap self-installation of setuptools + args.insert(0, setuptools.bootstrap_install_from) + + cmd.args = args + 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 + + + + + + + + + + + + + + + + +# diff --git a/vendor/distribute-0.6.35/setuptools/command/install_egg_info.py b/vendor/distribute-0.6.35/setuptools/command/install_egg_info.py new file mode 100644 index 00000000..f44b34b5 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/install_egg_info.py @@ -0,0 +1,125 @@ +from setuptools import Command +from setuptools.archive_util import unpack_archive +from distutils import log, dir_util +import os, shutil, pkg_resources + +class install_egg_info(Command): + """Install an .egg-info directory for the package""" + + description = "Install an .egg-info directory for the package" + + user_options = [ + ('install-dir=', 'd', "directory to install to"), + ] + + def initialize_options(self): + self.install_dir = None + + def finalize_options(self): + 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' + self.source = ei_cmd.egg_info + self.target = os.path.join(self.install_dir, basename) + self.outputs = [self.target] + + 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) + if not self.dry_run: + pkg_resources.ensure_directory(self.target) + self.execute(self.copytree, (), + "Copying %s to %s" % (self.source, self.target) + ) + self.install_namespaces() + + def get_outputs(self): + return self.outputs + + def copytree(self): + # Copy the .egg-info tree to site-packages + 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: + return None + self.outputs.append(dst) + log.debug("Copying %s to %s", src, dst) + return dst + 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() + + def _get_all_ns_packages(self): + nsp = {} + for pkg in self.distribution.namespace_packages or []: + pkg = pkg.split('.') + while pkg: + nsp['.'.join(pkg)] = 1 + pkg.pop() + nsp=list(nsp) + nsp.sort() # set up shorter names first + return nsp + + diff --git a/vendor/distribute-0.6.35/setuptools/command/install_lib.py b/vendor/distribute-0.6.35/setuptools/command/install_lib.py new file mode 100644 index 00000000..82afa142 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/install_lib.py @@ -0,0 +1,82 @@ +from distutils.command.install_lib import install_lib as _install_lib +import os + +class install_lib(_install_lib): + """Don't add compiled flags to filenames of non-Python files""" + + def _bytecode_filenames (self, py_filenames): + bytecode_files = [] + for py_file in py_filenames: + if not py_file.endswith('.py'): + continue + if self.compile: + bytecode_files.append(py_file + "c") + if self.optimize > 0: + bytecode_files.append(py_file + "o") + + return bytecode_files + + def run(self): + self.build() + outfiles = self.install() + if outfiles is not None: + # always compile, in case we have any extension stubs to deal with + self.byte_compile(outfiles) + + def get_exclusions(self): + exclude = {} + nsp = self.distribution.namespace_packages + + if (nsp and self.get_finalized_command('install') + .single_version_externally_managed + ): + 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 + + def copy_tree( + 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) + + # Exclude namespace package __init__.py* files from the output + + from setuptools.archive_util import unpack_directory + from distutils import log + + outfiles = [] + + def pf(src, dst): + if dst in exclude: + log.warn("Skipping installation of %s (namespace package)",dst) + return False + + log.info("copying %s -> %s", src, os.path.dirname(dst)) + outfiles.append(dst) + return dst + + unpack_directory(infile, outfile, pf) + return outfiles + + def get_outputs(self): + outputs = _install_lib.get_outputs(self) + exclude = self.get_exclusions() + if exclude: + return [f for f in outputs if f not in exclude] + return outputs + + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/install_scripts.py b/vendor/distribute-0.6.35/setuptools/command/install_scripts.py new file mode 100644 index 00000000..82456035 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/install_scripts.py @@ -0,0 +1,54 @@ +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 + +class install_scripts(_install_scripts): + """Do normal script install, plus any egg_info wrapper scripts""" + + def initialize_options(self): + _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 + + self.run_command("egg_info") + if self.distribution.scripts: + _install_scripts.run(self) # run first to set up self.outfiles + else: + self.outfiles = [] + if self.no_ep: + # don't install entry point scripts into .egg file! + return + + ei_cmd = self.get_finalized_command("egg_info") + dist = Distribution( + ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), + 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): + 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) + + mask = current_umask() + if not self.dry_run: + ensure_directory(target) + f = open(target,"w"+mode) + f.write(contents) + f.close() + chmod(target, 0777-mask) + diff --git a/vendor/distribute-0.6.35/setuptools/command/register.py b/vendor/distribute-0.6.35/setuptools/command/register.py new file mode 100644 index 00000000..3b2e0859 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/register.py @@ -0,0 +1,10 @@ +from distutils.command.register import register as _register + +class register(_register): + __doc__ = _register.__doc__ + + def run(self): + # Make sure that we are using valid current name/version info + self.run_command('egg_info') + _register.run(self) + diff --git a/vendor/distribute-0.6.35/setuptools/command/rotate.py b/vendor/distribute-0.6.35/setuptools/command/rotate.py new file mode 100644 index 00000000..11b6eae8 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/rotate.py @@ -0,0 +1,82 @@ +import distutils, os +from setuptools import Command +from distutils.util import convert_path +from distutils import log +from distutils.errors import * + +class rotate(Command): + """Delete older distributions""" + + description = "delete older distributions, keeping N newest files" + user_options = [ + ('match=', 'm', "patterns to match (required)"), + ('dist-dir=', 'd', "directory where the distributions are"), + ('keep=', 'k', "number of matching distributions to keep"), + ] + + boolean_options = [] + + def initialize_options(self): + self.match = None + self.dist_dir = None + self.keep = None + + def finalize_options(self): + if self.match is None: + raise DistutilsOptionError( + "Must specify one or more (comma-separated) match patterns " + "(e.g. '.zip' or '.egg')" + ) + if self.keep is None: + raise DistutilsOptionError("Must specify number of files to keep") + try: + self.keep = int(self.keep) + except ValueError: + raise DistutilsOptionError("--keep must be an integer") + if isinstance(self.match, basestring): + self.match = [ + convert_path(p.strip()) for p in self.match.split(',') + ] + 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] + files.sort() + files.reverse() + + log.info("%d file(s) matching %s", len(files), pattern) + files = files[self.keep:] + for (t,f) in files: + log.info("Deleting %s", f) + if not self.dry_run: + os.unlink(f) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/saveopts.py b/vendor/distribute-0.6.35/setuptools/command/saveopts.py new file mode 100644 index 00000000..1180a440 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/saveopts.py @@ -0,0 +1,25 @@ +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""" + + description = "save supplied options to setup.cfg or other config file" + + def run(self): + dist = self.distribution + commands = dist.command_options.keys() + settings = {} + + for cmd in commands: + + 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 + + edit_config(self.filename, settings, self.dry_run) + diff --git a/vendor/distribute-0.6.35/setuptools/command/sdist.py b/vendor/distribute-0.6.35/setuptools/command/sdist.py new file mode 100644 index 00000000..2fa3771a --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/sdist.py @@ -0,0 +1,313 @@ +from distutils.command.sdist import sdist as _sdist +from distutils.util import convert_path +from distutils import log +import os, re, sys, pkg_resources +from glob import glob + +READMES = ('README', 'README.rst', 'README.txt') + +entities = [ + ("<","<"), (">", ">"), (""", '"'), ("'", "'"), + ("&", "&") +] + +def unescape(data): + for old,new in entities: + data = data.replace(old,new) + return data + +def re_finder(pattern, postproc=None): + def find(dirname, filename): + f = open(filename,'rU') + data = f.read() + f.close() + for match in pattern.finditer(data): + path = match.group(1) + if postproc: + path = postproc(path) + yield joinpath(dirname,path) + return find + +def joinpath(prefix,suffix): + if not prefix: + return suffix + return os.path.join(prefix,suffix) + + + + + + + + + + +def walk_revctrl(dirname=''): + """Find all files under revision control""" + for ep in pkg_resources.iter_entry_points('setuptools.file_finders'): + for item in ep.load()(dirname): + yield item + +def _default_revctrl(dirname=''): + for path, finder in finders: + path = joinpath(dirname,path) + if os.path.isfile(path): + for path in finder(dirname,path): + if os.path.isfile(path): + yield path + elif os.path.isdir(path): + for item in _default_revctrl(path): + yield item + +def externals_finder(dirname, filename): + """Find any 'svn:externals' directories""" + found = False + f = open(filename,'rt') + 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=='svn:externals': + found = True + elif kind=='V' and found: + f.close() + break + else: + f.close() + return + + for line in data.splitlines(): + parts = line.split() + if parts: + yield joinpath(dirname, parts[0]) + + +entries_pattern = re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I) + +def entries_finder(dirname, filename): + f = open(filename,'rU') + data = f.read() + f.close() + if data.startswith('10') or data.startswith('9') or data.startswith('8'): + for record in map(str.splitlines, data.split('\n\x0c\n')[1:]): + # subversion 1.6/1.5/1.4 + if not record or len(record)>=6 and record[5]=="delete": + continue # skip deleted + yield joinpath(dirname, record[0]) + elif data.startswith('<?xml'): + for match in entries_pattern.finditer(data): + yield joinpath(dirname,unescape(match.group(1))) + else: + log.warn("unrecognized .svn/entries format in %s", os.path.abspath(dirname)) + + +finders = [ + (convert_path('CVS/Entries'), + re_finder(re.compile(r"^\w?/([^/]+)/", re.M))), + (convert_path('.svn/entries'), entries_finder), + (convert_path('.svn/dir-props'), externals_finder), + (convert_path('.svn/dir-prop-base'), externals_finder), # svn 1.4 +] + + + + + + + + + + + + + + + + +class sdist(_sdist): + """Smart sdist that finds anything supported by revision control""" + + user_options = [ + ('formats=', None, + "formats for source distribution (comma-separated list)"), + ('keep-temp', 'k', + "keep the distribution tree around after creating " + + "archive file(s)"), + ('dist-dir=', 'd', + "directory to put the source distribution archive(s) in " + "[default: dist]"), + ] + + negative_opt = {} + + def run(self): + 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.check_readme() + + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + # 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',[]) + for file in self.archive_files: + data = ('sdist', '', file) + if data not in dist_files: + dist_files.append(data) + + def add_defaults(self): + standards = [READMES, + self.distribution.script_name] + for fn in standards: + if isinstance(fn, tuple): + alts = fn + got_it = 0 + for fn in alts: + if os.path.exists(fn): + got_it = 1 + self.filelist.append(fn) + break + + if not got_it: + self.warn("standard file not found: should have one of " + + ', '.join(alts)) + else: + if os.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 = filter(os.path.isfile, glob(pattern)) + if files: + self.filelist.extend(files) + + # getting python files + if self.distribution.has_pure_modules(): + build_py = self.get_finalized_command('build_py') + self.filelist.extend(build_py.get_source_files()) + # This functionality is incompatible with include_package_data, and + # will in fact create an infinite recursion if include_package_data + # is True. Use of include_package_data will imply that + # distutils-style automatic handling of package_data is disabled + if not self.distribution.include_package_data: + for _, src_dir, _, filenames in build_py.data_files: + self.filelist.extend([os.path.join(src_dir, filename) + for filename in filenames]) + + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + self.filelist.extend(build_ext.get_source_files()) + + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.filelist.extend(build_clib.get_source_files()) + + if self.distribution.has_scripts(): + build_scripts = self.get_finalized_command('build_scripts') + self.filelist.extend(build_scripts.get_source_files()) + + def __read_template_hack(self): + # This grody hack closes the template file (MANIFEST.in) if an + # exception occurs during read_template. + # Doing so prevents an error when easy_install attempts to delete the + # file. + try: + _sdist.read_template(self) + except: + sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close() + raise + # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle + # has been fixed, so only override the method if we're using an earlier + # Python. + if ( + sys.version_info < (2,7,2) + or (3,0) <= sys.version_info < (3,1,4) + or (3,2) <= sys.version_info < (3,2,1) + ): + read_template = __read_template_hack + + def check_readme(self): + for f in READMES: + if os.path.exists(f): + return + else: + self.warn( + "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) + + # 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): + # unlink and re-copy, since it might be hard-linked, and + # we don't want to change the source version + os.unlink(dest) + self.copy_file('setup.cfg', dest) + + self.get_finalized_command('egg_info').save_version_info(dest) + + def _manifest_is_not_generated(self): + # check for special comment used in 2.7.1 and higher + if not os.path.isfile(self.manifest): + return False + + fp = open(self.manifest, 'rbU') + try: + first_line = fp.readline() + finally: + fp.close() + 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 + fill in 'self.filelist', the list of files to include in the source + distribution. + """ + log.info("reading manifest file '%s'", self.manifest) + manifest = open(self.manifest, 'rbU') + for line in manifest: + # The manifest must contain UTF-8. See #303. + if sys.version_info >= (3,): + try: + line = line.decode('UTF-8') + except UnicodeDecodeError: + log.warn("%r not UTF-8 decodable -- skipping" % line) + continue + # ignore comments and blank lines + line = line.strip() + if line.startswith('#') or not line: + continue + self.filelist.append(line) + manifest.close() + + + + + + + + + + + + + + + +# diff --git a/vendor/distribute-0.6.35/setuptools/command/setopt.py b/vendor/distribute-0.6.35/setuptools/command/setopt.py new file mode 100644 index 00000000..dbf3a94e --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/setopt.py @@ -0,0 +1,164 @@ +import distutils, os +from setuptools import Command +from distutils.util import convert_path +from distutils import log +from distutils.errors import * + +__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] + + +def config_file(kind="local"): + """Get the filename of the distutils, local, global, or per-user config + + `kind` must be one of "local", "global", or "user" + """ + if kind=='local': + return 'setup.cfg' + if kind=='global': + return os.path.join( + os.path.dirname(distutils.__file__),'distutils.cfg' + ) + 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` + + `settings` is a dictionary of dictionaries or ``None`` values, keyed by + command/section name. A ``None`` value means to delete the entire section, + while a dictionary lists settings to be changed or deleted in that section. + A setting of ``None`` means to delete that setting. + """ + from ConfigParser import RawConfigParser + log.debug("Reading configuration from %s", filename) + opts = RawConfigParser() + opts.read([filename]) + for section, options in settings.items(): + if options is None: + log.info("Deleting section [%s] from %s", section, filename) + opts.remove_section(section) + else: + 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(): + if value is None: + log.debug("Deleting %s.%s from %s", + section, option, filename + ) + opts.remove_option(section,option) + if not opts.options(section): + log.info("Deleting empty [%s] section from %s", + 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) + + log.info("Writing %s", filename) + if not dry_run: + f = open(filename,'w'); opts.write(f); f.close() + +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"), + ('user-config', 'u', + "save options to the current user's pydistutils.cfg file"), + ('filename=', 'f', + "configuration file to use (default=setup.cfg)"), + ] + + boolean_options = [ + 'global-config', 'user-config', + ] + + def initialize_options(self): + self.global_config = None + self.user_config = None + self.filename = None + + def finalize_options(self): + filenames = [] + if self.global_config: + filenames.append(config_file('global')) + if self.user_config: + filenames.append(config_file('user')) + if self.filename is not None: + filenames.append(self.filename) + if not filenames: + filenames.append(config_file('local')) + if len(filenames)>1: + raise DistutilsOptionError( + "Must specify only one configuration file option", + filenames + ) + self.filename, = filenames + + + + +class setopt(option_base): + """Save command-line options to a file""" + + description = "set an option in setup.cfg or another config file" + + 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_base.user_options + + boolean_options = option_base.boolean_options + ['remove'] + + def initialize_options(self): + option_base.initialize_options(self) + self.command = None + self.option = None + self.set_value = None + self.remove = None + + def finalize_options(self): + option_base.finalize_options(self) + if self.command is None or self.option is None: + raise DistutilsOptionError("Must specify --command *and* --option") + if self.set_value is None and not self.remove: + raise DistutilsOptionError("Must specify --set-value or --remove") + + def run(self): + edit_config( + self.filename, { + self.command: {self.option.replace('-','_'):self.set_value} + }, + self.dry_run + ) + + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/test.py b/vendor/distribute-0.6.35/setuptools/command/test.py new file mode 100644 index 00000000..a02ac142 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/test.py @@ -0,0 +1,198 @@ +from setuptools import Command +from distutils.errors import DistutilsOptionError +import sys +from pkg_resources import * +from pkg_resources import _namespace_packages +from unittest import TestLoader, main + +class ScanningLoader(TestLoader): + + def loadTestsFromModule(self, module): + """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. + If the module has an ``additional_tests`` function, call it and add + the return value to the tests. + """ + tests = [] + if module.__name__!='setuptools.tests.doctest': # ugh + 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] + else: + if resource_exists( + module.__name__, file+'/__init__.py' + ): + submodule = module.__name__+'.'+file + else: + continue + tests.append(self.loadTestsFromName(submodule)) + + if len(tests)!=1: + return self.suiteClass(tests) + else: + return tests[0] # don't create a nested suite for only one return + + +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')"), + ] + + def initialize_options(self): + self.test_suite = None + self.test_module = None + self.test_loader = None + + + def finalize_options(self): + + 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] + + if self.verbose: + self.test_args.insert(0,'--verbose') + if self.test_loader is None: + self.test_loader = getattr(self.distribution,'test_loader',None) + if self.test_loader is None: + self.test_loader = "setuptools.command.test:ScanningLoader" + + + + def with_project_on_sys_path(self, func): + if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False): + # If we run 2to3 we can not do this inplace: + + # Ensure metadata is up-to-date + self.reinitialize_command('build_py', inplace=0) + self.run_command('build_py') + bpy_cmd = self.get_finalized_command("build_py") + build_path = normalize_path(bpy_cmd.build_lib) + + # Build extensions + self.reinitialize_command('egg_info', egg_base=build_path) + self.run_command('egg_info') + + self.reinitialize_command('build_ext', inplace=0) + self.run_command('build_ext') + else: + # Without 2to3 inplace works fine: + self.run_command('egg_info') + + # Build extensions in-place + self.reinitialize_command('build_ext', inplace=1) + self.run_command('build_ext') + + ei_cmd = self.get_finalized_command("egg_info") + + old_path = sys.path[:] + old_modules = sys.modules.copy() + + try: + sys.path.insert(0, normalize_path(ei_cmd.egg_base)) + working_set.__init__() + add_activation_listener(lambda dist: dist.activate()) + require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) + func() + finally: + sys.path[:] = old_path + sys.modules.clear() + sys.modules.update(old_modules) + working_set.__init__() + + + def run(self): + if 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) + + + 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 module in _namespace_packages: + del_modules = [] + if module in sys.modules: + del_modules.append(module) + module += '.' + for name in sys.modules: + if name.startswith(module): + del_modules.append(name) + 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 + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/distribute-0.6.35/setuptools/command/upload.py b/vendor/distribute-0.6.35/setuptools/command/upload.py new file mode 100644 index 00000000..21b9615c --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/upload.py @@ -0,0 +1,185 @@ +"""distutils.command.upload + +Implements the Distutils 'upload' subcommand (upload package to PyPI).""" + +from distutils.errors import * +from distutils.core import Command +from distutils.spawn import spawn +from distutils import log +try: + from hashlib import md5 +except ImportError: + from md5 import md5 +import os +import socket +import platform +import ConfigParser +import httplib +import base64 +import urlparse +import cStringIO as StringIO + +class upload(Command): + + description = "upload binary package to PyPI" + + DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server'), + ('sign', 's', + 'sign files to upload using gpg'), + ('identity=', 'i', 'GPG identity used to sign files'), + ] + boolean_options = ['show-response', 'sign'] + + def initialize_options(self): + self.username = '' + self.password = '' + self.repository = '' + self.show_response = 0 + self.sign = False + self.identity = None + + def finalize_options(self): + if self.identity and not self.sign: + raise DistutilsOptionError( + "Must use --sign for --identity to have meaning" + ) + if os.environ.has_key('HOME'): + rc = os.path.join(os.environ['HOME'], '.pypirc') + if os.path.exists(rc): + self.announce('Using PyPI login from %s' % rc) + config = ConfigParser.ConfigParser({ + 'username':'', + 'password':'', + 'repository':''}) + config.read(rc) + if not self.repository: + self.repository = config.get('server-login', 'repository') + if not self.username: + self.username = config.get('server-login', 'username') + if not self.password: + self.password = config.get('server-login', 'password') + if not self.repository: + self.repository = self.DEFAULT_REPOSITORY + + def run(self): + if not self.distribution.dist_files: + raise DistutilsOptionError("No dist file created in earlier command") + for command, pyversion, filename in self.distribution.dist_files: + self.upload_file(command, pyversion, filename) + + def upload_file(self, command, pyversion, filename): + # Sign if requested + if self.sign: + gpg_args = ["gpg", "--detach-sign", "-a", filename] + if self.identity: + gpg_args[2:2] = ["--local-user", self.identity] + spawn(gpg_args, + dry_run=self.dry_run) + + # Fill in the data + f = open(filename,'rb') + content = f.read() + f.close() + basename = os.path.basename(filename) + comment = '' + if command=='bdist_egg' and self.distribution.has_ext_modules(): + comment = "built on %s" % platform.platform(terse=1) + data = { + ':action':'file_upload', + 'protocol_version':'1', + 'name':self.distribution.get_name(), + 'version':self.distribution.get_version(), + 'content':(basename,content), + 'filetype':command, + 'pyversion':pyversion, + 'md5_digest':md5(content).hexdigest(), + } + if command == 'bdist_rpm': + dist, version, id = platform.dist() + if dist: + comment = 'built for %s %s' % (dist, version) + elif command == 'bdist_dumb': + comment = 'built for %s' % platform.platform(terse=1) + data['comment'] = comment + + if self.sign: + asc_file = open(filename + ".asc") + data['gpg_signature'] = (os.path.basename(filename) + ".asc", asc_file.read()) + asc_file.close() + + # set up the authentication + auth = "Basic " + base64.encodestring(self.username + ":" + self.password).strip() + + # Build up the MIME payload for the POST data + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = '\n--' + boundary + end_boundary = sep_boundary + '--' + body = StringIO.StringIO() + for key, value in data.items(): + # handle multiple entries for the same name + if type(value) != type([]): + value = [value] + for value in value: + if type(value) is tuple: + fn = ';filename="%s"' % value[0] + value = value[1] + else: + fn = "" + value = str(value) + body.write(sep_boundary) + body.write('\nContent-Disposition: form-data; name="%s"'%key) + body.write(fn) + body.write("\n\n") + body.write(value) + if value and value[-1] == '\r': + body.write('\n') # write an extra newline (lurve Macs) + body.write(end_boundary) + body.write("\n") + body = body.getvalue() + + self.announce("Submitting %s to %s" % (filename, self.repository), log.INFO) + + # build the Request + # 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.urlparse(self.repository) + assert not params and not query and not fragments + if schema == 'http': + http = httplib.HTTPConnection(netloc) + elif schema == 'https': + http = httplib.HTTPSConnection(netloc) + else: + raise AssertionError, "unsupported schema "+schema + + data = '' + loglevel = log.INFO + try: + http.connect() + http.putrequest("POST", url) + http.putheader('Content-type', + 'multipart/form-data; boundary=%s'%boundary) + http.putheader('Content-length', str(len(body))) + http.putheader('Authorization', auth) + http.endheaders() + http.send(body) + except socket.error, e: + self.announce(str(e), log.ERROR) + return + + r = http.getresponse() + if r.status == 200: + self.announce('Server response (%s): %s' % (r.status, r.reason), + log.INFO) + else: + self.announce('Upload failed (%s): %s' % (r.status, r.reason), + log.ERROR) + if self.show_response: + print '-'*75, r.read(), '-'*75 + diff --git a/vendor/distribute-0.6.35/setuptools/command/upload_docs.py b/vendor/distribute-0.6.35/setuptools/command/upload_docs.py new file mode 100644 index 00000000..1d5a7445 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/command/upload_docs.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +"""upload_docs + +Implements a Distutils 'upload_docs' subcommand (upload documentation to +PyPI's packages.python.org). +""" + +import os +import socket +import zipfile +import httplib +import urlparse +import tempfile +import sys +import shutil + +from base64 import standard_b64encode +from pkg_resources import iter_entry_points + +from distutils import log +from distutils.errors import DistutilsOptionError + +try: + from distutils.command.upload import upload +except ImportError: + from setuptools.command.upload import upload + + +# 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): + return s.encode(encoding) + return s + + +class upload_docs(upload): + + description = 'Upload documentation to PyPI' + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server'), + ('upload-dir=', None, 'directory to upload'), + ] + boolean_options = upload.boolean_options + + def has_sphinx(self): + if self.upload_dir is None: + for ep in iter_entry_points('distutils.commands', 'build_sphinx'): + return True + + sub_commands = [('build_sphinx', has_sphinx)] + + def initialize_options(self): + upload.initialize_options(self) + self.upload_dir = None + self.target_dir = None + + def finalize_options(self): + upload.finalize_options(self) + if self.upload_dir is None: + if self.has_sphinx(): + build_sphinx = self.get_finalized_command('build_sphinx') + self.target_dir = build_sphinx.builder_target_dir + else: + build = self.get_finalized_command('build') + self.target_dir = os.path.join(build.build_base, 'docs') + else: + self.ensure_dirname('upload_dir') + self.target_dir = self.upload_dir + self.announce('Using upload directory %s' % self.target_dir) + + def create_zipfile(self, filename): + zip_file = zipfile.ZipFile(filename, "w") + try: + self.mkpath(self.target_dir) # just in case + for root, dirs, files in os.walk(self.target_dir): + if root == self.target_dir and not files: + raise DistutilsOptionError( + "no files found in upload directory '%s'" + % self.target_dir) + for name in files: + full = os.path.join(root, name) + relative = root[len(self.target_dir):].lstrip(os.path.sep) + dest = os.path.join(relative, name) + zip_file.write(full, dest) + finally: + zip_file.close() + + def run(self): + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + tmp_dir = tempfile.mkdtemp() + name = self.distribution.metadata.get_name() + zip_file = os.path.join(tmp_dir, "%s.zip" % name) + try: + self.create_zipfile(zip_file) + self.upload_file(zip_file) + finally: + shutil.rmtree(tmp_dir) + + def upload_file(self, filename): + f = open(filename, 'rb') + content = f.read() + f.close() + meta = self.distribution.metadata + data = { + ':action': 'doc_upload', + 'name': meta.get_name(), + 'content': (os.path.basename(filename), content), + } + # set up the authentication + credentials = b(self.username + ':' + self.password) + credentials = standard_b64encode(credentials) + if sys.version_info >= (3,): + credentials = credentials.decode('ascii') + auth = "Basic " + credentials + + # Build up the MIME payload for the POST data + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = b('\n--') + b(boundary) + end_boundary = sep_boundary + b('--') + body = [] + for key, values in data.iteritems(): + title = '\nContent-Disposition: form-data; name="%s"' % key + # handle multiple entries for the same name + if type(values) != type([]): + values = [values] + for value in values: + if type(value) is tuple: + title += '; filename="%s"' % value[0] + value = value[1] + else: + value = b(value) + body.append(sep_boundary) + body.append(b(title)) + body.append(b("\n\n")) + body.append(value) + if value and value[-1:] == b('\r'): + body.append(b('\n')) # write an extra newline (lurve Macs) + body.append(end_boundary) + body.append(b("\n")) + body = b('').join(body) + + self.announce("Submitting documentation to %s" % (self.repository), + log.INFO) + + # build the Request + # 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.urlparse(self.repository) + assert not params and not query and not fragments + if schema == 'http': + conn = httplib.HTTPConnection(netloc) + elif schema == 'https': + conn = httplib.HTTPSConnection(netloc) + else: + raise AssertionError("unsupported schema "+schema) + + data = '' + loglevel = log.INFO + try: + conn.connect() + conn.putrequest("POST", url) + conn.putheader('Content-type', + 'multipart/form-data; boundary=%s'%boundary) + conn.putheader('Content-length', str(len(body))) + conn.putheader('Authorization', auth) + conn.endheaders() + conn.send(body) + except socket.error, e: + self.announce(str(e), log.ERROR) + return + + r = conn.getresponse() + if r.status == 200: + self.announce('Server response (%s): %s' % (r.status, r.reason), + log.INFO) + elif r.status == 301: + location = r.getheader('Location') + if location is None: + location = 'http://packages.python.org/%s/' % meta.get_name() + self.announce('Upload successful. Visit %s' % location, + log.INFO) + else: + self.announce('Upload failed (%s): %s' % (r.status, r.reason), + log.ERROR) + if self.show_response: + print '-'*75, r.read(), '-'*75 diff --git a/vendor/distribute-0.6.35/setuptools/depends.py b/vendor/distribute-0.6.35/setuptools/depends.py new file mode 100644 index 00000000..4b7b3437 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/depends.py @@ -0,0 +1,246 @@ +from __future__ import generators +import sys, imp, marshal +from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN +from distutils.version import StrictVersion, LooseVersion + +__all__ = [ + 'Require', 'find_module', 'get_module_constant', 'extract_constant' +] + +class Require: + """A prerequisite to building or installing a distribution""" + + def __init__(self,name,requested_version,module,homepage='', + attribute=None,format=None + ): + + if format is None and requested_version is not None: + format = StrictVersion + + if format is not None: + requested_version = format(requested_version) + if attribute is None: + attribute = '__version__' + + 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): + """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' + + Search 'paths' for module. If not found, return 'None'. If found, + return the extracted version attribute, or 'default' if no version + attribute was specified, or the value cannot be determined without + importing the module. The version is formatted according to the + requirement's version format (if any), unless it is 'None' or the + supplied 'default'. + """ + + if self.attribute is None: + try: + f,p,i = find_module(self.module,paths) + if f: f.close() + return default + except ImportError: + return None + + 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): + """Return true if dependency is present on 'paths'""" + return self.get_version(paths) is not 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: + return False + return self.version_ok(version) + + +def _iter_code(code): + + """Yield '(op,arg)' pair for each operation in code object 'code'""" + + from array import array + from dis import HAVE_ARGUMENT, EXTENDED_ARG + + bytes = array('b',code.co_code) + eof = len(code.co_code) + + ptr = 0 + extended_arg = 0 + + while ptr<eof: + + op = bytes[ptr] + + if op>=HAVE_ARGUMENT: + + arg = bytes[ptr+1] + bytes[ptr+2]*256 + extended_arg + ptr += 3 + + if op==EXTENDED_ARG: + extended_arg = arg * 65536L + continue + + else: + arg = None + ptr += 1 + + yield op,arg + + + + + + + + + + +def find_module(module, paths=None): + """Just like 'imp.find_module()', but with package support""" + + parts = module.split('.') + + while parts: + part = parts.pop(0) + f, path, (suffix,mode,kind) = info = imp.find_module(part, paths) + + if kind==PKG_DIRECTORY: + parts = parts or ['__init__'] + paths = [path] + + elif parts: + raise ImportError("Can't find %r in %s" % (parts,module)) + + return info + + + + + + + + + + + + + + + + + + + + + + + + +def get_module_constant(module, symbol, default=-1, paths=None): + + """Find 'module' by searching 'paths', and extract 'symbol' + + Return 'None' if 'module' does not exist on 'paths', or it does not define + 'symbol'. If the module defines 'symbol' as a constant, return the + constant. Otherwise, return 'default'.""" + + try: + f, path, (suffix,mode,kind) = find_module(module,paths) + except ImportError: + # Module doesn't exist + return None + + try: + if kind==PY_COMPILED: + f.read(8) # skip magic & date + code = marshal.load(f) + elif kind==PY_FROZEN: + code = imp.get_frozen_object(module) + elif kind==PY_SOURCE: + code = compile(f.read(), path, 'exec') + 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) + + finally: + if f: + f.close() + + return extract_constant(code,symbol,default) + + + + + + + + +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 + object 'code', return that value. If 'symbol' is bound to an expression, + return 'default'. Otherwise, return 'None'. + + Return value is based on the first assignment to 'symbol'. 'symbol' must + be a global, or at least a non-"fast" local in the code block. That is, + only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol' + must be present in 'code.co_names'. + """ + + if symbol not in code.co_names: + # name's not there, can't possibly be an assigment + return None + + name_idx = list(code.co_names).index(symbol) + + STORE_NAME = 90 + STORE_GLOBAL = 97 + LOAD_CONST = 100 + + const = default + + for op, arg in _iter_code(code): + + if op==LOAD_CONST: + const = code.co_consts[arg] + elif arg==name_idx and (op==STORE_NAME or op==STORE_GLOBAL): + 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') + + diff --git a/vendor/distribute-0.6.35/setuptools/dist.py b/vendor/distribute-0.6.35/setuptools/dist.py new file mode 100644 index 00000000..998a4dbe --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/dist.py @@ -0,0 +1,855 @@ +__all__ = ['Distribution'] + +import re +from distutils.core import Distribution as _Distribution +from setuptools.depends import Require +from setuptools.command.install import install +from setuptools.command.sdist import sdist +from setuptools.command.install_lib import install_lib +from distutils.errors import DistutilsOptionError, DistutilsPlatformError +from distutils.errors import DistutilsSetupError +import setuptools, pkg_resources, distutils.core, distutils.dist, distutils.cmd +import os, distutils.log + +def _get_unpatched(cls): + """Protect against re-patching the distutils if reloaded + + Also ensures that no other distutils extension monkeypatched the distutils + first. + """ + while cls.__module__.startswith('setuptools'): + cls, = cls.__bases__ + if not cls.__module__.startswith('distutils'): + raise AssertionError( + "distutils has already been patched by %r" % cls + ) + return cls + +_Distribution = _get_unpatched(_Distribution) + +sequence = tuple, list + +def check_importable(dist, attr, value): + try: + ep = pkg_resources.EntryPoint.parse('x='+value) + assert not ep.extras + except (TypeError,ValueError,AttributeError,AssertionError): + raise DistutilsSetupError( + "%r must be importable 'module:attrs' string (got %r)" + % (attr,value) + ) + + +def assert_string_list(dist, attr, value): + """Verify that value is a string list or None""" + try: + assert ''.join(value)!=value + except (TypeError,ValueError,AttributeError,AssertionError): + raise DistutilsSetupError( + "%r must be a list of strings (got %r)" % (attr,value) + ) + +def check_nsp(dist, attr, value): + """Verify that namespace packages are valid""" + assert_string_list(dist,attr,value) + for nsp in value: + if not dist.has_contents_for(nsp): + raise DistutilsSetupError( + "Distribution contains no modules or packages for " + + "namespace package %r" % nsp + ) + if '.' in nsp: + parent = '.'.join(nsp.split('.')[:-1]) + if parent not in value: + distutils.log.warn( + "%r is declared as a package namespace, but %r is not:" + " please correct this in setup.py", nsp, parent + ) + +def check_extras(dist, attr, value): + """Verify that extras_require mapping is valid""" + try: + for k,v in value.items(): + list(pkg_resources.parse_requirements(v)) + except (TypeError,ValueError,AttributeError): + raise DistutilsSetupError( + "'extras_require' must be a dictionary whose values are " + "strings or lists of strings containing valid project/version " + "requirement specifiers." + ) + + + + +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) + ) +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,) + ) +def check_entry_points(dist, attr, value): + """Verify that entry_points map is parseable""" + try: + pkg_resources.EntryPoint.parse_map(value) + except ValueError, e: + raise DistutilsSetupError(e) + +def check_test_suite(dist, attr, value): + if not isinstance(value,basestring): + raise DistutilsSetupError("test_suite must be a string") + +def check_package_data(dist, attr, value): + """Verify that value is a dictionary of package names to glob lists""" + if isinstance(value,dict): + for k,v in value.items(): + if not isinstance(k,str): break + try: iter(v) + except TypeError: + break + else: + return + raise DistutilsSetupError( + attr+" must be a dictionary mapping package names to lists of " + "wildcard patterns" + ) + +class Distribution(_Distribution): + """Distribution with support for features, tests, and package data + + This is an enhanced version of 'distutils.dist.Distribution' that + effectively adds the following new optional keyword arguments to 'setup()': + + 'install_requires' -- a string or sequence of strings specifying project + versions that the distribution requires when installed, in the format + used by 'pkg_resources.require()'. They will be installed + automatically when the package is installed. If you wish to use + packages that are not available in PyPI, or want to give your users an + alternate download location, you can add a 'find_links' option to the + '[easy_install]' section of your project's 'setup.cfg' file, and then + setuptools will scan the listed web pages for links that satisfy the + requirements. + + 'extras_require' -- a dictionary mapping names of optional "extras" to the + additional requirement(s) that using those extras incurs. For example, + this:: + + extras_require = dict(reST = ["docutils>=0.3", "reSTedit"]) + + indicates that the distribution can optionally provide an extra + capability called "reST", but it can only be used if docutils and + reSTedit are installed. If the user installs your package using + EasyInstall and requests one of your extras, the corresponding + additional requirements will be installed if needed. + + 'features' -- a dictionary mapping option names to 'setuptools.Feature' + objects. Features are a portion of the distribution that can be + included or excluded based on user options, inter-feature dependencies, + and availability on the current system. Excluded features are omitted + from all setup commands, including source and binary distributions, so + you can create multiple distributions from the same source tree. + Feature names should be valid Python identifiers, except that they may + contain the '-' (minus) sign. Features can be included or excluded + via the command line options '--with-X' and '--without-X', where 'X' is + the name of the feature. Whether a feature is included by default, and + whether you are allowed to control this from the command line, is + determined by the Feature object. See the 'Feature' class for more + information. + + 'test_suite' -- the name of a test suite to run for the 'test' command. + If the user runs 'python setup.py test', the package will be installed, + and the named test suite will be run. The format is the same as + would be used on a 'unittest.py' command line. That is, it is the + dotted name of an object to import and call to generate a test suite. + + 'package_data' -- a dictionary mapping package names to lists of filenames + or globs to use to find data files contained in the named packages. + If the dictionary has filenames or globs listed under '""' (the empty + string), those names will be searched for in every package, in addition + to any names for the specific package. Data files found using these + names/globs will be installed along with the package, in the same + location as the package. Note that globs are allowed to reference + the contents of non-package subdirectories, as long as you use '/' as + a path separator. (Globs are automatically converted to + platform-specific paths at runtime.) + + In addition to these new keywords, this class also has several new methods + for manipulating the distribution's contents. For example, the 'include()' + and 'exclude()' methods can be thought of as in-place add and subtract + commands that add or remove packages, modules, extensions, and so on from + the distribution. They are used by the feature subsystem to configure the + distribution for the included and excluded features. + """ + + _patched_dist = None + + def patch_missing_pkg_info(self, attrs): + # Fake up a replacement for the data that would normally come from + # PKG-INFO, but which might not yet be built if this is a fresh + # checkout. + # + if not attrs or 'name' not in attrs or 'version' not in attrs: + return + key = pkg_resources.safe_name(str(attrs['name'])).lower() + dist = pkg_resources.working_set.by_key.get(key) + if dist is not None and not dist.has_metadata('PKG-INFO'): + dist._version = pkg_resources.safe_version(str(attrs['version'])) + self._patched_dist = dist + + def __init__ (self, attrs=None): + have_package_data = hasattr(self, "package_data") + if not have_package_data: + self.package_data = {} + self.require_features = [] + self.features = {} + self.dist_files = [] + self.src_root = attrs and attrs.pop("src_root", None) + self.patch_missing_pkg_info(attrs) + # Make sure we have any eggs needed to interpret 'attrs' + if attrs is not None: + 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')) + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + if not hasattr(self,ep.name): + setattr(self,ep.name,None) + _Distribution.__init__(self,attrs) + if isinstance(self.metadata.version, (int,long,float)): + # Some people apparently take "version number" too literally :) + self.metadata.version = str(self.metadata.version) + + def parse_command_line(self): + """Process features after parsing command line options""" + result = _Distribution.parse_command_line(self) + if self.features: + self._finalize_features() + return result + + def _feature_attrname(self,name): + """Convert feature name to corresponding option attribute name""" + return 'with_'+name.replace('-','_') + + 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 + ): + working_set.add(dist) + + def finalize_options(self): + _Distribution.finalize_options(self) + if self.features: + self._set_global_opts_from_features() + + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + value = getattr(self,ep.name,None) + if value is not None: + ep.require(installer=self.fetch_build_egg) + ep.load()(self, ep.name, value) + if getattr(self, 'convert_2to3_doctests', None): + # XXX may convert to set here when we can rely on set being builtin + self.convert_2to3_doctests = [os.path.abspath(p) for p in self.convert_2to3_doctests] + else: + self.convert_2to3_doctests = [] + + def fetch_build_egg(self, req): + """Fetch an egg needed for building""" + + try: + cmd = self._egg_fetcher + cmd.package_index.to_scan = [] + except AttributeError: + from setuptools.command.easy_install import easy_install + dist = self.__class__({'script_args':['easy_install']}) + dist.parse_config_files() + opts = dist.get_option_dict('easy_install') + keep = ( + 'find_links', 'site_dirs', 'index_url', 'optimize', + 'site_dirs', 'allow_hosts' + ) + for key in opts.keys(): + if key not in keep: + del opts[key] # don't use any other settings + if self.dependency_links: + links = self.dependency_links[:] + if 'find_links' in opts: + links = opts['find_links'][1].split() + links + opts['find_links'] = ('setup', links) + cmd = easy_install( + dist, args=["x"], install_dir=os.curdir, exclude_scripts=True, + always_copy=False, build_directory=None, editable=False, + upgrade=False, multi_version=True, no_report=True, user=False + ) + cmd.ensure_finalized() + self._egg_fetcher = cmd + return cmd.easy_install(req) + + def _set_global_opts_from_features(self): + """Add --with-X/--without-X options based on optional features""" + + go = [] + no = self.negative_opt.copy() + + for name,feature in self.features.items(): + self._set_feature(name,None) + feature.validate(self) + + if feature.optional: + descr = feature.description + incdef = ' (default)' + excdef='' + if not feature.include_by_default(): + excdef, incdef = incdef, excdef + + go.append(('with-'+name, None, 'include '+descr+incdef)) + go.append(('without-'+name, None, 'exclude '+descr+excdef)) + no['without-'+name] = 'with-'+name + + self.global_options = self.feature_options = go + self.global_options + self.negative_opt = self.feature_negopt = no + + + + + + + + + + + + + + + + + + + def _finalize_features(self): + """Add/remove features and resolve dependencies between them""" + + # First, flag all the enabled items (and thus their dependencies) + for name,feature in self.features.items(): + enabled = self.feature_is_included(name) + if enabled or (enabled is None and feature.include_by_default()): + feature.include_in(self) + self._set_feature(name,1) + + # Then disable the rest, so that off-by-default features don't + # get flagged as errors when they're required by an enabled feature + for name,feature in self.features.items(): + if not self.feature_is_included(name): + feature.exclude_from(self) + self._set_feature(name,0) + + + def get_command_class(self, command): + """Pluggable version of get_command_class()""" + if command in self.cmdclass: + return self.cmdclass[command] + + for ep in pkg_resources.iter_entry_points('distutils.commands',command): + ep.require(installer=self.fetch_build_egg) + self.cmdclass[command] = cmdclass = ep.load() + return cmdclass + else: + return _Distribution.get_command_class(self, command) + + 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 + self.cmdclass[ep.name] = cmdclass + return _Distribution.print_commands(self) + + + + + + def _set_feature(self,name,status): + """Set feature's inclusion status""" + setattr(self,self._feature_attrname(name),status) + + def feature_is_included(self,name): + """Return 1 if feature is included, 0 if excluded, 'None' if unknown""" + return getattr(self,self._feature_attrname(name)) + + def include_feature(self,name): + """Request inclusion of feature named 'name'""" + + if self.feature_is_included(name)==0: + descr = self.features[name].description + raise DistutilsOptionError( + descr + " is required, but was excluded or is not available" + ) + self.features[name].include_in(self) + self._set_feature(name,1) + + def include(self,**attrs): + """Add items to distribution that are named in keyword arguments + + For example, 'dist.exclude(py_modules=["x"])' would add 'x' to + the distribution's 'py_modules' attribute, if it was not already + there. + + Currently, this method only supports inclusion for attributes that are + lists or tuples. If you need to add support for adding to other + attributes in this or a subclass, you can add an '_include_X' method, + where 'X' is the name of the attribute. The method will be called with + the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})' + will try to call 'dist._include_foo({"bar":"baz"})', which can then + handle whatever special inclusion logic is needed. + """ + for k,v in attrs.items(): + include = getattr(self, '_include_'+k, None) + if include: + include(v) + else: + self._include_misc(k,v) + + def exclude_package(self,package): + """Remove packages, modules, and extensions in named package""" + + pfx = package+'.' + if self.packages: + self.packages = [ + p for p in self.packages + if p != package and not p.startswith(pfx) + ] + + if self.py_modules: + self.py_modules = [ + p for p in self.py_modules + if p != package and not p.startswith(pfx) + ] + + if self.ext_modules: + self.ext_modules = [ + p for p in self.ext_modules + if p.name != package and not p.name.startswith(pfx) + ] + + + def has_contents_for(self,package): + """Return true if 'exclude_package(package)' would do something""" + + pfx = package+'.' + + for p in self.iter_distribution_names(): + if p==package or p.startswith(pfx): + return True + + + + + + + + + + + def _exclude_misc(self,name,value): + """Handle 'exclude()' for list/tuple attrs without a special handler""" + if not isinstance(value,sequence): + raise DistutilsSetupError( + "%s: setting must be a list or tuple (%r)" % (name, value) + ) + try: + old = getattr(self,name) + except AttributeError: + raise DistutilsSetupError( + "%s: No such distribution setting" % name + ) + if old is not None and not isinstance(old,sequence): + raise DistutilsSetupError( + name+": this setting cannot be changed via include/exclude" + ) + elif old: + setattr(self,name,[item for item in old if item not in value]) + + def _include_misc(self,name,value): + """Handle 'include()' for list/tuple attrs without a special handler""" + + if not isinstance(value,sequence): + raise DistutilsSetupError( + "%s: setting must be a list (%r)" % (name, value) + ) + try: + old = getattr(self,name) + except AttributeError: + raise DistutilsSetupError( + "%s: No such distribution setting" % name + ) + if old is None: + setattr(self,name,value) + elif not isinstance(old,sequence): + raise DistutilsSetupError( + name+": this setting cannot be changed via include/exclude" + ) + else: + setattr(self,name,old+[item for item in value if item not in old]) + + def exclude(self,**attrs): + """Remove items from distribution that are named in keyword arguments + + For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from + the distribution's 'py_modules' attribute. Excluding packages uses + the 'exclude_package()' method, so all of the package's contained + packages, modules, and extensions are also excluded. + + Currently, this method only supports exclusion from attributes that are + lists or tuples. If you need to add support for excluding from other + attributes in this or a subclass, you can add an '_exclude_X' method, + where 'X' is the name of the attribute. The method will be called with + the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})' + will try to call 'dist._exclude_foo({"bar":"baz"})', which can then + handle whatever special exclusion logic is needed. + """ + for k,v in attrs.items(): + exclude = getattr(self, '_exclude_'+k, None) + if exclude: + exclude(v) + else: + self._exclude_misc(k,v) + + def _exclude_packages(self,packages): + if not isinstance(packages,sequence): + raise DistutilsSetupError( + "packages: setting must be a list or tuple (%r)" % (packages,) + ) + map(self.exclude_package, packages) + + + + + + + + + + + + + def _parse_command_opts(self, parser, args): + # Remove --with-X/--without-X options when processing command args + self.global_options = self.__class__.global_options + self.negative_opt = self.__class__.negative_opt + + # First, expand any aliases + command = args[0] + aliases = self.get_option_dict('aliases') + while command in aliases: + src,alias = aliases[command] + del aliases[command] # ensure each alias can expand only once! + import shlex + args[:1] = shlex.split(alias,True) + command = args[0] + + nargs = _Distribution._parse_command_opts(self, parser, args) + + # Handle commands that want to consume all remaining arguments + cmd_class = self.get_command_class(command) + if getattr(cmd_class,'command_consumes_arguments',None): + self.get_option_dict(command)['args'] = ("command line", nargs) + if nargs is not None: + return [] + + return nargs + + + + + + + + + + + + + + + + + def get_cmdline_options(self): + """Return a '{cmd: {opt:val}}' map of all command-line options + + Option names are all long, but do not include the leading '--', and + contain dashes rather than underscores. If the option doesn't take + an argument (e.g. '--quiet'), the 'val' is 'None'. + + Note that options provided by config files are intentionally excluded. + """ + + d = {} + + for cmd,opts in self.command_options.items(): + + for opt,(src,val) in opts.items(): + + if src != "command line": + continue + + opt = opt.replace('_','-') + + if val==0: + cmdobj = self.get_command_obj(cmd) + neg_opt = self.negative_opt.copy() + neg_opt.update(getattr(cmdobj,'negative_opt',{})) + for neg,pos in neg_opt.items(): + if pos==opt: + opt=neg + val=None + break + else: + raise AssertionError("Shouldn't be able to get here") + + elif val==1: + val = None + + d.setdefault(cmd,{})[opt] = val + + return d + + + def iter_distribution_names(self): + """Yield all packages, modules, and extension names in distribution""" + + for pkg in self.packages or (): + yield pkg + + for module in self.py_modules or (): + yield module + + for ext in self.ext_modules or (): + if isinstance(ext,tuple): + name, buildinfo = ext + else: + name = ext.name + if name.endswith('module'): + name = name[:-6] + yield name + + + def handle_display_options(self, option_order): + """If there were any non-global "display-only" options + (--help-commands or the metadata display options) on the command + line, display the requested info and return true; else return + false. + """ + import sys + + if sys.version_info < (3,) or self.help_commands: + return _Distribution.handle_display_options(self, option_order) + + # Stdout may be StringIO (e.g. in tests) + import io + if not isinstance(sys.stdout, io.TextIOWrapper): + return _Distribution.handle_display_options(self, option_order) + + # Don't wrap stdout if utf-8 is already the encoding. Provides + # workaround for #334. + if sys.stdout.encoding.lower() in ('utf-8', 'utf8'): + return _Distribution.handle_display_options(self, option_order) + + # Print metadata in UTF-8 no matter the platform + encoding = sys.stdout.encoding + errors = sys.stdout.errors + newline = sys.platform != 'win32' and '\n' or None + line_buffering = sys.stdout.line_buffering + + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), 'utf-8', errors, newline, line_buffering) + try: + return _Distribution.handle_display_options(self, option_order) + finally: + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), encoding, errors, newline, line_buffering) + + +# Install it throughout the distutils +for module in distutils.dist, distutils.core, distutils.cmd: + module.Distribution = Distribution + + + + + + + + + + + + + + + + + + + + +class Feature: + """A subset of the distribution that can be excluded if unneeded/wanted + + Features are created using these keyword arguments: + + 'description' -- a short, human readable description of the feature, to + be used in error messages, and option help messages. + + 'standard' -- if true, the feature is included by default if it is + available on the current system. Otherwise, the feature is only + included if requested via a command line '--with-X' option, or if + another included feature requires it. The default setting is 'False'. + + 'available' -- if true, the feature is available for installation on the + current system. The default setting is 'True'. + + 'optional' -- if true, the feature's inclusion can be controlled from the + command line, using the '--with-X' or '--without-X' options. If + false, the feature's inclusion status is determined automatically, + based on 'availabile', 'standard', and whether any other feature + requires it. The default setting is 'True'. + + 'require_features' -- a string or sequence of strings naming features + that should also be included if this feature is included. Defaults to + empty list. May also contain 'Require' objects that should be + added/removed from the distribution. + + 'remove' -- a string or list of strings naming packages to be removed + from the distribution if this feature is *not* included. If the + feature *is* included, this argument is ignored. This argument exists + to support removing features that "crosscut" a distribution, such as + defining a 'tests' feature that removes all the 'tests' subpackages + provided by other features. The default for this argument is an empty + list. (Note: the named package(s) or modules must exist in the base + distribution when the 'setup()' function is initially called.) + + other keywords -- any other keyword arguments are saved, and passed to + the distribution's 'include()' and 'exclude()' methods when the + feature is included or excluded, respectively. So, for example, you + could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be + added or removed from the distribution as appropriate. + + A feature must include at least one 'requires', 'remove', or other + keyword argument. Otherwise, it can't affect the distribution in any way. + Note also that you can subclass 'Feature' to create your own specialized + feature types that modify the distribution in other ways when included or + excluded. See the docstrings for the various methods here for more detail. + Aside from the methods, the only feature attributes that distributions look + at are 'description' and 'optional'. + """ + def __init__(self, description, standard=False, available=True, + optional=True, require_features=(), remove=(), **extras + ): + + self.description = description + self.standard = standard + self.available = available + self.optional = optional + if isinstance(require_features,(str,Require)): + require_features = require_features, + + self.require_features = [ + r for r in require_features if isinstance(r,str) + ] + er = [r for r in require_features if not isinstance(r,str)] + if er: extras['require_features'] = er + + if isinstance(remove,str): + remove = remove, + self.remove = remove + self.extras = extras + + if not remove and not require_features and not extras: + raise DistutilsSetupError( + "Feature %s: must define 'require_features', 'remove', or at least one" + " of 'packages', 'py_modules', etc." + ) + + def include_by_default(self): + """Should this feature be included by default?""" + return self.available and self.standard + + def include_in(self,dist): + + """Ensure feature and its requirements are included in distribution + + You may override this in a subclass to perform additional operations on + the distribution. Note that this method may be called more than once + per feature, and so should be idempotent. + + """ + + if not self.available: + raise DistutilsPlatformError( + self.description+" is required," + "but is not available on this platform" + ) + + dist.include(**self.extras) + + for f in self.require_features: + dist.include_feature(f) + + + + def exclude_from(self,dist): + + """Ensure feature is excluded from distribution + + You may override this in a subclass to perform additional operations on + the distribution. This method will be called at most once per + feature, and only after all included features have been asked to + include themselves. + """ + + dist.exclude(**self.extras) + + if self.remove: + for item in self.remove: + dist.exclude_package(item) + + + + def validate(self,dist): + + """Verify that feature makes sense in context of distribution + + This method is called by the distribution just before it parses its + command line. It checks to ensure that the 'remove' attribute, if any, + contains only valid package/module names that are present in the base + distribution when 'setup()' is called. You may override it in a + subclass to perform any other required validation of the feature + against a target distribution. + """ + + for item in self.remove: + if not dist.has_contents_for(item): + raise DistutilsSetupError( + "%s wants to be able to remove %s, but the distribution" + " doesn't contain any packages or modules under %s" + % (self.description, item, item) + ) + + + +def check_packages(dist, attr, value): + 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" + ".-separated package names in setup.py", pkgname + ) + diff --git a/vendor/distribute-0.6.35/setuptools/extension.py b/vendor/distribute-0.6.35/setuptools/extension.py new file mode 100644 index 00000000..eb8b836c --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/extension.py @@ -0,0 +1,46 @@ +import sys +import distutils.core +import distutils.extension + +from setuptools.dist import _get_unpatched + +_Extension = _get_unpatched(distutils.core.Extension) + +def have_pyrex(): + """ + Return True if Cython or Pyrex can be imported. + """ + pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext' + for pyrex_impl in pyrex_impls: + try: + # from (pyrex_impl) import build_ext + __import__(pyrex_impl, fromlist=['build_ext']).build_ext + return True + except Exception: + pass + return False + + +class Extension(_Extension): + """Extension that uses '.c' files in place of '.pyx' files""" + + def __init__(self, *args, **kw): + _Extension.__init__(self, *args, **kw) + if not have_pyrex(): + self._convert_pyx_sources_to_c() + + def _convert_pyx_sources_to_c(self): + "convert .pyx extensions to .c" + def pyx_to_c(source): + if source.endswith('.pyx'): + source = source[:-4] + '.c' + return source + self.sources = map(pyx_to_c, self.sources) + +class Library(Extension): + """Just like a regular Extension, but built as a library instead""" + +distutils.core.Extension = Extension +distutils.extension.Extension = Extension +if 'distutils.command.build_ext' in sys.modules: + sys.modules['distutils.command.build_ext'].Extension = Extension diff --git a/vendor/distribute-0.6.35/setuptools/gui-32.exe b/vendor/distribute-0.6.35/setuptools/gui-32.exe new file mode 100755 index 0000000000000000000000000000000000000000..3f64af7de42fd6597b4c6cf50896d32a98a7d6a2 GIT binary patch literal 65536 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≠Ip=#d8jxC7MfEgS%i`z+EI)@p2%8 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 literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.35/setuptools/gui-64.exe b/vendor/distribute-0.6.35/setuptools/gui-64.exe new file mode 100755 index 0000000000000000000000000000000000000000..3ab4378e1d401d198b92a33ce249d29bcdb26a63 GIT binary patch literal 75264 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�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 literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.35/setuptools/gui.exe b/vendor/distribute-0.6.35/setuptools/gui.exe new file mode 100755 index 0000000000000000000000000000000000000000..3f64af7de42fd6597b4c6cf50896d32a98a7d6a2 GIT binary patch literal 65536 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≠Ip=#d8jxC7MfEgS%i`z+EI)@p2%8 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 literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.35/setuptools/package_index.py b/vendor/distribute-0.6.35/setuptools/package_index.py new file mode 100644 index 00000000..0ee21e3b --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/package_index.py @@ -0,0 +1,920 @@ +"""PyPI and direct package downloading""" +import sys, os.path, re, urlparse, urllib, urllib2, shutil, random, socket, cStringIO +import base64 +import httplib +from pkg_resources import * +from distutils import log +from distutils.errors import DistutilsError +try: + from hashlib import md5 +except ImportError: + from md5 import md5 +from fnmatch import translate + +EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$') +HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) +# this is here to fix emacs' cruddy broken syntax highlighting +PYPI_MD5 = re.compile( + '<a href="([^"#]+)">([^<]+)</a>\n\s+\\(<a (?:title="MD5 hash"\n\s+)' + 'href="[^?]+\?:action=show_md5&digest=([0-9a-f]{32})">md5</a>\\)' +) +URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):',re.I).match +EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() + +__all__ = [ + 'PackageIndex', 'distros_for_url', 'parse_bdist_wininst', + 'interpret_distro_name', +] + +_SOCKET_TIMEOUT = 15 + +def parse_bdist_wininst(name): + """Return (base,pyversion) or (None,None) for possible .exe name""" + + lower = name.lower() + base, py_ver, plat = None, None, None + + if lower.endswith('.exe'): + if lower.endswith('.win32.exe'): + base = name[:-10] + plat = 'win32' + elif lower.startswith('.win32-py',-16): + py_ver = name[-7:-4] + base = name[:-16] + plat = 'win32' + elif lower.endswith('.win-amd64.exe'): + base = name[:-14] + plat = 'win-amd64' + elif lower.startswith('.win-amd64-py',-20): + py_ver = name[-7:-4] + base = name[:-20] + plat = 'win-amd64' + return base,py_ver,plat + + +def egg_info_for_url(url): + scheme, server, path, parameters, query, fragment = urlparse.urlparse(url) + base = urllib2.unquote(path.split('/')[-1]) + if '#' in base: base, fragment = base.split('#',1) + return base,fragment + +def distros_for_url(url, metadata=None): + """Yield egg or source distribution objects that might be found at a URL""" + base, fragment = egg_info_for_url(url) + for dist in distros_for_location(url, base, metadata): yield dist + if fragment: + match = EGG_FRAGMENT.match(fragment) + if match: + for dist in interpret_distro_name( + url, match.group(1), metadata, precedence = CHECKOUT_DIST + ): + yield dist + +def distros_for_location(location, basename, metadata=None): + """Yield egg or source distribution objects based on basename""" + if basename.endswith('.egg.zip'): + basename = basename[:-4] # strip the .zip + if basename.endswith('.egg') and '-' in basename: + # only one, unambiguous interpretation + return [Distribution.from_location(location, basename, metadata)] + + if basename.endswith('.exe'): + win_base, py_ver, platform = parse_bdist_wininst(basename) + if win_base is not None: + return interpret_distro_name( + location, win_base, metadata, py_ver, BINARY_DIST, platform + ) + + # Try source distro extensions (.zip, .tgz, etc.) + # + for ext in EXTENSIONS: + if basename.endswith(ext): + basename = basename[:-len(ext)] + return interpret_distro_name(location, basename, metadata) + return [] # no extension matched + +def distros_for_filename(filename, metadata=None): + """Yield possible egg or source distribution objects based on a filename""" + return distros_for_location( + normalize_path(filename), os.path.basename(filename), metadata + ) + + +def interpret_distro_name(location, basename, metadata, + py_version=None, precedence=SOURCE_DIST, platform=None +): + """Generate alternative interpretations of a source distro name + + Note: if `location` is a filesystem filename, you should call + ``pkg_resources.normalize_path()`` on it before passing it to this + routine! + """ + # Generate alternative interpretations of a source distro name + # Because some packages are ambiguous as to name/versions split + # e.g. "adns-python-1.1.0", "egenix-mx-commercial", etc. + # So, we generate each possible interepretation (e.g. "adns, python-1.1.0" + # "adns-python, 1.1.0", and "adns-python-1.1.0, no version"). In practice, + # the spurious interpretations should be ignored, because in the event + # there's also an "adns" package, the spurious "python-1.1.0" version will + # compare lower than any numeric version number, and is therefore unlikely + # to match a request for it. It's still a potential problem, though, and + # in the long run PyPI and the distutils should go for "safe" names and + # 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 + + for p in range(1,len(parts)+1): + yield Distribution( + location, metadata, '-'.join(parts[:p]), '-'.join(parts[p:]), + py_version=py_version, precedence = precedence, + platform = platform + ) + +REL = re.compile("""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) +# this line is here to fix emacs' cruddy broken syntax highlighting + +def find_external_links(url, page): + """Find rel="homepage" and rel="download" links in `page`, yielding URLs""" + + for match in REL.finditer(page): + tag, rel = match.groups() + rels = map(str.strip, rel.lower().split(',')) + if 'homepage' in rels or 'download' in rels: + for match in HREF.finditer(tag): + yield urlparse.urljoin(url, htmldecode(match.group(1))) + + for tag in ("<th>Home Page", "<th>Download URL"): + pos = page.find(tag) + if pos!=-1: + match = HREF.search(page,pos) + if match: + yield urlparse.urljoin(url, htmldecode(match.group(1))) + +user_agent = "Python-urllib/%s distribute/%s" % ( + sys.version[:3], require('distribute')[0].version +) + + +class PackageIndex(Environment): + """A distribution index that scans web pages for download URLs""" + + def __init__(self, index_url="http://pypi.python.org/simple", hosts=('*',), + *args, **kw + ): + Environment.__init__(self,*args,**kw) + self.index_url = index_url + "/"[:not index_url.endswith('/')] + self.scanned_urls = {} + self.fetched_urls = {} + self.package_pages = {} + self.allows = re.compile('|'.join(map(translate,hosts))).match + self.to_scan = [] + + + + def process_url(self, url, retrieve=False): + """Evaluate a URL as a possible download, and maybe retrieve it""" + if url in self.scanned_urls and not retrieve: + return + self.scanned_urls[url] = True + if not URL_SCHEME(url): + self.process_filename(url) + return + else: + dists = list(distros_for_url(url)) + if dists: + if not self.url_ok(url): + return + self.debug("Found link: %s", url) + + if dists or not retrieve or url in self.fetched_urls: + map(self.add, dists) + return # don't need the actual page + + if not self.url_ok(url): + self.fetched_urls[url] = True + return + + self.info("Reading %s", url) + f = self.open_url(url, "Download error on %s: %%s -- Some packages may not be found!" % url) + if f is None: return + self.fetched_urls[url] = self.fetched_urls[f.url] = True + + if 'html' not in f.headers.get('content-type', '').lower(): + f.close() # not html, we can't process it + return + + 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, urllib2.HTTPError): + # Errors have no charset, assume latin1: + charset = 'latin-1' + else: + charset = f.headers.get_param('charset') or 'latin-1' + page = page.decode(charset, "ignore") + f.close() + for match in HREF.finditer(page): + link = urlparse.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) + + def process_filename(self, fn, nested=False): + # process filenames or directories + if not os.path.exists(fn): + self.warn("Not found: %s", fn) + return + + if os.path.isdir(fn) and not nested: + path = os.path.realpath(fn) + for item in os.listdir(path): + self.process_filename(os.path.join(path,item), True) + + dists = distros_for_filename(fn) + if dists: + self.debug("Found: %s", fn) + map(self.add, dists) + + def url_ok(self, url, fatal=False): + s = URL_SCHEME(url) + if (s and s.group(1).lower()=='file') or self.allows(urlparse.urlparse(url)[1]): + return True + msg = "\nLink to % s ***BLOCKED*** by --allow-hosts\n" + if fatal: + raise DistutilsError(msg % url) + else: + 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) + + def scan_egg_link(self, path, entry): + lines = filter(None, map(str.strip, open(os.path.join(path, entry)))) + 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) + + def process_index(self,url,page): + """Process the contents of a PyPI page""" + def scan(link): + # Process a URL to see if it's for a package page + if link.startswith(self.index_url): + parts = map( + urllib2.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 + pkg = safe_name(parts[0]) + ver = safe_version(parts[1]) + self.package_pages.setdefault(pkg.lower(),{})[link] = True + return to_filename(pkg), to_filename(ver) + return None, None + + # process an index page into the package-page index + for match in HREF.finditer(page): + try: + scan( urlparse.urljoin(url, htmldecode(match.group(1))) ) + except ValueError: + pass + + pkg, ver = scan(url) # ensure this page is in the page index + if pkg: + # process individual package page + for new_url in find_external_links(url, page): + # Process the found URL + base, frag = egg_info_for_url(new_url) + if base.endswith('.py') and not frag: + if ver: + new_url+='#egg=%s-%s' % (pkg,ver) + else: + self.need_version_info(url) + self.scan_url(new_url) + + return PYPI_MD5.sub( + lambda m: '<a href="%s#md5=%s">%s</a>' % m.group(1,3,2), page + ) + else: + return "" # no sense double-scanning non-package pages + + + + def need_version_info(self, url): + self.scan_all( + "Page at %s links to .py file(s) without version info; an index " + "scan is required.", url + ) + + def scan_all(self, msg=None, *args): + if self.index_url not in self.fetched_urls: + if msg: self.warn(msg,*args) + self.info( + "Scanning index of all packages (this may take a while)" + ) + self.scan_url(self.index_url) + + def find_packages(self, requirement): + self.scan_url(self.index_url + requirement.unsafe_name+'/') + + if not self.package_pages.get(requirement.key): + # Fall back to safe version of the name + self.scan_url(self.index_url + requirement.project_name+'/') + + if not self.package_pages.get(requirement.key): + # We couldn't find the target package, so search the index page too + self.not_found_in_index(requirement) + + for url in list(self.package_pages.get(requirement.key,())): + # scan each page that might be related to the desired package + self.scan_url(url) + + def obtain(self, requirement, installer=None): + self.prescan(); self.find_packages(requirement) + for dist in self[requirement.key]: + if dist in requirement: + return dist + self.debug("%s does not match %s", requirement, dist) + return super(PackageIndex, self).obtain(requirement,installer) + + + + + + def check_md5(self, cs, info, filename, tfp): + if re.match('md5=[0-9a-f]{32}$', info): + self.debug("Validating md5 checksum for %s", filename) + if cs.hexdigest()<>info[4:]: + tfp.close() + os.unlink(filename) + raise DistutilsError( + "MD5 validation failed for "+os.path.basename(filename)+ + "; possible download problem?" + ) + + def add_find_links(self, urls): + """Add `urls` to the list that will be prescanned for searches""" + for url in urls: + if ( + self.to_scan is None # if we have already "gone online" + or not URL_SCHEME(url) # or it's a local file/directory + or url.startswith('file:') + or list(distros_for_url(url)) # or a direct package link + ): + # then go ahead and process it now + self.scan_url(url) + else: + # otherwise, defer retrieval till later + self.to_scan.append(url) + + def prescan(self): + """Scan urls scheduled for prescanning (e.g. --find-links)""" + if self.to_scan: + map(self.scan_url, self.to_scan) + self.to_scan = None # from now on, go ahead and process immediately + + def not_found_in_index(self, requirement): + if self[requirement.key]: # we've seen at least one distro + meth, msg = self.info, "Couldn't retrieve index page for %r" + else: # no distros seen for this name, might be misspelled + meth, msg = (self.warn, + "Couldn't find index page for %r (maybe misspelled?)") + meth(msg, requirement.unsafe_name) + self.scan_all() + + def download(self, spec, tmpdir): + """Locate and/or download `spec` to `tmpdir`, returning a local path + + `spec` may be a ``Requirement`` object, or a string containing a URL, + an existing local filename, or a project/version requirement spec + (i.e. the string form of a ``Requirement`` object). If it is the URL + of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one + that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is + automatically created alongside the downloaded file. + + If `spec` is a ``Requirement`` object or a string containing a + project/version requirement spec, this method returns the location of + a matching distribution (possibly after downloading it to `tmpdir`). + If `spec` is a locally existing file or directory name, it is simply + returned unchanged. If `spec` is a URL, it is downloaded to a subpath + of `tmpdir`, and the local filename is returned. Various errors may be + raised if a problem occurs during downloading. + """ + if not isinstance(spec,Requirement): + scheme = URL_SCHEME(spec) + if scheme: + # It's a url, download it to tmpdir + found = self._download_url(scheme.group(1), spec, tmpdir) + base, fragment = egg_info_for_url(spec) + if base.endswith('.py'): + found = self.gen_setup(found,fragment,tmpdir) + return found + elif os.path.exists(spec): + # Existing file or directory, just return it + return spec + else: + try: + spec = Requirement.parse(spec) + except ValueError: + raise DistutilsError( + "Not a URL, existing file, or requirement spec: %r" % + (spec,) + ) + return getattr(self.fetch_distribution(spec, tmpdir),'location',None) + + + def fetch_distribution(self, + requirement, tmpdir, force_scan=False, source=False, develop_ok=False, + local_index=None + ): + """Obtain a distribution suitable for fulfilling `requirement` + + `requirement` must be a ``pkg_resources.Requirement`` instance. + If necessary, or if the `force_scan` flag is set, the requirement is + searched for in the (online) package index as well as the locally + installed packages. If a distribution matching `requirement` is found, + the returned distribution's ``location`` is the value you would have + gotten from calling the ``download()`` method with the matching + distribution's URL or filename. If no matching distribution is found, + ``None`` is returned. + + If the `source` flag is set, only source distributions and source + checkout links will be considered. Unless the `develop_ok` flag is + set, development and system eggs (i.e., those using the ``.egg-info`` + format) will be ignored. + """ + + # process a Requirement + self.info("Searching for %s", requirement) + skipped = {} + dist = None + + def find(req, env=None): + if env is None: + env = self + # Find a matching distribution; may be called more than once + + for dist in env[req.key]: + + if dist.precedence==DEVELOP_DIST and not develop_ok: + if dist not in skipped: + self.warn("Skipping development or system egg: %s",dist) + skipped[dist] = 1 + continue + + if dist in req and (dist.precedence<=SOURCE_DIST or not source): + self.info("Best match: %s", dist) + return dist.clone( + location=self.download(dist.location, tmpdir) + ) + + if force_scan: + self.prescan() + self.find_packages(requirement) + dist = find(requirement) + + if local_index is not None: + dist = dist or find(requirement, local_index) + + if dist is None and self.to_scan is not None: + self.prescan() + dist = find(requirement) + + if dist is None and not force_scan: + self.find_packages(requirement) + dist = find(requirement) + + if dist is None: + self.warn( + "No local packages or download links found for %s%s", + (source and "a source distribution of " or ""), + requirement, + ) + return dist + + def fetch(self, requirement, tmpdir, force_scan=False, source=False): + """Obtain a file suitable for fulfilling `requirement` + + DEPRECATED; use the ``fetch_distribution()`` method now instead. For + backward compatibility, this routine is identical but returns the + ``location`` of the downloaded distribution instead of a distribution + object. + """ + dist = self.fetch_distribution(requirement,tmpdir,force_scan,source) + if dist is not None: + return dist.location + return None + + + + + + + + + def gen_setup(self, filename, fragment, tmpdir): + match = EGG_FRAGMENT.match(fragment) + dists = match and [d for d in + interpret_distro_name(filename, match.group(1), None) if d.version + ] or [] + + if len(dists)==1: # unambiguous ``#egg`` fragment + basename = os.path.basename(filename) + + # Make sure the file has been downloaded to the temp dir. + if os.path.dirname(filename) != tmpdir: + dst = os.path.join(tmpdir, basename) + from setuptools.command.easy_install import samefile + if not samefile(filename, dst): + 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] + ) + ) + file.close() + return filename + + elif match: + raise DistutilsError( + "Can't unambiguously interpret project/version identifier %r; " + "any dashes in the name or version should be escaped using " + "underscores. %r" % (fragment,dists) + ) + else: + raise DistutilsError( + "Can't process plain .py files without an '#egg=name-version'" + " suffix to enable automatic setup script generation." + ) + + dl_blocksize = 8192 + def _download_to(self, url, filename): + self.info("Downloading %s", url) + # Download the file + fp, tfp, info = None, None, None + try: + if '#' in url: + url, info = url.split('#', 1) + fp = self.open_url(url) + if isinstance(fp, urllib2.HTTPError): + raise DistutilsError( + "Can't download %s: %s %s" % (url, fp.code,fp.msg) + ) + cs = md5() + headers = fp.info() + blocknum = 0 + bs = self.dl_blocksize + size = -1 + if "content-length" in headers: + # Some servers return multiple Content-Length headers :( + content_length = headers.get("Content-Length") + size = int(content_length) + self.reporthook(url, filename, blocknum, bs, size) + tfp = open(filename,'wb') + while True: + block = fp.read(bs) + if block: + cs.update(block) + tfp.write(block) + blocknum += 1 + self.reporthook(url, filename, blocknum, bs, size) + else: + break + if info: self.check_md5(cs, info, filename, tfp) + return headers + finally: + if fp: fp.close() + if tfp: tfp.close() + + def reporthook(self, url, filename, blocknum, blksize, size): + pass # no-op + + + def open_url(self, url, warning=None): + if url.startswith('file:'): + return local_open(url) + try: + return open_with_auth(url) + except (ValueError, httplib.InvalidURL), 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: + return v + except urllib2.URLError, v: + if warning: + self.warn(warning, v.reason) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v.reason)) + except httplib.BadStatusLine, v: + if warning: + self.warn(warning, v.line) + else: + raise DistutilsError('%s returned a bad status line. ' + 'The server might be down, %s' % \ + (url, v.line)) + except httplib.HTTPException, v: + if warning: + self.warn(warning, v) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v)) + + def _download_url(self, scheme, url, tmpdir): + # Determine download filename + # + name = filter(None,urlparse.urlparse(url)[2].split('/')) + if name: + name = name[-1] + while '..' in name: + name = name.replace('..','.').replace('\\','_') + else: + name = "__downloaded__" # default if URL has no path contents + + if name.endswith('.egg.zip'): + name = name[:-4] # strip the extra .zip before download + + filename = os.path.join(tmpdir,name) + + # Download the file + # + if scheme=='svn' or scheme.startswith('svn+'): + return self._download_svn(url, filename) + elif scheme=='git' or scheme.startswith('git+'): + return self._download_git(url, filename) + elif scheme.startswith('hg+'): + return self._download_hg(url, filename) + elif scheme=='file': + return urllib.url2pathname(urlparse.urlparse(url)[2]) + else: + self.url_ok(url, True) # raises error if not allowed + return self._attempt_download(url, filename) + + + + def scan_url(self, url): + self.process_url(url, True) + + + def _attempt_download(self, url, filename): + headers = self._download_to(url, filename) + if 'html' in headers.get('content-type','').lower(): + return self._download_html(url, headers, filename) + else: + return filename + + def _download_html(self, url, headers, filename): + file = open(filename) + for line in file: + if line.strip(): + # Check for a subversion index page + if re.search(r'<title>([^- ]+ - )?Revision \d+:', line): + # it's a subversion index page: + file.close() + os.unlink(filename) + return self._download_svn(url, filename) + break # not an index page + file.close() + os.unlink(filename) + raise DistutilsError("Unexpected HTML page found at "+url) + + def _download_svn(self, url, filename): + url = url.split('#',1)[0] # remove any fragment for svn's sake + self.info("Doing subversion checkout from %s to %s", url, filename) + os.system("svn checkout -q %s %s" % (url, filename)) + return filename + + def _vcs_split_rev_from_url(self, url, pop_prefix=False): + scheme, netloc, path, query, frag = urlparse.urlsplit(url) + + scheme = scheme.split('+', 1)[-1] + + # Some fragment identification fails + path = path.split('#',1)[0] + + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + + # Also, discard fragment + url = urlparse.urlunsplit((scheme, netloc, path, query, '')) + + return url, rev + + def _download_git(self, url, filename): + filename = filename.split('#',1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing git clone from %s to %s", url, filename) + os.system("git clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Checking out %s", rev) + os.system("(cd %s && git checkout --quiet %s)" % ( + filename, + rev, + )) + + return filename + + def _download_hg(self, url, filename): + filename = filename.split('#',1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing hg clone from %s to %s", url, filename) + os.system("hg clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Updating to %s", rev) + os.system("(cd %s && hg up -C -r %s >&-)" % ( + filename, + rev, + )) + + return filename + + def debug(self, msg, *args): + log.debug(msg, *args) + + def info(self, msg, *args): + log.info(msg, *args) + + def warn(self, msg, *args): + log.warn(msg, *args) + +# This pattern matches a character entity reference (a decimal numeric +# references, a hexadecimal numeric reference, or a named reference). +entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub + +def uchr(c): + if not isinstance(c, int): + return c + if c>255: return unichr(c) + return chr(c) + +def decode_entity(match): + what = match.group(1) + if what.startswith('#x'): + what = int(what[2:], 16) + elif what.startswith('#'): + what = int(what[1:]) + else: + from htmlentitydefs import name2codepoint + what = name2codepoint.get(what, match.group(0)) + return uchr(what) + +def htmldecode(text): + """Decode HTML entities in the given text.""" + return entity_sub(decode_entity, text) + + + + + + + + + + + + + + + +def socket_timeout(timeout=15): + def _socket_timeout(func): + def _socket_timeout(*args, **kwargs): + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + return func(*args, **kwargs) + finally: + socket.setdefaulttimeout(old_timeout) + return _socket_timeout + return _socket_timeout + +def _encode_auth(auth): + """ + A function compatible with Python 2.3-3.3 that will encode + auth from a URL suitable for an HTTP header. + >>> _encode_auth('username%3Apassword') + u'dXNlcm5hbWU6cGFzc3dvcmQ=' + """ + auth_s = urllib2.unquote(auth) + # convert to bytes + auth_bytes = auth_s.encode() + # use the legacy interface for Python 2.3 support + encoded_bytes = base64.encodestring(auth_bytes) + # convert back to a string + encoded = encoded_bytes.decode() + # strip the trailing carriage return + return encoded.rstrip() + +def open_with_auth(url): + """Open a urllib2 request, handling HTTP authentication""" + + scheme, netloc, path, params, query, frag = urlparse.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: ''") + + if scheme in ('http', 'https'): + auth, host = urllib2.splituser(netloc) + else: + auth = None + + if auth: + auth = "Basic " + _encode_auth(auth) + new_url = urlparse.urlunparse((scheme,host,path,params,query,frag)) + request = urllib2.Request(new_url) + request.add_header("Authorization", auth) + else: + request = urllib2.Request(url) + + request.add_header('User-Agent', user_agent) + fp = urllib2.urlopen(request) + + 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.urlparse(fp.url) + if s2==scheme and h2==host: + fp.url = urlparse.urlunparse((s2,netloc,path2,param2,query2,frag2)) + + return fp + +# adding a timeout to avoid freezing package_index +open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth) + + + + + + + + + + + +def fix_sf_url(url): + return url # backward compatibility + +def local_open(url): + """Read a local path, with special support for directories""" + scheme, server, path, param, query, frag = urlparse.urlparse(url) + filename = urllib.url2pathname(path) + if os.path.isfile(filename): + return urllib2.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),'rb') + body = fp.read() + fp.close() + break + elif os.path.isdir(os.path.join(filename,f)): + f+='/' + files.append("<a href=%r>%s</a>" % (f,f)) + else: + body = ("<html><head><title>%s</title>" % url) + \ + "</head><body>%s</body></html>" % '\n'.join(files) + status, message = 200, "OK" + else: + status, message, body = 404, "Path not found", "Not found" + + return urllib2.HTTPError(url, status, message, + {'content-type':'text/html'}, cStringIO.StringIO(body)) + + + + + + + + + + + + + +# this line is a kludge to keep the trailing blank lines for pje's editor diff --git a/vendor/distribute-0.6.35/setuptools/sandbox.py b/vendor/distribute-0.6.35/setuptools/sandbox.py new file mode 100644 index 00000000..1583b81f --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/sandbox.py @@ -0,0 +1,293 @@ +import os, sys, __builtin__, tempfile, operator, pkg_resources +if os.name == "java": + import org.python.modules.posix.PosixModule as _os +else: + _os = sys.modules[os.name] +try: + _file = file +except NameError: + _file = None +_open = open +from distutils.errors import DistutilsError +__all__ = [ + "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", +] +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) + try: + sys.argv[:] = [setup_script]+list(args) + sys.path.insert(0, setup_dir) + DirectorySandbox(setup_dir).run( + lambda: execfile( + "setup.py", + {'__file__':setup_script, '__name__':'__main__'} + ) + ) + except SystemExit, 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.') + ] + map(sys.modules.__delitem__, del_modules) + os.chdir(old_dir) + sys.path[:] = save_path + sys.argv[:] = save_argv + tempfile.tempdir = save_tmp + +class AbstractSandbox: + """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts""" + + _active = False + + def __init__(self): + self._attrs = [ + name for name in dir(_os) + if not name.startswith('_') and hasattr(self,name) + ] + + def _copy(self, source): + for name in self._attrs: + setattr(os, name, getattr(source,name)) + + def run(self, func): + """Run 'func' under os sandboxing""" + try: + self._copy(self) + if _file: + __builtin__.file = self._file + __builtin__.open = self._open + self._active = True + return func() + finally: + self._active = False + if _file: + __builtin__.file = _file + __builtin__.open = _open + self._copy(_os) + + + def _mk_dual_path_wrapper(name): + original = getattr(_os,name) + def wrap(self,src,dst,*args,**kw): + if self._active: + src,dst = self._remap_pair(name,src,dst,*args,**kw) + return original(src,dst,*args,**kw) + return wrap + + + for name in ["rename", "link", "symlink"]: + if hasattr(_os,name): locals()[name] = _mk_dual_path_wrapper(name) + + + def _mk_single_path_wrapper(name, original=None): + original = original or getattr(_os,name) + def wrap(self,path,*args,**kw): + if self._active: + path = self._remap_input(name,path,*args,**kw) + return original(path,*args,**kw) + return wrap + + if _file: + _file = _mk_single_path_wrapper('file', _file) + _open = _mk_single_path_wrapper('open', _open) + for name in [ + "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", + "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", + "startfile", "mkfifo", "mknod", "pathconf", "access" + ]: + if hasattr(_os,name): locals()[name] = _mk_single_path_wrapper(name) + + + def _mk_single_with_return(name): + original = getattr(_os,name) + def wrap(self,path,*args,**kw): + if self._active: + path = self._remap_input(name,path,*args,**kw) + return self._remap_output(name, original(path,*args,**kw)) + return original(path,*args,**kw) + return wrap + + for name in ['readlink', 'tempnam']: + if hasattr(_os,name): locals()[name] = _mk_single_with_return(name) + + def _mk_query(name): + original = getattr(_os,name) + def wrap(self,*args,**kw): + retval = original(*args,**kw) + if self._active: + return self._remap_output(name, retval) + return retval + return wrap + + for name in ['getcwd', 'tmpnam']: + if hasattr(_os,name): locals()[name] = _mk_query(name) + + def _validate_path(self,path): + """Called to remap or validate any path, whether input or output""" + return path + + def _remap_input(self,operation,path,*args,**kw): + """Called for path inputs""" + return self._validate_path(path) + + def _remap_output(self,operation,path): + """Called for path outputs""" + return self._validate_path(path) + + def _remap_pair(self,operation,src,dst,*args,**kw): + """Called for path pairs like rename, link, and symlink operations""" + return ( + self._remap_input(operation+'-from',src,*args,**kw), + self._remap_input(operation+'-to',dst,*args,**kw) + ) + + +if hasattr(os, 'devnull'): + _EXCEPTIONS = [os.devnull,] +else: + _EXCEPTIONS = [] + +try: + from win32com.client.gencache import GetGeneratePath + _EXCEPTIONS.append(GetGeneratePath()) + del GetGeneratePath +except ImportError: + # it appears pywin32 is not installed, so no need to exclude. + pass + +class DirectorySandbox(AbstractSandbox): + """Restrict operations to a single subdirectory - pseudo-chroot""" + + write_ops = dict.fromkeys([ + "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", + "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam", + ]) + + def __init__(self, sandbox, exceptions=_EXCEPTIONS): + self._sandbox = os.path.normcase(os.path.realpath(sandbox)) + self._prefix = os.path.join(self._sandbox,'') + self._exceptions = [os.path.normcase(os.path.realpath(path)) for path in exceptions] + AbstractSandbox.__init__(self) + + def _violation(self, operation, *args, **kw): + raise SandboxViolation(operation, args, kw) + + if _file: + def _file(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("file", path, mode, *args, **kw) + return _file(path,mode,*args,**kw) + + def _open(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("open", path, mode, *args, **kw) + return _open(path,mode,*args,**kw) + + def tmpnam(self): + self._violation("tmpnam") + + def _ok(self,path): + active = self._active + try: + self._active = False + realpath = os.path.normcase(os.path.realpath(path)) + if (self._exempted(realpath) or realpath == self._sandbox + or realpath.startswith(self._prefix)): + return True + finally: + self._active = active + + def _exempted(self, filepath): + exception_matches = map(filepath.startswith, self._exceptions) + return True in exception_matches + + def _remap_input(self,operation,path,*args,**kw): + """Called for path inputs""" + if operation in self.write_ops and not self._ok(path): + self._violation(operation, os.path.realpath(path), *args, **kw) + return path + + def _remap_pair(self,operation,src,dst,*args,**kw): + """Called for path pairs like rename, link, and symlink operations""" + if not self._ok(src) or not self._ok(dst): + self._violation(operation, src, dst, *args, **kw) + return (src,dst) + + def open(self, file, flags, mode=0777): + """Called for low-level os.open()""" + if flags & WRITE_FLAGS and not self._ok(file): + self._violation("os.open", file, flags, mode) + return _os.open(file,flags,mode) + + +WRITE_FLAGS = reduce( + operator.or_, + [getattr(_os, a, 0) for a in + "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()] +) + + + + +class SandboxViolation(DistutilsError): + """A setup script attempted to modify the filesystem outside the sandbox""" + + def __str__(self): + return """SandboxViolation: %s%r %s + +The package setup script has attempted to modify files on your system +that are not within the EasyInstall build area, and has been aborted. + +This package cannot be safely installed by EasyInstall, and may not +support alternate installation locations even if you run its setup +script by hand. Please inform the package's author and the EasyInstall +maintainers to find out if a fix or workaround is available.""" % self.args + + + + + + + + + + + + + + + + + + + + + + + + + + + +# diff --git a/vendor/distribute-0.6.35/setuptools/script template (dev).py b/vendor/distribute-0.6.35/setuptools/script template (dev).py new file mode 100644 index 00000000..6dd9dd45 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/script template (dev).py @@ -0,0 +1,6 @@ +# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r +__requires__ = """%(spec)r""" +from pkg_resources import require; require("""%(spec)r""") +del require +__file__ = """%(dev_path)r""" +execfile(__file__) diff --git a/vendor/distribute-0.6.35/setuptools/script template.py b/vendor/distribute-0.6.35/setuptools/script template.py new file mode 100644 index 00000000..8dd5d510 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/script template.py @@ -0,0 +1,4 @@ +# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r +__requires__ = """%(spec)r""" +import pkg_resources +pkg_resources.run_script("""%(spec)r""", """%(script_name)r""") diff --git a/vendor/distribute-0.6.35/setuptools/tests/__init__.py b/vendor/distribute-0.6.35/setuptools/tests/__init__.py new file mode 100644 index 00000000..b6988a08 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/__init__.py @@ -0,0 +1,349 @@ +"""Tests for the 'setuptools' package""" +import sys +import os +import unittest +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 + +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 + +def makeSetup(**args): + """Return distribution from 'setup(**args)', without executing commands""" + + distutils.core._setup_stop_after = "commandline" + + # Don't let system command line leak into tests! + args.setdefault('script_args',['install']) + + try: + return setuptools.setup(**args) + finally: + distutils.core._setup_stop_after = None + + +class DependsTests(unittest.TestCase): + + def testExtractConst(self): + if not hasattr(dep, 'extract_constant'): + # skip on non-bytecode platforms + return + + def f1(): + global x, y, z + x = "test" + y = z + + # unrecognized name + self.assertEqual(dep.extract_constant(f1.func_code,'q', -1), None) + + # constant assigned + self.assertEqual(dep.extract_constant(f1.func_code,'x', -1), "test") + + # expression assigned + self.assertEqual(dep.extract_constant(f1.func_code,'y', -1), -1) + + # recognized name, not assigned + self.assertEqual(dep.extract_constant(f1.func_code,'z', -1), None) + + def testFindModule(self): + self.assertRaises(ImportError, dep.find_module, 'no-such.-thing') + self.assertRaises(ImportError, dep.find_module, 'setuptools.non-existent') + f,p,i = dep.find_module('setuptools.tests') + f.close() + + 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__ + ) + + 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') + + 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')) + + self.assertTrue(req.is_present()) + self.assertTrue(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')) + + req = Require('Do-what-I-mean','1.0','d-w-i-m') + self.assertTrue(not req.is_present()) + self.assertTrue(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') + + paths = [os.path.dirname(p) for p in __path__] + self.assertTrue(req.is_present(paths)) + self.assertTrue(req.is_current(paths)) + + +class DistroTests(unittest.TestCase): + + def setUp(self): + self.e1 = Extension('bar.ext',['bar.c']) + self.e2 = Extension('c.y', ['y.c']) + + self.dist = makeSetup( + packages=['a', 'a.b', 'a.b.c', 'b', 'c'], + py_modules=['b.d','x'], + ext_modules = (self.e1, self.e2), + package_dir = {}, + ) + + def testDistroType(self): + self.assertTrue(isinstance(self.dist,setuptools.dist.Distribution)) + + def testExcludePackage(self): + self.dist.exclude_package('a') + self.assertEqual(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]) + + 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]) + + # test removals from unspecified options + makeSetup().exclude_package('x') + + def testIncludeExclude(self): + # remove an extension + self.dist.exclude(ext_modules=[self.e1]) + self.assertEqual(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]) + + # should not add duplicate + self.dist.include(ext_modules=[self.e1]) + self.assertEqual(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]) + + def testEmpty(self): + dist = makeSetup() + dist.include(packages=['a'], py_modules=['b'], ext_modules=[self.e2]) + dist = makeSetup() + dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2]) + + def testContents(self): + self.assertTrue(self.dist.has_contents_for('a')) + self.dist.exclude_package('a') + self.assertTrue(not self.dist.has_contents_for('a')) + + self.assertTrue(self.dist.has_contents_for('b')) + self.dist.exclude_package('b') + self.assertTrue(not self.dist.has_contents_for('b')) + + self.assertTrue(self.dist.has_contents_for('c')) + self.dist.exclude_package('c') + self.assertTrue(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'] + ) + + +class FeatureTests(unittest.TestCase): + + def setUp(self): + self.req = Require('Distutils','1.0.3','distutils') + self.dist = makeSetup( + features={ + 'foo': Feature("foo",standard=True,require_features=['baz',self.req]), + 'bar': Feature("bar", standard=True, packages=['pkg.bar'], + py_modules=['bar_et'], remove=['bar.ext'], + ), + 'baz': Feature( + "baz", optional=False, packages=['pkg.baz'], + scripts = ['scripts/baz_it'], + libraries=[('libfoo','foo/foofoo.c')] + ), + 'dwim': Feature("DWIM", available=False, remove='bazish'), + }, + script_args=['--without-bar', 'install'], + packages = ['pkg.bar', 'pkg.foo'], + py_modules = ['bar_et', 'bazish'], + ext_modules = [Extension('bar.ext',['bar.c'])] + ) + + 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() + ) + # Feature must have either kwargs, removes, or require_features + self.assertRaises(DistutilsSetupError, Feature, "test") + + def testAvailability(self): + self.assertRaises( + DistutilsPlatformError, + self.dist.features['dwim'].include_in, self.dist + ) + + def testFeatureOptions(self): + dist = self.dist + self.assertTrue( + ('with-dwim',None,'include DWIM') in dist.feature_options + ) + self.assertTrue( + ('without-dwim',None,'exclude DWIM (default)') in dist.feature_options + ) + self.assertTrue( + ('with-bar',None,'include bar (default)') in dist.feature_options + ) + self.assertTrue( + ('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) + + 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]) + + # If we ask for bar, it should fail because we explicitly disabled + # it on the command line + self.assertRaises(DistutilsOptionError, dist.include_feature, 'bar') + + def testFeatureWithInvalidRemove(self): + self.assertRaises( + SystemExit, makeSetup, features = {'x':Feature('x', remove='y')} + ) + +class TestCommandTests(unittest.TestCase): + + def testTestIsCommand(self): + test_cmd = makeSetup().get_command_obj('test') + self.assertTrue(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') + + 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') + + def testDefaultWModuleOnCmdLine(self): + ts3 = makeSetup( + test_suite='bar.tests', + 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') + + 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) + + def testNoSuite(self): + ts5 = makeSetup().get_command_obj('test') + ts5.ensure_finalized() + self.assertEqual(ts5.test_suite, None) diff --git a/vendor/distribute-0.6.35/setuptools/tests/doctest.py b/vendor/distribute-0.6.35/setuptools/tests/doctest.py new file mode 100644 index 00000000..cc1e06c3 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/doctest.py @@ -0,0 +1,2683 @@ +# 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,unicode + +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 StringIO import StringIO + +# 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 <source, want> 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 = '<BLANKLINE>' +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, (str, unicode)): + 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 <source, want> 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 ('<DocTest %s from %s:%s (%s)>' % + (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<source> + (?:^(?P<indent> [ ]*) >>> .*) # PS1 line + (?:\n [ ]* \.\.\. .*)*) # PS2 lines + \n? + # Want consists of any non-blank lines that do not start with PS1. + (?P<want> (?:(?![ ]*$) # 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<hdr> Traceback\ \( + (?: most\ recent\ call\ last + | innermost\ last + ) \) : + ) + \s* $ # toss trailing whitespace on the header. + (?P<stack> .*?) # don't blink: absorb stuff until... + ^ (?P<msg> \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='<string>'): + """ + 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='<string>'): + """ + 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 object.func_globals + 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 = getattr(obj, valname).im_func + + # 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 = obj.im_func + if inspect.isfunction(obj): obj = obj.func_code + 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 = '<doctest %s[%d]>' % (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) in 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'<doctest ' + r'(?P<name>[\w\.]+)' + r'\[(?P<examplenum>\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 self.save_linecache_getlines.func_code.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 + + # <BLANKLINE> 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 <BLANKLINE> 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 <BLANKLINE>s are being used, then replace blank lines + # with <BLANKLINE> 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: <DocTest foo from foo.py:0 (2 examples)> + + >>> 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 <BLANKLINE>: + >>> print 'foo\n\nbar\n' + foo + <BLANKLINE> + bar + <BLANKLINE> + """, + + "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 --git a/vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/external.html b/vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/external.html new file mode 100644 index 00000000..92e4702f --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/external.html @@ -0,0 +1,3 @@ +<html><body> +<a href="/foobar-0.1.tar.gz#md5=1__bad_md5___">bad old link</a> +</body></html> diff --git a/vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html b/vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html new file mode 100644 index 00000000..fefb028b --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html @@ -0,0 +1,4 @@ +<html><body> +<a href="/foobar-0.1.tar.gz#md5=0_correct_md5">foobar-0.1.tar.gz</a><br/> +<a href="../../external.html" rel="homepage">external homepage</a><br/> +</body></html> diff --git a/vendor/distribute-0.6.35/setuptools/tests/py26compat.py b/vendor/distribute-0.6.35/setuptools/tests/py26compat.py new file mode 100644 index 00000000..d4fb891a --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/py26compat.py @@ -0,0 +1,14 @@ +import unittest + +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 diff --git a/vendor/distribute-0.6.35/setuptools/tests/server.py b/vendor/distribute-0.6.35/setuptools/tests/server.py new file mode 100644 index 00000000..b2ab7acc --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/server.py @@ -0,0 +1,82 @@ +"""Basic http server for tests to simulate PyPI or custom indexes +""" +import urllib2 +import sys +import time +import threading +import BaseHTTPServer +from BaseHTTPServer import HTTPServer +from SimpleHTTPServer import SimpleHTTPRequestHandler + +class IndexServer(HTTPServer): + """Basic single-threaded http server simulating a package index + + You can use this server in unittest like this:: + s = IndexServer() + s.start() + index_url = s.base_url() + 'mytestindex' + # do some test requests to the index + # The index files should be located in setuptools/tests/indexes + s.stop() + """ + def __init__(self, server_address=('', 0), + RequestHandlerClass=SimpleHTTPRequestHandler): + 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.start() + + def stop(self): + "Stop the server" + + # 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 urllib2.URLError: + # ignore any errors; all that's important is the request + pass + self.thread.join() + + def base_url(self): + port = self.server_port + return 'http://127.0.0.1:%s/setuptools/tests/indexes/' % port + +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): + """ + 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) + threading.Thread.__init__(self) + self.setDaemon(True) + self.requests = [] + + def run(self): + self.serve_forever() + + def url(self): + return 'http://localhost:%(server_port)s/' % vars(self) + url = property(url) diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_bdist_egg.py b/vendor/distribute-0.6.35/setuptools/tests/test_bdist_egg.py new file mode 100644 index 00000000..7da122cc --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_bdist_egg.py @@ -0,0 +1,69 @@ +"""develop tests +""" +import sys +import os, re, shutil, tempfile, unittest +import tempfile +import site +from StringIO import StringIO + +from distutils.errors import DistutilsError +from setuptools.command.bdist_egg import bdist_egg +from setuptools.command import easy_install as easy_install_pkg +from setuptools.dist import Distribution + +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') + f.write(SETUP_PY) + f.close() + f = open('hi.py', 'w') + 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 + + def test_bdist_egg(self): + dist = Distribution(dict( + script_name='setup.py', + script_args=['bdist_egg'], + name='foo', + py_modules=['hi'] + )) + os.makedirs(os.path.join('build', 'src')) + old_stdout = sys.stdout + sys.stdout = o = StringIO() + try: + 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) + diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_build_ext.py b/vendor/distribute-0.6.35/setuptools/tests/test_build_ext.py new file mode 100644 index 00000000..a520ced9 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_build_ext.py @@ -0,0 +1,20 @@ +"""build_ext tests +""" +import os, shutil, tempfile, unittest +from distutils.command.build_ext import build_ext as distutils_build_ext +from setuptools.command.build_ext import build_ext +from setuptools.dist import Distribution + +class TestBuildExtTest(unittest.TestCase): + + 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 + 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') + assert res == wanted + diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_develop.py b/vendor/distribute-0.6.35/setuptools/tests/test_develop.py new file mode 100644 index 00000000..315058c5 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_develop.py @@ -0,0 +1,118 @@ +"""develop tests +""" +import sys +import os, shutil, tempfile, unittest +import tempfile +import site +from StringIO import StringIO + +from distutils.errors import DistutilsError +from setuptools.command.develop import develop +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=['foo'], + use_2to3=True, +) +""" + +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') + 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') + f.write(INIT_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_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', + )) + 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: + 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']) + + # Check that we are using the right code. + egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt') + path = egg_link_file.read().split()[0].strip() + egg_link_file.close() + init_file = open(os.path.join(path, 'foo', '__init__.py'), 'rt') + init = init_file.read().strip() + 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: + error = str(e) + if error == wanted: + pass + finally: + os.chdir(old_dir) + diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_dist_info.py b/vendor/distribute-0.6.35/setuptools/tests/test_dist_info.py new file mode 100644 index 00000000..fcb78c36 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_dist_info.py @@ -0,0 +1,80 @@ +"""Test .dist-info style distributions. +""" +import os +import shutil +import tempfile +import unittest +import textwrap + +try: + import ast +except: + pass + +import pkg_resources + +from setuptools.tests.py26compat import skipIf + +def DALS(s): + "dedent and left-strip" + return textwrap.dedent(s).lstrip() + +class TestDistInfo(unittest.TestCase): + + def test_distinfo(self): + dists = {} + for d in pkg_resources.find_distributions(self.tmpdir): + dists[d.project_name] = d + + assert len(dists) == 2, dists + + unversioned = dists['UnversionedDistribution'] + versioned = dists['VersionedDistribution'] + + 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)") + def test_conditional_dependencies(self): + requires = [pkg_resources.Requirement.parse('splort==4'), + pkg_resources.Requirement.parse('quux>=1.1')] + + 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']) + + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + versioned = os.path.join(self.tmpdir, + 'VersionedDistribution-2.718.dist-info') + os.mkdir(versioned) + metadata_file = open(os.path.join(versioned, 'METADATA'), 'w+') + metadata_file.write(DALS( + """ + Metadata-Version: 1.2 + Name: VersionedDistribution + Requires-Dist: splort (4) + Provides-Extra: baz + Requires-Dist: quux (>=1.1); extra == 'baz' + """)) + metadata_file.close() + + unversioned = os.path.join(self.tmpdir, + 'UnversionedDistribution.dist-info') + os.mkdir(unversioned) + metadata_file = open(os.path.join(unversioned, 'METADATA'), 'w+') + 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' + """)) + metadata_file.close() + + def tearDown(self): + shutil.rmtree(self.tmpdir) diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_easy_install.py b/vendor/distribute-0.6.35/setuptools/tests/test_easy_install.py new file mode 100644 index 00000000..582219ce --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_easy_install.py @@ -0,0 +1,460 @@ +"""Easy install Tests +""" +import sys +import os +import shutil +import tempfile +import unittest +import site +import textwrap +import tarfile +import urlparse +import StringIO +import distutils.core + +from setuptools.sandbox import run_setup, SandboxViolation +from setuptools.command.easy_install import easy_install, fix_jython_executable, get_script_args, main +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 Distribution as PRDistribution +import setuptools.tests.server + +try: + # import multiprocessing solely for the purpose of testing its existence + __import__('multiprocessing') + import logging + _LOG = logging.getLogger('test_easy_install') + logging.basicConfig(level=logging.INFO, stream=sys.stderr) + _MULTIPROC = True +except ImportError: + _MULTIPROC = False + _LOG = None + +class FakeDist(object): + def get_entry_map(self, group): + if group != 'console_scripts': + return {} + return {'name': 'ep'} + + 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 + +if __name__ == '__main__': + sys.exit( + load_entry_point('spec', 'console_scripts', 'name')() + ) +""" % fix_jython_executable(sys.executable, "") + +SETUP_PY = """\ +from setuptools import setup + +setup(name='foo') +""" + +class TestEasyInstallTest(unittest.TestCase): + + def test_install_site_py(self): + dist = Distribution() + cmd = 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)) + finally: + shutil.rmtree(cmd.install_dir) + + def test_get_script_args(self): + dist = FakeDist() + + old_platform = sys.platform + try: + name, script = [i for i in get_script_args(dist).next()][0:2] + finally: + sys.platform = old_platform + + self.assertEqual(script, WANTED) + + def test_no_setup_cfg(self): + # makes sure easy_install as a command (main) + # doesn't use a setup.cfg file that is located + # in the current working directory + dir = tempfile.mkdtemp() + setup_cfg = open(os.path.join(dir, 'setup.cfg'), 'w') + setup_cfg.write('[easy_install]\nfind_links = http://example.com') + setup_cfg.close() + setup_py = open(os.path.join(dir, 'setup.py'), 'w') + setup_py.write(SETUP_PY) + setup_py.close() + + from setuptools.dist import Distribution + + def _parse_command_line(self): + msg = 'Error: a local setup.cfg was used' + opts = self.command_options + if 'easy_install' in opts: + assert 'find_links' not in opts['easy_install'], msg + return self._old_parse_command_line() + + Distribution._old_parse_command_line = Distribution.parse_command_line + Distribution.parse_command_line = _parse_command_line + + old_wd = os.getcwd() + try: + os.chdir(dir) + reset_setup_stop_context( + lambda: self.assertRaises(SystemExit, main, []) + ) + finally: + os.chdir(old_wd) + shutil.rmtree(dir) + Distribution.parse_command_line = Distribution._old_parse_command_line + + 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.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, {}) + + # let's try without it (default behavior) + cmd = 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 = cmd.package_index.scanned_urls.keys() + keys.sort() + self.assertEqual(keys, ['link1', 'link2']) + + +class TestPTHFileWriter(unittest.TestCase): + 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) + pth.add(PRDistribution(os.getcwd())) + self.assertTrue(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' + pth = PthDistributions('does-not_exist', [location, ]) + self.assertTrue(not pth.dirty) + pth.add(PRDistribution(location)) + self.assertTrue(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') + f.write(SETUP_PY) + f.close() + self.old_cwd = os.getcwd() + os.chdir(self.dir) + if sys.version >= "2.6": + self.old_has_site = easy_install_pkg.HAS_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) + 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 + easy_install_pkg.HAS_USER_SITE = self.old_has_site + easy_install_pkg.__file__ = self.old_file + + def test_user_install_implied(self): + easy_install_pkg.HAS_USER_SITE = True # disabled sometimes + #XXX: replace with something meaningfull + if sys.version < "2.6": + return #SKIP + dist = Distribution() + dist.script_name = 'setup.py' + cmd = easy_install(dist) + cmd.args = ['py'] + cmd.ensure_finalized() + self.assertTrue(cmd.user, 'user should be implied') + + def test_multiproc_atexit(self): + if not _MULTIPROC: + return + _LOG.info('this should not break') + + def test_user_install_not_implied_without_usersite_enabled(self): + easy_install_pkg.HAS_USER_SITE = False # usually enabled + #XXX: replace with something meaningfull + if sys.version < "2.6": + return #SKIP + 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() + + 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') + self.assertEqual(os.path.realpath(res.location), + os.path.realpath(new_location)) + 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 issue #318 + + Ensures that a package with setup_requires can be installed when + distribute is installed in the user site-packages without causing a + SandboxViolation. + """ + + test_setup_attrs = { + 'name': 'test_pkg', 'version': '0.0', + 'setup_requires': ['foobar'], + 'dependency_links': [os.path.abspath(self.dir)] + } + + test_pkg = os.path.join(self.dir, 'test_pkg') + test_setup_py = os.path.join(test_pkg, 'setup.py') + test_setup_cfg = os.path.join(test_pkg, 'setup.cfg') + 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(self.dir, 'foobar-0.1.tar.gz') + make_trivial_sdist( + foobar_path, + textwrap.dedent("""\ + import setuptools + setuptools.setup( + name='foobar', + version='0.1' + ) + """)) + + old_stdout = sys.stdout + old_stderr = sys.stderr + sys.stdout = StringIO.StringIO() + sys.stderr = StringIO.StringIO() + try: + reset_setup_stop_context( + lambda: run_setup(test_setup_py, ['install']) + ) + except SandboxViolation: + self.fail('Installation caused SandboxViolation') + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + + +class TestSetupRequires(unittest.TestCase): + + def test_setup_requires_honors_fetch_params(self): + """ + When easy_install installs a source distribution which specifies + setup_requires, it should honor the fetch parameters (such as + allow-hosts, index-url, and find-links). + """ + # set up a server which will simulate an alternate package index. + p_index = setuptools.tests.server.MockServer() + p_index.start() + netloc = 1 + p_index_loc = urlparse.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 + + # I realize this is all-but-impossible to read, because it was + # ported from some well-factored, safe code using 'with'. If you + # need to maintain this code, consider making the changes in + # the parent revision (of this comment) and then port the changes + # back for Python 2.4 (or deprecate Python 2.4). + + def install(dist_file): + def install_at(temp_install_dir): + def install_env(): + ei_params = ['--index-url', p_index.url, + '--allow-hosts', p_index_loc, + '--exclude-scripts', '--install-dir', temp_install_dir, + dist_file] + def install_clean_reset(): + def install_clean_argv(): + # attempt to install the dist. It should fail because + # it doesn't exist. + self.assertRaises(SystemExit, + easy_install_pkg.main, ei_params) + argv_context(install_clean_argv, ['easy_install']) + reset_setup_stop_context(install_clean_reset) + environment_context(install_env, PYTHONPATH=temp_install_dir) + tempdir_context(install_at) + + # create an sdist that has a build-time dependency. + self.create_sdist(install) + + # 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/') + + def create_sdist(self, installer): + """ + Create an sdist with a setup_requires dependency (of something that + doesn't exist) and invoke installer on it. + """ + def build_sdist(dir): + dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz') + make_trivial_sdist( + dist_path, + textwrap.dedent(""" + import setuptools + setuptools.setup( + name="distribute-test-fetcher", + version="1.0", + setup_requires = ['does-not-exist'], + ) + """).lstrip()) + installer(dist_path) + tempdir_context(build_sdist) + + +def make_trivial_sdist(dist_path, setup_py): + """Create a simple sdist tarball at dist_path, containing just a + setup.py, the contents of which are provided by the setup_py string. + """ + + setup_py_file = tarfile.TarInfo(name='setup.py') + try: + # Python 3 (StringIO gets converted to io module) + MemFile = StringIO.BytesIO + except AttributeError: + MemFile = StringIO.StringIO + setup_py_bytes = MemFile(setup_py.encode('utf-8')) + setup_py_file.size = len(setup_py_bytes.getvalue()) + dist = tarfile.open(dist_path, 'w:gz') + try: + dist.addfile(setup_py_file, fileobj=setup_py_bytes) + finally: + dist.close() + + +def tempdir_context(f, cd=lambda dir:None): + """ + Invoke f in the context + """ + temp_dir = tempfile.mkdtemp() + orig_dir = os.getcwd() + try: + cd(temp_dir) + f(temp_dir) + finally: + cd(orig_dir) + shutil.rmtree(temp_dir) + +def environment_context(f, **updates): + """ + Invoke f in the context + """ + old_env = os.environ.copy() + os.environ.update(updates) + try: + f() + finally: + for key in updates: + del os.environ[key] + os.environ.update(old_env) + +def argv_context(f, repl): + """ + Invoke f in the context + """ + old_argv = sys.argv[:] + sys.argv[:] = repl + try: + f() + finally: + sys.argv[:] = old_argv + +def reset_setup_stop_context(f): + """ + When the distribute 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 + try: + f() + finally: + distutils.core._setup_stop_after = setup_stop_after diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_markerlib.py b/vendor/distribute-0.6.35/setuptools/tests/test_markerlib.py new file mode 100644 index 00000000..aa461846 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_markerlib.py @@ -0,0 +1,64 @@ +import os +import unittest +from setuptools.tests.py26compat import skipIf + +try: + import ast +except ImportError: + pass + +class TestMarkerlib(unittest.TestCase): + + @skipIf('ast' not in globals(), + "ast not available (Python < 2.6?)") + 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("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("'buuuu' not in os.name")) + + 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'")) + + environment = default_environment() + environment['extra'] = 'test' + self.assertTrue(interpret("extra == 'test'", environment)) + self.assertFalse(interpret("extra == 'doc'", environment)) + + def raises_nameError(): + try: + interpret("python.version == '42'") + except NameError: + pass + else: + raise Exception("Expected NameError") + + raises_nameError() + + def raises_syntaxError(): + try: + interpret("(x for x in (4,))") + except SyntaxError: + pass + else: + raise Exception("Expected SyntaxError") + + raises_syntaxError() + + statement = "python_version == '5'" + self.assertEqual(compile(statement).__doc__, statement) + diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_packageindex.py b/vendor/distribute-0.6.35/setuptools/tests/test_packageindex.py new file mode 100644 index 00000000..3e446b54 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_packageindex.py @@ -0,0 +1,145 @@ +"""Package Index Tests +""" +import sys +import unittest +import urllib2 +import pkg_resources +import httplib +import distutils.errors +import setuptools.package_index +from server import IndexServer + +class TestPackageIndex(unittest.TestCase): + + 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: + self.assertTrue(url in str(v)) + else: + self.assertTrue(isinstance(v,urllib2.HTTPError)) + + def test_bad_url_typo(self): + # issue 16 + # easy_install inquant.contentmirror.plone breaks because of a typo + # in its home URL + index = setuptools.package_index.PackageIndex( + hosts=('www.example.com',) + ) + + url = 'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk' + try: + v = index.open_url(url) + except Exception, v: + self.assertTrue(url in str(v)) + else: + self.assertTrue(isinstance(v, urllib2.HTTPError)) + + def test_bad_url_bad_status_line(self): + index = setuptools.package_index.PackageIndex( + hosts=('www.example.com',) + ) + + def _urlopen(*args): + import httplib + raise httplib.BadStatusLine('line') + + old_urlopen = urllib2.urlopen + urllib2.urlopen = _urlopen + url = 'http://example.com' + try: + try: + v = index.open_url(url) + except Exception, v: + self.assertTrue('line' in str(v)) + else: + raise AssertionError('Should have raise here!') + finally: + urllib2.urlopen = old_urlopen + + def test_bad_url_double_scheme(self): + """ + A bad URL with a double scheme should raise a DistutilsError. + """ + index = setuptools.package_index.PackageIndex( + hosts=('www.example.com',) + ) + + # issue 20 + url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk' + try: + index.open_url(url) + except distutils.errors.DistutilsError, error: + msg = unicode(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") + + def test_bad_url_screwy_href(self): + index = setuptools.package_index.PackageIndex( + hosts=('www.example.com',) + ) + + # issue #160 + if sys.version_info[0] == 2 and sys.version_info[1] == 7: + # this should not fail + url = 'http://example.com' + page = ('<a href="http://www.famfamfam.com](' + 'http://www.famfamfam.com/">') + index.process_index(url, page) + + def test_url_ok(self): + index = setuptools.package_index.PackageIndex( + hosts=('www.example.com',) + ) + url = 'file:///tmp/test_package_index' + self.assertTrue(index.url_ok(url, True)) + + def test_links_priority(self): + """ + Download links from the pypi simple index should be used before + external download links. + http://bitbucket.org/tarek/distribute/issue/163/md5-validation-error + + Usecase : + - someone uploads a package on pypi, a md5 is generated + - someone manually copies this link (with the md5 in the url) onto an + external page accessible from the package page. + - someone reuploads the package (with a different md5) + - while easy_installing, an MD5 error occurs because the external link + is used + -> Distribute should use the link from pypi, not the external one. + """ + if sys.platform.startswith('java'): + # Skip this test on jython because binding to :0 fails + return + + # start an index server + server = IndexServer() + server.start() + index_url = server.base_url() + 'test_links_priority/simple/' + + # scan a test index + pi = setuptools.package_index.PackageIndex(index_url) + requirement = pkg_resources.Requirement.parse('foobar') + pi.find_packages(requirement) + server.stop() + + # the distribution has been found + self.assertTrue('foobar' in pi) + # we have only one link, because links are compared without md5 + self.assertTrue(len(pi['foobar'])==1) + # the link should be from the index + self.assertTrue('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')) diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_resources.py b/vendor/distribute-0.6.35/setuptools/tests/test_resources.py new file mode 100644 index 00000000..292b78d1 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_resources.py @@ -0,0 +1,645 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# NOTE: the shebang and encoding lines are for ScriptHeaderTests; do not remove +from unittest import TestCase, makeSuite; from pkg_resources import * +from setuptools.command.easy_install import get_script_header, is_sh +import os, pkg_resources, sys, StringIO, tempfile, shutil +try: frozenset +except NameError: + from sets import ImmutableSet as frozenset + +def safe_repr(obj, short=False): + """ copied from Python2.7""" + try: + result = repr(obj) + except Exception: + result = object.__repr__(obj) + if not short or len(result) < _MAX_LENGTH: + return result + return result[:_MAX_LENGTH] + ' [truncated]...' + +class Metadata(EmptyProvider): + """Mock object to return metadata as if from an on-disk distribution""" + + 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 yield_lines(self.get_metadata(name)) + +class DistroTests(TestCase): + + def testCollection(self): + # empty path should produce no distributions + ad = Environment([], platform=None, python=None) + self.assertEqual(list(ad), []) + self.assertEqual(ad['FooPkg'],[]) + ad.add(Distribution.from_filename("FooPkg-1.3_1.egg")) + ad.add(Distribution.from_filename("FooPkg-1.4-py2.4-win32.egg")) + ad.add(Distribution.from_filename("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(Distribution.from_filename("FooPkg-1.9.egg")) + self.assertEqual( + [dist.version for dist in ad['FooPkg']], ['1.9','1.4','1.2'] + ) + + ws = WorkingSet([]) + foo12 = Distribution.from_filename("FooPkg-1.2-py2.4.egg") + foo14 = Distribution.from_filename("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 = Distribution.from_filename("FooPkg-1.3_1-py2.4-win32.egg") + self.checkFooPkg(d) + d = Distribution.from_filename("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 = Environment([]); ws = WorkingSet([]) + # Resolving no requirements -> nothing to install + self.assertEqual( list(ws.resolve([],ad)), [] ) + # Request something not in the collection -> DistributionNotFound + self.assertRaises( + 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]) + 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( + 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(UnknownExtra, d.requires, ["foo"]) + + def testSetuptoolsDistributeCombination(self): + # Ensure that installing a 0.7-series setuptools fails. PJE says that + # it will not co-exist. + ws = WorkingSet([]) + d = Distribution( + "/some/path", + project_name="setuptools", + version="0.7a1") + self.assertRaises(ValueError, ws.add, d) + # A 0.6-series is no problem + d2 = Distribution( + "/some/path", + project_name="setuptools", + version="0.6c9") + ws.add(d2) + + # a unexisting version needs to work + ws = WorkingSet([]) + d3 = Distribution( + "/some/path", + project_name="setuptools") + ws.add(d3) + + +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 self.submap_expect.iteritems(): + 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(m.keys(),['xyz']) + m = EntryPoint.parse_map("[xyz]\n"+self.submap_str) + self.checkSubMap(m['xyz']) + self.assertEqual(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 testDistributeSetuptoolsOverride(self): + # Plain setuptools or distribute mean we return distribute. + self.assertEqual( + Requirement.parse('setuptools').project_name, 'distribute') + self.assertEqual( + Requirement.parse('distribute').project_name, 'distribute') + # setuptools lower than 0.7 means distribute + self.assertEqual( + Requirement.parse('setuptools==0.6c9').project_name, 'distribute') + self.assertEqual( + Requirement.parse('setuptools==0.6c10').project_name, 'distribute') + self.assertEqual( + Requirement.parse('setuptools>=0.6').project_name, 'distribute') + self.assertEqual( + Requirement.parse('setuptools < 0.7').project_name, 'distribute') + # 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): + self.assertEqual( + list( + pkg_resources.split_sections(""" + x + [Y] + z + + a + [b ] + # foo + c + [ d] + [q] + v + """ + ) + ), + [(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<p2, (s1,s2,p1,p2)) + + c('2.1','2.1.1') + c('2a1','2b0') + c('2a1','2.1') + c('2.3a1', '2.3') + c('2.1-1', '2.1-2') + c('2.1-1', '2.1.1') + c('2.1', '2.1pl4') + c('2.1a0-20040501', '2.1') + c('1.1', '02.1') + c('A56','B27') + c('3.2', '3.2.pl0') + c('3.2-1', '3.2pl1') + c('3.2pl1', '3.2pl1-1') + c('0.4', '4.0') + c('0.0.4', '0.4.0') + c('0pl1', '0.4pl1') + c('2.1.0-rc1','2.1.0') + c('2.1dev','2.1a0') + + torture =""" + 0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1 + 0.79.9999+0.80.0pre2-3 0.79.9999+0.80.0pre2-2 + 0.77.2-1 0.77.1-1 0.77.0-1 + """.split() + + for p,v1 in enumerate(torture): + for v2 in torture[p+1:]: + c(v2,v1) + + + + + + + + +class ScriptHeaderTests(TestCase): + non_ascii_exe = '/Users/José/bin/python' + + def test_get_script_header(self): + if not sys.platform.startswith('java') or not is_sh(sys.executable): + # This test is for non-Jython platforms + self.assertEqual(get_script_header('#!/usr/local/bin/python'), + '#!%s\n' % os.path.normpath(sys.executable)) + self.assertEqual(get_script_header('#!/usr/bin/python -x'), + '#!%s -x\n' % os.path.normpath(sys.executable)) + self.assertEqual(get_script_header('#!/usr/bin/python', + executable=self.non_ascii_exe), + '#!%s -x\n' % self.non_ascii_exe) + + def test_get_script_header_jython_workaround(self): + # This test doesn't work with Python 3 in some locales + if (sys.version_info >= (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 = sys.stdout + 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.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.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 = stdout + + + + +class NamespaceTests(TestCase): + + def setUp(self): + self._ns_pkgs = pkg_resources._namespace_packages.copy() + self._tmpdir = tempfile.mkdtemp(prefix="tests-distribute-") + 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, e: + self.fail("Distribute 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 --git a/vendor/distribute-0.6.35/setuptools/tests/test_sandbox.py b/vendor/distribute-0.6.35/setuptools/tests/test_sandbox.py new file mode 100644 index 00000000..1609ee86 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_sandbox.py @@ -0,0 +1,66 @@ +"""develop tests +""" +import sys +import os +import shutil +import unittest +import tempfile + +from setuptools.sandbox import DirectorySandbox, SandboxViolation + +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) + sandbox.run(self._file_writer(os.devnull)) + + def _file_writer(path): + def do_write(): + f = open(path, 'w') + f.write('xxx') + f.close() + 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) + +if __name__ == '__main__': + unittest.main() diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_sdist.py b/vendor/distribute-0.6.35/setuptools/tests/test_sdist.py new file mode 100644 index 00000000..a9d5d6e5 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_sdist.py @@ -0,0 +1,383 @@ +# -*- coding: utf-8 -*- +"""sdist tests""" + + +import os +import shutil +import sys +import tempfile +import unittest +import urllib +import unicodedata +from StringIO import StringIO + + +from setuptools.command.sdist import sdist +from setuptools.command.egg_info import manifest_maker +from setuptools.dist import Distribution + + +SETUP_ATTRS = { + 'name': 'sdist_test', + 'version': '0.0', + 'packages': ['sdist_test'], + 'package_data': {'sdist_test': ['*.txt']} +} + + +SETUP_PY = """\ +from setuptools import setup + +setup(**%r) +""" % SETUP_ATTRS + + +if sys.version_info >= (3,): + 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 +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 + + +# Fake byte literals for Python <= 2.5 +def b(s, encoding='utf-8'): + if sys.version_info >= (3,): + return s.encode(encoding) + return s + + +# Convert to POSIX path +def posix(path): + if sys.version_info >= (3,) and not isinstance(path, unicode): + return path.replace(os.sep.encode('ascii'), b('/')) + else: + return path.replace(os.sep, '/') + + +# HFS Plus uses decomposed UTF-8 +def decompose(path): + if isinstance(path, unicode): + 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 + + +class TestSdistTest(unittest.TestCase): + + def setUp(self): + 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) + # *.rst was not included in package_data, so c.rst should not be + # automatically added to the manifest when not under version control + for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']: + # Just touch the files; their contents are irrelevant + open(os.path.join(test_pkg, fname), 'w').close() + + self.old_cwd = os.getcwd() + os.chdir(self.temp_dir) + + def tearDown(self): + os.chdir(self.old_cwd) + shutil.rmtree(self.temp_dir) + + def test_package_data_in_sdist(self): + """Regression test for pull request #4: ensures that files listed in + package_data are included in the manifest even if they're not added to + version control. + """ + + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + cmd = sdist(dist) + cmd.ensure_finalized() + + # squelch output + quiet() + try: + 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) + + def test_manifest_is_written_with_utf8_encoding(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('sdist_test', 'smörbröd.py') + + # Add UTF-8 filename and write manifest + quiet() + try: + mm.run() + mm.filelist.files.append(filename) + mm.write_manifest() + finally: + unquiet() + + manifest = open(mm.manifest, 'rbU') + contents = manifest.read() + manifest.close() + + # The manifest should be UTF-8 encoded + try: + u_contents = contents.decode('UTF-8') + except UnicodeDecodeError, e: + self.fail(e) + + # 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) + + # Python 3 only + if sys.version_info >= (3,): + + 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')) + + # 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() + + # The manifest should be UTF-8 encoded + try: + contents.decode('UTF-8') + except UnicodeDecodeError, e: + self.fail(e) + + # The manifest should contain the UTF-8 filename + self.assertTrue(posix(filename) in contents) + + # The filelist should have been updated as well + self.assertTrue(u_filename in mm.filelist.files) + + 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') + + # Latin-1 filename + filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) + + # 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() + + # The manifest should be UTF-8 encoded + try: + contents.decode('UTF-8') + except UnicodeDecodeError, e: + self.fail(e) + + # The Latin-1 filename should have been skipped + self.assertFalse(posix(filename) in contents) + + # The filelist should have been updated as well + self.assertFalse(u_filename in mm.filelist.files) + + def test_manifest_is_read_with_utf8_encoding(self): + # Test for #303. + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + cmd = sdist(dist) + cmd.ensure_finalized() + + # Create manifest + quiet() + try: + 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.close() + + # The file must exist to be included in the filelist + open(filename, 'w').close() + + # Re-read manifest + cmd.filelist.files = [] + quiet() + try: + cmd.read_manifest() + finally: + unquiet() + + # The filelist should contain the UTF-8 filename + if sys.version_info >= (3,): + filename = filename.decode('utf-8') + self.assertTrue(filename in cmd.filelist.files) + + # Python 3 only + if sys.version_info >= (3,): + + 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 + 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: + 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) + + def test_sdist_with_utf8_encoded_filename(self): + # Test for #303. + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + cmd = sdist(dist) + cmd.ensure_finalized() + + # UTF-8 filename + filename = os.path.join(b('sdist_test'), b('smörbröd.py')) + open(filename, 'w').close() + + quiet() + try: + cmd.run() + finally: + unquiet() + + if sys.platform == 'darwin': + filename = decompose(filename) + + if sys.version_info >= (3,): + if sys.platform == 'win32': + # Python 3 mangles the UTF-8 filename + filename = filename.decode('cp1252') + self.assertTrue(filename in cmd.filelist.files) + else: + filename = filename.decode('utf-8') + self.assertTrue(filename in cmd.filelist.files) + else: + self.assertTrue(filename in cmd.filelist.files) + + def test_sdist_with_latin1_encoded_filename(self): + # Test for #303. + dist = Distribution(SETUP_ATTRS) + dist.script_name = 'setup.py' + cmd = sdist(dist) + cmd.ensure_finalized() + + # Latin-1 filename + filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) + open(filename, 'w').close() + + quiet() + try: + cmd.run() + finally: + unquiet() + + if sys.version_info >= (3,): + filename = filename.decode('latin-1') + if sys.platform == 'win32': + # Latin-1 is similar to Windows-1252 + self.assertTrue(filename in cmd.filelist.files) + else: + # The Latin-1 filename should have been skipped + self.assertFalse(filename 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) + + +def test_suite(): + return unittest.defaultTestLoader.loadTestsFromName(__name__) + diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_test.py b/vendor/distribute-0.6.35/setuptools/tests/test_test.py new file mode 100644 index 00000000..ad7cbd0f --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_test.py @@ -0,0 +1,124 @@ +# -*- coding: UTF-8 -*- + +"""develop tests +""" +import sys +import os, shutil, tempfile, unittest +import tempfile +import site +from StringIO import StringIO + +from distutils.errors import DistutilsError +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') + +TEST_PY = """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) +""" + +class TestTestTest(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, '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') + 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') + 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 + + dist = Distribution(dict( + name='foo', + packages=['name', 'name.space', 'name.space.tests'], + namespace_packages=['name'], + test_suite='name.space.tests.test_suite', + use_2to3=True, + )) + 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. + cmd.run() + except SystemExit: # The test runner calls sys.exit, stop that making an error. + pass + finally: + sys.stdout = old_stdout + \ No newline at end of file diff --git a/vendor/distribute-0.6.35/setuptools/tests/test_upload_docs.py b/vendor/distribute-0.6.35/setuptools/tests/test_upload_docs.py new file mode 100644 index 00000000..769f16cc --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/test_upload_docs.py @@ -0,0 +1,72 @@ +"""build_ext tests +""" +import sys, os, shutil, tempfile, unittest, site, zipfile +from setuptools.command.upload_docs import upload_docs +from setuptools.dist import Distribution + +SETUP_PY = """\ +from setuptools import setup + +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') + 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) + + # A test document. + f = open(os.path.join(self.upload_dir, 'index.html'), 'w') + f.write("Hello world.") + f.close() + + # An empty folder. + os.mkdir(os.path.join(self.upload_dir, '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 + + def test_create_zipfile(self): + # Test to make sure zipfile creation handles common cases. + # This explicitly includes 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: + 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) + diff --git a/vendor/distribute-0.6.35/setuptools/tests/win_script_wrapper.txt b/vendor/distribute-0.6.35/setuptools/tests/win_script_wrapper.txt new file mode 100644 index 00000000..9f7c81d6 --- /dev/null +++ b/vendor/distribute-0.6.35/setuptools/tests/win_script_wrapper.txt @@ -0,0 +1,151 @@ +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') + >>> 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') + >>> f.write( + ... pkg_resources.resource_string('setuptools', 'cli.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 os + >>> input, output = os.popen4('"'+nt_quote_arg(os.path.join(sample_directory, 'foo.exe')) + ... + r' arg1 "arg 2" "arg \"2\\\"" "arg 4\\" "arg5 a\\b"') + >>> input.write('hello\nworld\n') + >>> input.close() + >>> print output.read(), + \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') + >>> 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() + + >>> input, output = os.popen4(nt_quote_arg(os.path.join(sample_directory, 'foo.exe'))) + >>> input.close() + >>> print output.read(), + \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') + >>> f.write( + ... """#!%(python_exe)s + ... import sys + ... f = open(sys.argv[1], 'wb') + ... f.write(repr(sys.argv[2])) + ... 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') + >>> f.write( + ... pkg_resources.resource_string('setuptools', 'gui.exe') + ... ) + >>> f.close() + +Finally, we'll run the script and check the result: + + >>> import os + >>> input, output = os.popen4('"'+nt_quote_arg(os.path.join(sample_directory, 'bar.exe')) + ... + r' "%s" "Test Argument"' % os.path.join(sample_directory, 'test_output.txt')) + >>> input.close() + >>> print output.read() + <BLANKLINE> + >>> f = open(os.path.join(sample_directory, 'test_output.txt'), 'rb') + >>> print f.read() + 'Test Argument' + >>> f.close() + + +We're done with the sample_directory: + + >>> import shutil + >>> shutil.rmtree(sample_directory) + diff --git a/vendor/distribute-0.6.35/site.py b/vendor/distribute-0.6.35/site.py new file mode 100644 index 00000000..a7166f14 --- /dev/null +++ b/vendor/distribute-0.6.35/site.py @@ -0,0 +1,83 @@ +def __boot(): + import sys, os, os.path + PYTHONPATH = os.environ.get('PYTHONPATH') + if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH): + PYTHONPATH = [] + else: + PYTHONPATH = PYTHONPATH.split(os.pathsep) + + pic = getattr(sys,'path_importer_cache',{}) + stdpath = sys.path[len(PYTHONPATH):] + mydir = os.path.dirname(__file__) + #print "searching",stdpath,sys.path + + for item in stdpath: + if item==mydir or not item: + continue # skip if current dir. on Windows, or my own directory + importer = pic.get(item) + if importer is not None: + loader = importer.find_module('site') + if loader is not None: + # This should actually reload the current module + loader.load_module('site') + break + else: + try: + import imp # Avoid import loop in Python >= 3.3 + stream, path, descr = imp.find_module('site',[item]) + except ImportError: + continue + if stream is None: + continue + try: + # This should actually reload the current module + imp.load_module('site',stream,path,descr) + finally: + stream.close() + break + else: + raise ImportError("Couldn't find the real 'site' module") + + #print "loaded", __file__ + + known_paths = dict([(makepath(item)[1],1) for item in sys.path]) # 2.2 comp + + oldpos = getattr(sys,'__egginsert',0) # save old insertion position + sys.__egginsert = 0 # and reset the current one + + for item in PYTHONPATH: + addsitedir(item) + + sys.__egginsert += oldpos # restore effective old position + + d,nd = makepath(stdpath[0]) + insert_at = None + new_path = [] + + for item in sys.path: + p,np = makepath(item) + + if np==nd and insert_at is None: + # We've hit the first 'system' path entry, so added entries go here + insert_at = len(new_path) + + if np in known_paths or insert_at is None: + new_path.append(item) + else: + # new path after the insert point, back-insert it + new_path.insert(insert_at, item) + insert_at += 1 + + sys.path[:] = new_path + +if __name__=='site': + __boot() + del __boot + + + + + + + + diff --git a/vendor/distribute-0.6.35/tests/api_tests.txt b/vendor/distribute-0.6.35/tests/api_tests.txt new file mode 100644 index 00000000..6cf6e66f --- /dev/null +++ b/vendor/distribute-0.6.35/tests/api_tests.txt @@ -0,0 +1,330 @@ +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, VersionConflict + +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.__file__] + True + +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 VersionConflict: + ... print 'ok' + ok + +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", 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 + diff --git a/vendor/distribute-0.6.35/tests/install_test.py b/vendor/distribute-0.6.35/tests/install_test.py new file mode 100644 index 00000000..02deb818 --- /dev/null +++ b/vendor/distribute-0.6.35/tests/install_test.py @@ -0,0 +1,75 @@ +import urllib2 +import sys +import os + +if os.path.exists('distribute_setup.py'): + print 'distribute_setup.py exists in the current dir, aborting' + sys.exit(2) + +print '**** Starting Test' +print '\n\n' + +is_jython = sys.platform.startswith('java') +if is_jython: + import subprocess + +print 'Downloading bootstrap' +file = urllib2.urlopen('http://nightly.ziade.org/distribute_setup.py') +f = open('distribute_setup.py', 'w') +f.write(file.read()) +f.close() + +# running it +args = [sys.executable] + ['distribute_setup.py'] +if is_jython: + res = subprocess.call(args) +else: + res = os.spawnv(os.P_WAIT, sys.executable, args) + +if res != 0: + print '**** Test failed, please send me the output at tarek@ziade.org' + os.remove('distribute_setup.py') + sys.exit(2) + +# now checking if Distribute is installed +script = """\ +import sys +try: + import setuptools +except ImportError: + sys.exit(0) + +sys.exit(hasattr(setuptools, "_distribute")) +""" + +root = 'script' +seed = 0 +script_name = '%s%d.py' % (root, seed) + +while os.path.exists(script_name): + seed += 1 + script_name = '%s%d.py' % (root, seed) + +f = open(script_name, 'w') +try: + f.write(script) +finally: + f.close() + +try: + args = [sys.executable] + [script_name] + if is_jython: + res = subprocess.call(args) + else: + res = os.spawnv(os.P_WAIT, sys.executable, args) + + print '\n\n' + if res: + print '**** Test is OK' + else: + print '**** Test failed, please send me the output at tarek@ziade.org' +finally: + if os.path.exists(script_name): + os.remove(script_name) + os.remove('distribute_setup.py') + diff --git a/vendor/distribute-0.6.35/tests/manual_test.py b/vendor/distribute-0.6.35/tests/manual_test.py new file mode 100644 index 00000000..0d5051f1 --- /dev/null +++ b/vendor/distribute-0.6.35/tests/manual_test.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +import sys + +if sys.version_info[0] >= 3: + raise NotImplementedError('Py3 not supported in this test yet') + +import os +import shutil +import tempfile +from distutils.command.install import INSTALL_SCHEMES +from string import Template +from urllib2 import urlopen + +try: + import subprocess + def _system_call(*args): + assert subprocess.call(args) == 0 +except ImportError: + # Python 2.3 + def _system_call(*args): + # quoting arguments if windows + if sys.platform == 'win32': + def quote(arg): + if ' ' in arg: + return '"%s"' % arg + return arg + args = [quote(arg) for arg in args] + assert os.system(' '.join(args)) == 0 + +def tempdir(func): + def _tempdir(*args, **kwargs): + test_dir = tempfile.mkdtemp() + old_dir = os.getcwd() + os.chdir(test_dir) + try: + return func(*args, **kwargs) + finally: + os.chdir(old_dir) + shutil.rmtree(test_dir) + return _tempdir + +SIMPLE_BUILDOUT = """\ +[buildout] + +parts = eggs + +[eggs] +recipe = zc.recipe.egg + +eggs = + extensions +""" + +BOOTSTRAP = 'http://python-distribute.org/bootstrap.py' +PYVER = sys.version.split()[0][:3] +DEV_URL = 'http://bitbucket.org/tarek/distribute/get/0.6-maintenance.zip#egg=distribute-dev' + +_VARS = {'base': '.', + 'py_version_short': PYVER} + +if sys.platform == 'win32': + PURELIB = INSTALL_SCHEMES['nt']['purelib'] +else: + PURELIB = INSTALL_SCHEMES['unix_prefix']['purelib'] + + +@tempdir +def test_virtualenv(): + """virtualenv with distribute""" + purelib = os.path.abspath(Template(PURELIB).substitute(**_VARS)) + _system_call('virtualenv', '--no-site-packages', '.', '--distribute') + _system_call('bin/easy_install', 'distribute==dev') + # linux specific + site_pkg = os.listdir(purelib) + site_pkg.sort() + assert 'distribute' in site_pkg[0] + easy_install = os.path.join(purelib, 'easy-install.pth') + with open(easy_install) as f: + res = f.read() + assert 'distribute' in res + assert 'setuptools' not in res + +@tempdir +def test_full(): + """virtualenv + pip + buildout""" + _system_call('virtualenv', '--no-site-packages', '.') + _system_call('bin/easy_install', '-q', 'distribute==dev') + _system_call('bin/easy_install', '-qU', 'distribute==dev') + _system_call('bin/easy_install', '-q', 'pip') + _system_call('bin/pip', 'install', '-q', 'zc.buildout') + + with open('buildout.cfg', 'w') as f: + f.write(SIMPLE_BUILDOUT) + + with open('bootstrap.py', 'w') as f: + f.write(urlopen(BOOTSTRAP).read()) + + _system_call('bin/python', 'bootstrap.py', '--distribute') + _system_call('bin/buildout', '-q') + eggs = os.listdir('eggs') + eggs.sort() + assert len(eggs) == 3 + assert eggs[0].startswith('distribute') + assert eggs[1:] == ['extensions-0.3-py2.6.egg', + 'zc.recipe.egg-1.2.2-py2.6.egg'] + +if __name__ == '__main__': + test_virtualenv() + test_full() + diff --git a/vendor/distribute-0.6.35/tests/shlib_test/hello.c b/vendor/distribute-0.6.35/tests/shlib_test/hello.c new file mode 100644 index 00000000..9998372c --- /dev/null +++ b/vendor/distribute-0.6.35/tests/shlib_test/hello.c @@ -0,0 +1,168 @@ +/* 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 --git a/vendor/distribute-0.6.35/tests/shlib_test/hello.pyx b/vendor/distribute-0.6.35/tests/shlib_test/hello.pyx new file mode 100644 index 00000000..58ce6919 --- /dev/null +++ b/vendor/distribute-0.6.35/tests/shlib_test/hello.pyx @@ -0,0 +1,4 @@ +cdef extern char *get_hello_msg() + +def hello(): + return get_hello_msg() diff --git a/vendor/distribute-0.6.35/tests/shlib_test/hellolib.c b/vendor/distribute-0.6.35/tests/shlib_test/hellolib.c new file mode 100644 index 00000000..88d65cee --- /dev/null +++ b/vendor/distribute-0.6.35/tests/shlib_test/hellolib.c @@ -0,0 +1,3 @@ +extern char* get_hello_msg() { + return "Hello, world!"; +} diff --git a/vendor/distribute-0.6.35/tests/shlib_test/setup.py b/vendor/distribute-0.6.35/tests/shlib_test/setup.py new file mode 100644 index 00000000..b0c93996 --- /dev/null +++ b/vendor/distribute-0.6.35/tests/shlib_test/setup.py @@ -0,0 +1,10 @@ +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 --git a/vendor/distribute-0.6.35/tests/shlib_test/test_hello.py b/vendor/distribute-0.6.35/tests/shlib_test/test_hello.py new file mode 100644 index 00000000..6da02e31 --- /dev/null +++ b/vendor/distribute-0.6.35/tests/shlib_test/test_hello.py @@ -0,0 +1,7 @@ +from unittest import TestCase + +class HelloWorldTest(TestCase): + def testHelloMsg(self): + from hello import hello + self.assertEqual(hello(), "Hello, world!") + diff --git a/vendor/distribute-0.6.35/tests/test_distribute_setup.py b/vendor/distribute-0.6.35/tests/test_distribute_setup.py new file mode 100644 index 00000000..1f3da058 --- /dev/null +++ b/vendor/distribute-0.6.35/tests/test_distribute_setup.py @@ -0,0 +1,73 @@ +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 distribute_setup import (use_setuptools, _build_egg, _python_cmd, + _do_download, _install, DEFAULT_URL, + DEFAULT_VERSION) +import distribute_setup + +class TestSetup(unittest.TestCase): + + def urlopen(self, url): + return open(self.tarball) + + 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) + 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(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 + distribute_setup.python_cmd = _faked + _install(self.tarball) + + def test_use_setuptools(self): + self.assertEqual(use_setuptools(), None) + + # make sure fake_setuptools is not called by default + import pkg_resources + del pkg_resources._distribute + def fake_setuptools(*args): + raise AssertionError + + pkg_resources._fake_setuptools = fake_setuptools + use_setuptools() + +if __name__ == '__main__': + unittest.main() -- GitLab