From 1abaaf6cf148f3f2776b3cb38c70bcf560a9ee90 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 19 Dec 2012 22:45:05 -0500 Subject: [PATCH] update deps --- bin/typescript | 3 + vendor/distribute-0.6.31/CHANGES.txt | 459 +++ vendor/distribute-0.6.31/CONTRIBUTORS.txt | 30 + vendor/distribute-0.6.31/DEVGUIDE.txt | 22 + vendor/distribute-0.6.31/MANIFEST.in | 9 + vendor/distribute-0.6.31/PKG-INFO | 837 +++++ vendor/distribute-0.6.31/README.txt | 228 ++ .../distribute-0.6.31/_markerlib/__init__.py | 16 + .../distribute-0.6.31/_markerlib/markers.py | 106 + .../distribute_setup.py | 0 vendor/distribute-0.6.31/docs/Makefile | 75 + .../docs/_templates/indexsidebar.html | 8 + .../docs/_theme/nature/static/nature.css_t | 122 +- .../docs/_theme/nature/static/pygments.css | 0 .../docs/_theme/nature/theme.conf | 0 vendor/distribute-0.6.31/docs/conf.py | 197 + .../distribute-0.6.31/docs/easy_install.txt | 1597 ++++++++ vendor/distribute-0.6.31/docs/index.txt | 36 + .../distribute-0.6.31/docs/pkg_resources.txt | 1955 ++++++++++ vendor/distribute-0.6.31/docs/python3.txt | 121 + vendor/distribute-0.6.31/docs/roadmap.txt | 86 + vendor/distribute-0.6.31/docs/setuptools.txt | 3236 +++++++++++++++++ vendor/distribute-0.6.31/docs/using.txt | 21 + vendor/distribute-0.6.31/easy_install.py | 5 + vendor/distribute-0.6.31/launcher.c | 327 ++ vendor/distribute-0.6.31/pkg_resources.py | 2851 +++++++++++++++ vendor/distribute-0.6.31/release.py | 170 + vendor/distribute-0.6.31/setup.cfg | 21 + vendor/distribute-0.6.31/setup.py | 245 ++ .../distribute-0.6.31/setuptools/__init__.py | 104 + .../setuptools/archive_util.py | 214 ++ .../distribute-0.6.31/setuptools/cli-32.exe | Bin 0 -> 69632 bytes .../distribute-0.6.31/setuptools/cli-64.exe | Bin 0 -> 75264 bytes vendor/distribute-0.6.31/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 | 165 + .../setuptools/command/easy_install.py | 1942 ++++++++++ .../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 | 184 + .../setuptools/command/upload_docs.py | 193 + .../distribute-0.6.31/setuptools/depends.py | 246 ++ vendor/distribute-0.6.31/setuptools/dist.py | 856 +++++ .../distribute-0.6.31/setuptools/extension.py | 46 + .../distribute-0.6.31/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../distribute-0.6.31/setuptools/gui-64.exe | Bin 0 -> 75264 bytes vendor/distribute-0.6.31/setuptools/gui.exe | Bin 0 -> 65536 bytes .../setuptools/package_index.py | 920 +++++ .../distribute-0.6.31/setuptools/sandbox.py | 290 ++ .../setuptools/script template (dev).py | 6 + .../setuptools/script template.py | 4 + .../setuptools/tests/__init__.py | 349 ++ .../setuptools/tests/doctest.py | 2679 ++++++++++++++ .../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 | 114 + .../setuptools/tests/test_dist_info.py | 80 + .../setuptools/tests/test_easy_install.py | 526 +++ .../setuptools/tests/test_markerlib.py | 64 + .../setuptools/tests/test_packageindex.py | 145 + .../setuptools/tests/test_resources.py | 649 ++++ .../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 | 137 + vendor/distribute-0.6.31/site.py | 83 + vendor/distribute-0.6.31/tests/api_tests.txt | 330 ++ .../distribute-0.6.31/tests/install_test.py | 75 + vendor/distribute-0.6.31/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 + .../virtualenv_support => }/pip-1.2.1.tar.gz | Bin vendor/pip-1.2.1/.gitignore | 23 + vendor/pip-1.2.1/AUTHORS.txt | 48 + .../LICENSE.txt | 4 +- vendor/pip-1.2.1/MANIFEST.in | 6 + vendor/pip-1.2.1/contrib/build-installer | 38 + vendor/pip-1.2.1/contrib/build-standalone | 38 + vendor/pip-1.2.1/contrib/get-pip.py | 1153 ++++++ vendor/pip-1.2.1/contrib/packager/__init__.py | 68 + vendor/pip-1.2.1/contrib/packager/template.py | 48 + .../docs/Makefile | 0 .../docs/_static/launch-jnlp-slave.JPG | Bin 0 -> 112547 bytes .../docs/_static/slave-launch-icon.png | Bin 0 -> 46369 bytes .../docs/_theme/nature/static/nature.css_t | 237 ++ .../docs/_theme/nature/static/pygments.css | 54 + .../pip-1.2.1/docs/_theme/nature/theme.conf | 4 + .../pip-1.2.1/docs/ci-server-step-by-step.txt | 252 ++ vendor/pip-1.2.1/docs/conf.py | 195 + vendor/pip-1.2.1/docs/configuration.txt | 141 + vendor/pip-1.2.1/docs/contributing.txt | 167 + vendor/pip-1.2.1/docs/glossary.txt | 12 + vendor/pip-1.2.1/docs/index.txt | 54 + vendor/pip-1.2.1/docs/installing.txt | 66 + .../docs/make.bat | 0 vendor/pip-1.2.1/docs/news.txt | 558 +++ vendor/pip-1.2.1/docs/other-tools.txt | 131 + vendor/pip-1.2.1/docs/requirements.txt | 246 ++ vendor/pip-1.2.1/docs/usage.txt | 160 + vendor/pip-1.2.1/pip/__init__.py | 268 ++ vendor/pip-1.2.1/pip/_pkgutil.py | 592 +++ vendor/pip-1.2.1/pip/backwardcompat.py | 135 + vendor/pip-1.2.1/pip/basecommand.py | 193 + vendor/pip-1.2.1/pip/baseparser.py | 226 ++ vendor/pip-1.2.1/pip/commands/__init__.py | 1 + vendor/pip-1.2.1/pip/commands/bundle.py | 38 + vendor/pip-1.2.1/pip/commands/completion.py | 60 + vendor/pip-1.2.1/pip/commands/freeze.py | 111 + vendor/pip-1.2.1/pip/commands/help.py | 33 + vendor/pip-1.2.1/pip/commands/install.py | 279 ++ vendor/pip-1.2.1/pip/commands/search.py | 127 + vendor/pip-1.2.1/pip/commands/uninstall.py | 43 + vendor/pip-1.2.1/pip/commands/unzip.py | 9 + vendor/pip-1.2.1/pip/commands/zip.py | 346 ++ vendor/pip-1.2.1/pip/download.py | 481 +++ vendor/pip-1.2.1/pip/exceptions.py | 27 + vendor/pip-1.2.1/pip/index.py | 708 ++++ vendor/pip-1.2.1/pip/locations.py | 52 + vendor/pip-1.2.1/pip/log.py | 188 + vendor/pip-1.2.1/pip/req.py | 1517 ++++++++ vendor/pip-1.2.1/pip/runner.py | 18 + vendor/pip-1.2.1/pip/status_codes.py | 5 + vendor/pip-1.2.1/pip/util.py | 509 +++ vendor/pip-1.2.1/pip/vcs/__init__.py | 244 ++ vendor/pip-1.2.1/pip/vcs/bazaar.py | 129 + vendor/pip-1.2.1/pip/vcs/git.py | 206 ++ vendor/pip-1.2.1/pip/vcs/mercurial.py | 151 + vendor/pip-1.2.1/pip/vcs/subversion.py | 272 ++ vendor/pip-1.2.1/setup.cfg | 2 + vendor/pip-1.2.1/setup.py | 55 + .../tests}/__init__.py | 0 .../tests/in dex/FSPkg/FSPkg-0.1dev.tar.gz | Bin 0 -> 1034 bytes .../pip-1.2.1/tests/in dex/FSPkg/index.html | 3 + vendor/pip-1.2.1/tests/in dex/README.txt | 2 + vendor/pip-1.2.1/tests/local_repos.py | 75 + .../tests/packages/BrokenEmitsUTF8/broken.py | 0 .../tests/packages/BrokenEmitsUTF8/setup.py | 25 + .../tests/packages/FSPkg/fspkg/__init__.py | 1 + .../pip-1.2.1/tests/packages/FSPkg/setup.cfg | 3 + .../pip-1.2.1/tests/packages/FSPkg/setup.py | 25 + .../tests/packages/LineEndings/setup.py | 3 + vendor/pip-1.2.1/tests/packages/README.txt | 6 + .../tests/packages/broken-0.1.tar.gz | Bin 0 -> 407 bytes .../tests/packages/broken-0.2broken.tar.gz | Bin 0 -> 509 bytes .../pip-1.2.1/tests/packages/paxpkg.tar.bz2 | Bin 0 -> 1094 bytes .../pkgwithmpkg-1.0-py2.7-macosx10.7.mpkg.zip | 0 .../tests/packages/pkgwithmpkg-1.0.tar.gz | 0 vendor/pip-1.2.1/tests/path.py | 209 ++ vendor/pip-1.2.1/tests/pypi_server.py | 129 + vendor/pip-1.2.1/tests/test_all_pip.py | 118 + vendor/pip-1.2.1/tests/test_basic.py | 603 +++ vendor/pip-1.2.1/tests/test_bundle.py | 33 + vendor/pip-1.2.1/tests/test_cleanup.py | 114 + vendor/pip-1.2.1/tests/test_compat.py | 56 + vendor/pip-1.2.1/tests/test_completion.py | 95 + vendor/pip-1.2.1/tests/test_config.py | 152 + vendor/pip-1.2.1/tests/test_download.py | 43 + vendor/pip-1.2.1/tests/test_extras.py | 27 + .../pip-1.2.1/tests/test_file_scheme_index.py | 16 + vendor/pip-1.2.1/tests/test_finder.py | 18 + vendor/pip-1.2.1/tests/test_freeze.py | 241 ++ vendor/pip-1.2.1/tests/test_help.py | 66 + vendor/pip-1.2.1/tests/test_index.py | 28 + vendor/pip-1.2.1/tests/test_pip.py | 618 ++++ vendor/pip-1.2.1/tests/test_proxy.py | 64 + vendor/pip-1.2.1/tests/test_requirements.py | 108 + vendor/pip-1.2.1/tests/test_search.py | 131 + vendor/pip-1.2.1/tests/test_unicode.py | 25 + vendor/pip-1.2.1/tests/test_uninstall.py | 139 + vendor/pip-1.2.1/tests/test_upgrade.py | 192 + vendor/pip-1.2.1/tests/test_vcs_backends.py | 131 + vendor/pip-1.2.1/tests/test_vcs_bazaar.py | 29 + vendor/pip-1.2.1/tests/test_vcs_git.py | 77 + vendor/pip-1.2.1/tests/test_vcs_subversion.py | 21 + vendor/virtualenv-1.8.4/AUTHORS.txt | 58 - vendor/virtualenv-1.8.4/MANIFEST.in | 11 - vendor/virtualenv-1.8.4/PKG-INFO | 1208 ------ vendor/virtualenv-1.8.4/README.rst | 7 - vendor/virtualenv-1.8.4/bin/rebuild-script.py | 71 - .../bin/refresh-support-files.py | 59 - vendor/virtualenv-1.8.4/docs/conf.py | 139 - vendor/virtualenv-1.8.4/docs/index.txt | 573 --- vendor/virtualenv-1.8.4/docs/news.txt | 626 ---- vendor/virtualenv-1.8.4/scripts/virtualenv | 3 - vendor/virtualenv-1.8.4/setup.cfg | 5 - vendor/virtualenv-1.8.4/setup.py | 91 - .../virtualenv.egg-info/PKG-INFO | 1208 ------ .../virtualenv.egg-info/SOURCES.txt | 42 - .../virtualenv.egg-info/dependency_links.txt | 1 - .../virtualenv.egg-info/entry_points.txt | 4 - .../virtualenv.egg-info/not-zip-safe | 1 - .../virtualenv.egg-info/top_level.txt | 2 - vendor/virtualenv-1.8.4/virtualenv.py | 2564 ------------- .../virtualenv_embedded/activate.bat | 26 - .../virtualenv_embedded/activate.csh | 42 - .../virtualenv_embedded/activate.fish | 74 - .../virtualenv_embedded/activate.ps1 | 148 - .../virtualenv_embedded/activate.sh | 80 - .../virtualenv_embedded/activate_this.py | 34 - .../virtualenv_embedded/deactivate.bat | 18 - .../distribute_from_egg.py | 8 - .../virtualenv_embedded/distutils-init.py | 101 - .../virtualenv_embedded/distutils.cfg | 6 - .../virtualenv_embedded/ez_setup.py | 284 -- .../virtualenv_embedded/site.py | 743 ---- .../distribute-0.6.31.tar.gz | Bin 643910 -> 0 bytes .../setuptools-0.6c11-py2.5.egg | Bin 333390 -> 0 bytes .../setuptools-0.6c11-py2.6.egg | Bin 333447 -> 0 bytes .../setuptools-0.6c11-py2.7.egg | Bin 332005 -> 0 bytes 233 files changed, 41701 insertions(+), 8297 deletions(-) create mode 100644 bin/typescript create mode 100644 vendor/distribute-0.6.31/CHANGES.txt create mode 100644 vendor/distribute-0.6.31/CONTRIBUTORS.txt create mode 100644 vendor/distribute-0.6.31/DEVGUIDE.txt create mode 100644 vendor/distribute-0.6.31/MANIFEST.in create mode 100644 vendor/distribute-0.6.31/PKG-INFO create mode 100644 vendor/distribute-0.6.31/README.txt create mode 100644 vendor/distribute-0.6.31/_markerlib/__init__.py create mode 100644 vendor/distribute-0.6.31/_markerlib/markers.py rename vendor/{virtualenv-1.8.4/virtualenv_embedded => distribute-0.6.31}/distribute_setup.py (100%) create mode 100644 vendor/distribute-0.6.31/docs/Makefile create mode 100644 vendor/distribute-0.6.31/docs/_templates/indexsidebar.html rename vendor/{virtualenv-1.8.4 => distribute-0.6.31}/docs/_theme/nature/static/nature.css_t (61%) rename vendor/{virtualenv-1.8.4 => distribute-0.6.31}/docs/_theme/nature/static/pygments.css (100%) rename vendor/{virtualenv-1.8.4 => distribute-0.6.31}/docs/_theme/nature/theme.conf (100%) create mode 100644 vendor/distribute-0.6.31/docs/conf.py create mode 100644 vendor/distribute-0.6.31/docs/easy_install.txt create mode 100644 vendor/distribute-0.6.31/docs/index.txt create mode 100644 vendor/distribute-0.6.31/docs/pkg_resources.txt create mode 100644 vendor/distribute-0.6.31/docs/python3.txt create mode 100644 vendor/distribute-0.6.31/docs/roadmap.txt create mode 100644 vendor/distribute-0.6.31/docs/setuptools.txt create mode 100644 vendor/distribute-0.6.31/docs/using.txt create mode 100644 vendor/distribute-0.6.31/easy_install.py create mode 100644 vendor/distribute-0.6.31/launcher.c create mode 100644 vendor/distribute-0.6.31/pkg_resources.py create mode 100644 vendor/distribute-0.6.31/release.py create mode 100644 vendor/distribute-0.6.31/setup.cfg create mode 100644 vendor/distribute-0.6.31/setup.py create mode 100644 vendor/distribute-0.6.31/setuptools/__init__.py create mode 100644 vendor/distribute-0.6.31/setuptools/archive_util.py create mode 100755 vendor/distribute-0.6.31/setuptools/cli-32.exe create mode 100755 vendor/distribute-0.6.31/setuptools/cli-64.exe create mode 100755 vendor/distribute-0.6.31/setuptools/cli.exe create mode 100644 vendor/distribute-0.6.31/setuptools/command/__init__.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/alias.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/bdist_egg.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/bdist_rpm.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/bdist_wininst.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/build_ext.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/build_py.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/develop.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/easy_install.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/egg_info.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/install.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/install_egg_info.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/install_lib.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/install_scripts.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/register.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/rotate.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/saveopts.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/sdist.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/setopt.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/test.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/upload.py create mode 100644 vendor/distribute-0.6.31/setuptools/command/upload_docs.py create mode 100644 vendor/distribute-0.6.31/setuptools/depends.py create mode 100644 vendor/distribute-0.6.31/setuptools/dist.py create mode 100644 vendor/distribute-0.6.31/setuptools/extension.py create mode 100755 vendor/distribute-0.6.31/setuptools/gui-32.exe create mode 100755 vendor/distribute-0.6.31/setuptools/gui-64.exe create mode 100755 vendor/distribute-0.6.31/setuptools/gui.exe create mode 100644 vendor/distribute-0.6.31/setuptools/package_index.py create mode 100644 vendor/distribute-0.6.31/setuptools/sandbox.py create mode 100644 vendor/distribute-0.6.31/setuptools/script template (dev).py create mode 100644 vendor/distribute-0.6.31/setuptools/script template.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/__init__.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/doctest.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/external.html create mode 100644 vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html create mode 100644 vendor/distribute-0.6.31/setuptools/tests/py26compat.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/server.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_bdist_egg.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_build_ext.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_develop.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_dist_info.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_easy_install.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_markerlib.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_packageindex.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_resources.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_sandbox.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_sdist.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_test.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/test_upload_docs.py create mode 100644 vendor/distribute-0.6.31/setuptools/tests/win_script_wrapper.txt create mode 100644 vendor/distribute-0.6.31/site.py create mode 100644 vendor/distribute-0.6.31/tests/api_tests.txt create mode 100644 vendor/distribute-0.6.31/tests/install_test.py create mode 100644 vendor/distribute-0.6.31/tests/manual_test.py create mode 100644 vendor/distribute-0.6.31/tests/shlib_test/hello.c create mode 100644 vendor/distribute-0.6.31/tests/shlib_test/hello.pyx create mode 100644 vendor/distribute-0.6.31/tests/shlib_test/hellolib.c create mode 100644 vendor/distribute-0.6.31/tests/shlib_test/setup.py create mode 100644 vendor/distribute-0.6.31/tests/shlib_test/test_hello.py create mode 100644 vendor/distribute-0.6.31/tests/test_distribute_setup.py rename vendor/{virtualenv-1.8.4/virtualenv_support => }/pip-1.2.1.tar.gz (100%) create mode 100644 vendor/pip-1.2.1/.gitignore create mode 100644 vendor/pip-1.2.1/AUTHORS.txt rename vendor/{virtualenv-1.8.4 => pip-1.2.1}/LICENSE.txt (86%) create mode 100644 vendor/pip-1.2.1/MANIFEST.in create mode 100755 vendor/pip-1.2.1/contrib/build-installer create mode 100755 vendor/pip-1.2.1/contrib/build-standalone create mode 100755 vendor/pip-1.2.1/contrib/get-pip.py create mode 100644 vendor/pip-1.2.1/contrib/packager/__init__.py create mode 100644 vendor/pip-1.2.1/contrib/packager/template.py rename vendor/{virtualenv-1.8.4 => pip-1.2.1}/docs/Makefile (100%) create mode 100644 vendor/pip-1.2.1/docs/_static/launch-jnlp-slave.JPG create mode 100644 vendor/pip-1.2.1/docs/_static/slave-launch-icon.png create mode 100644 vendor/pip-1.2.1/docs/_theme/nature/static/nature.css_t create mode 100644 vendor/pip-1.2.1/docs/_theme/nature/static/pygments.css create mode 100644 vendor/pip-1.2.1/docs/_theme/nature/theme.conf create mode 100644 vendor/pip-1.2.1/docs/ci-server-step-by-step.txt create mode 100644 vendor/pip-1.2.1/docs/conf.py create mode 100644 vendor/pip-1.2.1/docs/configuration.txt create mode 100644 vendor/pip-1.2.1/docs/contributing.txt create mode 100644 vendor/pip-1.2.1/docs/glossary.txt create mode 100644 vendor/pip-1.2.1/docs/index.txt create mode 100644 vendor/pip-1.2.1/docs/installing.txt rename vendor/{virtualenv-1.8.4 => pip-1.2.1}/docs/make.bat (100%) create mode 100644 vendor/pip-1.2.1/docs/news.txt create mode 100644 vendor/pip-1.2.1/docs/other-tools.txt create mode 100644 vendor/pip-1.2.1/docs/requirements.txt create mode 100644 vendor/pip-1.2.1/docs/usage.txt create mode 100755 vendor/pip-1.2.1/pip/__init__.py create mode 100644 vendor/pip-1.2.1/pip/_pkgutil.py create mode 100644 vendor/pip-1.2.1/pip/backwardcompat.py create mode 100644 vendor/pip-1.2.1/pip/basecommand.py create mode 100644 vendor/pip-1.2.1/pip/baseparser.py create mode 100644 vendor/pip-1.2.1/pip/commands/__init__.py create mode 100644 vendor/pip-1.2.1/pip/commands/bundle.py create mode 100644 vendor/pip-1.2.1/pip/commands/completion.py create mode 100644 vendor/pip-1.2.1/pip/commands/freeze.py create mode 100644 vendor/pip-1.2.1/pip/commands/help.py create mode 100644 vendor/pip-1.2.1/pip/commands/install.py create mode 100644 vendor/pip-1.2.1/pip/commands/search.py create mode 100644 vendor/pip-1.2.1/pip/commands/uninstall.py create mode 100644 vendor/pip-1.2.1/pip/commands/unzip.py create mode 100644 vendor/pip-1.2.1/pip/commands/zip.py create mode 100644 vendor/pip-1.2.1/pip/download.py create mode 100644 vendor/pip-1.2.1/pip/exceptions.py create mode 100644 vendor/pip-1.2.1/pip/index.py create mode 100644 vendor/pip-1.2.1/pip/locations.py create mode 100644 vendor/pip-1.2.1/pip/log.py create mode 100644 vendor/pip-1.2.1/pip/req.py create mode 100644 vendor/pip-1.2.1/pip/runner.py create mode 100644 vendor/pip-1.2.1/pip/status_codes.py create mode 100644 vendor/pip-1.2.1/pip/util.py create mode 100644 vendor/pip-1.2.1/pip/vcs/__init__.py create mode 100644 vendor/pip-1.2.1/pip/vcs/bazaar.py create mode 100644 vendor/pip-1.2.1/pip/vcs/git.py create mode 100644 vendor/pip-1.2.1/pip/vcs/mercurial.py create mode 100644 vendor/pip-1.2.1/pip/vcs/subversion.py create mode 100644 vendor/pip-1.2.1/setup.cfg create mode 100644 vendor/pip-1.2.1/setup.py rename vendor/{virtualenv-1.8.4/virtualenv_support => pip-1.2.1/tests}/__init__.py (100%) create mode 100644 vendor/pip-1.2.1/tests/in dex/FSPkg/FSPkg-0.1dev.tar.gz create mode 100644 vendor/pip-1.2.1/tests/in dex/FSPkg/index.html create mode 100644 vendor/pip-1.2.1/tests/in dex/README.txt create mode 100644 vendor/pip-1.2.1/tests/local_repos.py create mode 100644 vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/broken.py create mode 100644 vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/setup.py create mode 100644 vendor/pip-1.2.1/tests/packages/FSPkg/fspkg/__init__.py create mode 100644 vendor/pip-1.2.1/tests/packages/FSPkg/setup.cfg create mode 100644 vendor/pip-1.2.1/tests/packages/FSPkg/setup.py create mode 100644 vendor/pip-1.2.1/tests/packages/LineEndings/setup.py create mode 100644 vendor/pip-1.2.1/tests/packages/README.txt create mode 100644 vendor/pip-1.2.1/tests/packages/broken-0.1.tar.gz create mode 100644 vendor/pip-1.2.1/tests/packages/broken-0.2broken.tar.gz create mode 100644 vendor/pip-1.2.1/tests/packages/paxpkg.tar.bz2 create mode 100644 vendor/pip-1.2.1/tests/packages/pkgwithmpkg-1.0-py2.7-macosx10.7.mpkg.zip create mode 100644 vendor/pip-1.2.1/tests/packages/pkgwithmpkg-1.0.tar.gz create mode 100644 vendor/pip-1.2.1/tests/path.py create mode 100644 vendor/pip-1.2.1/tests/pypi_server.py create mode 100644 vendor/pip-1.2.1/tests/test_all_pip.py create mode 100644 vendor/pip-1.2.1/tests/test_basic.py create mode 100644 vendor/pip-1.2.1/tests/test_bundle.py create mode 100644 vendor/pip-1.2.1/tests/test_cleanup.py create mode 100644 vendor/pip-1.2.1/tests/test_compat.py create mode 100644 vendor/pip-1.2.1/tests/test_completion.py create mode 100644 vendor/pip-1.2.1/tests/test_config.py create mode 100644 vendor/pip-1.2.1/tests/test_download.py create mode 100644 vendor/pip-1.2.1/tests/test_extras.py create mode 100644 vendor/pip-1.2.1/tests/test_file_scheme_index.py create mode 100644 vendor/pip-1.2.1/tests/test_finder.py create mode 100644 vendor/pip-1.2.1/tests/test_freeze.py create mode 100644 vendor/pip-1.2.1/tests/test_help.py create mode 100644 vendor/pip-1.2.1/tests/test_index.py create mode 100644 vendor/pip-1.2.1/tests/test_pip.py create mode 100644 vendor/pip-1.2.1/tests/test_proxy.py create mode 100644 vendor/pip-1.2.1/tests/test_requirements.py create mode 100644 vendor/pip-1.2.1/tests/test_search.py create mode 100644 vendor/pip-1.2.1/tests/test_unicode.py create mode 100644 vendor/pip-1.2.1/tests/test_uninstall.py create mode 100644 vendor/pip-1.2.1/tests/test_upgrade.py create mode 100644 vendor/pip-1.2.1/tests/test_vcs_backends.py create mode 100644 vendor/pip-1.2.1/tests/test_vcs_bazaar.py create mode 100644 vendor/pip-1.2.1/tests/test_vcs_git.py create mode 100644 vendor/pip-1.2.1/tests/test_vcs_subversion.py delete mode 100644 vendor/virtualenv-1.8.4/AUTHORS.txt delete mode 100644 vendor/virtualenv-1.8.4/MANIFEST.in delete mode 100644 vendor/virtualenv-1.8.4/PKG-INFO delete mode 100644 vendor/virtualenv-1.8.4/README.rst delete mode 100755 vendor/virtualenv-1.8.4/bin/rebuild-script.py delete mode 100755 vendor/virtualenv-1.8.4/bin/refresh-support-files.py delete mode 100644 vendor/virtualenv-1.8.4/docs/conf.py delete mode 100644 vendor/virtualenv-1.8.4/docs/index.txt delete mode 100644 vendor/virtualenv-1.8.4/docs/news.txt delete mode 100644 vendor/virtualenv-1.8.4/scripts/virtualenv delete mode 100644 vendor/virtualenv-1.8.4/setup.cfg delete mode 100644 vendor/virtualenv-1.8.4/setup.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv.egg-info/PKG-INFO delete mode 100644 vendor/virtualenv-1.8.4/virtualenv.egg-info/SOURCES.txt delete mode 100644 vendor/virtualenv-1.8.4/virtualenv.egg-info/dependency_links.txt delete mode 100644 vendor/virtualenv-1.8.4/virtualenv.egg-info/entry_points.txt delete mode 100644 vendor/virtualenv-1.8.4/virtualenv.egg-info/not-zip-safe delete mode 100644 vendor/virtualenv-1.8.4/virtualenv.egg-info/top_level.txt delete mode 100755 vendor/virtualenv-1.8.4/virtualenv.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/activate.bat delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/activate.csh delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/activate.fish delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/activate.ps1 delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/activate.sh delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/activate_this.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/deactivate.bat delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/distribute_from_egg.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/distutils-init.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/distutils.cfg delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/ez_setup.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_embedded/site.py delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_support/distribute-0.6.31.tar.gz delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_support/setuptools-0.6c11-py2.5.egg delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_support/setuptools-0.6c11-py2.6.egg delete mode 100644 vendor/virtualenv-1.8.4/virtualenv_support/setuptools-0.6c11-py2.7.egg diff --git a/bin/typescript b/bin/typescript new file mode 100644 index 0000000..04f4899 --- /dev/null +++ b/bin/typescript @@ -0,0 +1,3 @@ +Script started on Wed Dec 19 22:40:46 2012 +% ]2;kreitz@kr2: ~/repos/heroku/python/bin]1;..ku/python/bin bin :: (versions*) » ~/repos/heroku/python/bin ggitx +]2;github .]1;gitx% ]2;kreitz@kr2: ~/repos/heroku/python/bin]1;..ku/python/bin bin :: (versions*) » ~/repos/heroku/python/bin  \ No newline at end of file diff --git a/vendor/distribute-0.6.31/CHANGES.txt b/vendor/distribute-0.6.31/CHANGES.txt new file mode 100644 index 0000000..29843ab --- /dev/null +++ b/vendor/distribute-0.6.31/CHANGES.txt @@ -0,0 +1,459 @@ +======= +CHANGES +======= + +------ +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 `_ and + `#1981 `_. +* Issue #334: Provide workaround for packages that reference `sys.__stdout__` + such as numpy does. This change should address + `virtualenv #359 `_ as long + as the system encoding is UTF-8 or the IO encoding is specified in the + environment, i.e.:: + + PYTHONIOENCODING=utf8 pip install numpy + +* Fix for encoding issue when installing from Windows executable on Python 3. +* 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.31/CONTRIBUTORS.txt b/vendor/distribute-0.6.31/CONTRIBUTORS.txt new file mode 100644 index 0000000..22c90ab --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/DEVGUIDE.txt b/vendor/distribute-0.6.31/DEVGUIDE.txt new file mode 100644 index 0000000..8dcabfd --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/MANIFEST.in b/vendor/distribute-0.6.31/MANIFEST.in new file mode 100644 index 0000000..9837747 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/PKG-INFO b/vendor/distribute-0.6.31/PKG-INFO new file mode 100644 index 0000000..3d1c814 --- /dev/null +++ b/vendor/distribute-0.6.31/PKG-INFO @@ -0,0 +1,837 @@ +Metadata-Version: 1.1 +Name: distribute +Version: 0.6.31 +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 `_ + 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.31.tar.gz + $ tar -xzvf distribute-0.6.31.tar.gz + $ cd distribute-0.6.31 + $ 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.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 `_ and + `#1981 `_. + * `Issue #334`_: Provide workaround for packages that reference `sys.__stdout__` + such as numpy does. This change should address + `virtualenv #359 `_ as long + as the system encoding is UTF-8 or the IO encoding is specified in the + environment, i.e.:: + + PYTHONIOENCODING=utf8 pip install numpy + + * Fix for encoding issue when installing from Windows executable on Python 3. + * `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 #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 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 + .. _`issue1980`: http://bitbucket.org/tarek/distribute/issue/1980 + .. _`issue1981`: http://bitbucket.org/tarek/distribute/issue/1981 + .. _`issue2`: http://bitbucket.org/tarek/distribute/issue/2 + .. _`issue20`: http://bitbucket.org/tarek/distribute/issue/20 + .. _`issue33`: http://bitbucket.org/tarek/distribute/issue/33 + .. _`issue39`: http://bitbucket.org/tarek/distribute/issue/39 + .. _`issue40`: http://bitbucket.org/tarek/distribute/issue/40 + .. _`issue41`: http://bitbucket.org/tarek/distribute/issue/41 + .. _`issue44`: http://bitbucket.org/tarek/distribute/issue/44 + + +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.31/README.txt b/vendor/distribute-0.6.31/README.txt new file mode 100644 index 0000000..7b5ae24 --- /dev/null +++ b/vendor/distribute-0.6.31/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 `_ +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.31.tar.gz + $ tar -xzvf distribute-0.6.31.tar.gz + $ cd distribute-0.6.31 + $ 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.31/_markerlib/__init__.py b/vendor/distribute-0.6.31/_markerlib/__init__.py new file mode 100644 index 0000000..e2b237b --- /dev/null +++ b/vendor/distribute-0.6.31/_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.31/_markerlib/markers.py b/vendor/distribute-0.6.31/_markerlib/markers.py new file mode 100644 index 0000000..23091e6 --- /dev/null +++ b/vendor/distribute-0.6.31/_markerlib/markers.py @@ -0,0 +1,106 @@ +# -*- 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 + +from platform import python_implementation + +# 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, '', '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/virtualenv-1.8.4/virtualenv_embedded/distribute_setup.py b/vendor/distribute-0.6.31/distribute_setup.py similarity index 100% rename from vendor/virtualenv-1.8.4/virtualenv_embedded/distribute_setup.py rename to vendor/distribute-0.6.31/distribute_setup.py diff --git a/vendor/distribute-0.6.31/docs/Makefile b/vendor/distribute-0.6.31/docs/Makefile new file mode 100644 index 0000000..30bf10a --- /dev/null +++ b/vendor/distribute-0.6.31/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 ' where 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.31/docs/_templates/indexsidebar.html b/vendor/distribute-0.6.31/docs/_templates/indexsidebar.html new file mode 100644 index 0000000..932909f --- /dev/null +++ b/vendor/distribute-0.6.31/docs/_templates/indexsidebar.html @@ -0,0 +1,8 @@ +

Download

+ +

Current version: {{ version }}

+

Get Distribute from the Python Package Index + +

Questions? Suggestions? Contributions?

+ +

Visit the Distribute project page

diff --git a/vendor/virtualenv-1.8.4/docs/_theme/nature/static/nature.css_t b/vendor/distribute-0.6.31/docs/_theme/nature/static/nature.css_t similarity index 61% rename from vendor/virtualenv-1.8.4/docs/_theme/nature/static/nature.css_t rename to vendor/distribute-0.6.31/docs/_theme/nature/static/nature.css_t index 03b0379..1a65426 100644 --- a/vendor/virtualenv-1.8.4/docs/_theme/nature/static/nature.css_t +++ b/vendor/distribute-0.6.31/docs/_theme/nature/static/nature.css_t @@ -10,8 +10,8 @@ body { font-family: Arial, sans-serif; font-size: 100%; - background-color: #111; - color: #555; + background-color: #111111; + color: #555555; margin: 0; padding: 0; } @@ -22,7 +22,7 @@ div.documentwrapper { } div.bodywrapper { - margin: 0 0 0 230px; + margin: 0 0 0 300px; } hr{ @@ -30,14 +30,14 @@ hr{ } div.document { - background-color: #eee; + background-color: #fafafa; } div.body { background-color: #ffffff; color: #3E4349; - padding: 0 30px 30px 30px; - font-size: 0.8em; + padding: 1em 30px 30px 30px; + font-size: 0.9em; } div.footer { @@ -49,25 +49,29 @@ div.footer { } div.footer a { - color: #444; - text-decoration: underline; + color: #444444; } div.related { background-color: #6BA81E; - line-height: 32px; - color: #fff; - text-shadow: 0px 1px 0 #444; - font-size: 0.80em; + 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.75em; + font-size: 0.9em; line-height: 1.5em; + width: 300px; } div.sphinxsidebarwrapper{ @@ -77,46 +81,46 @@ div.sphinxsidebarwrapper{ div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: Arial, sans-serif; - color: #222; + color: #222222; font-size: 1.2em; - font-weight: normal; + font-weight: bold; margin: 0; padding: 5px 10px; - background-color: #ddd; text-shadow: 1px 1px 0 white } -div.sphinxsidebar h4{ - font-size: 1.1em; -} - div.sphinxsidebar h3 a { - color: #444; + color: #444444; } - - + div.sphinxsidebar p { - color: #888; + color: #888888; padding: 5px 20px; + margin: 0.5em 0px; } div.sphinxsidebar p.topless { } div.sphinxsidebar ul { - margin: 10px 20px; + margin: 10px 10px 10px 20px; padding: 0; - color: #000; + color: #000000; } div.sphinxsidebar a { - color: #444; + color: #444444; } - + +div.sphinxsidebar a:hover { + color: #E32E00; +} + div.sphinxsidebar input { - border: 1px solid #ccc; + border: 1px solid #cccccc; font-family: sans-serif; - font-size: 1em; + font-size: 1.1em; + padding: 0.15em 0.3em; } div.sphinxsidebar input[type=text]{ @@ -132,7 +136,6 @@ a { a:hover { color: #E32E00; - text-decoration: underline; } div.body h1, @@ -142,20 +145,20 @@ div.body h4, div.body h5, div.body h6 { font-family: Arial, sans-serif; - background-color: #BED4EB; font-weight: normal; color: #212224; margin: 30px 0px 10px 0px; - padding: 5px 0 5px 10px; - text-shadow: 0px 1px 0 white + padding: 5px 0 5px 0px; + text-shadow: 0px 1px 0 white; + border-bottom: 1px solid #C8D5E3; } -div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } -div.body h2 { font-size: 150%; background-color: #C8D5E3; } -div.body h3 { font-size: 120%; background-color: #D8DEE3; } -div.body h4 { font-size: 110%; background-color: #D8DEE3; } -div.body h5 { font-size: 100%; background-color: #D8DEE3; } -div.body h6 { font-size: 100%; background-color: #D8DEE3; } +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; @@ -170,7 +173,7 @@ a.headerlink:hover { } div.body p, div.body dd, div.body li { - line-height: 1.5em; + line-height: 1.8em; } div.admonition p.admonition-title + p { @@ -182,22 +185,23 @@ div.highlight{ } div.note { - background-color: #eee; - border: 1px solid #ccc; + background-color: #eeeeee; + border: 1px solid #cccccc; } div.seealso { - background-color: #ffc; - border: 1px solid #ff6; + background-color: #ffffcc; + border: 1px solid #ffff66; } div.topic { - background-color: #eee; + background-color: #fafafa; + border-width: 0; } div.warning { background-color: #ffe4e4; - border: 1px solid #f66; + border: 1px solid #ff6666; } p.admonition-title { @@ -210,20 +214,24 @@ p.admonition-title:after { pre { padding: 10px; - background-color: White; - color: #222; - line-height: 1.2em; - border: 1px solid #C6C9CB; - font-size: 1.2em; + background-color: #fafafa; + color: #222222; + line-height: 1.5em; + font-size: 1.1em; margin: 1.5em 0 1.5em 0; - -webkit-box-shadow: 1px 1px 1px #d8d8d8; - -moz-box-shadow: 1px 1px 1px #d8d8d8; + -webkit-box-shadow: 0px 0px 4px #d8d8d8; + -moz-box-shadow: 0px 0px 4px #d8d8d8; + box-shadow: 0px 0px 4px #d8d8d8; } tt { - background-color: #ecf0f3; - color: #222; + color: #222222; padding: 1px 2px; font-size: 1.2em; font-family: monospace; } + +#table-of-contents ul { + padding-left: 2em; +} + diff --git a/vendor/virtualenv-1.8.4/docs/_theme/nature/static/pygments.css b/vendor/distribute-0.6.31/docs/_theme/nature/static/pygments.css similarity index 100% rename from vendor/virtualenv-1.8.4/docs/_theme/nature/static/pygments.css rename to vendor/distribute-0.6.31/docs/_theme/nature/static/pygments.css diff --git a/vendor/virtualenv-1.8.4/docs/_theme/nature/theme.conf b/vendor/distribute-0.6.31/docs/_theme/nature/theme.conf similarity index 100% rename from vendor/virtualenv-1.8.4/docs/_theme/nature/theme.conf rename to vendor/distribute-0.6.31/docs/_theme/nature/theme.conf diff --git a/vendor/distribute-0.6.31/docs/conf.py b/vendor/distribute-0.6.31/docs/conf.py new file mode 100644 index 0000000..08fa643 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31' +# The full version, including alpha/beta/rc tags. +release = '0.6.31' + +# 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 +# " v 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 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.31/docs/easy_install.txt b/vendor/distribute-0.6.31/docs/easy_install.txt new file mode 100644 index 0000000..9b4fcfb --- /dev/null +++ b/vendor/distribute-0.6.31/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 +`_. (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 `_ +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 `_, 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 `_ 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 `_. + +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 ``"Home Page"`` or + ``"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:: + +
  • + Home Page: + + http://sqlobject.org +
  • + + 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"`` 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):: + + ([^<]+)\n\s+\(md5\) + +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.31/docs/index.txt b/vendor/distribute-0.6.31/docs/index.txt new file mode 100644 index 0000000..5f3b945 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/docs/pkg_resources.txt b/vendor/distribute-0.6.31/docs/pkg_resources.txt new file mode 100644 index 0000000..480f954 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/docs/python3.txt b/vendor/distribute-0.6.31/docs/python3.txt new file mode 100644 index 0000000..2f6cde4 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/docs/roadmap.txt b/vendor/distribute-0.6.31/docs/roadmap.txt new file mode 100644 index 0000000..ea5070e --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/docs/setuptools.txt b/vendor/distribute-0.6.31/docs/setuptools.txt new file mode 100644 index 0000000..31ecc93 --- /dev/null +++ b/vendor/distribute-0.6.31/docs/setuptools.txt @@ -0,0 +1,3236 @@ +================================================== +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 `_, + 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 `_ - + 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 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`` both 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 use ``-`` or any other character than ``.`` as a separator, unless you + really want a post-release. Remember that ``2.1-rc2`` means you've + *already* released ``2.1``, whereas ``2.1rc2`` and ``2.1.c2`` are candidates + you're putting out *before* ``2.1``. If you accidentally distribute copies + of a post-release that you meant to be a pre-release, the only safe fix is to + bump your main release number (e.g. to ``2.1.1``) and re-release the project. + +* 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') + False + >>> 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 +`_ 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//. + +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 `_ +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 `_ 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.31/docs/using.txt b/vendor/distribute-0.6.31/docs/using.txt new file mode 100644 index 0000000..192f1dc --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/easy_install.py b/vendor/distribute-0.6.31/easy_install.py new file mode 100644 index 0000000..d87e984 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/launcher.c b/vendor/distribute-0.6.31/launcher.c new file mode 100644 index 0000000..ea4c80b --- /dev/null +++ b/vendor/distribute-0.6.31/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 +#include +#include +#include +#include +#include + +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; counterscript && *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= "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, replace=False): + """Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to the ``.location`` of `dist`. + On exit from this routine, `entry` is added to the end of the working + set's ``.entries`` (if it wasn't already present). + + `dist` is only added to the working set if it's for a project that + doesn't already have a distribution in the set, unless `replace=True`. + If it's added, any callbacks registered with the ``subscribe()`` method + will be called. + """ + if insert: + dist.insert_on(self.entries, entry) + + if entry is None: + entry = dist.location + keys = self.entry_keys.setdefault(entry,[]) + keys2 = self.entry_keys.setdefault(dist.location,[]) + if not replace and dist.key in self.by_key: + return # ignore hidden distros + + self.by_key[dist.key] = dist + if dist.key not in keys: + keys.append(dist.key) + if dist.key not in keys2: + keys2.append(dist.key) + self._added_new(dist) + + def resolve(self, requirements, env=None, installer=None, + replacement=True, replace_conflicting=False): + """List all distributions needed to (recursively) meet `requirements` + + `requirements` must be a sequence of ``Requirement`` objects. `env`, + if supplied, should be an ``Environment`` instance. If + not supplied, it defaults to all distributions available within any + entry or distribution in the working set. `installer`, if supplied, + will be invoked with each requirement that cannot be met by an + already-installed distribution; it should return a ``Distribution`` or + ``None``. + + Unless `replace_conflicting=True`, raises a VersionConflict exception if + any requirements are found on the path that have the correct name but + the wrong version. Otherwise, if an `installer` is supplied it will be + invoked to obtain the correct version of the requirement and activate + it. + """ + + requirements = list(requirements)[::-1] # set up the stack + processed = {} # set of processed requirements + best = {} # key -> dist + to_activate = [] + + while requirements: + req = requirements.pop(0) # process dependencies breadth-first + if _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 or (dist not in req and replace_conflicting): + ws = self + if env is None: + if dist is None: + env = Environment(self.entries) + else: + # Use an empty environment and workingset to avoid + # any further conflicts with the conflicting + # distribution + env = Environment([]) + ws = WorkingSet([]) + dist = best[req.key] = env.best_match(req, ws, installer) + if dist is None: + #msg = ("The '%s' distribution was not found on this " + # "system, and is required by this application.") + #raise DistributionNotFound(msg % req) + + # unfortunately, zc.buildout uses a str(err) + # to get the name of the distribution here.. + raise DistributionNotFound(req) + to_activate.append(dist) + if dist not in req: + # Oops, the "best" so far conflicts with a dependency + raise VersionConflict(dist,req) # XXX put more info here + requirements.extend(dist.requires(req.extras)[::-1]) + processed[req] = True + + return to_activate # return list of distros to activate + + def find_plugins(self, + plugin_env, full_env=None, installer=None, fallback=True + ): + """Find all activatable distributions in `plugin_env` + + Example usage:: + + distributions, errors = working_set.find_plugins( + Environment(plugin_dirlist) + ) + map(working_set.add, distributions) # add plugins+libs to sys.path + print 'Could not load', errors # display errors + + The `plugin_env` should be an ``Environment`` instance that contains + only distributions that are in the project's "plugin directory" or + directories. The `full_env`, if supplied, should be an ``Environment`` + contains all currently-available distributions. If `full_env` is not + supplied, one is created automatically from the ``WorkingSet`` this + method is called on, which will typically mean that every directory on + ``sys.path`` will be scanned for distributions. + + `installer` is a standard installer callback as used by the + ``resolve()`` method. The `fallback` flag indicates whether we should + attempt to resolve older versions of a plugin if the newest version + cannot be resolved. + + This method returns a 2-tuple: (`distributions`, `error_info`), where + `distributions` is a list of the distributions found in `plugin_env` + that were loadable, along with any other distributions that are needed + to resolve their dependencies. `error_info` is a dictionary mapping + unloadable plugin distributions to an exception instance describing the + error that occurred. Usually this will be a ``DistributionNotFound`` or + ``VersionConflict`` instance. + """ + + plugin_projects = list(plugin_env) + plugin_projects.sort() # scan project names in alphabetic order + + error_info = {} + distributions = {} + + if full_env is None: + env = Environment(self.entries) + env += plugin_env + else: + env = full_env + plugin_env + + shadow_set = self.__class__([]) + 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) + +try: + # CPython >=3.3 + import _frozen_importlib +except ImportError: + pass +else: + register_loader_type(_frozen_importlib.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'): + for line in open(os.path.join(path_item, entry)): + 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) + +try: + # CPython >=3.3 + import _frozen_importlib +except ImportError: + pass +else: + register_finder(_frozen_importlib.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) + for path_item in path: + if path_item not in module.__path__: + module.__path__.append(path_item) + return subpath + +def declare_namespace(packageName): + """Declare that package 'packageName' is a namespace package""" + + imp.acquire_lock() + try: + if packageName in _namespace_packages: + return + + path, parent = sys.path, None + if '.' in packageName: + parent = '.'.join(packageName.split('.')[:-1]) + declare_namespace(parent) + if parent not in _namespace_packages: + __import__(parent) + try: + path = sys.modules[parent].__path__ + except AttributeError: + raise TypeError("Not a package:", parent) + + # Track what packages are namespaces, so when new path items are added, + # they can be updated + _namespace_packages.setdefault(parent,[]).append(packageName) + _namespace_packages.setdefault(packageName,[]) + + for path_item in path: + # Ensure all the parent's path items are reflected in the child, + # if they apply + _handle_ns(packageName, path_item) + + finally: + imp.release_lock() + +def fixup_namespace_packages(path_item, parent=None): + """Ensure that previously-declared namespace packages include path_item""" + imp.acquire_lock() + try: + for package in _namespace_packages.get(parent,()): + subpath = _handle_ns(package, path_item) + if subpath: fixup_namespace_packages(subpath,package) + finally: + imp.release_lock() + +def file_ns_handler(importer, path_item, packageName, module): + """Compute an ns-package subpath for a filesystem or zipfile importer""" + + subpath = os.path.join(path_item, packageName.split('.')[-1]) + normalized = _normalize_cached(subpath) + for item in module.__path__: + if _normalize_cached(item)==normalized: + break + else: + # Only return the path if it's not already there + return subpath + +register_namespace_handler(ImpWrapper,file_ns_handler) +register_namespace_handler(zipimport.zipimporter,file_ns_handler) + +try: + # CPython >=3.3 + import _frozen_importlib +except ImportError: + pass +else: + register_namespace_handler(_frozen_importlib.FileFinder, file_ns_handler) + + +def null_ns_handler(importer, path_item, packageName, module): + return None + +register_namespace_handler(object,null_ns_handler) + + +def normalize_path(filename): + """Normalize a file/dir name for comparison purposes""" + return os.path.normcase(os.path.realpath(filename)) + +def _normalize_cached(filename,_cache={}): + try: + return _cache[filename] + except KeyError: + _cache[filename] = result = normalize_path(filename) + return result + +def _set_parent_ns(packageName): + parts = packageName.split('.') + name = parts.pop() + if parts: + parent = '.'.join(parts) + setattr(sys.modules[parent], name, sys.modules[packageName]) + + +def yield_lines(strs): + """Yield non-empty/non-comment lines of a ``basestring`` or sequence""" + if isinstance(strs,basestring): + for s in strs.splitlines(): + s = s.strip() + if s and not s.startswith('#'): # skip blank lines/comments + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + +LINE_END = re.compile(r"\s*(#.*)?$").match # whitespace and comment +CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match # line continuation +DISTRO = re.compile(r"\s*((\w|[-.])+)").match # Distribution or extra +VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|[-.])+)").match # ver. info +COMMA = re.compile(r"\s*,").match # comma between items +OBRACKET = re.compile(r"\s*\[").match +CBRACKET = re.compile(r"\s*\]").match +MODULE = re.compile(r"\w+(\.\w+)*$").match +EGG_NAME = re.compile( + r"(?P[^-]+)" + r"( -(?P[^-]+) (-py(?P[^-]+) (-(?P.+))? )? )?", + re.VERBOSE | re.IGNORECASE +).match + +component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE) +replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get + +def _parse_version_parts(s): + for part in component_re.split(s): + part = replace(part,part) + if part in ['', '.']: + 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('*'): + # 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.31/release.py b/vendor/distribute-0.6.31/release.py new file mode 100644 index 0000000..18299a4 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31' + +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.31/setup.cfg b/vendor/distribute-0.6.31/setup.cfg new file mode 100644 index 0000000..319f941 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setup.py b/vendor/distribute-0.6.31/setup.py new file mode 100644 index 0000000..13c9be7 --- /dev/null +++ b/vendor/distribute-0.6.31/setup.py @@ -0,0 +1,245 @@ +#!/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() + for line in open("MANIFEST.in"): + fl.process_template_line(line) + 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') +exec(open(init_path).read(), d) + +SETUP_COMMANDS = d['__all__'] +VERSION = "0.6.31" + +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): + try: + _test.run(self) + finally: + return + + 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(rstfile): + bitroot = 'http://bitbucket.org/tarek/distribute' + revision = re.compile(r'\b(issue\s*#?\d+)\b', re.M | re.I) + + rstext = open(rstfile).read() + + anchors = revision.findall(rstext) # ['Issue #43', ...] + anchors = sorted(set(anchors)) + rstext = revision.sub(r'`\1`_', rstext) + rstext += "\n" + for x in anchors: + issue = re.findall(r'\d+', x)[0] + rstext += '.. _`%s`: %s/issue/%s\n' % (x, bitroot, issue) + rstext += "\n" + return rstext + +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 = open('README.txt').read() + _linkified('CHANGES.txt'), + 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.31/setuptools/__init__.py b/vendor/distribute-0.6.31/setuptools/__init__.py new file mode 100644 index 0000000..9de373f --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/archive_util.py b/vendor/distribute-0.6.31/setuptools/archive_util.py new file mode 100644 index 0000000..e22b25c --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/cli-32.exe b/vendor/distribute-0.6.31/setuptools/cli-32.exe new file mode 100755 index 0000000000000000000000000000000000000000..9b7717b78bbf71f105ccde26746a0f6e3a4d12db GIT binary patch literal 69632 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

    l38TtwK&i|C2wHp80$`=KgRZxh1|83=+DI7LEpU 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 bsj9#HerbVUTHu!!_@xDYX@UROTi|~I?X2KC literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.31/setuptools/cli-64.exe b/vendor/distribute-0.6.31/setuptools/cli-64.exe new file mode 100755 index 0000000000000000000000000000000000000000..265585afc4042ce55c59d28ef1aab37f0a68ecdc GIT binary patch literal 75264 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 J@V|uu{}h+)rm_rlr&i&=6>I2?&b&D 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

    l38TtwK&i|C2wHp80$`=KgRZxh1|83=+DI7LEpU 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 bsj9#HerbVUTHu!!_@xDYX@UROTi|~I?X2KC literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.31/setuptools/command/__init__.py b/vendor/distribute-0.6.31/setuptools/command/__init__.py new file mode 100644 index 0000000..b063fa1 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/alias.py b/vendor/distribute-0.6.31/setuptools/command/alias.py new file mode 100644 index 0000000..f5368b2 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/bdist_egg.py b/vendor/distribute-0.6.31/setuptools/command/bdist_egg.py new file mode 100644 index 0000000..17fae98 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/bdist_rpm.py b/vendor/distribute-0.6.31/setuptools/command/bdist_rpm.py new file mode 100644 index 0000000..8c48da3 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/bdist_wininst.py b/vendor/distribute-0.6.31/setuptools/command/bdist_wininst.py new file mode 100644 index 0000000..93e6846 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/build_ext.py b/vendor/distribute-0.6.31/setuptools/command/build_ext.py new file mode 100644 index 0000000..4a94572 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/build_py.py b/vendor/distribute-0.6.31/setuptools/command/build_py.py new file mode 100644 index 0000000..8751acd --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/develop.py b/vendor/distribute-0.6.31/setuptools/command/develop.py new file mode 100644 index 0000000..709e349 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/command/develop.py @@ -0,0 +1,165 @@ +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) + contents = [line.rstrip() for line in open(self.egg_link)] + 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.31/setuptools/command/easy_install.py b/vendor/distribute-0.6.31/setuptools/command/easy_install.py new file mode 100644 index 0000000..337532b --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/command/easy_install.py @@ -0,0 +1,1942 @@ +#!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;open(%r,'w').write('OK')\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("= (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=''): + "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 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.31/setuptools/command/egg_info.py b/vendor/distribute-0.6.31/setuptools/command/egg_info.py new file mode 100644 index 0000000..0c2ea0c --- /dev/null +++ b/vendor/distribute-0.6.31/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('= (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.31/setuptools/command/install.py b/vendor/distribute-0.6.31/setuptools/command/install.py new file mode 100644 index 0000000..247c4f2 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/install_egg_info.py b/vendor/distribute-0.6.31/setuptools/command/install_egg_info.py new file mode 100644 index 0000000..f44b34b --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/install_lib.py b/vendor/distribute-0.6.31/setuptools/command/install_lib.py new file mode 100644 index 0000000..82afa14 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/install_scripts.py b/vendor/distribute-0.6.31/setuptools/command/install_scripts.py new file mode 100644 index 0000000..8245603 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/register.py b/vendor/distribute-0.6.31/setuptools/command/register.py new file mode 100644 index 0000000..3b2e085 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/rotate.py b/vendor/distribute-0.6.31/setuptools/command/rotate.py new file mode 100644 index 0000000..11b6eae --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/saveopts.py b/vendor/distribute-0.6.31/setuptools/command/saveopts.py new file mode 100644 index 0000000..1180a44 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/sdist.py b/vendor/distribute-0.6.31/setuptools/command/sdist.py new file mode 100644 index 0000000..2fa3771 --- /dev/null +++ b/vendor/distribute-0.6.31/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('= (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.31/setuptools/command/setopt.py b/vendor/distribute-0.6.31/setuptools/command/setopt.py new file mode 100644 index 0000000..dbf3a94 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/test.py b/vendor/distribute-0.6.31/setuptools/command/test.py new file mode 100644 index 0000000..a02ac14 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/command/upload.py b/vendor/distribute-0.6.31/setuptools/command/upload.py new file mode 100644 index 0000000..9f9366b --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/command/upload.py @@ -0,0 +1,184 @@ +"""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: + data['gpg_signature'] = (os.path.basename(filename) + ".asc", + open(filename+".asc").read()) + + # 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.31/setuptools/command/upload_docs.py b/vendor/distribute-0.6.31/setuptools/command/upload_docs.py new file mode 100644 index 0000000..98fb723 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/command/upload_docs.py @@ -0,0 +1,193 @@ +# -*- 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): + content = open(filename, 'rb').read() + 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.31/setuptools/depends.py b/vendor/distribute-0.6.31/setuptools/depends.py new file mode 100644 index 0000000..4b7b343 --- /dev/null +++ b/vendor/distribute-0.6.31/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=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.31/setuptools/dist.py b/vendor/distribute-0.6.31/setuptools/dist.py new file mode 100644 index 0000000..6236d5b --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/dist.py @@ -0,0 +1,856 @@ +__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, + replace_conflicting=True + ): + working_set.add(dist, replace=True) + + 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.31/setuptools/extension.py b/vendor/distribute-0.6.31/setuptools/extension.py new file mode 100644 index 0000000..eb8b836 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/gui-32.exe b/vendor/distribute-0.6.31/setuptools/gui-32.exe new file mode 100755 index 0000000000000000000000000000000000000000..3f64af7de42fd6597b4c6cf50896d32a98a7d6a2 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.31/setuptools/gui-64.exe b/vendor/distribute-0.6.31/setuptools/gui-64.exe new file mode 100755 index 0000000000000000000000000000000000000000..3ab4378e1d401d198b92a33ce249d29bcdb26a63 GIT binary patch literal 75264 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 literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.31/setuptools/gui.exe b/vendor/distribute-0.6.31/setuptools/gui.exe new file mode 100755 index 0000000000000000000000000000000000000000..3f64af7de42fd6597b4c6cf50896d32a98a7d6a2 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/vendor/distribute-0.6.31/setuptools/package_index.py b/vendor/distribute-0.6.31/setuptools/package_index.py new file mode 100644 index 0000000..0ee21e3 --- /dev/null +++ b/vendor/distribute-0.6.31/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( + '([^<]+)\n\s+\\(md5\\)' +) +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 ("Home Page", "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: '%s' % 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'([^- ]+ - )?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" % url) + \ + "%s" % '\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.31/setuptools/sandbox.py b/vendor/distribute-0.6.31/setuptools/sandbox.py new file mode 100644 index 0000000..64f725e --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/sandbox.py @@ -0,0 +1,290 @@ +import os, sys, __builtin__, tempfile, operator, pkg_resources +_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.31/setuptools/script template (dev).py b/vendor/distribute-0.6.31/setuptools/script template (dev).py new file mode 100644 index 0000000..6dd9dd4 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/script template.py b/vendor/distribute-0.6.31/setuptools/script template.py new file mode 100644 index 0000000..8dd5d51 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/__init__.py b/vendor/distribute-0.6.31/setuptools/tests/__init__.py new file mode 100644 index 0000000..b6988a0 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/doctest.py b/vendor/distribute-0.6.31/setuptools/tests/doctest.py new file mode 100644 index 0000000..be399a9 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/doctest.py @@ -0,0 +1,2679 @@ +# 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 pair, plus an intra-docstring line number. +# - DocTest: a collection of examples, parsed from a docstring, plus +# info about where the docstring came from (name, filename, lineno). +# - DocTestFinder: extracts DocTests from a given object's docstring and +# its contained objects' docstrings. +# - DocTestRunner: runs DocTest cases, and accumulates statistics. +# +# So the basic picture is: +# +# list of: +# +------+ +---------+ +-------+ +# |object| --DocTestFinder-> | DocTest | --DocTestRunner-> |results| +# +------+ +---------+ +-------+ +# | Example | +# | ... | +# | Example | +# +---------+ + +# Option constants. + +OPTIONFLAGS_BY_NAME = {} +def register_optionflag(name): + flag = 1 << len(OPTIONFLAGS_BY_NAME) + OPTIONFLAGS_BY_NAME[name] = flag + return flag + +DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1') +DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE') +NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE') +ELLIPSIS = register_optionflag('ELLIPSIS') +IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL') + +COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 | + DONT_ACCEPT_BLANKLINE | + NORMALIZE_WHITESPACE | + ELLIPSIS | + IGNORE_EXCEPTION_DETAIL) + +REPORT_UDIFF = register_optionflag('REPORT_UDIFF') +REPORT_CDIFF = register_optionflag('REPORT_CDIFF') +REPORT_NDIFF = register_optionflag('REPORT_NDIFF') +REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE') + +REPORTING_FLAGS = (REPORT_UDIFF | + REPORT_CDIFF | + REPORT_NDIFF | + REPORT_ONLY_FIRST_FAILURE) + +# Special string markers for use in `want` strings: +BLANKLINE_MARKER = '' +ELLIPSIS_MARKER = '...' + +###################################################################### +## Table of Contents +###################################################################### +# 1. Utility Functions +# 2. Example & DocTest -- store test cases +# 3. DocTest Parser -- extracts examples from strings +# 4. DocTest Finder -- extracts test cases from objects +# 5. DocTest Runner -- runs test cases +# 6. Test Functions -- convenient wrappers for testing +# 7. Tester Class -- for backwards compatibility +# 8. Unittest Support +# 9. Debugging Support +# 10. Example Usage + +###################################################################### +## 1. Utility Functions +###################################################################### + +def is_private(prefix, base): + """prefix, base -> true iff name prefix + "." + base is "private". + + Prefix may be an empty string, and base does not contain a period. + Prefix is ignored (although functions you write conforming to this + protocol may make use of it). + Return true iff base begins with an (at least one) underscore, but + does not both begin and end with (at least) two underscores. + + >>> is_private("a.b", "my_func") + False + >>> is_private("____", "_my_func") + True + >>> is_private("someclass", "__init__") + False + >>> is_private("sometypo", "__init_") + True + >>> is_private("x.y.z", "_") + True + >>> is_private("_x.y.z", "__") + False + >>> is_private("", "") # senseless but consistent + False + """ + warnings.warn("is_private is deprecated; it wasn't useful; " + "examine DocTestFinder.find() lists instead", + DeprecationWarning, stacklevel=2) + return base[:1] == "_" and not base[:2] == "__" == base[-2:] + +def _extract_future_flags(globs): + """ + Return the compiler-flags associated with the future features that + have been imported into the given namespace (globs). + """ + flags = 0 + for fname in __future__.all_feature_names: + feature = globs.get(fname, None) + if feature is getattr(__future__, fname): + flags |= feature.compiler_flag + return flags + +def _normalize_module(module, depth=2): + """ + Return the module specified by `module`. In particular: + - If `module` is a module, then return module. + - If `module` is a string, then import and return the + module with that name. + - If `module` is None, then return the calling module. + The calling module is assumed to be the module of + the stack frame at the given depth in the call stack. + """ + if inspect.ismodule(module): + return module + elif isinstance(module, (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 pair, where "source" is a +## fragment of source code, and "want" is the expected output for +## "source." The Example class also includes information about +## where the example was extracted from. +## +## - A "doctest" is a collection of examples, typically extracted from +## a string (such as an object's docstring). The DocTest class also +## includes information about where the string was extracted from. + +class Example: + """ + A single doctest example, consisting of source code and expected + output. `Example` defines the following attributes: + + - source: A single Python statement, always ending with a newline. + The constructor adds a newline if needed. + + - want: The expected output from running the source code (either + from stdout, or a traceback in case of exception). `want` ends + with a newline unless it's empty, in which case it's an empty + string. The constructor adds a newline if needed. + + - exc_msg: The exception message generated by the example, if + the example is expected to generate an exception; or `None` if + it is not expected to generate an exception. This exception + message is compared against the return value of + `traceback.format_exception_only()`. `exc_msg` ends with a + newline unless it's `None`. The constructor adds a newline + if needed. + + - lineno: The line number within the DocTest string containing + this Example where the Example begins. This line number is + zero-based, with respect to the beginning of the DocTest. + + - indent: The example's indentation in the DocTest string. + I.e., the number of space characters that preceed the + example's first prompt. + + - options: A dictionary mapping from option flags to True or + False, which is used to override default options for this + example. Any option flags not contained in this dictionary + are left at their default value (as specified by the + DocTestRunner's optionflags). By default, no options are set. + """ + def __init__(self, source, want, exc_msg=None, lineno=0, indent=0, + options=None): + # Normalize inputs. + if not source.endswith('\n'): + source += '\n' + if want and not want.endswith('\n'): + want += '\n' + if exc_msg is not None and not exc_msg.endswith('\n'): + exc_msg += '\n' + # Store properties. + self.source = source + self.want = want + self.lineno = lineno + self.indent = indent + if options is None: options = {} + self.options = options + self.exc_msg = exc_msg + +class DocTest: + """ + A collection of doctest examples that should be run in a single + namespace. Each `DocTest` defines the following attributes: + + - examples: the list of examples. + + - globs: The namespace (aka globals) that the examples should + be run in. + + - name: A name identifying the DocTest (typically, the name of + the object whose docstring this DocTest was extracted from). + + - filename: The name of the file that this DocTest was extracted + from, or `None` if the filename is unknown. + + - lineno: The line number within filename where this DocTest + begins, or `None` if the line number is unavailable. This + line number is zero-based, with respect to the beginning of + the file. + + - docstring: The string that the examples were extracted from, + or `None` if the string is unavailable. + """ + def __init__(self, examples, globs, name, filename, lineno, docstring): + """ + Create a new DocTest containing the given examples. The + DocTest's globals are initialized with a copy of `globs`. + """ + assert not isinstance(examples, basestring), \ + "DocTest no longer accepts str; use DocTestParser instead" + self.examples = examples + self.docstring = docstring + self.globs = globs.copy() + self.name = name + self.filename = filename + self.lineno = lineno + + def __repr__(self): + if len(self.examples) == 0: + examples = 'no examples' + elif len(self.examples) == 1: + examples = '1 example' + else: + examples = '%d examples' % len(self.examples) + return ('' % + (self.name, self.filename, self.lineno, examples)) + + + # This lets us sort tests by name: + def __cmp__(self, other): + if not isinstance(other, DocTest): + return -1 + return cmp((self.name, self.filename, self.lineno, id(self)), + (other.name, other.filename, other.lineno, id(other))) + +###################################################################### +## 3. DocTestParser +###################################################################### + +class DocTestParser: + """ + A class used to parse strings containing doctest examples. + """ + # This regular expression is used to find doctest examples in a + # string. It defines three groups: `source` is the source code + # (including leading indentation and prompts); `indent` is the + # indentation of the first (PS1) line of the source code; and + # `want` is the expected output (including leading indentation). + _EXAMPLE_RE = re.compile(r''' + # Source consists of a PS1 line followed by zero or more PS2 lines. + (?P + (?:^(?P [ ]*) >>> .*) # PS1 line + (?:\n [ ]* \.\.\. .*)*) # PS2 lines + \n? + # Want consists of any non-blank lines that do not start with PS1. + (?P (?:(?![ ]*$) # Not a blank line + (?![ ]*>>>) # Not a line starting with PS1 + .*$\n? # But any other line + )*) + ''', re.MULTILINE | re.VERBOSE) + + # A regular expression for handling `want` strings that contain + # expected exceptions. It divides `want` into three pieces: + # - the traceback header line (`hdr`) + # - the traceback stack (`stack`) + # - the exception message (`msg`), as generated by + # traceback.format_exception_only() + # `msg` may have multiple lines. We assume/require that the + # exception message is the first non-indented line starting with a word + # character following the traceback header line. + _EXCEPTION_RE = re.compile(r""" + # Grab the traceback header. Different versions of Python have + # said different things on the first traceback line. + ^(?P Traceback\ \( + (?: most\ recent\ call\ last + | innermost\ last + ) \) : + ) + \s* $ # toss trailing whitespace on the header. + (?P .*?) # don't blink: absorb stuff until... + ^ (?P \w+ .*) # a line *starts* with alphanum. + """, re.VERBOSE | re.MULTILINE | re.DOTALL) + + # A callable returning a true value iff its argument is a blank line + # or contains a single comment. + _IS_BLANK_OR_COMMENT = re.compile(r'^[ ]*(#.*)?$').match + + def parse(self, string, name=''): + """ + Divide the given string into examples and intervening text, + and return them as a list of alternating Examples and strings. + Line numbers for the Examples are 0-based. The optional + argument `name` is a name identifying this string, and is only + used for error messages. + """ + string = string.expandtabs() + # If all lines begin with the same indentation, then strip it. + min_indent = self._min_indent(string) + if min_indent > 0: + string = '\n'.join([l[min_indent:] for l in string.split('\n')]) + + output = [] + charno, lineno = 0, 0 + # Find all doctest examples in the string: + for m in self._EXAMPLE_RE.finditer(string): + # Add the pre-example text to `output`. + output.append(string[charno:m.start()]) + # Update lineno (lines before this example) + lineno += string.count('\n', charno, m.start()) + # Extract info from the regexp match. + (source, options, want, exc_msg) = \ + self._parse_example(m, name, lineno) + # Create an Example, and add it to the list. + if not self._IS_BLANK_OR_COMMENT(source): + output.append( Example(source, want, exc_msg, + lineno=lineno, + indent=min_indent+len(m.group('indent')), + options=options) ) + # Update lineno (lines inside this example) + lineno += string.count('\n', m.start(), m.end()) + # Update charno. + charno = m.end() + # Add any remaining post-example text to `output`. + output.append(string[charno:]) + return output + + def get_doctest(self, string, globs, name, filename, lineno): + """ + Extract all doctest examples from the given string, and + collect them into a `DocTest` object. + + `globs`, `name`, `filename`, and `lineno` are attributes for + the new `DocTest` object. See the documentation for `DocTest` + for more information. + """ + return DocTest(self.get_examples(string, name), globs, + name, filename, lineno, string) + + def get_examples(self, string, name=''): + """ + Extract all doctest examples from the given string, and return + them as a list of `Example` objects. Line numbers are + 0-based, because it's most common in doctests that nothing + interesting appears on the same line as opening triple-quote, + and so the first interesting line is called \"line 1\" then. + + The optional argument `name` is a name identifying this + string, and is only used for error messages. + """ + return [x for x in self.parse(string, name) + if isinstance(x, Example)] + + def _parse_example(self, m, name, lineno): + """ + Given a regular expression match from `_EXAMPLE_RE` (`m`), + return a pair `(source, want)`, where `source` is the matched + example's source code (with prompts and indentation stripped); + and `want` is the example's expected output (with indentation + stripped). + + `name` is the string's name, and `lineno` is the line number + where the example starts; both are used for error messages. + """ + # Get the example's indentation level. + indent = len(m.group('indent')) + + # Divide source into lines; check that they're properly + # indented; and then strip their indentation & prompts. + source_lines = m.group('source').split('\n') + self._check_prompt_blank(source_lines, indent, name, lineno) + self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno) + source = '\n'.join([sl[indent+4:] for sl in source_lines]) + + # Divide want into lines; check that it's properly indented; and + # then strip the indentation. Spaces before the last newline should + # be preserved, so plain rstrip() isn't good enough. + want = m.group('want') + want_lines = want.split('\n') + if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]): + del want_lines[-1] # forget final newline & spaces after it + self._check_prefix(want_lines, ' '*indent, name, + lineno + len(source_lines)) + want = '\n'.join([wl[indent:] for wl in want_lines]) + + # If `want` contains a traceback message, then extract it. + m = self._EXCEPTION_RE.match(want) + if m: + exc_msg = m.group('msg') + else: + exc_msg = None + + # Extract options from the source. + options = self._find_options(source, name, lineno) + + return source, options, want, exc_msg + + # This regular expression looks for option directives in the + # source code of an example. Option directives are comments + # starting with "doctest:". Warning: this may give false + # positives for string-literals that contain the string + # "#doctest:". Eliminating these false positives would require + # actually parsing the string; but we limit them by ignoring any + # line containing "#doctest:" that is *followed* by a quote mark. + _OPTION_DIRECTIVE_RE = re.compile(r'#\s*doctest:\s*([^\n\'"]*)$', + re.MULTILINE) + + def _find_options(self, source, name, lineno): + """ + Return a dictionary containing option overrides extracted from + option directives in the given source string. + + `name` is the string's name, and `lineno` is the line number + where the example starts; both are used for error messages. + """ + options = {} + # (note: with the current regexp, this will match at most once:) + for m in self._OPTION_DIRECTIVE_RE.finditer(source): + option_strings = m.group(1).replace(',', ' ').split() + for option in option_strings: + if (option[0] not in '+-' or + option[1:] not in OPTIONFLAGS_BY_NAME): + raise ValueError('line %r of the doctest for %s ' + 'has an invalid option: %r' % + (lineno+1, name, option)) + flag = OPTIONFLAGS_BY_NAME[option[1:]] + options[flag] = (option[0] == '+') + if options and self._IS_BLANK_OR_COMMENT(source): + raise ValueError('line %r of the doctest for %s has an option ' + 'directive on a line with no example: %r' % + (lineno, name, source)) + return options + + # This regular expression finds the indentation of every non-blank + # line in a string. + _INDENT_RE = re.compile('^([ ]*)(?=\S)', re.MULTILINE) + + def _min_indent(self, s): + "Return the minimum indentation of any non-blank line in `s`" + indents = [len(indent) for indent in self._INDENT_RE.findall(s)] + if len(indents) > 0: + return min(indents) + else: + return 0 + + def _check_prompt_blank(self, lines, indent, name, lineno): + """ + Given the lines of a source string (including prompts and + leading indentation), check to make sure that every prompt is + followed by a space character. If any line is not followed by + a space character, then raise ValueError. + """ + for i, line in enumerate(lines): + if len(line) >= indent+4 and line[indent+3] != ' ': + raise ValueError('line %r of the docstring for %s ' + 'lacks blank after %s: %r' % + (lineno+i+1, name, + line[indent:indent+3], line)) + + def _check_prefix(self, lines, prefix, name, lineno): + """ + Check that every line in the given list starts with the given + prefix; if any line does not, then raise a ValueError. + """ + for i, line in enumerate(lines): + if line and not line.startswith(prefix): + raise ValueError('line %r of the docstring for %s has ' + 'inconsistent leading whitespace: %r' % + (lineno+i+1, name, line)) + + +###################################################################### +## 4. DocTest Finder +###################################################################### + +class DocTestFinder: + """ + A class used to extract the DocTests that are relevant to a given + object, from its docstring and the docstrings of its contained + objects. Doctests can currently be extracted from the following + object types: modules, functions, classes, methods, staticmethods, + classmethods, and properties. + """ + + def __init__(self, verbose=False, parser=DocTestParser(), + recurse=True, _namefilter=None, exclude_empty=True): + """ + Create a new doctest finder. + + The optional argument `parser` specifies a class or + function that should be used to create new DocTest objects (or + objects that implement the same interface as DocTest). The + signature for this factory function should match the signature + of the DocTest constructor. + + If the optional argument `recurse` is false, then `find` will + only examine the given object, and not any contained objects. + + If the optional argument `exclude_empty` is false, then `find` + will include tests for objects with empty docstrings. + """ + self._parser = parser + self._verbose = verbose + self._recurse = recurse + self._exclude_empty = exclude_empty + # _namefilter is undocumented, and exists only for temporary backward- + # compatibility support of testmod's deprecated isprivate mess. + self._namefilter = _namefilter + + def find(self, obj, name=None, module=None, globs=None, + extraglobs=None): + """ + Return a list of the DocTests that are defined by the given + object's docstring, or by any of its contained objects' + docstrings. + + The optional parameter `module` is the module that contains + the given object. If the module is not specified or is None, then + the test finder will attempt to automatically determine the + correct module. The object's module is used: + + - As a default namespace, if `globs` is not specified. + - To prevent the DocTestFinder from extracting DocTests + from objects that are imported from other modules. + - To find the name of the file containing the object. + - To help find the line number of the object within its + file. + + Contained objects whose module does not match `module` are ignored. + + If `module` is False, no attempt to find the module will be made. + This is obscure, of use mostly in tests: if `module` is False, or + is None but cannot be found automatically, then all objects are + considered to belong to the (non-existent) module, so all contained + objects will (recursively) be searched for doctests. + + The globals for each DocTest is formed by combining `globs` + and `extraglobs` (bindings in `extraglobs` override bindings + in `globs`). A new copy of the globals dictionary is created + for each DocTest. If `globs` is not specified, then it + defaults to the module's `__dict__`, if specified, or {} + otherwise. If `extraglobs` is not specified, then it defaults + to {}. + + """ + # If name was not specified, then extract it from the object. + if name is None: + name = getattr(obj, '__name__', None) + if name is None: + raise ValueError("DocTestFinder.find: name must be given " + "when obj.__name__ doesn't exist: %r" % + (type(obj),)) + + # Find the module that contains the given object (if obj is + # a module, then module=obj.). Note: this may fail, in which + # case module will be None. + if module is False: + module = None + elif module is None: + module = inspect.getmodule(obj) + + # Read the module's source code. This is used by + # DocTestFinder._find_lineno to find the line number for a + # given object's docstring. + try: + file = inspect.getsourcefile(obj) or inspect.getfile(obj) + source_lines = linecache.getlines(file) + if not source_lines: + source_lines = None + except TypeError: + source_lines = None + + # Initialize globals, and merge in extraglobs. + if globs is None: + if module is None: + globs = {} + else: + globs = module.__dict__.copy() + else: + globs = globs.copy() + if extraglobs is not None: + globs.update(extraglobs) + + # Recursively expore `obj`, extracting DocTests. + tests = [] + self._find(tests, obj, name, module, source_lines, globs, {}) + return tests + + def _filter(self, obj, prefix, base): + """ + Return true if the given object should not be examined. + """ + return (self._namefilter is not None and + self._namefilter(prefix, base)) + + def _from_module(self, module, object): + """ + Return true if the given object is defined in the given + module. + """ + if module is None: + return True + elif inspect.isfunction(object): + return module.__dict__ is 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 = '' % (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'[\w\.]+)' + r'\[(?P\d+)\]>$') + def __patched_linecache_getlines(self, filename, module_globals=None): + m = self.__LINECACHE_FILENAME_RE.match(filename) + if m and m.group('name') == self.test.name: + example = self.test.examples[int(m.group('examplenum'))] + return example.source.splitlines(True) + elif 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 + + # can be used as a special sequence to signify a + # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. + if not (optionflags & DONT_ACCEPT_BLANKLINE): + # Replace in want with a blank line. + want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER), + '', want) + # If a line in got contains only spaces, then remove the + # spaces. + got = re.sub('(?m)^\s*?$', '', got) + if got == want: + return True + + # This flag causes doctest to ignore any differences in the + # contents of whitespace strings. Note that this can be used + # in conjunction with the ELLIPSIS flag. + if optionflags & NORMALIZE_WHITESPACE: + got = ' '.join(got.split()) + want = ' '.join(want.split()) + if got == want: + return True + + # The ELLIPSIS flag says to let the sequence "..." in `want` + # match any substring in `got`. + if optionflags & ELLIPSIS: + if _ellipsis_match(want, got): + return True + + # We didn't find any match; return false. + return False + + # Should we do a fancy diff? + def _do_a_fancy_diff(self, want, got, optionflags): + # Not unless they asked for a fancy diff. + if not optionflags & (REPORT_UDIFF | + REPORT_CDIFF | + REPORT_NDIFF): + return False + + # If expected output uses ellipsis, a meaningful fancy diff is + # too hard ... or maybe not. In two real-life failures Tim saw, + # a diff was a major help anyway, so this is commented out. + # [todo] _ellipsis_match() knows which pieces do and don't match, + # and could be the basis for a kick-ass diff in this case. + ##if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want: + ## return False + + # ndiff does intraline difference marking, so can be useful even + # for 1-line differences. + if optionflags & REPORT_NDIFF: + return True + + # The other diff types need at least a few lines to be helpful. + return want.count('\n') > 2 and got.count('\n') > 2 + + def output_difference(self, example, got, optionflags): + """ + Return a string describing the differences between the + expected output for a given example (`example`) and the actual + output (`got`). `optionflags` is the set of option flags used + to compare `want` and `got`. + """ + want = example.want + # If s are being used, then replace blank lines + # with in the actual output string. + if not (optionflags & DONT_ACCEPT_BLANKLINE): + got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got) + + # Check if we should use diff. + if self._do_a_fancy_diff(want, got, optionflags): + # Split want & got into lines. + want_lines = want.splitlines(True) # True == keep line ends + got_lines = got.splitlines(True) + # Use difflib to find their differences. + if optionflags & REPORT_UDIFF: + diff = difflib.unified_diff(want_lines, got_lines, n=2) + diff = list(diff)[2:] # strip the diff header + kind = 'unified diff with -expected +actual' + elif optionflags & REPORT_CDIFF: + diff = difflib.context_diff(want_lines, got_lines, n=2) + diff = list(diff)[2:] # strip the diff header + kind = 'context diff with expected followed by actual' + elif optionflags & REPORT_NDIFF: + engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) + diff = list(engine.compare(want_lines, got_lines)) + kind = 'ndiff with -expected +actual' + else: + assert 0, 'Bad diff option' + # Remove trailing whitespace on diff output. + diff = [line.rstrip() + '\n' for line in diff] + return 'Differences (%s):\n' % kind + _indent(''.join(diff)) + + # If we're not using diff, then simply list the expected + # output followed by the actual output. + if want and got: + return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got)) + elif want: + return 'Expected:\n%sGot nothing\n' % _indent(want) + elif got: + return 'Expected nothing\nGot:\n%s' % _indent(got) + else: + return 'Expected nothing\nGot nothing\n' + +class DocTestFailure(Exception): + """A DocTest example has failed in debugging mode. + + The exception instance has variables: + + - test: the DocTest object being run + + - excample: the Example object that failed + + - got: the actual output + """ + def __init__(self, test, example, got): + self.test = test + self.example = example + self.got = got + + def __str__(self): + return str(self.test) + +class UnexpectedException(Exception): + """A DocTest example has encountered an unexpected exception + + The exception instance has variables: + + - test: the DocTest object being run + + - excample: the Example object that failed + + - exc_info: the exception info + """ + def __init__(self, test, example, exc_info): + self.test = test + self.example = example + self.exc_info = exc_info + + def __str__(self): + return str(self.test) + +class DebugRunner(DocTestRunner): + r"""Run doc tests but raise an exception as soon as there is a failure. + + If an unexpected exception occurs, an UnexpectedException is raised. + It contains the test, the example, and the original exception: + + >>> runner = DebugRunner(verbose=False) + >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', + ... {}, 'foo', 'foo.py', 0) + >>> try: + ... runner.run(test) + ... except UnexpectedException, failure: + ... pass + + >>> failure.test is test + True + + >>> failure.example.want + '42\n' + + >>> exc_info = failure.exc_info + >>> raise exc_info[0], exc_info[1], exc_info[2] + Traceback (most recent call last): + ... + KeyError + + We wrap the original exception to give the calling application + access to the test and example information. + + If the output doesn't match, then a DocTestFailure is raised: + + >>> test = DocTestParser().get_doctest(''' + ... >>> x = 1 + ... >>> x + ... 2 + ... ''', {}, 'foo', 'foo.py', 0) + + >>> try: + ... runner.run(test) + ... except DocTestFailure, failure: + ... pass + + DocTestFailure objects provide access to the test: + + >>> failure.test is test + True + + As well as to the example: + + >>> failure.example.want + '2\n' + + and the actual output: + + >>> failure.got + '1\n' + + If a failure or error occurs, the globals are left intact: + + >>> del test.globs['__builtins__'] + >>> test.globs + {'x': 1} + + >>> test = DocTestParser().get_doctest(''' + ... >>> x = 2 + ... >>> raise KeyError + ... ''', {}, 'foo', 'foo.py', 0) + + >>> runner.run(test) + Traceback (most recent call last): + ... + UnexpectedException: + + >>> del test.globs['__builtins__'] + >>> test.globs + {'x': 2} + + But the globals are cleared if there is no error: + + >>> test = DocTestParser().get_doctest(''' + ... >>> x = 2 + ... ''', {}, 'foo', 'foo.py', 0) + + >>> runner.run(test) + (0, 1) + + >>> test.globs + {} + + """ + + def run(self, test, compileflags=None, out=None, clear_globs=True): + r = DocTestRunner.run(self, test, compileflags, out, False) + if clear_globs: + test.globs.clear() + return r + + def report_unexpected_exception(self, out, test, example, exc_info): + raise UnexpectedException(test, example, exc_info) + + def report_failure(self, out, test, example, got): + raise DocTestFailure(test, example, got) + +###################################################################### +## 6. Test Functions +###################################################################### +# These should be backwards compatible. + +# For backward compatibility, a global instance of a DocTestRunner +# class, updated by testmod. +master = None + +def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None, + report=True, optionflags=0, extraglobs=None, + raise_on_error=False, exclude_empty=False): + """m=None, name=None, globs=None, verbose=None, isprivate=None, + report=True, optionflags=0, extraglobs=None, raise_on_error=False, + exclude_empty=False + + Test examples in docstrings in functions and classes reachable + from module m (or the current module if m is not supplied), starting + with m.__doc__. Unless isprivate is specified, private names + are not skipped. + + Also test examples reachable from dict m.__test__ if it exists and is + not None. m.__test__ maps names to functions, classes and strings; + function and class docstrings are tested even if the name is private; + strings are tested directly, as if they were docstrings. + + Return (#failures, #tests). + + See doctest.__doc__ for an overview. + + Optional keyword arg "name" gives the name of the module; by default + use m.__name__. + + Optional keyword arg "globs" gives a dict to be used as the globals + when executing examples; by default, use m.__dict__. A copy of this + dict is actually used for each docstring, so that each docstring's + examples start with a clean slate. + + Optional keyword arg "extraglobs" gives a dictionary that should be + merged into the globals that are used to execute examples. By + default, no extra globals are used. This is new in 2.4. + + Optional keyword arg "verbose" prints lots of stuff if true, prints + only failures if false; by default, it's true iff "-v" is in sys.argv. + + Optional keyword arg "report" prints a summary at the end when true, + else prints nothing at the end. In verbose mode, the summary is + detailed, else very brief (in fact, empty if all tests passed). + + Optional keyword arg "optionflags" or's together module constants, + and defaults to 0. This is new in 2.3. Possible values (see the + docs for details): + + DONT_ACCEPT_TRUE_FOR_1 + DONT_ACCEPT_BLANKLINE + NORMALIZE_WHITESPACE + ELLIPSIS + IGNORE_EXCEPTION_DETAIL + REPORT_UDIFF + REPORT_CDIFF + REPORT_NDIFF + REPORT_ONLY_FIRST_FAILURE + + Optional keyword arg "raise_on_error" raises an exception on the + first unexpected exception or failure. This allows failures to be + post-mortem debugged. + + Deprecated in Python 2.4: + Optional keyword arg "isprivate" specifies a function used to + determine whether a name is private. The default function is + treat all functions as public. Optionally, "isprivate" can be + set to doctest.is_private to skip over functions marked as private + using the underscore naming convention; see its docs for details. + + Advanced tomfoolery: testmod runs methods of a local instance of + class doctest.Tester, then merges the results into (or creates) + global Tester instance doctest.master. Methods of doctest.master + can be called directly too, if you want to do something unusual. + Passing report=0 to testmod is especially useful then, to delay + displaying a summary. Invoke doctest.master.summarize(verbose) + when you're done fiddling. + """ + global master + + if isprivate is not None: + warnings.warn("the isprivate argument is deprecated; " + "examine DocTestFinder.find() lists instead", + DeprecationWarning) + + # If no module was given, then use __main__. + if m is None: + # DWA - m will still be None if this wasn't invoked from the command + # line, in which case the following TypeError is about as good an error + # as we should expect + m = sys.modules.get('__main__') + + # Check that we were actually given a module. + if not inspect.ismodule(m): + raise TypeError("testmod: module required; %r" % (m,)) + + # If no name was given, then use the module's name. + if name is None: + name = m.__name__ + + # Find, parse, and run all tests in the given module. + finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty) + + if raise_on_error: + runner = DebugRunner(verbose=verbose, optionflags=optionflags) + else: + runner = DocTestRunner(verbose=verbose, optionflags=optionflags) + + for test in finder.find(m, name, globs=globs, extraglobs=extraglobs): + runner.run(test) + + if report: + runner.summarize() + + if master is None: + master = runner + else: + master.merge(runner) + + return runner.failures, runner.tries + +def testfile(filename, module_relative=True, name=None, package=None, + globs=None, verbose=None, report=True, optionflags=0, + extraglobs=None, raise_on_error=False, parser=DocTestParser()): + """ + Test examples in the given file. Return (#failures, #tests). + + Optional keyword arg "module_relative" specifies how filenames + should be interpreted: + + - If "module_relative" is True (the default), then "filename" + specifies a module-relative path. By default, this path is + relative to the calling module's directory; but if the + "package" argument is specified, then it is relative to that + package. To ensure os-independence, "filename" should use + "/" characters to separate path segments, and should not + be an absolute path (i.e., it may not begin with "/"). + + - If "module_relative" is False, then "filename" specifies an + os-specific path. The path may be absolute or relative (to + the current working directory). + + Optional keyword arg "name" gives the name of the test; by default + use the file's basename. + + Optional keyword argument "package" is a Python package or the + name of a Python package whose directory should be used as the + base directory for a module relative filename. If no package is + specified, then the calling module's directory is used as the base + directory for module relative filenames. It is an error to + specify "package" if "module_relative" is False. + + Optional keyword arg "globs" gives a dict to be used as the globals + when executing examples; by default, use {}. A copy of this dict + is actually used for each docstring, so that each docstring's + examples start with a clean slate. + + Optional keyword arg "extraglobs" gives a dictionary that should be + merged into the globals that are used to execute examples. By + default, no extra globals are used. + + Optional keyword arg "verbose" prints lots of stuff if true, prints + only failures if false; by default, it's true iff "-v" is in sys.argv. + + Optional keyword arg "report" prints a summary at the end when true, + else prints nothing at the end. In verbose mode, the summary is + detailed, else very brief (in fact, empty if all tests passed). + + Optional keyword arg "optionflags" or's together module constants, + and defaults to 0. Possible values (see the docs for details): + + DONT_ACCEPT_TRUE_FOR_1 + DONT_ACCEPT_BLANKLINE + NORMALIZE_WHITESPACE + ELLIPSIS + IGNORE_EXCEPTION_DETAIL + REPORT_UDIFF + REPORT_CDIFF + REPORT_NDIFF + REPORT_ONLY_FIRST_FAILURE + + Optional keyword arg "raise_on_error" raises an exception on the + first unexpected exception or failure. This allows failures to be + post-mortem debugged. + + Optional keyword arg "parser" specifies a DocTestParser (or + subclass) that should be used to extract tests from the files. + + Advanced tomfoolery: testmod runs methods of a local instance of + class doctest.Tester, then merges the results into (or creates) + global Tester instance doctest.master. Methods of doctest.master + can be called directly too, if you want to do something unusual. + Passing report=0 to testmod is especially useful then, to delay + displaying a summary. Invoke doctest.master.summarize(verbose) + when you're done fiddling. + """ + global master + + if package and not module_relative: + raise ValueError("Package may only be specified for module-" + "relative paths.") + + # Relativize the path + if module_relative: + package = _normalize_module(package) + filename = _module_relative_path(package, filename) + + # If no name was given, then use the file's name. + if name is None: + name = os.path.basename(filename) + + # Assemble the globals. + if globs is None: + globs = {} + else: + globs = globs.copy() + if extraglobs is not None: + globs.update(extraglobs) + + if raise_on_error: + runner = DebugRunner(verbose=verbose, optionflags=optionflags) + else: + runner = DocTestRunner(verbose=verbose, optionflags=optionflags) + + # Read the file, convert it to a test, and run it. + s = open(filename).read() + 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) + doc = open(path).read() + + # Convert it to a test, and wrap it in a DocFileCase. + test = parser.get_doctest(doc, globs, name, path, 0) + return DocFileCase(test, **options) + +def DocFileSuite(*paths, **kw): + """A unittest suite for one or more doctest files. + + The path to each doctest file is given as a string; the + interpretation of that string depends on the keyword argument + "module_relative". + + A number of options may be provided as keyword arguments: + + module_relative + If "module_relative" is True, then the given file paths are + interpreted as os-independent module-relative paths. By + default, these paths are relative to the calling module's + directory; but if the "package" argument is specified, then + they are relative to that package. To ensure os-independence, + "filename" should use "/" characters to separate path + segments, and may not be an absolute path (i.e., it may not + begin with "/"). + + If "module_relative" is False, then the given file paths are + interpreted as os-specific paths. These paths may be absolute + or relative (to the current working directory). + + package + A Python package or the name of a Python package whose directory + should be used as the base directory for module relative paths. + If "package" is not specified, then the calling module's + directory is used as the base directory for module relative + filenames. It is an error to specify "package" if + "module_relative" is False. + + setUp + A set-up function. This is called before running the + tests in each file. The setUp function will be passed a DocTest + object. The setUp function can access the test globals as the + globs attribute of the test passed. + + tearDown + A tear-down function. This is called after running the + tests in each file. The tearDown function will be passed a DocTest + object. The tearDown function can access the test globals as the + globs attribute of the test passed. + + globs + A dictionary containing initial global variables for the tests. + + optionflags + A set of doctest option flags expressed as an integer. + + parser + A DocTestParser (or subclass) that should be used to extract + tests from the files. + """ + suite = unittest.TestSuite() + + # We do this here so that _normalize_module is called at the right + # level. If it were called in DocFileTest, then this function + # would be the caller and we might guess the package incorrectly. + if kw.get('module_relative', True): + kw['package'] = _normalize_module(kw.get('package')) + + for path in paths: + suite.addTest(DocFileTest(path, **kw)) + + return suite + +###################################################################### +## 9. Debugging Support +###################################################################### + +def script_from_examples(s): + r"""Extract script from text with examples. + + Converts text with examples to a Python script. Example input is + converted to regular code. Example output and all other words + are converted to comments: + + >>> text = ''' + ... Here are examples of simple math. + ... + ... Python has super accurate integer addition + ... + ... >>> 2 + 2 + ... 5 + ... + ... And very friendly error messages: + ... + ... >>> 1/0 + ... To Infinity + ... And + ... Beyond + ... + ... You can use logic if you want: + ... + ... >>> if 0: + ... ... blah + ... ... blah + ... ... + ... + ... Ho hum + ... ''' + + >>> print script_from_examples(text) + # Here are examples of simple math. + # + # Python has super accurate integer addition + # + 2 + 2 + # Expected: + ## 5 + # + # And very friendly error messages: + # + 1/0 + # Expected: + ## To Infinity + ## And + ## Beyond + # + # You can use logic if you want: + # + if 0: + blah + blah + # + # Ho hum + """ + output = [] + for piece in DocTestParser().parse(s): + if isinstance(piece, Example): + # Add the example's source code (strip trailing NL) + output.append(piece.source[:-1]) + # Add the expected output: + want = piece.want + if want: + output.append('# Expected:') + output += ['## '+l for l in want.split('\n')[:-1]] + else: + # Add non-example text. + output += [_comment_line(l) + for l in piece.split('\n')[:-1]] + + # Trim junk on both ends. + while output and output[-1] == '#': + output.pop() + while output and output[0] == '#': + output.pop(0) + # Combine the output, and return it. + return '\n'.join(output) + +def testsource(module, name): + """Extract the test sources from a doctest docstring as a script. + + Provide the module (or dotted name of the module) containing the + test to be debugged and the name (within the module) of the object + with the doc string with tests to be debugged. + """ + module = _normalize_module(module) + tests = DocTestFinder().find(module) + test = [t for t in tests if t.name == name] + if not test: + raise ValueError(name, "not found in tests") + test = test[0] + testsrc = script_from_examples(test.docstring) + return testsrc + +def debug_src(src, pm=False, globs=None): + """Debug a single doctest docstring, in argument `src`'""" + testsrc = script_from_examples(src) + debug_script(testsrc, pm, globs) + +def debug_script(src, pm=False, globs=None): + "Debug a test script. `src` is the script, as a string." + import pdb + + # Note that tempfile.NameTemporaryFile() cannot be used. As the + # docs say, a file so created cannot be opened by name a second time + # on modern Windows boxes, and execfile() needs to open it. + srcfilename = tempfile.mktemp(".py", "doctestdebug") + f = open(srcfilename, 'w') + f.write(src) + f.close() + + try: + if globs: + globs = globs.copy() + else: + globs = {} + + if pm: + try: + execfile(srcfilename, globs, globs) + except: + print sys.exc_info()[1] + pdb.post_mortem(sys.exc_info()[2]) + else: + # Note that %r is vital here. '%s' instead can, e.g., cause + # backslashes to get treated as metacharacters on Windows. + pdb.run("execfile(%r)" % srcfilename, globs, globs) + + finally: + os.remove(srcfilename) + +def debug(module, name, pm=False): + """Debug a single doctest docstring. + + Provide the module (or dotted name of the module) containing the + test to be debugged and the name (within the module) of the object + with the docstring with tests to be debugged. + """ + module = _normalize_module(module) + testsrc = testsource(module, name) + debug_script(testsrc, pm, module.__dict__) + +###################################################################### +## 10. Example Usage +###################################################################### +class _TestClass: + """ + A pointless class, for sanity-checking of docstring testing. + + Methods: + square() + get() + + >>> _TestClass(13).get() + _TestClass(-12).get() + 1 + >>> hex(_TestClass(13).square().get()) + '0xa9' + """ + + def __init__(self, val): + """val -> _TestClass object with associated value val. + + >>> t = _TestClass(123) + >>> print t.get() + 123 + """ + + self.val = val + + def square(self): + """square() -> square TestClass's associated value + + >>> _TestClass(13).square().get() + 169 + """ + + self.val = self.val ** 2 + return self + + def get(self): + """get() -> return TestClass's associated value. + + >>> x = _TestClass(-42) + >>> print x.get() + -42 + """ + + return self.val + +__test__ = {"_TestClass": _TestClass, + "string": r""" + Example of a string object, searched as-is. + >>> x = 1; y = 2 + >>> x + y, x * y + (3, 2) + """, + + "bool-int equivalence": r""" + In 2.2, boolean expressions displayed + 0 or 1. By default, we still accept + them. This can be disabled by passing + DONT_ACCEPT_TRUE_FOR_1 to the new + optionflags argument. + >>> 4 == 4 + 1 + >>> 4 == 4 + True + >>> 4 > 4 + 0 + >>> 4 > 4 + False + """, + + "blank lines": r""" + Blank lines can be marked with : + >>> print 'foo\n\nbar\n' + foo + + bar + + """, + + "ellipsis": r""" + If the ellipsis flag is used, then '...' can be used to + elide substrings in the desired output: + >>> print range(1000) #doctest: +ELLIPSIS + [0, 1, 2, ..., 999] + """, + + "whitespace normalization": r""" + If the whitespace normalization flag is used, then + differences in whitespace are ignored. + >>> print range(30) #doctest: +NORMALIZE_WHITESPACE + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29] + """, + } + +def _test(): + r = unittest.TextTestRunner() + r.run(DocTestSuite()) + +if __name__ == "__main__": + _test() + diff --git a/vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/external.html b/vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/external.html new file mode 100644 index 0000000..92e4702 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/external.html @@ -0,0 +1,3 @@ + +bad old link + diff --git a/vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html b/vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html new file mode 100644 index 0000000..fefb028 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/indexes/test_links_priority/simple/foobar/index.html @@ -0,0 +1,4 @@ + +foobar-0.1.tar.gz
    +external homepage
    + diff --git a/vendor/distribute-0.6.31/setuptools/tests/py26compat.py b/vendor/distribute-0.6.31/setuptools/tests/py26compat.py new file mode 100644 index 0000000..d4fb891 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/server.py b/vendor/distribute-0.6.31/setuptools/tests/server.py new file mode 100644 index 0000000..b2ab7ac --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_bdist_egg.py b/vendor/distribute-0.6.31/setuptools/tests/test_bdist_egg.py new file mode 100644 index 0000000..7da122c --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_build_ext.py b/vendor/distribute-0.6.31/setuptools/tests/test_build_ext.py new file mode 100644 index 0000000..a520ced --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_develop.py b/vendor/distribute-0.6.31/setuptools/tests/test_develop.py new file mode 100644 index 0000000..3e071da --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/test_develop.py @@ -0,0 +1,114 @@ +"""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. + path = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt').read().split()[0].strip() + init = open(os.path.join(path, 'foo', '__init__.py'), 'rt').read().strip() + 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.31/setuptools/tests/test_dist_info.py b/vendor/distribute-0.6.31/setuptools/tests/test_dist_info.py new file mode 100644 index 0000000..fcb78c3 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_easy_install.py b/vendor/distribute-0.6.31/setuptools/tests/test_easy_install.py new file mode 100644 index 0000000..1540bdc --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/test_easy_install.py @@ -0,0 +1,526 @@ +"""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, 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 working_set, VersionConflict +from pkg_resources import Distribution as PRDistribution +import setuptools.tests.server +import pkg_resources + +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')() + ) +""" % 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') + except: + 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_pkg = create_setup_requires_package(self.dir) + test_setup_py = os.path.join(test_pkg, 'setup.py') + + try: + quiet_context( + lambda: reset_setup_stop_context( + lambda: run_setup(test_setup_py, ['install']) + )) + except SandboxViolation: + self.fail('Installation caused SandboxViolation') + + +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. + quiet_context(lambda: 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 test_setup_requires_overrides_version_conflict(self): + """ + Regression test for issue #323. + + Ensures that a distribution's setup_requires requirements can still be + installed and used locally even if a conflicting version of that + requirement is already on the path. + """ + + pr_state = pkg_resources.__getstate__() + fake_dist = PRDistribution('does-not-matter', project_name='foobar', + version='0.0') + working_set.add(fake_dist) + + def setup_and_run(temp_dir): + test_pkg = create_setup_requires_package(temp_dir) + test_setup_py = os.path.join(test_pkg, 'setup.py') + try: + stdout, stderr = quiet_context( + lambda: reset_setup_stop_context( + # Don't even need to install the package, just running + # the setup.py at all is sufficient + lambda: run_setup(test_setup_py, ['--name']) + )) + except VersionConflict: + self.fail('Installing setup.py requirements caused ' + 'VersionConflict') + + lines = stdout.splitlines() + self.assertGreater(len(lines), 0) + self.assert_(lines[-1].strip(), 'test_pkg') + + try: + tempdir_context(setup_and_run) + finally: + pkg_resources.__setstate__(pr_state) + + +def create_setup_requires_package(path): + """Creates a source tree under path for a trivial test package that has a + single requirement in setup_requires--a tarball for that requirement is + also created and added to the dependency_links argument. + """ + + test_setup_attrs = { + 'name': 'test_pkg', 'version': '0.0', + 'setup_requires': ['foobar==0.1'], + 'dependency_links': [os.path.abspath(path)] + } + + test_pkg = os.path.join(path, '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(path, 'foobar-0.1.tar.gz') + make_trivial_sdist( + foobar_path, + textwrap.dedent("""\ + import setuptools + setuptools.setup( + name='foobar', + version='0.1' + ) + """)) + + return test_pkg + + +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 + + +def quiet_context(f): + """ + Redirect stdout/stderr to StringIO objects to prevent console output from + distutils commands. + """ + + old_stdout = sys.stdout + old_stderr = sys.stderr + new_stdout = sys.stdout = StringIO.StringIO() + new_stderr = sys.stderr = StringIO.StringIO() + try: + f() + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + return new_stdout.getvalue(), new_stderr.getvalue() diff --git a/vendor/distribute-0.6.31/setuptools/tests/test_markerlib.py b/vendor/distribute-0.6.31/setuptools/tests/test_markerlib.py new file mode 100644 index 0000000..7ff2f58 --- /dev/null +++ b/vendor/distribute-0.6.31/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.assert_(interpret("")) + + self.assert_(interpret("os.name != 'buuuu'")) + self.assert_(interpret("python_version > '1.0'")) + self.assert_(interpret("python_version < '5.0'")) + self.assert_(interpret("python_version <= '5.0'")) + self.assert_(interpret("python_version >= '1.0'")) + self.assert_(interpret("'%s' in os.name" % os_name)) + self.assert_(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.assert_(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.31/setuptools/tests/test_packageindex.py b/vendor/distribute-0.6.31/setuptools/tests/test_packageindex.py new file mode 100644 index 0000000..3e446b5 --- /dev/null +++ b/vendor/distribute-0.6.31/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 = ('') + 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.31/setuptools/tests/test_resources.py b/vendor/distribute-0.6.31/setuptools/tests/test_resources.py new file mode 100644 index 0000000..d08fa32 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/test_resources.py @@ -0,0 +1,649 @@ +#!/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('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', '0rc1') + c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a') + + def testVersionOrdering(self): + def c(s1,s2): + p1, p2 = parse_version(s1),parse_version(s2) + self.assertTrue(p1= (3,) and os.environ.get("LC_CTYPE") + in (None, "C", "POSIX")): + return + 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: + 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.31/setuptools/tests/test_sandbox.py b/vendor/distribute-0.6.31/setuptools/tests/test_sandbox.py new file mode 100644 index 0000000..1609ee8 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_sdist.py b/vendor/distribute-0.6.31/setuptools/tests/test_sdist.py new file mode 100644 index 0000000..a9d5d6e --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_test.py b/vendor/distribute-0.6.31/setuptools/tests/test_test.py new file mode 100644 index 0000000..ad7cbd0 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/test_upload_docs.py b/vendor/distribute-0.6.31/setuptools/tests/test_upload_docs.py new file mode 100644 index 0000000..769f16c --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/setuptools/tests/win_script_wrapper.txt b/vendor/distribute-0.6.31/setuptools/tests/win_script_wrapper.txt new file mode 100644 index 0000000..2e1bff7 --- /dev/null +++ b/vendor/distribute-0.6.31/setuptools/tests/win_script_wrapper.txt @@ -0,0 +1,137 @@ +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() + >>> open(os.path.join(sample_directory, 'foo-script.py'), 'w').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))) + +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 + >>> open(os.path.join(sample_directory, 'foo.exe'), 'wb').write( + ... pkg_resources.resource_string('setuptools', 'cli.exe') + ... ) + +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: + + >>> open(os.path.join(sample_directory, 'foo-script.py'), 'w').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))) + + >>> 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() + >>> open(os.path.join(sample_directory, 'bar-script.pyw'), 'w').write( + ... """#!%(python_exe)s + ... import sys + ... open(sys.argv[1], 'wb').write(repr(sys.argv[2])) + ... """ % dict(python_exe=nt_quote_arg(sys.executable))) + +We'll also copy gui.exe to the sample-directory with the name bar.exe: + + >>> import pkg_resources + >>> open(os.path.join(sample_directory, 'bar.exe'), 'wb').write( + ... pkg_resources.resource_string('setuptools', 'gui.exe') + ... ) + +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() + + >>> print open(os.path.join(sample_directory, 'test_output.txt'), 'rb').read() + 'Test Argument' + + +We're done with the sample_directory: + + >>> import shutil + >>> shutil.rmtree(sample_directory) + diff --git a/vendor/distribute-0.6.31/site.py b/vendor/distribute-0.6.31/site.py new file mode 100644 index 0000000..a7166f1 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/api_tests.txt b/vendor/distribute-0.6.31/tests/api_tests.txt new file mode 100644 index 0000000..6cf6e66 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/install_test.py b/vendor/distribute-0.6.31/tests/install_test.py new file mode 100644 index 0000000..02deb81 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/manual_test.py b/vendor/distribute-0.6.31/tests/manual_test.py new file mode 100644 index 0000000..0d5051f --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/shlib_test/hello.c b/vendor/distribute-0.6.31/tests/shlib_test/hello.c new file mode 100644 index 0000000..9998372 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/shlib_test/hello.pyx b/vendor/distribute-0.6.31/tests/shlib_test/hello.pyx new file mode 100644 index 0000000..58ce691 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/shlib_test/hellolib.c b/vendor/distribute-0.6.31/tests/shlib_test/hellolib.c new file mode 100644 index 0000000..88d65ce --- /dev/null +++ b/vendor/distribute-0.6.31/tests/shlib_test/hellolib.c @@ -0,0 +1,3 @@ +extern char* get_hello_msg() { + return "Hello, world!"; +} diff --git a/vendor/distribute-0.6.31/tests/shlib_test/setup.py b/vendor/distribute-0.6.31/tests/shlib_test/setup.py new file mode 100644 index 0000000..b0c9399 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/shlib_test/test_hello.py b/vendor/distribute-0.6.31/tests/shlib_test/test_hello.py new file mode 100644 index 0000000..6da02e3 --- /dev/null +++ b/vendor/distribute-0.6.31/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.31/tests/test_distribute_setup.py b/vendor/distribute-0.6.31/tests/test_distribute_setup.py new file mode 100644 index 0000000..1f3da05 --- /dev/null +++ b/vendor/distribute-0.6.31/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() diff --git a/vendor/virtualenv-1.8.4/virtualenv_support/pip-1.2.1.tar.gz b/vendor/pip-1.2.1.tar.gz similarity index 100% rename from vendor/virtualenv-1.8.4/virtualenv_support/pip-1.2.1.tar.gz rename to vendor/pip-1.2.1.tar.gz diff --git a/vendor/pip-1.2.1/.gitignore b/vendor/pip-1.2.1/.gitignore new file mode 100644 index 0000000..0fe9490 --- /dev/null +++ b/vendor/pip-1.2.1/.gitignore @@ -0,0 +1,23 @@ +MANIFEST +tests/test-scratch/* +tests/test-cache/* +tests/packages/FSPkg/FSPkg.egg-info +testenv +pip.egg-info/* +ScriptTest-*.egg +virtualenv-*.egg +nose-*.egg/* +wsgi_intercept-*.egg/* +WSGIProxy-*.egg/* +WebOb-*.egg +Paste-*.egg/* +mock-*egg +tests/tests_cache/* +dist/* +docs/_build/* +build/* +*.pyc +*.pyo +pip-log.txt +pip.log +*.~ diff --git a/vendor/pip-1.2.1/AUTHORS.txt b/vendor/pip-1.2.1/AUTHORS.txt new file mode 100644 index 0000000..5fa5711 --- /dev/null +++ b/vendor/pip-1.2.1/AUTHORS.txt @@ -0,0 +1,48 @@ +Alex Grönholm +Alex Morega +Alexandre Conrad +Antti Kaihola +Armin Ronacher +Brian Rosner +Carl Meyer +Christian Oudard +Cody Soyland +Daniel Holth +Dave Abrahams +Francesco +Hugo Lopes Tavares +Ian Bicking +Igor Sobreira +Ionel Maries Cristian +Jakub Vysoky +Jannis Leidel +Jay Graves +John-Scott Atlakson +Jon Parise +Josh Bronson +Kelsey Hightower +Kenneth Belitzky +Kumar McMillan +Luke Macken +Masklinn +Marc Abramowitz +Marcus Smith +Matt Maker +Nowell Strite +Oliver Tonnhofer +Olivier Girardot +Patrick Jenkins +Paul Nasrat +Paul Oswald +Paul van der Linden +Peter Waller +Piet Delport +Qiangning Hong +Rene Dudfield +Ronny Pfannschmidt +Simon Cross +Stavros Korokithakis +Thomas Johansson +Vinay Sajip +Vitaly Babiy +Wil Tan diff --git a/vendor/virtualenv-1.8.4/LICENSE.txt b/vendor/pip-1.2.1/LICENSE.txt similarity index 86% rename from vendor/virtualenv-1.8.4/LICENSE.txt rename to vendor/pip-1.2.1/LICENSE.txt index 0d82cc9..7951a03 100644 --- a/vendor/virtualenv-1.8.4/LICENSE.txt +++ b/vendor/pip-1.2.1/LICENSE.txt @@ -1,6 +1,4 @@ -Copyright (c) 2007 Ian Bicking and Contributors -Copyright (c) 2009 Ian Bicking, The Open Planning Project -Copyright (c) 2011-2012 The virtualenv developers +Copyright (c) 2008-2011 The pip developers (see AUTHORS.txt file) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/vendor/pip-1.2.1/MANIFEST.in b/vendor/pip-1.2.1/MANIFEST.in new file mode 100644 index 0000000..add9bf1 --- /dev/null +++ b/vendor/pip-1.2.1/MANIFEST.in @@ -0,0 +1,6 @@ +include AUTHORS.txt +include LICENSE.txt +recursive-include docs *.txt +recursive-include docs *.html +recursive-exclude docs/_build *.txt +prune docs/_build/_sources diff --git a/vendor/pip-1.2.1/contrib/build-installer b/vendor/pip-1.2.1/contrib/build-installer new file mode 100755 index 0000000..8a0e1af --- /dev/null +++ b/vendor/pip-1.2.1/contrib/build-installer @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import os +import sys +from packager import generate_script + +here = os.path.dirname(os.path.abspath(__file__)) +file_name = os.path.join(here, 'get-pip.py') + +entry = """ +import sys +try: + import setuptools + import pkg_resources +except ImportError: + raise SystemExit("An error occured while trying to run %s. Make sure " + "you have setuptools or distribute installed." % __file__) +import pip +pip.bootstrap() +""" + +def main(): + sys.stdout.write("Creating pip bootstrapper...") + script = generate_script(entry, ['pip']) + f = open(file_name, 'w') + try: + f.write(script) + finally: + f.close() + sys.stdout.write('done.\n') + if hasattr(os, 'chmod'): + oldmode = os.stat(file_name).st_mode & 07777 + newmode = (oldmode | 0555) & 07777 + os.chmod(file_name, newmode) + sys.stdout.write('Made resulting file %s executable.\n\n' % file_name) + +if __name__ == '__main__': + main() diff --git a/vendor/pip-1.2.1/contrib/build-standalone b/vendor/pip-1.2.1/contrib/build-standalone new file mode 100755 index 0000000..b2a1aeb --- /dev/null +++ b/vendor/pip-1.2.1/contrib/build-standalone @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import os +import sys +from packager import generate_script + +here = os.path.dirname(os.path.abspath(__file__)) +file_name = os.path.join(here, 'run-pip.py') + +entry = """ +import sys +try: + import setuptools + import pkg_resources +except ImportError: + raise SystemExit("An error occured while trying to run %s. Make sure " + "you have setuptools or distribute installed." % __file__) +import pip +pip.main() +""" + +def main(): + sys.stdout.write("Creating standalone pip...") + script = generate_script(entry, ['pip']) + f = open(file_name, 'w') + try: + f.write(script) + finally: + f.close() + sys.stdout.write('done.\n') + if hasattr(os, 'chmod'): + oldmode = os.stat(file_name).st_mode & 07777 + newmode = (oldmode | 0555) & 07777 + os.chmod(file_name, newmode) + sys.stdout.write('Made resulting file %s executable.\n\n' % file_name) + +if __name__ == '__main__': + main() diff --git a/vendor/pip-1.2.1/contrib/get-pip.py b/vendor/pip-1.2.1/contrib/get-pip.py new file mode 100755 index 0000000..9fd5b30 --- /dev/null +++ b/vendor/pip-1.2.1/contrib/get-pip.py @@ -0,0 +1,1153 @@ +#! /usr/bin/env python + +sources = """ +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 +""" + +import os +import sys +import base64 +import zlib +import tempfile +import shutil + + +def unpack(sources): + temp_dir = tempfile.mkdtemp('-scratchdir', 'unpacker-') + for package, content in sources.items(): + filepath = package.split(".") + dirpath = os.sep.join(filepath[:-1]) + packagedir = os.path.join(temp_dir, dirpath) + if not os.path.isdir(packagedir): + os.makedirs(packagedir) + mod = open(os.path.join(packagedir, "%s.py" % filepath[-1]), 'wb') + try: + mod.write(content.encode("ascii")) + finally: + mod.close() + return temp_dir + +if __name__ == "__main__": + if sys.version_info >= (3, 0): + exec("def do_exec(co, loc): exec(co, loc)\n") + import pickle + sources = sources.encode("ascii") # ensure bytes + sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) + else: + import cPickle as pickle + exec("def do_exec(co, loc): exec co in loc\n") + sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) + + try: + temp_dir = unpack(sources) + sys.path.insert(0, temp_dir) + + entry = """ +import sys +try: + import setuptools + import pkg_resources +except ImportError: + raise SystemExit("An error occured while trying to run %s. Make sure " + "you have setuptools or distribute installed." % __file__) +import pip +pip.bootstrap() +""" + do_exec(entry, locals()) + finally: + shutil.rmtree(temp_dir) diff --git a/vendor/pip-1.2.1/contrib/packager/__init__.py b/vendor/pip-1.2.1/contrib/packager/__init__.py new file mode 100644 index 0000000..9606831 --- /dev/null +++ b/vendor/pip-1.2.1/contrib/packager/__init__.py @@ -0,0 +1,68 @@ +# Port of Ronny Pfannschmidt's genscript package +# https://bitbucket.org/RonnyPfannschmidt/genscript + +import sys +import pickle +import zlib +import base64 +import os +import fnmatch + + +def find_toplevel(name): + for syspath in sys.path: + lib = os.path.join(syspath, name) + if os.path.isdir(lib): + return lib + mod = lib + '.py' + if os.path.isfile(mod): + return mod + raise LookupError(name) + + +def pkgname(toplevel, rootpath, path): + parts = path.split(os.sep)[len(rootpath.split(os.sep)):] + return '.'.join([toplevel] + [os.path.splitext(x)[0] for x in parts]) + + +def pkg_to_mapping(name): + toplevel = find_toplevel(name) + if os.path.isfile(toplevel): + return {name: toplevel.read()} + + name2src = {} + for root, dirs, files in os.walk(toplevel): + for pyfile in files: + if fnmatch.fnmatch(pyfile, '*.py'): + pkg = pkgname(name, toplevel, os.path.join(root, pyfile)) + f = open(os.path.join(root, pyfile)) + try: + name2src[pkg] = f.read() + finally: + f.close() + return name2src + + +def compress_mapping(mapping): + data = pickle.dumps(mapping, 2) + data = zlib.compress(data, 9) + data = base64.encodestring(data) + data = data.decode('ascii') + return data + + +def compress_packages(names): + mapping = {} + for name in names: + mapping.update(pkg_to_mapping(name)) + return compress_mapping(mapping) + + +def generate_script(entry, packages): + data = compress_packages(packages) + tmpl = open(os.path.join(os.path.dirname(__file__), 'template.py')) + exe = tmpl.read() + tmpl.close() + exe = exe.replace('@SOURCES@', data) + exe = exe.replace('@ENTRY@', entry) + return exe diff --git a/vendor/pip-1.2.1/contrib/packager/template.py b/vendor/pip-1.2.1/contrib/packager/template.py new file mode 100644 index 0000000..4069589 --- /dev/null +++ b/vendor/pip-1.2.1/contrib/packager/template.py @@ -0,0 +1,48 @@ +#! /usr/bin/env python + +sources = """ +@SOURCES@""" + +import os +import sys +import base64 +import zlib +import tempfile +import shutil + + +def unpack(sources): + temp_dir = tempfile.mkdtemp('-scratchdir', 'unpacker-') + for package, content in sources.items(): + filepath = package.split(".") + dirpath = os.sep.join(filepath[:-1]) + packagedir = os.path.join(temp_dir, dirpath) + if not os.path.isdir(packagedir): + os.makedirs(packagedir) + mod = open(os.path.join(packagedir, "%s.py" % filepath[-1]), 'wb') + try: + mod.write(content.encode("ascii")) + finally: + mod.close() + return temp_dir + + +if __name__ == "__main__": + if sys.version_info >= (3, 0): + exec("def do_exec(co, loc): exec(co, loc)\n") + import pickle + sources = sources.encode("ascii") # ensure bytes + sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) + else: + import cPickle as pickle + exec("def do_exec(co, loc): exec co in loc\n") + sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) + + try: + temp_dir = unpack(sources) + sys.path.insert(0, temp_dir) + + entry = """@ENTRY@""" + do_exec(entry, locals()) + finally: + shutil.rmtree(temp_dir) diff --git a/vendor/virtualenv-1.8.4/docs/Makefile b/vendor/pip-1.2.1/docs/Makefile similarity index 100% rename from vendor/virtualenv-1.8.4/docs/Makefile rename to vendor/pip-1.2.1/docs/Makefile diff --git a/vendor/pip-1.2.1/docs/_static/launch-jnlp-slave.JPG b/vendor/pip-1.2.1/docs/_static/launch-jnlp-slave.JPG new file mode 100644 index 0000000000000000000000000000000000000000..01b91e7f76d66650f761eb9ed5babaa2b2118562 GIT binary patch literal 112547 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 E1zx2-i2wiq literal 0 HcmV?d00001 diff --git a/vendor/pip-1.2.1/docs/_theme/nature/static/nature.css_t b/vendor/pip-1.2.1/docs/_theme/nature/static/nature.css_t new file mode 100644 index 0000000..c144c22 --- /dev/null +++ b/vendor/pip-1.2.1/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/pip-1.2.1/docs/_theme/nature/static/pygments.css b/vendor/pip-1.2.1/docs/_theme/nature/static/pygments.css new file mode 100644 index 0000000..652b761 --- /dev/null +++ b/vendor/pip-1.2.1/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/pip-1.2.1/docs/_theme/nature/theme.conf b/vendor/pip-1.2.1/docs/_theme/nature/theme.conf new file mode 100644 index 0000000..1cc4004 --- /dev/null +++ b/vendor/pip-1.2.1/docs/_theme/nature/theme.conf @@ -0,0 +1,4 @@ +[theme] +inherit = basic +stylesheet = nature.css +pygments_style = tango diff --git a/vendor/pip-1.2.1/docs/ci-server-step-by-step.txt b/vendor/pip-1.2.1/docs/ci-server-step-by-step.txt new file mode 100644 index 0000000..0d0f662 --- /dev/null +++ b/vendor/pip-1.2.1/docs/ci-server-step-by-step.txt @@ -0,0 +1,252 @@ +========================================== +Hudson CI server installation step by step +========================================== + +Why Hudson +========== + +One of the advantages of `Hudson `_ over +`Buildbot `_, for instance, is that +almost everything is done via its web interface. So anyone can +manage the continuous integration server easily. +Another advantage over the other alternatives is Hudson has many +`available plugins `_, +so you don't need to write your own. + +Hudson runs on Java, so the next step is to install Java and its dependencies. + + +Java and its dependencies +========================= + +You can install all Java related packages this [not recommended] way:: + + $ [sudo] apt-get install ca-certificates-java daemon default-jre\ + > default-jre-headless gcj-4.4-base gcj-4.4-jre-headless gcj-4.4-jre-lib\ + > icedtea-6-jre-cacao java-common libaccess-bridge-java\ + > libaccess-bridge-java-jni libgcj-common libgcj10 libjline-java \ + > openjdk-6-jre openjdk-6-jre-headless openjdk-6-jre-lib\ + > rhino tzdata-java tzdata + + +Or try installing with the information in the next section and +if you have problems, run:: + + $ [sudo] apt-get install -f + + + + +Installation +============ + +The recommended installation from `Hudson site for Debian users +`_ is installing through the `.deb` package. +The advantages are: you can automatically upgrade hudson via apt and +use the `service` or `/etc/init.d` resource to start the daemon on boot. + +To install Hudson as they recommend, do the following: + +* Add the key to your system:: + + $ wget -O /tmp/key http://hudson-ci.org/debian/hudson-ci.org.key + $ [sudo] apt-key add /tmp/key + + +* Then install Hudson:: + + $ wget -O /tmp/hudson.deb http://hudson-ci.org/latest/debian/hudson.deb + $ [sudo] dpkg --install /tmp/hudson.deb + + +When you reboot the computer the web daemon will be started at +http://localhost:8080. If you don't want to reboot the computer, run:: + + $ [sudo] service hudson start + or + $ [sudo] /etc/init.d/hudson start + + + + +Apache +====== + +It is not necessary for all users, but if you want to set up apache to run +the web interface, you should follow this tutorial: +http://wiki.hudson-ci.org/display/HUDSON/Running+Hudson+behind+Apache + + +Plugins +======= + +Installing plugins in Hudson is very easy. +Just click *Manage Hudson*, then *Manage Plugins*. +The tab *Updates* shows all available updates to installed plugins. +But what we need now is to install plugins. So we must go to the +*Available* tab and check what we want to be installed and then press the +*Install* button in the end of the page. + +The Hudson server hosted at http://ci.cloudsilverlining.org has the following +plugins installed for pip project: + +* Hudson IRC Plugin +* Green Balls +* Hudson Continuous Integration game +* Hudson instant-messaging plugin +* Hudson Jabber notifier plugin +* Hudson Email Extension Plugin +* Hudson Mercurial plugin + + +Creating a Job +============== + +Before Creating a Job for pip +----------------------------- + +Hudson manages "jobs". Jobs are complete builds to Hudson. For instance, +you want to build pip project and run its tests with nosetests. +This section assumes you have all needed `dependencies installed`_. + +You need to set up some configuration in Hudson before creating your first job. +Go to Hudson home page, "Manage Hudson", then "Configure System". + +In the Mercurial section, fill the "Add Mercurial" section with: + +* Name: `hg` +* Installation directory: `/usr` +* Executable: `INSTALLATION/bin/hg` + +In the Shell section fill the shell executable with `/bin/bash`. + +Then press the "Save" button in the bottom of the page. + + + + +Configuring a Job Step by Step +------------------------------ + +* Go to the home of the Hudson web interface +* Click *New Job* +* Pick a name for the job - pip, for instance +* Mark the option "Build a free-style software project" +* Press "OK" button + +Now you were redirected to the job's configuration page. Here you will +tell Hudson how it will build your job. The most important +steps are listed (assume Mercurial plugin is installed): + +* Check "Mercurial" in Source Control Management section +* Fill in the repository URL with **https://github.com/pypa/pip** +* Mark "Build periodically" in *Build Triggers* section +* Add "0 0 \* \* \*" (without quotes) to tell hudson you want to + run your build everyday at midnight +* Click "Add Build Step" in the *Build* section and pick "Execute Shell" + +This box will contain all code you want your build run. To run pip's tests +we need to install pip tests's depencies and run nosetests. +Add the following lines to the box (it assumes you have virtualenv +in your system's python):: + + python -mvirtualenv --no-site-packages pip_virtualenv + source pip_virtualenv/bin/activate + cd $WORKSPACE/.. + easy_install -U pip + cd $WORKSPACE + pip install virtualenv scripttest nose + nosetests tests -v + +The *$WORKSPACE* environment variable is the current build workspace, +in the case above it is the clone repository path. The `cd` stuff is +a work around to a pip's bug. + +The process execute above means: + +* create a virtualenv called **pip_virtualenv** without shared site-packages +* activate the environment +* updates system's pip +* install pip tests's dependencies +* run nosetests in the current directory + + +Press the "Save" button and in the next page test if the build is correct +by clicking "Build now" button. + +In the left sidebar will appear the run builds and the running (if exists). +Click the top build, then "Console Output". Now you can +watch what Hudson is doing to build your job and watch the results. + + + + +Notes +===== + +If you change anything in your system environment, like updating +your environment configuration files, and realize Hudson +didn't catch your changes, try restarting it:: + + $ [sudo] service hudson stop + $ [sudo] service hudson start + +If when you run the `start` command you get an error telling you the port +is being used, wait about 2 or 3 seconds and try the command again - it's the +time the port releasing may take. + +What is covered here is the basic knowledge to start setting up and using +a Hudson server, the goal is not teaching all about Hudson or all about +how to set up every detail. + +There is a running Hudson server aimed for pip project here: +http://ci.cloudsilverlining.org/view/pip + + +Creating a Windows Slave to Run Jobs +==================================== + +After starting Hudson on Linux, start your Windows machine and access the +Hudson web interface. + +Adding a Windows Node to Hudson CI Server +----------------------------------------- + +Click "Manage Hudson", "Manage Nodes", "New Node". The **Node name** value +must be the Windows machine domain name - mywindowsslave.myhost.com, for +instance. + +The "Launch method" should be **Launch slave agents via JNLP** + +.. image:: _static/launch-jnlp-slave.JPG + :width: 500px + :target: _static/launch-jnlp-slave.JPG + +Then press the **Add** button, and in the next page click +the **Launch** icon. + +.. image:: _static/slave-launch-icon.png + :width: 500px + :target: _static/launch-jnlp-slave.JPG + +Now you are able to create jobs tied to this Windows machine. + + +Creating Tied Jobs +------------------ + +The process of creating a job is almost the same as the list in the +`Creating a Job`_ section, the only difference is that you need +to mark the **Tie this project to a node** option and select what +node you want to run that build. + +There is a difference in build commands, relying on variables. On Linux +they all start with `$`, like `$WORKSPACE`. +In Windows they will be enclosed by `%`, like `%WORKSPACE%`. And everything +you were doing depending on Bash, you will need to change to DOS +prompt commands and batch files. + + + +.. _dependencies installed: running-tests.html#system-requirements +.. _creating a job: #creating-a-job diff --git a/vendor/pip-1.2.1/docs/conf.py b/vendor/pip-1.2.1/docs/conf.py new file mode 100644 index 0000000..7dd29dc --- /dev/null +++ b/vendor/pip-1.2.1/docs/conf.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# +# pip documentation build configuration file, created by +# sphinx-quickstart on Tue Apr 22 22:08:49 2008 +# +# This file is execfile()d with the current directory set to its containing dir. +# +# 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('.')) +#sys.path.append(os.path.join(os.path.dirname(__file__), '../')) + +# -- 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 = ['sphinx.ext.autodoc'] +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 = 'pip' +copyright = '2008-2011, The pip developers' + +# 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. +release = "1.1" +version = '.'.join(release.split('.')[:2]) + +# 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 = ['build'] + +# 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 +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = '_static/piplogo.png' + +# 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 = 'favicon.png' + +# 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 = {} + +# 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 = False + +# If true, an OpenSearch description file will be output, and all pages will +# contain a 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 = 'pipdocs' + + +# -- 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', 'pip.tex', u'pip Documentation', + u'The pip developers', '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/pip-1.2.1/docs/configuration.txt b/vendor/pip-1.2.1/docs/configuration.txt new file mode 100644 index 0000000..35d0a34 --- /dev/null +++ b/vendor/pip-1.2.1/docs/configuration.txt @@ -0,0 +1,141 @@ +Configuration +============= + +pip allows you to set its default options by using the following facilities, +in the order of each item's importance: + +1. Command line options + +2. `Environment variables`_ + +3. `Config files`_ + + 1. Command specific section, e.g. ``[install]`` + 2. Global section ``[global]`` + +That means it will check each of those configuration sources and set the +defaults appropriately. + +Examples +-------- + +- ``--host=foo`` overrides ``PIP_HOST=foo`` +- ``PIP_HOST=foo`` overrides a config file with ``[global] host = foo`` +- A command specific section in the config file ``[] host = bar`` + overrides the option with same name in the ``[global]`` config file section +- Environment variables override config files + +Config files +------------ + +pip allows you to set all command line option defaults in a standard ini +style config file. + +The names of the settings are derived from the long command line option, e.g. +if you want to use a different package index (``--index-url``) and set the +HTTP timeout (``--default-timeout``) to 60 seconds your config file would +look like this: + +.. code-block:: ini + + [global] + timeout = 60 + index-url = http://download.zope.org/ppix + +Each subcommand can be configured optionally in its own section so that every +global setting with the same name will be overridden; e.g. decreasing the +``timeout`` to ``10`` seconds when running the `freeze` +(`Freezing Requirements <./#freezing-requirements>`_) command and using +``60`` seconds for all other commands is possible with: + +.. code-block:: ini + + [global] + timeout = 60 + + [freeze] + timeout = 10 + +Boolean options like ``--ignore-installed`` or ``--no-dependencies`` can be +set like this: + +.. code-block:: ini + + [install] + ignore-installed = true + no-dependencies = yes + +Appending options like ``--find-links`` can be written on multiple lines: + +.. code-block:: ini + + [global] + find-links = + http://download.example.com + + [install] + find-links = + http://mirror1.example.com + http://mirror2.example.com + +Location +******** + +The names and locations of the configuration files vary slightly across +platforms. + +On Unix and Mac OS X the configuration file is: :file:`$HOME/.pip/pip.conf` + +And on Windows, the configuration file is: :file:`%HOME%\\pip\\pip.ini` + +Environment variables +----------------------- + +Just like with `config files`_, each of pip's command line options +(long version, e.g. ``--find-links``) are automatically set by looking for +environment variables with the name format ``PIP_``. That means +the name of the command line options are capitalized and have dashes (``-``) +replaced with underscores (``_``). + +For example, to redefine the default timeout you can also set an +environment variable:: + + export PIP_DEFAULT_TIMEOUT=60 + pip install ipython + +Which is the same as passing the option to pip directly:: + + pip --default-timeout=60 install ipython + +This also works for appending command line options, like ``--find-links``. +Just leave an empty space between the passsed values, e.g.:: + + export PIP_FIND_LINKS="http://mirror1.example.com http://mirror2.example.com" + +is the same as calling:: + + pip install --find-links=http://mirror1.example.com --find-links=http://mirror2.example.com + +Configuration options +--------------------- + +Mirror support +************** + +The `PyPI mirroring infrastructure `_ as +described in `PEP 381 `_ can be +used by passing the ``--use-mirrors`` option to the install command. +Alternatively, you can use the other ways to configure pip, e.g.:: + + $ export PIP_USE_MIRRORS=true + +If enabled, pip will automatically query the DNS entry of the mirror index URL +to find the list of mirrors to use. In case you want to override this list, +please use the ``--mirrors`` option of the install command, or add to your pip +configuration file:: + + [install] + use-mirrors = true + mirrors = + http://d.pypi.python.org + http://b.pypi.python.org diff --git a/vendor/pip-1.2.1/docs/contributing.txt b/vendor/pip-1.2.1/docs/contributing.txt new file mode 100644 index 0000000..c3d0c13 --- /dev/null +++ b/vendor/pip-1.2.1/docs/contributing.txt @@ -0,0 +1,167 @@ +================= +How to contribute +================= + + +All kinds of contributions are welcome - code, tests, documentation, +bug reports, ideas, etc. + + +Release Schedule +================ + +Minor releases of pip (e.g. 1.1, 1.2, 1.3...) occur every four months +(beginning with the release of pip 1.0 on April 4, 2011). Two weeks before a +scheduled release, a new branch ``release/X.Y`` is created for release testing +and preparation. This branch is only open to bugfixes. + +.. _contributing-with-code: + +Contributing with Code +====================== + +Forking through Github +---------------------- + +First of all, you need to fork the the official repository, which is +https://github.com/pypa/pip. + +Log in to Github, go to the `pip repository page +`_, follow the **fork** link, wait for Github +to copy the repository and then clone your fork, like:: + + $ git clone https://github.com/YOU_USER_NAME/pip + +Now you can change whatever you want, commit, push to your fork and when your +contribution is done, follow the **pull request** link and send us a request +explaining what you did and why. + +Branches +-------- + +Pip uses the `git-flow`_ branching model. The default branch on GitHub is +``develop``, and all development work (new features and bugfixes) should happen +in that branch. The ``master`` branch is stable, and reflects the last released +state. + +.. _git-flow: http://nvie.com/posts/a-successful-git-branching-model/ + +All tests should pass +--------------------- + +Almost all changes to pip should be accompanied by automated tests - +especially ones adding new behavior. + +`Nose`_ is used to find and run all tests. Take a look at :doc:`running-tests` +to see what you need and how you should run the tests. + +Before sending us a pull request, please, be sure all tests pass. + +Supported Python versions +------------------------- + +Pip supports Python versions 2.4, 2.5, 2.6, 2.7, 3.1, and 3.2, from a single +codebase (without use of 2to3 translation). Untested contributions frequently +break Python 2.4 or 3.x compatibility. Please run the tests on at least 2.4 and +3.2 and report your results when sending a pull request. + +Continuous Integration server +----------------------------- + +We have a continuous integration server running all pip related tests at +http://ci.cloudsilverlining.org/view/pip. But if you want to have your own, +you can learn how to set up a Hudson CI server like that in the +:doc:`ci-server-step-by-step` page. + + + +Running the Tests +================= + +Pip uses some system tools - VCS related tools - in its tests, so you need to +intall them (Linux):: + + sudo apt-get install subversion bzr git-core mercurial + +Or downloading and installing `Subversion +`_, `Bazaar +`_, `Git +`_ and `Mercurial +`_ manually. + + +After all requirements (system and python) are installed, +just run the following command:: + + $ python setup.py test + +Running tests directly with Nose +-------------------------------- + +If you want to run only a selection of the tests, you'll need to run them +directly with nose instead. Create a virtualenv, and install required +packages:: + + pip install nose virtualenv scripttest mock + +Run nosetests:: + + nosetests + +Or select just a single test to run:: + + cd tests; nosetests test_upgrade.py:test_uninstall_rollback + + +Troubleshooting +--------------- + +Locale Warnings + There was a problem with locales configuration when running tests in a Hudson + CI Server that broke some tests. The problem was not with pip, but with + `locales` configuration. Hudson was not setting LANG environment variable + correctly, so the solution to fix it was changing default language to + en_US.UTF-8. + The following has been done in a Ubuntu Server 9.10 machine:: + + $ sudo locale-gen en_US en_US.UTF-8 + $ sudo dpkg-reconfigure locales + $ sudo update-locale LANG=en_US.UTF-8 + + + +Contributing with Tests +======================= + +Pip's test coverage is not as good as we would like, so contributions of +additional tests are welcome. You can contribute these the same way you would +contribute any other kind of code: see the :ref:`contributing-with-code` +section. + + +Contributing with Bug Reports +============================= + +Pip project is hosted at `Github`_ and uses its issue tracker system. + +If you have found a bug and want to report it, go to `pip issue tracker page`_, +click **Create new**, add a descriptive +title (so we can easily identify what the bug is) and fill the description box +explaining how you got the bug, what pip version you were using and what is +your operating system, so we can reproduce the bug to try fixing it. + + + +Contributing with Ideas +======================= + +We are always open to new ideas, and we will enjoy yours. You can send +enhancement ideas and proposals via `pip issue tracker page`_, +`virtualenv mailing list`_, or #pip channel at freenode. + + + +.. _nose: http://somethingaboutorange.com/mrl/projects/nose/0.11.3/ +.. _Github: http://github.com/ +.. _pip issue tracker page: https://github.com/pypa/pip/issues +.. _virtualenv mailing list: http://groups.google.com/group/python-virtualenv/ diff --git a/vendor/pip-1.2.1/docs/glossary.txt b/vendor/pip-1.2.1/docs/glossary.txt new file mode 100644 index 0000000..c9decea --- /dev/null +++ b/vendor/pip-1.2.1/docs/glossary.txt @@ -0,0 +1,12 @@ +======== +Glossary +======== + +.. glossary:: + + PyPI + The `Python Package Index`_, formerly known as the Cheese Shop, + is a central catalog of Python packages. By default, when + installing packages,`pip` searches for them in PyPI. + + .. _`Python Package Index`: http://pypi.python.org/pypi diff --git a/vendor/pip-1.2.1/docs/index.txt b/vendor/pip-1.2.1/docs/index.txt new file mode 100644 index 0000000..3f117c0 --- /dev/null +++ b/vendor/pip-1.2.1/docs/index.txt @@ -0,0 +1,54 @@ +pip +=== + +`pip` is a tool for installing and managing Python packages, such as +those found in the `Python Package Index`_. It's a replacement for +easy_install_. +:: + + $ pip install simplejson + [... progress report ...] + Successfully installed simplejson + +.. _`Python Package Index`: http://pypi.python.org/pypi +.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall + +Upgrading a package:: + + $ pip install --upgrade simplejson + [... progress report ...] + Successfully installed simplejson + +Removing a package:: + + $ pip uninstall simplejson + Uninstalling simplejson: + /home/me/env/lib/python2.7/site-packages/simplejson + /home/me/env/lib/python2.7/site-packages/simplejson-2.2.1-py2.7.egg-info + Proceed (y/n)? y + Successfully uninstalled simplejson + +.. comment: split here + +.. toctree:: + :maxdepth: 2 + + installing + usage + requirements + configuration + other-tools + contributing + news + glossary + +.. comment: split here + +Community +--------- + +The homepage for pip is at `pip-installer.org `_. +Bugs can be filed in the `pip issue tracker +`_. Discussion happens on the +`virtualenv email group +`_. diff --git a/vendor/pip-1.2.1/docs/installing.txt b/vendor/pip-1.2.1/docs/installing.txt new file mode 100644 index 0000000..5f86c6a --- /dev/null +++ b/vendor/pip-1.2.1/docs/installing.txt @@ -0,0 +1,66 @@ +Installation instructions +========================= + +The recommended way to use pip is within `virtualenv +`_, since every virtualenv has pip installed in it +automatically. This does not require root access or modify your system Python +installation. For instance:: + + $ curl -O https://raw.github.com/pypa/virtualenv/master/virtualenv.py + $ python virtualenv.py my_new_env + $ . my_new_env/bin/activate + (my_new_env)$ pip install ... + +When used in this manner, pip will only affect the active virtual environment. +If you do want to install pip globally into your Python installation, see the +instructions below. + +Prerequisites +------------- + +Prior to installing pip make sure you have either `setuptools +`_ or `distribute +`_ installed. Please consult your +operating system's package manager or install it manually:: + + $ curl http://python-distribute.org/distribute_setup.py | python + +.. warning:: + + If you are using Python 3.X you **must** use distribute; setuptools doesn't + support Python 3.X. + +Using the installer +------------------- + +Download `get-pip.py `_ +and execute it, using the Python interpreter of your choice:: + + $ curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python + +This may have to be run as root. + +Alternative installation procedures +----------------------------------- + +Using the source distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can find the source on `PyPI `_:: + + $ curl -O http://pypi.python.org/packages/source/p/pip/pip-1.0.tar.gz + $ tar xvfz pip-1.0.tar.gz + $ cd pip-1.0 + $ python setup.py install # may need to be root + +Installing the development version +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +First you will need to clone the git repo:: + + $ git clone https://github.com/pypa/pip.git + +Now we can install from the repo:: + + $ cd pip + $ python setup.py install # may need to be root diff --git a/vendor/virtualenv-1.8.4/docs/make.bat b/vendor/pip-1.2.1/docs/make.bat similarity index 100% rename from vendor/virtualenv-1.8.4/docs/make.bat rename to vendor/pip-1.2.1/docs/make.bat diff --git a/vendor/pip-1.2.1/docs/news.txt b/vendor/pip-1.2.1/docs/news.txt new file mode 100644 index 0000000..3bcdb2a --- /dev/null +++ b/vendor/pip-1.2.1/docs/news.txt @@ -0,0 +1,558 @@ +==== +News +==== + +Changelog +========= + +Next release (1.2) schedule +--------------------------- + +Beta and final releases planned for the second half of 2012. + +1.1 (2012-02-16) +---------------- + +* Fixed issue #326 - don't crash when a package's setup.py emits UTF-8 and + then fails. Thanks Marc Abramowitz. + +* Added ``--target`` option for installing directly to arbitrary directory. + Thanks Stavros Korokithakis. + +* Added support for authentication with Subversion repositories. Thanks + Qiangning Hong. + +* Fixed issue #315 - ``--download`` now downloads dependencies as well. + Thanks Qiangning Hong. + +* Errors from subprocesses will display the current working directory. + Thanks Antti Kaihola. + +* Fixed issue #369 - compatibility with Subversion 1.7. Thanks Qiangning + Hong. Note that setuptools remains incompatible with Subversion 1.7; to + get the benefits of pip's support you must use Distribute rather than + setuptools. + +* Fixed issue #57 - ignore py2app-generated OS X mpkg zip files in finder. + Thanks Rene Dudfield. + +* Fixed issue #182 - log to ~/Library/Logs/ by default on OS X framework + installs. Thanks Dan Callahan for report and patch. + +* Fixed issue #310 - understand version tags without minor version ("py3") + in sdist filenames. Thanks Stuart Andrews for report and Olivier Girardot for + patch. + +* Fixed issue #7 - Pip now supports optionally installing setuptools + "extras" dependencies; e.g. "pip install Paste[openid]". Thanks Matt Maker + and Olivier Girardot. + +* Fixed issue #391 - freeze no longer borks on requirements files with + --index-url or --find-links. Thanks Herbert Pfennig. + +* Fixed issue #288 - handle symlinks properly. Thanks lebedov for the patch. + +* Fixed issue #49 - pip install -U no longer reinstalls the same versions of + packages. Thanks iguananaut for the pull request. + +* Removed ``-E`` option and ``PIP_RESPECT_VIRTUALENV``; both use a + restart-in-venv mechanism that's broken, and neither one is useful since + every virtualenv now has pip inside it. + +* Fixed issue #366 - pip throws IndexError when it calls `scraped_rel_links` + +* Fixed issue #22 - pip search should set and return a userful shell status code + +* Fixed issue #351 and #365 - added global ``--exists-action`` command line + option to easier script file exists conflicts, e.g. from editable + requirements from VCS that have a changed repo URL. + + +1.0.2 (2011-07-16) +------------------ + +* Fixed docs issues. +* Fixed issue #295 - Reinstall a package when using the ``install -I`` option +* Fixed issue #283 - Finds a Git tag pointing to same commit as origin/master +* Fixed issue #279 - Use absolute path for path to docs in setup.py +* Fixed issue #314 - Correctly handle exceptions on Python3. +* Fixed issue #320 - Correctly parse ``--editable`` lines in requirements files + +1.0.1 (2011-04-30) +------------------ + +* Start to use git-flow. +* Fixed issue #274 - `find_command` should not raise AttributeError +* Fixed issue #273 - respect Content-Disposition header. Thanks Bradley Ayers. +* Fixed issue #233 - pathext handling on Windows. +* Fixed issue #252 - svn+svn protocol. +* Fixed issue #44 - multiple CLI searches. +* Fixed issue #266 - current working directory when running setup.py clean. + +1.0 (2011-04-04) +---------------- + +* Added Python 3 support! Huge thanks to Vinay Sajip, Vitaly Babiy, Kelsey + Hightower, and Alex Gronholm, among others. + +* Download progress only shown on a real TTY. Thanks Alex Morega. + +* Fixed finding of VCS binaries to not be fooled by same-named directories. + Thanks Alex Morega. + +* Fixed uninstall of packages from system Python for users of Debian/Ubuntu + python-setuptools package (workaround until fixed in Debian and Ubuntu). + +* Added `get-pip.py `_ + installer. Simply download and execute it, using the Python interpreter of + your choice:: + + $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py + $ python get-pip.py + + This may have to be run as root. + + .. note:: + + Make sure you have `distribute `_ + installed before using the installer! + +0.8.3 +----- + +* Moved main repository to Github: https://github.com/pypa/pip + +* Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer, Brian Rosner + +* Fixed issue #14 - No uninstall-on-upgrade with URL package. Thanks Oliver Tonnhofer + +* Fixed issue #163 - Egg name not properly resolved. Thanks Igor Sobreira + +* Fixed issue #178 - Non-alphabetical installation of requirements. Thanks Igor Sobreira + +* Fixed issue #199 - Documentation mentions --index instead of --index-url. Thanks Kelsey Hightower + +* Fixed issue #204 - rmtree undefined in mercurial.py. Thanks Kelsey Hightower + +* Fixed bug in Git vcs backend that would break during reinstallation. + +* Fixed bug in Mercurial vcs backend related to pip freeze and branch/tag resolution. + +* Fixed bug in version string parsing related to the suffix "-dev". + +0.8.2 +----- + +* Avoid redundant unpacking of bundles (from pwaller) + +* Fixed issue #32, #150, #161 - Fixed checking out the correct + tag/branch/commit when updating an editable Git requirement. + +* Fixed issue #49 - Added ability to install version control requirements + without making them editable, e.g.:: + + pip install git+https://github.com/pypa/pip/ + +* Fixed issue #175 - Correctly locate build and source directory on Mac OS X. + +* Added ``git+https://`` scheme to Git VCS backend. + +0.8.1 +----- + +* Added global --user flag as shortcut for --install-option="--user". From + Ronny Pfannschmidt. + +* Added support for `PyPI mirrors `_ as + defined in `PEP 381 `_, from + Jannis Leidel. + +* Fixed issue #138 - Git revisions ignored. Thanks John-Scott Atlakson. + +* Fixed issue #95 - Initial editable install of github package from a tag fails. Thanks John-Scott Atlakson. + +* Fixed issue #107 - Can't install if a directory in cwd has the same name as the package you're installing. + +* Fixed issue #39 - --install-option="--prefix=~/.local" ignored with -e. + Thanks Ronny Pfannschmidt and Wil Tan. + + + +0.8 +--- + +* Track which ``build/`` directories pip creates, never remove directories + it doesn't create. From Hugo Lopes Tavares. + +* Pip now accepts file:// index URLs. Thanks Dave Abrahams. + +* Various cleanup to make test-running more consistent and less fragile. + Thanks Dave Abrahams. + +* Real Windows support (with passing tests). Thanks Dave Abrahams. + +* ``pip-2.7`` etc. scripts are created (Python-version specific scripts) + +* ``contrib/build-standalone`` script creates a runnable ``.zip`` form of + pip, from Jannis Leidel + +* Editable git repos are updated when reinstalled + +* Fix problem with ``--editable`` when multiple ``.egg-info/`` directories + are found. + +* A number of VCS-related fixes for ``pip freeze``, from Hugo Lopes Tavares. + +* Significant test framework changes, from Hugo Lopes Tavares. + +0.7.2 +----- + +* Set zip_safe=False to avoid problems some people are encountering where + pip is installed as a zip file. + +0.7.1 +----- + +* Fixed opening of logfile with no directory name. Thanks Alexandre Conrad. + +* Temporary files are consistently cleaned up, especially after + installing bundles, also from Alex Conrad. + +* Tests now require at least ScriptTest 1.0.3. + +0.7 +--- + +* Fixed uninstallation on Windows +* Added ``pip search`` command. +* Tab-complete names of installed distributions for ``pip uninstall``. +* Support tab-completion when there is a global-option before the + subcommand. +* Install header files in standard (scheme-default) location when installing + outside a virtualenv. Install them to a slightly more consistent + non-standard location inside a virtualenv (since the standard location is + a non-writable symlink to the global location). +* pip now logs to a central location by default (instead of creating + ``pip-log.txt`` all over the place) and constantly overwrites the + file in question. On Unix and Mac OS X this is ``'$HOME/.pip/pip.log'`` + and on Windows it's ``'%HOME%\\pip\\pip.log'``. You are still able to + override this location with the ``$PIP_LOG_FILE`` environment variable. + For a complete (appended) logfile use the separate ``'--log'`` command line + option. +* Fixed an issue with Git that left an editable packge as a checkout of a + remote branch, even if the default behaviour would have been fine, too. +* Fixed installing from a Git tag with older versions of Git. +* Expand "~" in logfile and download cache paths. +* Speed up installing from Mercurial repositories by cloning without + updating the working copy multiple times. +* Fixed installing directly from directories (e.g. + ``pip install path/to/dir/``). +* Fixed installing editable packages with ``svn+ssh`` URLs. +* Don't print unwanted debug information when running the freeze command. +* Create log file directory automatically. Thanks Alexandre Conrad. +* Make test suite easier to run successfully. Thanks Dave Abrahams. +* Fixed "pip install ." and "pip install .."; better error for directory + without setup.py. Thanks Alexandre Conrad. +* Support Debian/Ubuntu "dist-packages" in zip command. Thanks duckx. +* Fix relative --src folder. Thanks Simon Cross. +* Handle missing VCS with an error message. Thanks Alexandre Conrad. +* Added --no-download option to install; pairs with --no-install to separate + download and installation into two steps. Thanks Simon Cross. +* Fix uninstalling from requirements file containing -f, -i, or + --extra-index-url. +* Leftover build directories are now removed. Thanks Alexandre Conrad. + +0.6.3 +----- + +* Fixed import error on Windows with regard to the backwards compatibility + package + +0.6.2 +----- + +* Fixed uninstall when /tmp is on a different filesystem. + +* Fixed uninstallation of distributions with namespace packages. + +0.6.1 +----- + +* Added support for the ``https`` and ``http-static`` schemes to the + Mercurial and ``ftp`` scheme to the Bazaar backend. + +* Fixed uninstallation of scripts installed with easy_install. + +* Fixed an issue in the package finder that could result in an + infinite loop while looking for links. + +* Fixed issue with ``pip bundle`` and local files (which weren't being + copied into the bundle), from Whit Morriss. + +0.6 +--- + +* Add ``pip uninstall`` and uninstall-before upgrade (from Carl + Meyer). + +* Extended configurability with config files and environment variables. + +* Allow packages to be upgraded, e.g., ``pip install Package==0.1`` + then ``pip install Package==0.2``. + +* Allow installing/upgrading to Package==dev (fix "Source version does not + match target version" errors). + +* Added command and option completion for bash and zsh. + +* Extended integration with virtualenv by providing an option to + automatically use an active virtualenv and an option to warn if no active + virtualenv is found. + +* Fixed a bug with pip install --download and editable packages, where + directories were being set with 0000 permissions, now defaults to 755. + +* Fixed uninstallation of easy_installed console_scripts. + +* Fixed uninstallation on Mac OS X Framework layout installs + +* Fixed bug preventing uninstall of editables with source outside venv. + +* Creates download cache directory if not existing. + +0.5.1 +----- + +* Fixed a couple little bugs, with git and with extensions. + +0.5 +--- + +* Added ability to override the default log file name (``pip-log.txt``) + with the environmental variable ``$PIP_LOG_FILE``. + +* Made the freeze command print installed packages to stdout instead of + writing them to a file. Use simple redirection (e.g. + ``pip freeze > stable-req.txt``) to get a file with requirements. + +* Fixed problem with freezing editable packages from a Git repository. + +* Added support for base URLs using ```` when parsing + HTML pages. + +* Fixed installing of non-editable packages from version control systems. + +* Fixed issue with Bazaar's bzr+ssh scheme. + +* Added --download-dir option to the install command to retrieve package + archives. If given an editable package it will create an archive of it. + +* Added ability to pass local file and directory paths to ``--find-links``, + e.g. ``--find-links=file:///path/to/my/private/archive`` + +* Reduced the amount of console log messages when fetching a page to find a + distribution was problematic. The full messages can be found in pip-log.txt. + +* Added ``--no-deps`` option to install ignore package dependencies + +* Added ``--no-index`` option to ignore the package index (PyPI) temporarily + +* Fixed installing editable packages from Git branches. + +* Fixes freezing of editable packages from Mercurial repositories. + +* Fixed handling read-only attributes of build files, e.g. of Subversion and + Bazaar on Windows. + +* When downloading a file from a redirect, use the redirected + location's extension to guess the compression (happens specifically + when redirecting to a bitbucket.org tip.gz file). + +* Editable freeze URLs now always use revision hash/id rather than tip or + branch names which could move. + +* Fixed comparison of repo URLs so incidental differences such as + presence/absence of final slashes or quoted/unquoted special + characters don't trigger "ignore/switch/wipe/backup" choice. + +* Fixed handling of attempt to checkout editable install to a + non-empty, non-repo directory. + +0.4 +--- + +* Make ``-e`` work better with local hg repositories + +* Construct PyPI URLs the exact way easy_install constructs URLs (you + might notice this if you use a custom index that is + slash-sensitive). + +* Improvements on Windows (from `Ionel Maries Cristian + `_). + +* Fixed problem with not being able to install private git repositories. + +* Make ``pip zip`` zip all its arguments, not just the first. + +* Fix some filename issues on Windows. + +* Allow the ``-i`` and ``--extra-index-url`` options in requirements + files. + +* Fix the way bundle components are unpacked and moved around, to make + bundles work. + +* Adds ``-s`` option to allow the access to the global site-packages if a + virtualenv is to be created. + +* Fixed support for Subversion 1.6. + +0.3.1 +----- + +* Improved virtualenv restart and various path/cleanup problems on win32. + +* Fixed a regression with installing from svn repositories (when not + using ``-e``). + +* Fixes when installing editable packages that put their source in a + subdirectory (like ``src/``). + +* Improve ``pip -h`` + +0.3 +--- + +* Added support for editable packages created from Git, Mercurial and Bazaar + repositories and ability to freeze them. Refactored support for version + control systems. + +* Do not use ``sys.exit()`` from inside the code, instead use a + return. This will make it easier to invoke programmatically. + +* Put the install record in ``Package.egg-info/installed-files.txt`` + (previously they went in + ``site-packages/install-record-Package.txt``). + +* Fix a problem with ``pip freeze`` not including ``-e svn+`` when an + svn structure is peculiar. + +* Allow ``pip -E`` to work with a virtualenv that uses a different + version of Python than the parent environment. + +* Fixed Win32 virtualenv (``-E``) option. + +* Search the links passed in with ``-f`` for packages. + +* Detect zip files, even when the file doesn't have a ``.zip`` + extension and it is served with the wrong Content-Type. + +* Installing editable from existing source now works, like ``pip + install -e some/path/`` will install the package in ``some/path/``. + Most importantly, anything that package requires will also be + installed by pip. + +* Add a ``--path`` option to ``pip un/zip``, so you can avoid zipping + files that are outside of where you expect. + +* Add ``--simulate`` option to ``pip zip``. + +0.2.1 +----- + +* Fixed small problem that prevented using ``pip.py`` without actually + installing pip. + +* Fixed ``--upgrade``, which would download and appear to install + upgraded packages, but actually just reinstall the existing package. + +* Fixed Windows problem with putting the install record in the right + place, and generating the ``pip`` script with Setuptools. + +* Download links that include embedded spaces or other unsafe + characters (those characters get %-encoded). + +* Fixed use of URLs in requirement files, and problems with some blank + lines. + +* Turn some tar file errors into warnings. + +0.2 +--- + +* Renamed to ``pip``, and to install you now do ``pip install + PACKAGE`` + +* Added command ``pip zip PACKAGE`` and ``pip unzip PACKAGE``. This + is particularly intended for Google App Engine to manage libraries + to stay under the 1000-file limit. + +* Some fixes to bundles, especially editable packages and when + creating a bundle using unnamed packages (like just an svn + repository without ``#egg=Package``). + +0.1.4 +----- + +* Added an option ``--install-option`` to pass options to pass + arguments to ``setup.py install`` + +* ``.svn/`` directories are no longer included in bundles, as these + directories are specific to a version of svn -- if you build a + bundle on a system with svn 1.5, you can't use the checkout on a + system with svn 1.4. Instead a file ``svn-checkout.txt`` is + included that notes the original location and revision, and the + command you can use to turn it back into an svn checkout. (Probably + unpacking the bundle should, maybe optionally, recreate this + information -- but that is not currently implemented, and it would + require network access.) + +* Avoid ambiguities over project name case, where for instance + MyPackage and mypackage would be considered different packages. + This in particular caused problems on Macs, where ``MyPackage/`` and + ``mypackage/`` are the same directory. + +* Added support for an environmental variable + ``$PIP_DOWNLOAD_CACHE`` which will cache package downloads, so + future installations won't require large downloads. Network access + is still required, but just some downloads will be avoided when + using this. + +0.1.3 +----- + +* Always use ``svn checkout`` (not ``export``) so that + ``tag_svn_revision`` settings give the revision of the package. + +* Don't update checkouts that came from ``.pybundle`` files. + +0.1.2 +----- + +* Improve error text when there are errors fetching HTML pages when + seeking packages. + +* Improve bundles: include empty directories, make them work with + editable packages. + +* If you use ``-E env`` and the environment ``env/`` doesn't exist, a + new virtual environment will be created. + +* Fix ``dependency_links`` for finding packages. + +0.1.1 +----- + +* Fixed a NameError exception when running pip outside of a + virtualenv environment. + +* Added HTTP proxy support (from Prabhu Ramachandran) + +* Fixed use of ``hashlib.md5`` on python2.5+ (also from Prabhu + Ramachandran) + +0.1 +--- + +* Initial release diff --git a/vendor/pip-1.2.1/docs/other-tools.txt b/vendor/pip-1.2.1/docs/other-tools.txt new file mode 100644 index 0000000..a705e8a --- /dev/null +++ b/vendor/pip-1.2.1/docs/other-tools.txt @@ -0,0 +1,131 @@ +============================= +Relationship with other tools +============================= + +Pip Compared To easy_install +---------------------------- + +pip is meant to improve on easy_install. Some of the improvements: + +* All packages are downloaded before installation. Partially-completed + installation doesn't occur as a result. + +* Care is taken to present useful output on the console. + +* The reasons for actions are kept track of. For instance, if a package is + being installed, pip keeps track of why that package was required. + +* Error messages should be useful. + +* The code is relatively concise and cohesive, making it easier to use + programmatically. + +* Packages don't have to be installed as egg archives, they can be installed + flat (while keeping the egg metadata). + +* Native support for other version control systems (Git, Mercurial and Bazaar) + +* Uninstallation of packages. + +* Simple to define fixed sets of requirements and reliably reproduce a + set of packages. + +pip doesn't do everything that easy_install does. Specifically: + +* It cannot install from eggs. It only installs from source. (In the + future it would be good if it could install binaries from Windows ``.exe`` + or ``.msi`` -- binary install on other platforms is not a priority.) + +* It doesn't understand Setuptools extras (like ``package[test]``). This should + be added eventually. + +* It is incompatible with some packages that extensively customize distutils + or setuptools in their ``setup.py`` files. + +pip is complementary with `virtualenv +`__, and it is encouraged that you use +virtualenv to isolate your installation. + +Using pip with virtualenv +------------------------- + +pip is most nutritious when used with `virtualenv +`__. One of the reasons pip +doesn't install "multi-version" eggs is that virtualenv removes much of the need +for it. Because pip is installed by virtualenv, just use +``path/to/my/environment/bin/pip`` to install things into that +specific environment. + +To tell pip to only run if there is a virtualenv currently activated, +and to bail if not, use:: + + export PIP_REQUIRE_VIRTUALENV=true + + +Using pip with virtualenvwrapper +--------------------------------- + +If you are using `virtualenvwrapper +`_, you might +want pip to automatically create its virtualenvs in your +``$WORKON_HOME``. + +You can tell pip to do so by defining ``PIP_VIRTUALENV_BASE`` in your +environment and setting it to the same value as that of +``$WORKON_HOME``. + +Do so by adding the line:: + + export PIP_VIRTUALENV_BASE=$WORKON_HOME + +in your .bashrc under the line starting with ``export WORKON_HOME``. + +Using pip with buildout +----------------------- + +If you are using `zc.buildout +`_ you should look at +`gp.recipe.pip `_ as an +option to use pip and virtualenv in your buildouts. + +Using pip with the "user scheme" +-------------------------------- + +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. +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 ``pip install``. + +Moreover, the "user scheme" can be customized by setting the +``PYTHONUSERBASE`` environment variable, which updates the value of ``site.USER_BASE``. + +To install "somepackage" into an environment with site.USER_BASE customized to '/myappenv', do the following:: + + export PYTHONUSERBASE=/myappenv + pip install --user somepackage + + +Command line completion +----------------------- + +pip comes with support for command line completion in bash and zsh and +allows you tab complete commands and options. To enable it you simply +need copy the required shell script to the your shell startup file +(e.g. ``.profile`` or ``.zprofile``) by running the special ``completion`` +command, e.g. for bash:: + + $ pip completion --bash >> ~/.profile + +And for zsh:: + + $ pip completion --zsh >> ~/.zprofile + +Alternatively, you can use the result of the ``completion`` command +directly with the eval function of you shell, e.g. by adding:: + + eval "`pip completion --bash`" + +to your startup file. diff --git a/vendor/pip-1.2.1/docs/requirements.txt b/vendor/pip-1.2.1/docs/requirements.txt new file mode 100644 index 0000000..326937d --- /dev/null +++ b/vendor/pip-1.2.1/docs/requirements.txt @@ -0,0 +1,246 @@ +.. _`requirements-files`: + +================== +Requirements files +================== + +When installing software, and Python packages in particular, it's common that +you get a lot of libraries installed. You just did ``easy_install MyPackage`` +and you get a dozen packages. Each of these packages has its own version. + +Maybe you ran that installation and it works. Great! Will it keep working? +Did you have to provide special options to get it to find everything? Did you +have to install a bunch of other optional pieces? Most of all, will you be able +to do it again? Requirements files give you a way to create an *environment*: +a *set* of packages that work together. + +If you've ever tried to setup an application on a new system, or with slightly +updated pieces, and had it fail, pip requirements are for you. If you +haven't had this problem then you will eventually, so pip requirements are +for you too -- requirements make explicit, repeatable installation of packages. + +So what are requirements files? They are very simple: lists of packages to +install. Instead of running something like ``pip install MyApp`` and +getting whatever libraries come along, you can create a requirements file +something like:: + + MyApp + Framework==0.9.4 + Library>=0.2 + +If you save this in ``requirements.txt``, then you can ``pip install -r +requirements.txt``. Regardless of what MyApp lists in ``setup.py``, you'll +get a specific version of Framework (0.9.4) and at least the 0.2 version of +Library. (You might think you could list these specific versions in MyApp's +``setup.py`` -- but if you do that you'll have to edit MyApp if you want to +try a new version of Framework, or release a new version of MyApp if you +determine that Library 0.3 doesn't work with your application.) You can also +add optional libraries and support tools that MyApp doesn't strictly +require, giving people a set of recommended libraries. + +You can also include "editable" packages -- packages that are checked out from +Subversion, Git, Mercurial and Bazaar. These are just like using the ``-e`` +option to pip. They look like:: + + -e svn+http://myrepo/svn/MyApp#egg=MyApp + +You have to start the URL with ``svn+`` (``git+``, ``hg+`` or ``bzr+``), and +you have to include ``#egg=Package`` so pip knows what to expect at that URL. +You can also include ``@rev`` in the URL, e.g., ``@275`` to check out +revision 275. + +Requirement files are mostly *flat*. Maybe ``MyApp`` requires +``Framework``, and ``Framework`` requires ``Library``. I encourage +you to still list all these in a single requirement file; it is the +nature of Python programs that there are implicit bindings *directly* +between MyApp and Library. For instance, Framework might expose one +of Library's objects, and so if Library is updated it might directly +break MyApp. If that happens you can update the requirements file to +force an earlier version of Library, and you can do that without +having to re-release MyApp at all. + +Read the `requirements file format`_ to learn about other features. + +Freezing Requirements +===================== + +So you have a working set of packages, and you want to be able to install them +elsewhere. `Requirements files`_ let you install exact versions, but it won't +tell you what all the exact versions are. + +To create a new requirements file from a known working environment, use:: + + $ pip freeze > stable-req.txt + +This will write a listing of *all* installed libraries to ``stable-req.txt`` +with exact versions for every library. You may want to edit the file down after +generating (e.g., to eliminate unnecessary libraries), but it'll give you a +stable starting point for constructing your requirements file. + +You can also give it an existing requirements file, and it will use that as a +sort of template for the new file. So if you do:: + + $ pip freeze -r devel-req.txt > stable-req.txt + +it will keep the packages listed in ``devel-req.txt`` in order and preserve +comments. + +The _`requirements file format` +=============================== + +The requirements file is a way to get pip to install specific packages +to make up an *environment*. This document describes that format. To +read about *when* you should use requirement files, see `Requirements +Files <./#requirements-files>`_. + +Each line of the requirements file indicates something to be +installed. For example:: + + MyPackage==3.0 + +tells pip to install the 3.0 version of MyPackage. + +You can also request `extras`_ in the requirements file:: + + MyPackage==3.0 [PDF] + +.. _extras: http://peak.telecommunity.com/DevCenter/setuptools#declaring-extras-optional-features-with-their-own-dependencies + +Packages may also be installed in an "editable" form. This puts the +source code into ``src/distname`` (making the name lower case) and +runs ``python setup.py develop`` on the package. To indicate +editable, use ``-e``, like:: + + -e svn+http://svn.myproject.org/svn/MyProject/trunk#egg=MyProject + +The ``#egg=MyProject`` part is important, because while you can +install simply given the svn location, the project name is useful in +other places. + +You can also specify the egg name for a non-editable url. This is useful to +point to HEAD locations on the local filesystem: + + file:///path/to/your/lib/project#egg=MyProject + +or relative paths: + + file:../../lib/project#egg=MyProject + +If you need to give pip (and by association easy_install) hints +about where to find a package, you can use the ``-f`` +(``--find-links``) option, like:: + + $ pip -f http://someserver.org/index-of-packages MyPackage==3.0 + +Pip will then look for a link at http://someserver.org/index-of-packages +that matches version ``3.0`` of ``MyPackage`` -- the link should be +like ``MyPackage-3.0.tar.gz``. + +And if you want to install from a tarball or zip file with a direct link, +you don't need ``-f`` option, you just need to pass the absolute url, like:: + + $ pip install http://someserver.org/packages/MyPackage-3.0.tar.gz + + +Version Control +--------------- + +Right now pip knows of the following major version control systems: + +Subversion +~~~~~~~~~~ + +Pip supports the URL schemes ``svn``, ``svn+svn``, ``svn+http``, ``svn+https``, ``svn+ssh``. +You can also give specific revisions to an SVN URL, like:: + + -e svn+svn://svn.myproject.org/svn/MyProject#egg=MyProject + -e svn+http://svn.myproject.org/svn/MyProject/trunk@2019#egg=MyProject + +which will check out revision 2019. ``@{20080101}`` would also check +out the revision from 2008-01-01. You can only check out specific +revisions using ``-e svn+...``. + +Git +~~~ + +Pip currently supports cloning over ``git``, ``git+http`` and ``git+ssh``:: + + -e git://git.myproject.org/MyProject.git#egg=MyProject + -e git+http://git.myproject.org/MyProject/#egg=MyProject + -e git+ssh://git@myproject.org/MyProject/#egg=MyProject + +Passing branch names, a commit hash or a tag name is also possible:: + + -e git://git.myproject.org/MyProject.git@master#egg=MyProject + -e git://git.myproject.org/MyProject.git@v1.0#egg=MyProject + -e git://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject + +Mercurial +~~~~~~~~~ + +The supported schemes are: ``hg+http``, ``hg+https``, +``hg+static-http`` and ``hg+ssh``:: + + -e hg+http://hg.myproject.org/MyProject/#egg=MyProject + -e hg+https://hg.myproject.org/MyProject/#egg=MyProject + -e hg+ssh://hg@myproject.org/MyProject/#egg=MyProject + +You can also specify a revision number, a revision hash, a tag name or a local +branch name:: + + -e hg+http://hg.myproject.org/MyProject/@da39a3ee5e6b#egg=MyProject + -e hg+http://hg.myproject.org/MyProject/@2019#egg=MyProject + -e hg+http://hg.myproject.org/MyProject/@v1.0#egg=MyProject + -e hg+http://hg.myproject.org/MyProject/@special_feature#egg=MyProject + +Bazaar +~~~~~~ + +Pip supports Bazaar using the ``bzr+http``, ``bzr+https``, ``bzr+ssh``, +``bzr+sftp``, ``bzr+ftp`` and ``bzr+lp`` schemes:: + + -e bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject + -e bzr+sftp://user@myproject.org/MyProject/trunk/#egg=MyProject + -e bzr+ssh://user@myproject.org/MyProject/trunk/#egg=MyProject + -e bzr+ftp://user@myproject.org/MyProject/trunk/#egg=MyProject + -e bzr+lp:MyProject#egg=MyProject + +Tags or revisions can be installed like this:: + + -e bzr+https://bzr.myproject.org/MyProject/trunk/@2019#egg=MyProject + -e bzr+http://bzr.myproject.org/MyProject/trunk/@v1.0#egg=MyProject + +Recursive Requirements +---------------------- + +If you wish, you can also refer to other requirements files, like:: + + -r Pylons-requirements.txt + +This gives you a way of abstracting out sets of requirements. This +isn't, however, very friendly with `frozen requirements +<./#freezing-requirements>`_, as everything in +``Pylons-requirements.txt`` will show up in your frozen file. + +Indexes, find-links +------------------- + +You can also provide values for the ``--index-url`` and ``--find-links`` +options in your requirement files, like:: + + --index-url http://example.com/private-pypi/ + +Note that using ``--index-url`` removes the use of `PyPI +`_, while using ``--extra-index-url`` will add +additional indexes. + +``--find-links`` is more ad-hoc; instead of a complete "index", you +only need an HTML page of links to available packages. Simply by +putting all your private packages in a directory and using the Apache +auto-index, you can publish your packages so pip can find them. +``--find-links`` is always additive; pip looks at everything it can +find. Use it like:: + + --find-links http://example.com/private-packages/ + +Note that all these options must be on a line of their own. diff --git a/vendor/pip-1.2.1/docs/usage.txt b/vendor/pip-1.2.1/docs/usage.txt new file mode 100644 index 0000000..991d0d5 --- /dev/null +++ b/vendor/pip-1.2.1/docs/usage.txt @@ -0,0 +1,160 @@ +===== +Usage +===== + +Install packages +---------------- + +The simplest way to install a package is by specifying its name:: + + $ pip install SomePackage + +`SomePackage` is downloaded from :term:`PyPI`, along with its +dependencies, and installed. + +If `SomePackage` is already installed, and you need a newer version, use ``pip +install --upgrade SomePackage``. You can also request a specific version (``pip +install SomePackage==1.0.4``) and specify `setuptools extras`_ (``pip install +SomePackage[PDF]``). + +You can also install from a particular source distribution file, either +local or remote:: + + $ pip install ./downloads/SomePackage-1.0.4.tar.gz + $ pip install http://my.package.repo/SomePackage-1.0.4.zip + +.. _setuptools extras: http://peak.telecommunity.com/DevCenter/setuptools#declaring-extras-optional-features-with-their-own-dependencies + + +Edit mode +********* + +Packages normally_ install under ``site-packages``, but when you're +making changes, it makes more sense to run the package straight from the +checked-out source tree. "Editable" installs create a ``.pth`` file in +``site-packages`` that extends Python's import path to find the +package:: + + $ pip install -e path/to/SomePackage + +.. _normally: http://docs.python.org/install/index.html#how-installation-works + + +Version control systems +*********************** + +Pip knows how to check out a package from version control. `Subversion`, +`Git`, `Mercurial` and `Bazaar` are supported. The repository will be +checked out in a temporary folder, installed, and cleaned up:: + + $ pip install git+https://github.com/simplejson/simplejson.git + $ pip install svn+svn://svn.zope.org/repos/main/zope.interface/trunk/ + +This can be combined with the `-e` flag, and Pip will perform the +checkout in ``./src/``. You need to supply a name for the checkout +folder by appending a hash to the repository URL:: + + $ pip install -e git+https://github.com/lakshmivyas/hyde.git#egg=hyde + +Note that only basic checking-out of a repo is supported; pip will not +handle advanced VCS-specific features such as submodules or subrepos. + + +Alternate package repositories +****************************** + +pip searches in :term:`PyPI` by default, but this can be overridden using the +``--index-url`` option:: + + $ pip install --index-url http://d.pypi.python.org/simple/ SomePackage + +If you have your own package index with a few additional packages, you may want +to to specify additional index URLs while still also using :term:`PyPI`:: + + $ pip install --extra-index-url http://my.package.repo/ SomePackage + +A "package index" used with ``--index-url`` or ``--extra-index-url`` can be as +simple as a static-web-served directory, with automatic indexes on, with a +subdirectory per package and sdists (tarballs created with ``python setup.py +sdist``) in that directory:: + + mypackage/ + mypackage-0.7.8.tar.gz + mypackage-1.0.1.tar.gz + otherpackage/ + otherpackage-2.3.5.tar.gz + +If the number of packages in the index is small, it's even simpler to skip the +subdirectories: put all of the sdists in a single directory and use pip's +``--find-links`` option with a URL to that directory:: + + mypackage-0.7.8.tar.gz + mypackage-1.0.1.tar.gz + otherpackage-2.3.5.tar.gz + +``--find-links`` also supports local paths, so installation need not require a +network connection. + +Like ``--extra-index-url``, ``--find-links`` is additive by default, it does +not replace or supersede the index. All package sources are checked, and the +latest qualifying version for every requested package is used. If you want only +your ``-find-links`` URL used as package source, you need to pair it with +``--no-index``. + +``--index-url``, ``--extra-index-url`` and ``--find-links`` can all be used +within a :ref:`requirements file ` in addition to on the +command line directly. + + +Uninstall packages +------------------ + +pip is able to uninstall most installed packages with ``pip uninstall +package-name``. + +Known exceptions include pure-distutils packages installed with +``python setup.py install`` (such packages leave behind no metadata allowing +determination of what files were installed), and script wrappers installed +by develop-installs (``python setup.py develop``). + +pip also performs an automatic uninstall of an old version of a package +before upgrading to a newer version, so outdated files (and egg-info data) +from conflicting versions aren't left hanging around to cause trouble. The +old version of the package is automatically restored if the new version +fails to download or install. + + +Searching for packages +---------------------- + +pip can search :term:`PyPI` for packages using the ``pip search`` +command:: + + $ pip search "query" + +The query will be used to search the names and summaries of all +packages. With the ``--index`` option you can search in a different +repository. + + +Bundles +------- + +Another way to distribute a set of libraries is a bundle format (specific to +pip). This format is not stable at this time (there simply hasn't been +any feedback, nor a great deal of thought). A bundle file contains all the +source for your package, and you can have pip install them all together. +Once you have the bundle file further network access won't be necessary. To +build a bundle file, do:: + + $ pip bundle MyApp.pybundle MyApp + +(Using a :ref:`requirements file ` would be wise.) Then +someone else can get the file ``MyApp.pybundle`` and run:: + + $ pip install MyApp.pybundle + +This is *not* a binary format. This only packages source. If you have binary +packages, then the person who installs the files will have to have a compiler, +any necessary headers installed, etc. Binary packages are hard, this is +relatively easy. diff --git a/vendor/pip-1.2.1/pip/__init__.py b/vendor/pip-1.2.1/pip/__init__.py new file mode 100755 index 0000000..9580790 --- /dev/null +++ b/vendor/pip-1.2.1/pip/__init__.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python +import os +import optparse + +import subprocess +import sys +import re +import difflib + +from pip.backwardcompat import walk_packages, console_to_str +from pip.basecommand import command_dict, load_command, load_all_commands, command_names +from pip.baseparser import parser +from pip.exceptions import InstallationError +from pip.log import logger +from pip.util import get_installed_distributions + + +def autocomplete(): + """Command and option completion for the main option parser (and options) + and its subcommands (and options). + + Enable by sourcing one of the completion shell scripts (bash or zsh). + """ + # Don't complete if user hasn't sourced bash_completion file. + if 'PIP_AUTO_COMPLETE' not in os.environ: + return + cwords = os.environ['COMP_WORDS'].split()[1:] + cword = int(os.environ['COMP_CWORD']) + try: + current = cwords[cword-1] + except IndexError: + current = '' + load_all_commands() + subcommands = [cmd for cmd, cls in command_dict.items() if not cls.hidden] + options = [] + # subcommand + try: + subcommand_name = [w for w in cwords if w in subcommands][0] + except IndexError: + subcommand_name = None + # subcommand options + if subcommand_name: + # special case: 'help' subcommand has no options + if subcommand_name == 'help': + sys.exit(1) + # special case: list locally installed dists for uninstall command + if subcommand_name == 'uninstall' and not current.startswith('-'): + installed = [] + lc = current.lower() + for dist in get_installed_distributions(local_only=True): + if dist.key.startswith(lc) and dist.key not in cwords[1:]: + installed.append(dist.key) + # if there are no dists installed, fall back to option completion + if installed: + for dist in installed: + print(dist) + sys.exit(1) + subcommand = command_dict.get(subcommand_name) + options += [(opt.get_opt_string(), opt.nargs) + for opt in subcommand.parser.option_list + if opt.help != optparse.SUPPRESS_HELP] + # filter out previously specified options from available options + prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]] + options = [(x, v) for (x, v) in options if x not in prev_opts] + # filter options by current input + options = [(k, v) for k, v in options if k.startswith(current)] + for option in options: + opt_label = option[0] + # append '=' to options which require args + if option[1]: + opt_label += '=' + print(opt_label) + else: + # show options of main parser only when necessary + if current.startswith('-') or current.startswith('--'): + subcommands += [opt.get_opt_string() + for opt in parser.option_list + if opt.help != optparse.SUPPRESS_HELP] + print(' '.join([x for x in subcommands if x.startswith(current)])) + sys.exit(1) + + +def version_control(): + # Import all the version control support modules: + from pip import vcs + for importer, modname, ispkg in \ + walk_packages(path=vcs.__path__, prefix=vcs.__name__+'.'): + __import__(modname) + + +def main(initial_args=None): + if initial_args is None: + initial_args = sys.argv[1:] + autocomplete() + version_control() + options, args = parser.parse_args(initial_args) + if options.help and not args: + args = ['help'] + if not args: + parser.error('You must give a command (use "pip help" to see a list of commands)') + command = args[0].lower() + load_command(command) + if command not in command_dict: + close_commands = difflib.get_close_matches(command, command_names()) + if close_commands: + guess = close_commands[0] + if args[1:]: + guess = "%s %s" % (guess, " ".join(args[1:])) + else: + guess = 'install %s' % command + error_dict = {'arg': command, 'guess': guess, + 'script': os.path.basename(sys.argv[0])} + parser.error('No command by the name %(script)s %(arg)s\n ' + '(maybe you meant "%(script)s %(guess)s")' % error_dict) + command = command_dict[command] + return command.main(args[1:], options) + + +def bootstrap(): + """ + Bootstrapping function to be called from install-pip.py script. + """ + return main(['install', '--upgrade', 'pip']) + +############################################################ +## Writing freeze files + + +class FrozenRequirement(object): + + def __init__(self, name, req, editable, comments=()): + self.name = name + self.req = req + self.editable = editable + self.comments = comments + + _rev_re = re.compile(r'-r(\d+)$') + _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') + + @classmethod + def from_dist(cls, dist, dependency_links, find_tags=False): + location = os.path.normcase(os.path.abspath(dist.location)) + comments = [] + from pip.vcs import vcs, get_src_requirement + if vcs.get_backend_name(location): + editable = True + req = get_src_requirement(dist, location, find_tags) + if req is None: + logger.warn('Could not determine repository location of %s' % location) + comments.append('## !! Could not determine repository location') + req = dist.as_requirement() + editable = False + else: + editable = False + req = dist.as_requirement() + specs = req.specs + assert len(specs) == 1 and specs[0][0] == '==' + version = specs[0][1] + ver_match = cls._rev_re.search(version) + date_match = cls._date_re.search(version) + if ver_match or date_match: + svn_backend = vcs.get_backend('svn') + if svn_backend: + svn_location = svn_backend( + ).get_location(dist, dependency_links) + if not svn_location: + logger.warn( + 'Warning: cannot find svn location for %s' % req) + comments.append('## FIXME: could not find svn URL in dependency_links for this package:') + else: + comments.append('# Installing as editable to satisfy requirement %s:' % req) + if ver_match: + rev = ver_match.group(1) + else: + rev = '{%s}' % date_match.group(1) + editable = True + req = '%s@%s#egg=%s' % (svn_location, rev, cls.egg_name(dist)) + return cls(dist.project_name, req, editable, comments) + + @staticmethod + def egg_name(dist): + name = dist.egg_name() + match = re.search(r'-py\d\.\d$', name) + if match: + name = name[:match.start()] + return name + + def __str__(self): + req = self.req + if self.editable: + req = '-e %s' % req + return '\n'.join(list(self.comments)+[str(req)])+'\n' + +############################################################ +## Requirement files + + +def call_subprocess(cmd, show_stdout=True, + filter_stdout=None, cwd=None, + raise_on_returncode=True, + command_level=logger.DEBUG, command_desc=None, + extra_environ=None): + if command_desc is None: + cmd_parts = [] + for part in cmd: + if ' ' in part or '\n' in part or '"' in part or "'" in part: + part = '"%s"' % part.replace('"', '\\"') + cmd_parts.append(part) + command_desc = ' '.join(cmd_parts) + if show_stdout: + stdout = None + else: + stdout = subprocess.PIPE + logger.log(command_level, "Running command %s" % command_desc) + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + try: + proc = subprocess.Popen( + cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, + cwd=cwd, env=env) + except Exception: + e = sys.exc_info()[1] + logger.fatal( + "Error %s while executing command %s" % (e, command_desc)) + raise + all_output = [] + if stdout is not None: + stdout = proc.stdout + while 1: + line = console_to_str(stdout.readline()) + if not line: + break + line = line.rstrip() + all_output.append(line + '\n') + if filter_stdout: + level = filter_stdout(line) + if isinstance(level, tuple): + level, line = level + logger.log(level, line) + if not logger.stdout_level_matches(level): + logger.show_progress() + else: + logger.info(line) + else: + returned_stdout, returned_stderr = proc.communicate() + all_output = [returned_stdout or ''] + proc.wait() + if proc.returncode: + if raise_on_returncode: + if all_output: + logger.notify('Complete output from command %s:' % command_desc) + logger.notify('\n'.join(all_output) + '\n----------------------------------------') + raise InstallationError( + "Command %s failed with error code %s in %s" + % (command_desc, proc.returncode, cwd)) + else: + logger.warn( + "Command %s had error code %s in %s" + % (command_desc, proc.returncode, cwd)) + if stdout is not None: + return ''.join(all_output) + + +if __name__ == '__main__': + exit = main() + if exit: + sys.exit(exit) diff --git a/vendor/pip-1.2.1/pip/_pkgutil.py b/vendor/pip-1.2.1/pip/_pkgutil.py new file mode 100644 index 0000000..fe37d04 --- /dev/null +++ b/vendor/pip-1.2.1/pip/_pkgutil.py @@ -0,0 +1,592 @@ +"""Utilities to support packages.""" + +# NOTE: This module must remain compatible with Python 2.3, as it is shared +# by setuptools for distribution with Python 2.3 and up. + +import os +import sys +import imp +import os.path +from types import ModuleType + +__all__ = [ + 'get_importer', 'iter_importers', 'get_loader', 'find_loader', + 'walk_packages', 'iter_modules', + 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path', +] + + +def read_code(stream): + # This helper is needed in order for the PEP 302 emulation to + # correctly handle compiled files + import marshal + + magic = stream.read(4) + if magic != imp.get_magic(): + return None + + stream.read(4) # Skip timestamp + return marshal.load(stream) + + +def simplegeneric(func): + """Make a trivial single-dispatch generic function""" + registry = {} + + def wrapper(*args, **kw): + ob = args[0] + try: + cls = ob.__class__ + except AttributeError: + cls = type(ob) + try: + mro = cls.__mro__ + except AttributeError: + try: + + class cls(cls, object): + pass + + mro = cls.__mro__[1:] + except TypeError: + mro = object, # must be an ExtensionClass or some such :( + for t in mro: + if t in registry: + return registry[t](*args, **kw) + else: + return func(*args, **kw) + try: + wrapper.__name__ = func.__name__ + except (TypeError, AttributeError): + pass # Python 2.3 doesn't allow functions to be renamed + + def register(typ, func=None): + if func is None: + return lambda f: register(typ, f) + registry[typ] = func + return func + + wrapper.__dict__ = func.__dict__ + wrapper.__doc__ = func.__doc__ + wrapper.register = register + return wrapper + + +def walk_packages(path=None, prefix='', onerror=None): + """Yields (module_loader, name, ispkg) for all modules recursively + on path, or, if path is None, all accessible modules. + + 'path' should be either None or a list of paths to look for + modules in. + + 'prefix' is a string to output on the front of every module name + on output. + + Note that this function must import all *packages* (NOT all + modules!) on the given path, in order to access the __path__ + attribute to find submodules. + + 'onerror' is a function which gets called with one argument (the + name of the package which was being imported) if any exception + occurs while trying to import a package. If no onerror function is + supplied, ImportErrors are caught and ignored, while all other + exceptions are propagated, terminating the search. + + Examples: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__+'.') + """ + + def seen(p, m={}): + if p in m: + return True + m[p] = True + + for importer, name, ispkg in iter_modules(path, prefix): + yield importer, name, ispkg + + if ispkg: + try: + __import__(name) + except ImportError: + if onerror is not None: + onerror(name) + except Exception: + if onerror is not None: + onerror(name) + else: + raise + else: + path = getattr(sys.modules[name], '__path__', None) or [] + + # don't traverse path items we've seen before + path = [p for p in path if not seen(p)] + + for item in walk_packages(path, name+'.', onerror): + yield item + + +def iter_modules(path=None, prefix=''): + """Yields (module_loader, name, ispkg) for all submodules on path, + or, if path is None, all top-level modules on sys.path. + + 'path' should be either None or a list of paths to look for + modules in. + + 'prefix' is a string to output on the front of every module name + on output. + """ + + if path is None: + importers = iter_importers() + else: + importers = map(get_importer, path) + + yielded = {} + for i in importers: + for name, ispkg in iter_importer_modules(i, prefix): + if name not in yielded: + yielded[name] = 1 + yield i, name, ispkg + + +#@simplegeneric +def iter_importer_modules(importer, prefix=''): + if not hasattr(importer, 'iter_modules'): + return [] + return importer.iter_modules(prefix) + +iter_importer_modules = simplegeneric(iter_importer_modules) + + +class ImpImporter: + """PEP 302 Importer that wraps Python's "classic" import algorithm + + ImpImporter(dirname) produces a PEP 302 importer that searches that + directory. ImpImporter(None) produces a PEP 302 importer that searches + the current sys.path, plus any modules that are frozen or built-in. + + Note that ImpImporter does not currently support being used by placement + on sys.meta_path. + """ + + def __init__(self, path=None): + self.path = path + + def find_module(self, fullname, path=None): + # Note: we ignore 'path' argument since it is only used via meta_path + subname = fullname.split(".")[-1] + if subname != fullname and self.path is None: + return None + if self.path is None: + path = None + else: + path = [os.path.realpath(self.path)] + try: + file, filename, etc = imp.find_module(subname, path) + except ImportError: + return None + return ImpLoader(fullname, file, filename, etc) + + def iter_modules(self, prefix=''): + if self.path is None or not os.path.isdir(self.path): + return + + yielded = {} + import inspect + + filenames = os.listdir(self.path) + filenames.sort() # handle packages before same-named modules + + for fn in filenames: + modname = inspect.getmodulename(fn) + if modname=='__init__' or modname in yielded: + continue + + path = os.path.join(self.path, fn) + ispkg = False + + if not modname and os.path.isdir(path) and '.' not in fn: + modname = fn + for fn in os.listdir(path): + subname = inspect.getmodulename(fn) + if subname=='__init__': + ispkg = True + break + else: + continue # not a package + + if modname and '.' not in modname: + yielded[modname] = 1 + yield prefix + modname, ispkg + + +class ImpLoader: + """PEP 302 Loader that wraps Python's "classic" import algorithm + """ + code = source = None + + def __init__(self, fullname, file, filename, etc): + self.file = file + self.filename = filename + self.fullname = fullname + self.etc = etc + + def load_module(self, fullname): + self._reopen() + 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_data(self, pathname): + return open(pathname, "rb").read() + + def _reopen(self): + if self.file and self.file.closed: + mod_type = self.etc[2] + if mod_type==imp.PY_SOURCE: + self.file = open(self.filename, 'rU') + elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION): + self.file = open(self.filename, 'rb') + + def _fix_name(self, fullname): + if fullname is None: + fullname = self.fullname + elif fullname != self.fullname: + raise ImportError("Loader for module %s cannot handle " + "module %s" % (self.fullname, fullname)) + return fullname + + def is_package(self, fullname): + fullname = self._fix_name(fullname) + return self.etc[2]==imp.PKG_DIRECTORY + + def get_code(self, fullname=None): + fullname = self._fix_name(fullname) + if self.code is None: + mod_type = self.etc[2] + if mod_type==imp.PY_SOURCE: + source = self.get_source(fullname) + self.code = compile(source, self.filename, 'exec') + elif mod_type==imp.PY_COMPILED: + self._reopen() + try: + self.code = read_code(self.file) + finally: + self.file.close() + elif mod_type==imp.PKG_DIRECTORY: + self.code = self._get_delegate().get_code() + return self.code + + def get_source(self, fullname=None): + fullname = self._fix_name(fullname) + if self.source is None: + mod_type = self.etc[2] + if mod_type==imp.PY_SOURCE: + self._reopen() + try: + self.source = self.file.read() + finally: + self.file.close() + elif mod_type==imp.PY_COMPILED: + if os.path.exists(self.filename[:-1]): + f = open(self.filename[:-1], 'rU') + self.source = f.read() + f.close() + elif mod_type==imp.PKG_DIRECTORY: + self.source = self._get_delegate().get_source() + return self.source + + def _get_delegate(self): + return ImpImporter(self.filename).find_module('__init__') + + def get_filename(self, fullname=None): + fullname = self._fix_name(fullname) + mod_type = self.etc[2] + if self.etc[2]==imp.PKG_DIRECTORY: + return self._get_delegate().get_filename() + elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): + return self.filename + return None + + +try: + import zipimport + from zipimport import zipimporter + + def iter_zipimport_modules(importer, prefix=''): + dirlist = list(zipimport._zip_directory_cache[importer.archive].keys()) + dirlist.sort() + _prefix = importer.prefix + plen = len(_prefix) + yielded = {} + import inspect + for fn in dirlist: + if not fn.startswith(_prefix): + continue + + fn = fn[plen:].split(os.sep) + + if len(fn)==2 and fn[1].startswith('__init__.py'): + if fn[0] not in yielded: + yielded[fn[0]] = 1 + yield fn[0], True + + if len(fn)!=1: + continue + + modname = inspect.getmodulename(fn[0]) + if modname=='__init__': + continue + + if modname and '.' not in modname and modname not in yielded: + yielded[modname] = 1 + yield prefix + modname, False + + iter_importer_modules.register(zipimporter, iter_zipimport_modules) + +except ImportError: + pass + + +def get_importer(path_item): + """Retrieve a PEP 302 importer for the given path item + + The returned importer is cached in sys.path_importer_cache + if it was newly created by a path hook. + + If there is no importer, a wrapper around the basic import + machinery is returned. This wrapper is never inserted into + the importer cache (None is inserted instead). + + The cache (or part of it) can be cleared manually if a + rescan of sys.path_hooks is necessary. + """ + try: + importer = sys.path_importer_cache[path_item] + except KeyError: + for path_hook in sys.path_hooks: + try: + importer = path_hook(path_item) + break + except ImportError: + pass + else: + importer = None + sys.path_importer_cache.setdefault(path_item, importer) + + if importer is None: + try: + importer = ImpImporter(path_item) + except ImportError: + importer = None + return importer + + +def iter_importers(fullname=""): + """Yield PEP 302 importers for the given module name + + If fullname contains a '.', the importers will be for the package + containing fullname, otherwise they will be importers for sys.meta_path, + sys.path, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side + effect of invoking this function. + + Non PEP 302 mechanisms (e.g. the Windows registry) used by the + standard import machinery to find files in alternative locations + are partially supported, but are searched AFTER sys.path. Normally, + these locations are searched BEFORE sys.path, preventing sys.path + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must + be a module or package name that is accessible via both sys.path + and one of the non PEP 302 file system mechanisms. In this case, + the emulation will find the former version, while the builtin + import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY + """ + if fullname.startswith('.'): + raise ImportError("Relative module names not supported") + if '.' in fullname: + # Get the containing package's __path__ + pkg = '.'.join(fullname.split('.')[:-1]) + if pkg not in sys.modules: + __import__(pkg) + path = getattr(sys.modules[pkg], '__path__', None) or [] + else: + for importer in sys.meta_path: + yield importer + path = sys.path + for item in path: + yield get_importer(item) + if '.' not in fullname: + yield ImpImporter() + + +def get_loader(module_or_name): + """Get a PEP 302 "loader" object for module_or_name + + If the module or package is accessible via the normal import + mechanism, a wrapper around the relevant part of that machinery + is returned. Returns None if the module cannot be found or imported. + If the named module is not already imported, its containing package + (if any) is imported, in order to establish the package __path__. + + This function uses iter_importers(), and is thus subject to the same + limitations regarding platform-specific special import locations such + as the Windows registry. + """ + if module_or_name in sys.modules: + module_or_name = sys.modules[module_or_name] + if isinstance(module_or_name, ModuleType): + module = module_or_name + loader = getattr(module, '__loader__', None) + if loader is not None: + return loader + fullname = module.__name__ + else: + fullname = module_or_name + return find_loader(fullname) + + +def find_loader(fullname): + """Find a PEP 302 "loader" object for fullname + + If fullname contains dots, path must be the containing package's __path__. + Returns None if the module cannot be found or imported. This function uses + iter_importers(), and is thus subject to the same limitations regarding + platform-specific special import locations such as the Windows registry. + """ + for importer in iter_importers(fullname): + loader = importer.find_module(fullname) + if loader is not None: + return loader + + return None + + +def extend_path(path, name): + """Extend a package's path. + + Intended use is to place the following code in a package's __init__.py: + + from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) + + This will add to the package's __path__ all subdirectories of + directories on sys.path named after the package. This is useful + if one wants to distribute different parts of a single logical + package as multiple directories. + + It also looks for *.pkg files beginning where * matches the name + argument. This feature is similar to *.pth files (see site.py), + except that it doesn't special-case lines starting with 'import'. + A *.pkg file is trusted at face value: apart from checking for + duplicates, all entries found in a *.pkg file are added to the + path, regardless of whether they are exist the filesystem. (This + is a feature.) + + If the input path is not a list (as is the case for frozen + packages) it is returned unchanged. The input path is not + modified; an extended copy is returned. Items are only appended + to the copy at the end. + + It is assumed that sys.path is a sequence. Items of sys.path that + are not (unicode or 8-bit) strings referring to existing + directories are ignored. Unicode items of sys.path that cause + errors when used as filenames may cause this function to raise an + exception (in line with os.path.isdir() behavior). + """ + + if not isinstance(path, list): + # This could happen e.g. when this is called from inside a + # frozen package. Return the path unchanged in that case. + return path + + pname = os.path.join(*name.split('.')) # Reconstitute as relative path + # Just in case os.extsep != '.' + sname = os.extsep.join(name.split('.')) + sname_pkg = sname + os.extsep + "pkg" + init_py = "__init__" + os.extsep + "py" + + path = path[:] # Start with a copy of the existing path + + from pip.backwardcompat import string_types + + for dir in sys.path: + if not isinstance(dir, string_types) or not os.path.isdir(dir): + continue + subdir = os.path.join(dir, pname) + # XXX This may still add duplicate entries to path on + # case-insensitive filesystems + initfile = os.path.join(subdir, init_py) + if subdir not in path and os.path.isfile(initfile): + path.append(subdir) + # XXX Is this the right thing for subpackages like zope.app? + # It looks for a file named "zope.app.pkg" + pkgfile = os.path.join(dir, sname_pkg) + if os.path.isfile(pkgfile): + try: + f = open(pkgfile) + except IOError: + msg = sys.exc_info()[1] + sys.stderr.write("Can't open %s: %s\n" % + (pkgfile, msg)) + else: + for line in f: + line = line.rstrip('\n') + if not line or line.startswith('#'): + continue + path.append(line) # Don't check for existence! + f.close() + + return path + + +def get_data(package, resource): + """Get a resource from a package. + + This is a wrapper round the PEP 302 loader get_data API. The package + argument should be the name of a package, in standard module format + (foo.bar). The resource argument should be in the form of a relative + filename, using '/' as the path separator. The parent directory name '..' + is not allowed, and nor is a rooted name (starting with a '/'). + + The function returns a binary string, which is the contents of the + specified resource. + + For packages located in the filesystem, which have already been imported, + this is the rough equivalent of + + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() + + If the package cannot be located or loaded, or it uses a PEP 302 loader + which does not support get_data(), then None is returned. + """ + + loader = get_loader(package) + if loader is None or not hasattr(loader, 'get_data'): + return None + mod = sys.modules.get(package) or loader.load_module(package) + if mod is None or not hasattr(mod, '__file__'): + return None + + # Modify the resource name to be compatible with the loader.get_data + # signature - an os.path format "filename" starting with the dirname of + # the package's __file__ + parts = resource.split('/') + parts.insert(0, os.path.dirname(mod.__file__)) + resource_name = os.path.join(*parts) + return loader.get_data(resource_name) diff --git a/vendor/pip-1.2.1/pip/backwardcompat.py b/vendor/pip-1.2.1/pip/backwardcompat.py new file mode 100644 index 0000000..e33da98 --- /dev/null +++ b/vendor/pip-1.2.1/pip/backwardcompat.py @@ -0,0 +1,135 @@ +"""Stuff that differs in different Python versions""" + +import sys +import os +import shutil + +__all__ = ['any', 'WindowsError', 'md5', 'copytree'] + +try: + WindowsError = WindowsError +except NameError: + class NeverUsedException(Exception): + """this exception should never be raised""" + WindowsError = NeverUsedException +try: + from hashlib import md5 +except ImportError: + import md5 as md5_module + md5 = md5_module.new + +try: + from pkgutil import walk_packages +except ImportError: + # let's fall back as long as we can + from pip._pkgutil import walk_packages + +try: + any = any +except NameError: + + def any(seq): + for item in seq: + if item: + return True + return False + +console_encoding = sys.__stdout__.encoding + +if sys.version_info >= (3,): + from io import StringIO, BytesIO + from functools import reduce + from urllib.error import URLError, HTTPError + from queue import Queue, Empty + from urllib.request import url2pathname + from urllib.request import urlretrieve + from email import message as emailmessage + import urllib.parse as urllib + import urllib.request as urllib2 + import configparser as ConfigParser + import xmlrpc.client as xmlrpclib + import urllib.parse as urlparse + import http.client as httplib + + def cmp(a, b): + return (a > b) - (a < b) + + def b(s): + return s.encode('utf-8') + + def u(s): + return s.decode('utf-8') + + def console_to_str(s): + try: + return s.decode(console_encoding) + except UnicodeDecodeError: + return s.decode('utf_8') + + def fwrite(f, s): + f.buffer.write(b(s)) + + bytes = bytes + string_types = (str,) + raw_input = input +else: + from cStringIO import StringIO + from urllib2 import URLError, HTTPError + from Queue import Queue, Empty + from urllib import url2pathname, urlretrieve + from email import Message as emailmessage + import urllib + import urllib2 + import urlparse + import ConfigParser + import xmlrpclib + import httplib + + def b(s): + return s + + def u(s): + return s + + def console_to_str(s): + return s + + def fwrite(f, s): + f.write(s) + + bytes = str + string_types = (basestring,) + reduce = reduce + cmp = cmp + raw_input = raw_input + BytesIO = StringIO + +try: + from email.parser import FeedParser +except ImportError: + # python lesser than 2.5 + from email.FeedParser import FeedParser + +from distutils.sysconfig import get_python_lib, get_python_version + + +def copytree(src, dst): + if sys.version_info < (2, 5): + before_last_dir = os.path.dirname(dst) + if not os.path.exists(before_last_dir): + os.makedirs(before_last_dir) + shutil.copytree(src, dst) + shutil.copymode(src, dst) + else: + shutil.copytree(src, dst) + + +def product(*args, **kwds): + # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy + # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 + pools = list(map(tuple, args)) * kwds.get('repeat', 1) + result = [[]] + for pool in pools: + result = [x+[y] for x in result for y in pool] + for prod in result: + yield tuple(prod) diff --git a/vendor/pip-1.2.1/pip/basecommand.py b/vendor/pip-1.2.1/pip/basecommand.py new file mode 100644 index 0000000..12bcd62 --- /dev/null +++ b/vendor/pip-1.2.1/pip/basecommand.py @@ -0,0 +1,193 @@ +"""Base Command class, and related routines""" + +import os +import socket +import sys +import traceback +import time + +from pip import commands +from pip.log import logger +from pip.baseparser import parser, ConfigOptionParser, UpdatingDefaultsHelpFormatter +from pip.download import urlopen +from pip.exceptions import (BadCommand, InstallationError, UninstallationError, + CommandError) +from pip.backwardcompat import StringIO, walk_packages +from pip.status_codes import SUCCESS, ERROR, UNKNOWN_ERROR, VIRTUALENV_NOT_FOUND + + +__all__ = ['command_dict', 'Command', 'load_all_commands', + 'load_command', 'command_names'] + +command_dict = {} + +# for backwards compatibiliy +get_proxy = urlopen.get_proxy + + +class Command(object): + name = None + usage = None + hidden = False + + def __init__(self): + assert self.name + self.parser = ConfigOptionParser( + usage=self.usage, + prog='%s %s' % (sys.argv[0], self.name), + version=parser.version, + formatter=UpdatingDefaultsHelpFormatter(), + name=self.name) + for option in parser.option_list: + if not option.dest or option.dest == 'help': + # -h, --version, etc + continue + self.parser.add_option(option) + command_dict[self.name] = self + + def merge_options(self, initial_options, options): + # Make sure we have all global options carried over + for attr in ['log', 'proxy', 'require_venv', + 'log_explicit_levels', 'log_file', + 'timeout', 'default_vcs', + 'skip_requirements_regex', + 'no_input', 'exists_action']: + setattr(options, attr, getattr(initial_options, attr) or getattr(options, attr)) + options.quiet += initial_options.quiet + options.verbose += initial_options.verbose + + def setup_logging(self): + pass + + def main(self, args, initial_options): + options, args = self.parser.parse_args(args) + self.merge_options(initial_options, options) + + level = 1 # Notify + level += options.verbose + level -= options.quiet + level = logger.level_for_integer(4-level) + complete_log = [] + logger.consumers.extend( + [(level, sys.stdout), + (logger.DEBUG, complete_log.append)]) + if options.log_explicit_levels: + logger.explicit_levels = True + + self.setup_logging() + + if options.no_input: + os.environ['PIP_NO_INPUT'] = '1' + + if options.exists_action: + os.environ['PIP_EXISTS_ACTION'] = ''.join(options.exists_action) + + if options.require_venv: + # If a venv is required check if it can really be found + if not os.environ.get('VIRTUAL_ENV'): + logger.fatal('Could not find an activated virtualenv (required).') + sys.exit(VIRTUALENV_NOT_FOUND) + + if options.log: + log_fp = open_logfile(options.log, 'a') + logger.consumers.append((logger.DEBUG, log_fp)) + else: + log_fp = None + + socket.setdefaulttimeout(options.timeout or None) + + urlopen.setup(proxystr=options.proxy, prompting=not options.no_input) + + exit = SUCCESS + store_log = False + try: + status = self.run(options, args) + # FIXME: all commands should return an exit status + # and when it is done, isinstance is not needed anymore + if isinstance(status, int): + exit = status + except (InstallationError, UninstallationError): + e = sys.exc_info()[1] + logger.fatal(str(e)) + logger.info('Exception information:\n%s' % format_exc()) + store_log = True + exit = ERROR + except BadCommand: + e = sys.exc_info()[1] + logger.fatal(str(e)) + logger.info('Exception information:\n%s' % format_exc()) + store_log = True + exit = ERROR + except CommandError: + e = sys.exc_info()[1] + logger.fatal('ERROR: %s' % e) + logger.info('Exception information:\n%s' % format_exc()) + exit = ERROR + except KeyboardInterrupt: + logger.fatal('Operation cancelled by user') + logger.info('Exception information:\n%s' % format_exc()) + store_log = True + exit = ERROR + except: + logger.fatal('Exception:\n%s' % format_exc()) + store_log = True + exit = UNKNOWN_ERROR + if log_fp is not None: + log_fp.close() + if store_log: + log_fn = options.log_file + text = '\n'.join(complete_log) + logger.fatal('Storing complete log in %s' % log_fn) + log_fp = open_logfile(log_fn, 'w') + log_fp.write(text) + log_fp.close() + return exit + + +def format_exc(exc_info=None): + if exc_info is None: + exc_info = sys.exc_info() + out = StringIO() + traceback.print_exception(*exc_info, **dict(file=out)) + return out.getvalue() + + +def open_logfile(filename, mode='a'): + """Open the named log file in append mode. + + If the file already exists, a separator will also be printed to + the file to separate past activity from current activity. + """ + filename = os.path.expanduser(filename) + filename = os.path.abspath(filename) + dirname = os.path.dirname(filename) + if not os.path.exists(dirname): + os.makedirs(dirname) + exists = os.path.exists(filename) + + log_fp = open(filename, mode) + if exists: + log_fp.write('%s\n' % ('-'*60)) + log_fp.write('%s run on %s\n' % (sys.argv[0], time.strftime('%c'))) + return log_fp + + +def load_command(name): + full_name = 'pip.commands.%s' % name + if full_name in sys.modules: + return + try: + __import__(full_name) + except ImportError: + pass + + +def load_all_commands(): + for name in command_names(): + load_command(name) + + +def command_names(): + names = set((pkg[1] for pkg in walk_packages(path=commands.__path__))) + return list(names) + diff --git a/vendor/pip-1.2.1/pip/baseparser.py b/vendor/pip-1.2.1/pip/baseparser.py new file mode 100644 index 0000000..b3864f3 --- /dev/null +++ b/vendor/pip-1.2.1/pip/baseparser.py @@ -0,0 +1,226 @@ +"""Base option parser setup""" + +import sys +import optparse +import pkg_resources +import os +from distutils.util import strtobool +from pip.backwardcompat import ConfigParser, string_types +from pip.locations import default_config_file, default_log_file + + +class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): + """Custom help formatter for use in ConfigOptionParser that updates + the defaults before expanding them, allowing them to show up correctly + in the help listing""" + + def expand_default(self, option): + if self.parser is not None: + self.parser.update_defaults(self.parser.defaults) + return optparse.IndentedHelpFormatter.expand_default(self, option) + + +class ConfigOptionParser(optparse.OptionParser): + """Custom option parser which updates its defaults by by checking the + configuration files and environmental variables""" + + def __init__(self, *args, **kwargs): + self.config = ConfigParser.RawConfigParser() + self.name = kwargs.pop('name') + self.files = self.get_config_files() + self.config.read(self.files) + assert self.name + optparse.OptionParser.__init__(self, *args, **kwargs) + + def get_config_files(self): + config_file = os.environ.get('PIP_CONFIG_FILE', False) + if config_file and os.path.exists(config_file): + return [config_file] + return [default_config_file] + + def update_defaults(self, defaults): + """Updates the given defaults with values from the config files and + the environ. Does a little special handling for certain types of + options (lists).""" + # Then go and look for the other sources of configuration: + config = {} + # 1. config files + for section in ('global', self.name): + config.update(self.normalize_keys(self.get_config_section(section))) + # 2. environmental variables + config.update(self.normalize_keys(self.get_environ_vars())) + # Then set the options with those values + for key, val in config.items(): + option = self.get_option(key) + if option is not None: + # ignore empty values + if not val: + continue + # handle multiline configs + if option.action == 'append': + val = val.split() + else: + option.nargs = 1 + if option.action in ('store_true', 'store_false', 'count'): + val = strtobool(val) + try: + val = option.convert_value(key, val) + except optparse.OptionValueError: + e = sys.exc_info()[1] + print("An error occured during configuration: %s" % e) + sys.exit(3) + defaults[option.dest] = val + return defaults + + def normalize_keys(self, items): + """Return a config dictionary with normalized keys regardless of + whether the keys were specified in environment variables or in config + files""" + normalized = {} + for key, val in items: + key = key.replace('_', '-') + if not key.startswith('--'): + key = '--%s' % key # only prefer long opts + normalized[key] = val + return normalized + + def get_config_section(self, name): + """Get a section of a configuration""" + if self.config.has_section(name): + return self.config.items(name) + return [] + + def get_environ_vars(self, prefix='PIP_'): + """Returns a generator with all environmental vars with prefix PIP_""" + for key, val in os.environ.items(): + if key.startswith(prefix): + yield (key.replace(prefix, '').lower(), val) + + def get_default_values(self): + """Overridding to make updating the defaults after instantiation of + the option parser possible, update_defaults() does the dirty work.""" + if not self.process_default_values: + # Old, pre-Optik 1.5 behaviour. + return optparse.Values(self.defaults) + + defaults = self.update_defaults(self.defaults.copy()) # ours + for option in self._get_all_options(): + default = defaults.get(option.dest) + if isinstance(default, string_types): + opt_str = option.get_opt_string() + defaults[option.dest] = option.check_value(opt_str, default) + return optparse.Values(defaults) + +try: + pip_dist = pkg_resources.get_distribution('pip') + version = '%s from %s (python %s)' % ( + pip_dist, pip_dist.location, sys.version[:3]) +except pkg_resources.DistributionNotFound: + # when running pip.py without installing + version=None + +parser = ConfigOptionParser( + usage='%prog COMMAND [OPTIONS]', + version=version, + add_help_option=False, + formatter=UpdatingDefaultsHelpFormatter(), + name='global') + +parser.add_option( + '-h', '--help', + dest='help', + action='store_true', + help='Show help') +parser.add_option( + # Run only if inside a virtualenv, bail if not. + '--require-virtualenv', '--require-venv', + dest='require_venv', + action='store_true', + default=False, + help=optparse.SUPPRESS_HELP) + +parser.add_option( + '-v', '--verbose', + dest='verbose', + action='count', + default=0, + help='Give more output') +parser.add_option( + '-q', '--quiet', + dest='quiet', + action='count', + default=0, + help='Give less output') +parser.add_option( + '--log', + dest='log', + metavar='FILENAME', + help='Log file where a complete (maximum verbosity) record will be kept') +parser.add_option( + # Writes the log levels explicitely to the log' + '--log-explicit-levels', + dest='log_explicit_levels', + action='store_true', + default=False, + help=optparse.SUPPRESS_HELP) +parser.add_option( + # The default log file + '--local-log', '--log-file', + dest='log_file', + metavar='FILENAME', + default=default_log_file, + help=optparse.SUPPRESS_HELP) +parser.add_option( + # Don't ask for input + '--no-input', + dest='no_input', + action='store_true', + default=False, + help=optparse.SUPPRESS_HELP) + +parser.add_option( + '--proxy', + dest='proxy', + type='str', + default='', + help="Specify a proxy in the form user:passwd@proxy.server:port. " + "Note that the user:password@ is optional and required only if you " + "are behind an authenticated proxy. If you provide " + "user@proxy.server:port then you will be prompted for a password.") +parser.add_option( + '--timeout', '--default-timeout', + metavar='SECONDS', + dest='timeout', + type='float', + default=15, + help='Set the socket timeout (default %default seconds)') +parser.add_option( + # The default version control system for editables, e.g. 'svn' + '--default-vcs', + dest='default_vcs', + type='str', + default='', + help=optparse.SUPPRESS_HELP) +parser.add_option( + # A regex to be used to skip requirements + '--skip-requirements-regex', + dest='skip_requirements_regex', + type='str', + default='', + help=optparse.SUPPRESS_HELP) + +parser.add_option( + # Option when path already exist + '--exists-action', + dest='exists_action', + type='choice', + choices=['s', 'i', 'w', 'b'], + default=[], + action='append', + help="Default action when a path already exists." + "Use this option more then one time to specify " + "another action if a certain option is not " + "available, choices: " + "(s)witch, (i)gnore, (w)ipe, (b)ackup") + +parser.disable_interspersed_args() diff --git a/vendor/pip-1.2.1/pip/commands/__init__.py b/vendor/pip-1.2.1/pip/commands/__init__.py new file mode 100644 index 0000000..792d600 --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/__init__.py @@ -0,0 +1 @@ +# diff --git a/vendor/pip-1.2.1/pip/commands/bundle.py b/vendor/pip-1.2.1/pip/commands/bundle.py new file mode 100644 index 0000000..f782f1b --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/bundle.py @@ -0,0 +1,38 @@ +from pip.locations import build_prefix, src_prefix +from pip.util import display_path, backup_dir +from pip.log import logger +from pip.exceptions import InstallationError +from pip.commands.install import InstallCommand + + +class BundleCommand(InstallCommand): + name = 'bundle' + usage = '%prog [OPTIONS] BUNDLE_NAME.pybundle PACKAGE_NAMES...' + summary = 'Create pybundles (archives containing multiple packages)' + bundle = True + + def __init__(self): + super(BundleCommand, self).__init__() + # bundle uses different default source and build dirs + build_opt = self.parser.get_option("--build") + build_opt.default = backup_dir(build_prefix, '-bundle') + src_opt = self.parser.get_option("--src") + src_opt.default = backup_dir(src_prefix, '-bundle') + self.parser.set_defaults(**{ + src_opt.dest: src_opt.default, + build_opt.dest: build_opt.default, + }) + + def run(self, options, args): + if not args: + raise InstallationError('You must give a bundle filename') + # We have to get everything when creating a bundle: + options.ignore_installed = True + logger.notify('Putting temporary build files in %s and source/develop files in %s' + % (display_path(options.build_dir), display_path(options.src_dir))) + self.bundle_filename = args.pop(0) + requirement_set = super(BundleCommand, self).run(options, args) + return requirement_set + + +BundleCommand() diff --git a/vendor/pip-1.2.1/pip/commands/completion.py b/vendor/pip-1.2.1/pip/commands/completion.py new file mode 100644 index 0000000..5b93d9c --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/completion.py @@ -0,0 +1,60 @@ +import sys +from pip.basecommand import Command + +BASE_COMPLETION = """ +# pip %(shell)s completion start%(script)s# pip %(shell)s completion end +""" + +COMPLETION_SCRIPTS = { + 'bash': """ +_pip_completion() +{ + COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 ) ) +} +complete -o default -F _pip_completion pip +""", 'zsh': """ +function _pip_completion { + local words cword + read -Ac words + read -cn cword + reply=( $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$(( cword-1 )) \\ + PIP_AUTO_COMPLETE=1 $words[1] ) ) +} +compctl -K _pip_completion pip +"""} + + +class CompletionCommand(Command): + name = 'completion' + summary = 'A helper command to be used for command completion' + hidden = True + + def __init__(self): + super(CompletionCommand, self).__init__() + self.parser.add_option( + '--bash', '-b', + action='store_const', + const='bash', + dest='shell', + help='Emit completion code for bash') + self.parser.add_option( + '--zsh', '-z', + action='store_const', + const='zsh', + dest='shell', + help='Emit completion code for zsh') + + def run(self, options, args): + """Prints the completion code of the given shell""" + shells = COMPLETION_SCRIPTS.keys() + shell_options = ['--'+shell for shell in sorted(shells)] + if options.shell in shells: + script = COMPLETION_SCRIPTS.get(options.shell, '') + print(BASE_COMPLETION % {'script': script, 'shell': options.shell}) + else: + sys.stderr.write('ERROR: You must pass %s\n' % ' or '.join(shell_options)) + +CompletionCommand() diff --git a/vendor/pip-1.2.1/pip/commands/freeze.py b/vendor/pip-1.2.1/pip/commands/freeze.py new file mode 100644 index 0000000..03ac80f --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/freeze.py @@ -0,0 +1,111 @@ +import re +import sys +import pkg_resources +import pip +from pip.req import InstallRequirement +from pip.log import logger +from pip.basecommand import Command +from pip.util import get_installed_distributions + + +class FreezeCommand(Command): + name = 'freeze' + usage = '%prog [OPTIONS]' + summary = 'Output all currently installed packages (exact versions) to stdout' + + def __init__(self): + super(FreezeCommand, self).__init__() + self.parser.add_option( + '-r', '--requirement', + dest='requirement', + action='store', + default=None, + metavar='FILENAME', + help='Use the given requirements file as a hint about how to generate the new frozen requirements') + self.parser.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL for finding packages, which will be added to the frozen requirements file') + self.parser.add_option( + '-l', '--local', + dest='local', + action='store_true', + default=False, + help='If in a virtualenv, do not report globally-installed packages') + + def setup_logging(self): + logger.move_stdout_to_stderr() + + def run(self, options, args): + requirement = options.requirement + find_links = options.find_links or [] + local_only = options.local + ## FIXME: Obviously this should be settable: + find_tags = False + skip_match = None + + skip_regex = options.skip_requirements_regex + if skip_regex: + skip_match = re.compile(skip_regex) + + dependency_links = [] + + f = sys.stdout + + for dist in pkg_resources.working_set: + if dist.has_metadata('dependency_links.txt'): + dependency_links.extend(dist.get_metadata_lines('dependency_links.txt')) + for link in find_links: + if '#egg=' in link: + dependency_links.append(link) + for link in find_links: + f.write('-f %s\n' % link) + installations = {} + for dist in get_installed_distributions(local_only=local_only): + req = pip.FrozenRequirement.from_dist(dist, dependency_links, find_tags=find_tags) + installations[req.name] = req + if requirement: + req_f = open(requirement) + for line in req_f: + if not line.strip() or line.strip().startswith('#'): + f.write(line) + continue + if skip_match and skip_match.search(line): + f.write(line) + continue + elif line.startswith('-e') or line.startswith('--editable'): + if line.startswith('-e'): + line = line[2:].strip() + else: + line = line[len('--editable'):].strip().lstrip('=') + line_req = InstallRequirement.from_editable(line, default_vcs=options.default_vcs) + elif (line.startswith('-r') or line.startswith('--requirement') + or line.startswith('-Z') or line.startswith('--always-unzip') + or line.startswith('-f') or line.startswith('-i') + or line.startswith('--extra-index-url') + or line.startswith('--find-links') + or line.startswith('--index-url')): + f.write(line) + continue + else: + line_req = InstallRequirement.from_line(line) + if not line_req.name: + logger.notify("Skipping line because it's not clear what it would install: %s" + % line.strip()) + logger.notify(" (add #egg=PackageName to the URL to avoid this warning)") + continue + if line_req.name not in installations: + logger.warn("Requirement file contains %s, but that package is not installed" + % line.strip()) + continue + f.write(str(installations[line_req.name])) + del installations[line_req.name] + f.write('## The following requirements were added by pip --freeze:\n') + for installation in sorted(installations.values(), key=lambda x: x.name): + f.write(str(installation)) + + +FreezeCommand() diff --git a/vendor/pip-1.2.1/pip/commands/help.py b/vendor/pip-1.2.1/pip/commands/help.py new file mode 100644 index 0000000..4d504c5 --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/help.py @@ -0,0 +1,33 @@ +from pip.basecommand import (Command, command_dict, + load_all_commands, SUCCESS, + ERROR) +from pip.exceptions import CommandError +from pip.baseparser import parser + + +class HelpCommand(Command): + name = 'help' + usage = '%prog' + summary = 'Show available commands' + + def run(self, options, args): + load_all_commands() + if args: + ## FIXME: handle errors better here + command = args[0] + if command not in command_dict: + raise CommandError('No command with the name: %s' % command) + command = command_dict[command] + command.parser.print_help() + return SUCCESS + parser.print_help() + print('\nCommands available:') + commands = list(set(command_dict.values())) + commands.sort(key=lambda x: x.name) + for command in commands: + if command.hidden: + continue + print(' %s: %s' % (command.name, command.summary)) + return SUCCESS + +HelpCommand() diff --git a/vendor/pip-1.2.1/pip/commands/install.py b/vendor/pip-1.2.1/pip/commands/install.py new file mode 100644 index 0000000..925d57f --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/install.py @@ -0,0 +1,279 @@ +import os +import sys +import tempfile +import shutil +from pip.req import InstallRequirement, RequirementSet +from pip.req import parse_requirements +from pip.log import logger +from pip.locations import build_prefix, src_prefix +from pip.basecommand import Command +from pip.index import PackageFinder +from pip.exceptions import InstallationError, CommandError + + +class InstallCommand(Command): + name = 'install' + usage = '%prog [OPTIONS] PACKAGE_NAMES...' + summary = 'Install packages' + bundle = False + + def __init__(self): + super(InstallCommand, self).__init__() + self.parser.add_option( + '-e', '--editable', + dest='editables', + action='append', + default=[], + metavar='VCS+REPOS_URL[@REV]#egg=PACKAGE', + help='Install a package directly from a checkout. Source will be checked ' + 'out into src/PACKAGE (lower-case) and installed in-place (using ' + 'setup.py develop). You can run this on an existing directory/checkout (like ' + 'pip install -e src/mycheckout). This option may be provided multiple times. ' + 'Possible values for VCS are: svn, git, hg and bzr.') + self.parser.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='FILENAME', + help='Install all the packages listed in the given requirements file. ' + 'This option can be used multiple times.') + self.parser.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL to look for packages at') + self.parser.add_option( + '-i', '--index-url', '--pypi-url', + dest='index_url', + metavar='URL', + default='http://pypi.python.org/simple/', + help='Base URL of Python Package Index (default %default)') + self.parser.add_option( + '--extra-index-url', + dest='extra_index_urls', + metavar='URL', + action='append', + default=[], + help='Extra URLs of package indexes to use in addition to --index-url') + self.parser.add_option( + '--no-index', + dest='no_index', + action='store_true', + default=False, + help='Ignore package index (only looking at --find-links URLs instead)') + self.parser.add_option( + '-M', '--use-mirrors', + dest='use_mirrors', + action='store_true', + default=False, + help='Use the PyPI mirrors as a fallback in case the main index is down.') + self.parser.add_option( + '--mirrors', + dest='mirrors', + metavar='URL', + action='append', + default=[], + help='Specific mirror URLs to query when --use-mirrors is used') + + self.parser.add_option( + '-b', '--build', '--build-dir', '--build-directory', + dest='build_dir', + metavar='DIR', + default=build_prefix, + help='Unpack packages into DIR (default %default) and build from there') + self.parser.add_option( + '-t', '--target', + dest='target_dir', + metavar='DIR', + default=None, + help='Install packages into DIR.') + self.parser.add_option( + '-d', '--download', '--download-dir', '--download-directory', + dest='download_dir', + metavar='DIR', + default=None, + help='Download packages into DIR instead of installing them') + self.parser.add_option( + '--download-cache', + dest='download_cache', + metavar='DIR', + default=None, + help='Cache downloaded packages in DIR') + self.parser.add_option( + '--src', '--source', '--source-dir', '--source-directory', + dest='src_dir', + metavar='DIR', + default=src_prefix, + help='Check out --editable packages into DIR (default %default)') + + self.parser.add_option( + '-U', '--upgrade', + dest='upgrade', + action='store_true', + help='Upgrade all packages to the newest available version') + self.parser.add_option( + '--force-reinstall', + dest='force_reinstall', + action='store_true', + help='When upgrading, reinstall all packages even if they are ' + 'already up-to-date.') + self.parser.add_option( + '-I', '--ignore-installed', + dest='ignore_installed', + action='store_true', + help='Ignore the installed packages (reinstalling instead)') + self.parser.add_option( + '--no-deps', '--no-dependencies', + dest='ignore_dependencies', + action='store_true', + default=False, + help='Ignore package dependencies') + self.parser.add_option( + '--no-install', + dest='no_install', + action='store_true', + help="Download and unpack all packages, but don't actually install them") + self.parser.add_option( + '--no-download', + dest='no_download', + action="store_true", + help="Don't download any packages, just install the ones already downloaded " + "(completes an install run with --no-install)") + + self.parser.add_option( + '--install-option', + dest='install_options', + action='append', + help="Extra arguments to be supplied to the setup.py install " + "command (use like --install-option=\"--install-scripts=/usr/local/bin\"). " + "Use multiple --install-option options to pass multiple options to setup.py install. " + "If you are using an option with a directory path, be sure to use absolute path.") + + self.parser.add_option( + '--global-option', + dest='global_options', + action='append', + help="Extra global options to be supplied to the setup.py" + "call before the install command") + + self.parser.add_option( + '--user', + dest='use_user_site', + action='store_true', + help='Install to user-site') + + def _build_package_finder(self, options, index_urls): + """ + Create a package finder appropriate to this install command. + This method is meant to be overridden by subclasses, not + called directly. + """ + return PackageFinder(find_links=options.find_links, + index_urls=index_urls, + use_mirrors=options.use_mirrors, + mirrors=options.mirrors) + + def run(self, options, args): + if options.download_dir: + options.no_install = True + options.ignore_installed = True + options.build_dir = os.path.abspath(options.build_dir) + options.src_dir = os.path.abspath(options.src_dir) + install_options = options.install_options or [] + if options.use_user_site: + install_options.append('--user') + if options.target_dir: + options.ignore_installed = True + temp_target_dir = tempfile.mkdtemp() + options.target_dir = os.path.abspath(options.target_dir) + if os.path.exists(options.target_dir) and not os.path.isdir(options.target_dir): + raise CommandError("Target path exists but is not a directory, will not continue.") + install_options.append('--home=' + temp_target_dir) + global_options = options.global_options or [] + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.notify('Ignoring indexes: %s' % ','.join(index_urls)) + index_urls = [] + + finder = self._build_package_finder(options, index_urls) + + requirement_set = RequirementSet( + build_dir=options.build_dir, + src_dir=options.src_dir, + download_dir=options.download_dir, + download_cache=options.download_cache, + upgrade=options.upgrade, + ignore_installed=options.ignore_installed, + ignore_dependencies=options.ignore_dependencies, + force_reinstall=options.force_reinstall) + for name in args: + requirement_set.add_requirement( + InstallRequirement.from_line(name, None)) + for name in options.editables: + requirement_set.add_requirement( + InstallRequirement.from_editable(name, default_vcs=options.default_vcs)) + for filename in options.requirements: + for req in parse_requirements(filename, finder=finder, options=options): + requirement_set.add_requirement(req) + if not requirement_set.has_requirements: + opts = {'name': self.name} + if options.find_links: + msg = ('You must give at least one requirement to %(name)s ' + '(maybe you meant "pip %(name)s %(links)s"?)' % + dict(opts, links=' '.join(options.find_links))) + else: + msg = ('You must give at least one requirement ' + 'to %(name)s (see "pip help %(name)s")' % opts) + logger.warn(msg) + return + + if (options.use_user_site and + sys.version_info < (2, 6)): + raise InstallationError('--user is only supported in Python version 2.6 and newer') + + import setuptools + if (options.use_user_site and + requirement_set.has_editables and + not getattr(setuptools, '_distribute', False)): + + raise InstallationError('--user --editable not supported with setuptools, use distribute') + + if not options.no_download: + requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle) + else: + requirement_set.locate_files() + + if not options.no_install and not self.bundle: + requirement_set.install(install_options, global_options) + installed = ' '.join([req.name for req in + requirement_set.successfully_installed]) + if installed: + logger.notify('Successfully installed %s' % installed) + elif not self.bundle: + downloaded = ' '.join([req.name for req in + requirement_set.successfully_downloaded]) + if downloaded: + logger.notify('Successfully downloaded %s' % downloaded) + elif self.bundle: + requirement_set.create_bundle(self.bundle_filename) + logger.notify('Created bundle in %s' % self.bundle_filename) + # Clean up + if not options.no_install or options.download_dir: + requirement_set.cleanup_files(bundle=self.bundle) + if options.target_dir: + if not os.path.exists(options.target_dir): + os.makedirs(options.target_dir) + lib_dir = os.path.join(temp_target_dir, "lib/python/") + for item in os.listdir(lib_dir): + shutil.move( + os.path.join(lib_dir, item), + os.path.join(options.target_dir, item) + ) + shutil.rmtree(temp_target_dir) + return requirement_set + + +InstallCommand() diff --git a/vendor/pip-1.2.1/pip/commands/search.py b/vendor/pip-1.2.1/pip/commands/search.py new file mode 100644 index 0000000..9f287e5 --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/search.py @@ -0,0 +1,127 @@ +import sys +import textwrap +import pkg_resources +import pip.download +from pip.basecommand import Command, SUCCESS +from pip.util import get_terminal_size +from pip.log import logger +from pip.backwardcompat import xmlrpclib, reduce, cmp +from pip.exceptions import CommandError +from pip.status_codes import NO_MATCHES_FOUND +from distutils.version import StrictVersion, LooseVersion + + +class SearchCommand(Command): + name = 'search' + usage = '%prog QUERY' + summary = 'Search PyPI' + + def __init__(self): + super(SearchCommand, self).__init__() + self.parser.add_option( + '--index', + dest='index', + metavar='URL', + default='http://pypi.python.org/pypi', + help='Base URL of Python Package Index (default %default)') + + def run(self, options, args): + if not args: + raise CommandError('Missing required argument (search query).') + query = args + index_url = options.index + + pypi_hits = self.search(query, index_url) + hits = transform_hits(pypi_hits) + + terminal_width = None + if sys.stdout.isatty(): + terminal_width = get_terminal_size()[0] + + print_results(hits, terminal_width=terminal_width) + if pypi_hits: + return SUCCESS + return NO_MATCHES_FOUND + + def search(self, query, index_url): + pypi = xmlrpclib.ServerProxy(index_url, pip.download.xmlrpclib_transport) + hits = pypi.search({'name': query, 'summary': query}, 'or') + return hits + + +def transform_hits(hits): + """ + The list from pypi is really a list of versions. We want a list of + packages with the list of versions stored inline. This converts the + list from pypi into one we can use. + """ + packages = {} + for hit in hits: + name = hit['name'] + summary = hit['summary'] + version = hit['version'] + score = hit['_pypi_ordering'] + + if name not in packages.keys(): + packages[name] = {'name': name, 'summary': summary, 'versions': [version], 'score': score} + else: + packages[name]['versions'].append(version) + + # if this is the highest version, replace summary and score + if version == highest_version(packages[name]['versions']): + packages[name]['summary'] = summary + packages[name]['score'] = score + + # each record has a unique name now, so we will convert the dict into a list sorted by score + package_list = sorted(packages.values(), key=lambda x: x['score'], reverse=True) + return package_list + + +def print_results(hits, name_column_width=25, terminal_width=None): + installed_packages = [p.project_name for p in pkg_resources.working_set] + for hit in hits: + name = hit['name'] + summary = hit['summary'] or '' + if terminal_width is not None: + # wrap and indent summary to fit terminal + summary = textwrap.wrap(summary, terminal_width - name_column_width - 5) + summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) + line = '%s - %s' % (name.ljust(name_column_width), summary) + try: + logger.notify(line) + if name in installed_packages: + dist = pkg_resources.get_distribution(name) + logger.indent += 2 + try: + latest = highest_version(hit['versions']) + if dist.version == latest: + logger.notify('INSTALLED: %s (latest)' % dist.version) + else: + logger.notify('INSTALLED: %s' % dist.version) + logger.notify('LATEST: %s' % latest) + finally: + logger.indent -= 2 + except UnicodeEncodeError: + pass + + +def compare_versions(version1, version2): + try: + return cmp(StrictVersion(version1), StrictVersion(version2)) + # in case of abnormal version number, fall back to LooseVersion + except ValueError: + pass + try: + return cmp(LooseVersion(version1), LooseVersion(version2)) + except TypeError: + # certain LooseVersion comparions raise due to unorderable types, + # fallback to string comparison + return cmp([str(v) for v in LooseVersion(version1).version], + [str(v) for v in LooseVersion(version2).version]) + + +def highest_version(versions): + return reduce((lambda v1, v2: compare_versions(v1, v2) == 1 and v1 or v2), versions) + + +SearchCommand() diff --git a/vendor/pip-1.2.1/pip/commands/uninstall.py b/vendor/pip-1.2.1/pip/commands/uninstall.py new file mode 100644 index 0000000..9f2b891 --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/uninstall.py @@ -0,0 +1,43 @@ +from pip.req import InstallRequirement, RequirementSet, parse_requirements +from pip.basecommand import Command +from pip.exceptions import InstallationError + + +class UninstallCommand(Command): + name = 'uninstall' + usage = '%prog [OPTIONS] PACKAGE_NAMES ...' + summary = 'Uninstall packages' + + def __init__(self): + super(UninstallCommand, self).__init__() + self.parser.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='FILENAME', + help='Uninstall all the packages listed in the given requirements file. ' + 'This option can be used multiple times.') + self.parser.add_option( + '-y', '--yes', + dest='yes', + action='store_true', + help="Don't ask for confirmation of uninstall deletions.") + + def run(self, options, args): + requirement_set = RequirementSet( + build_dir=None, + src_dir=None, + download_dir=None) + for name in args: + requirement_set.add_requirement( + InstallRequirement.from_line(name)) + for filename in options.requirements: + for req in parse_requirements(filename, options=options): + requirement_set.add_requirement(req) + if not requirement_set.has_requirements: + raise InstallationError('You must give at least one requirement ' + 'to %(name)s (see "pip help %(name)s")' % dict(name=self.name)) + requirement_set.uninstall(auto_confirm=options.yes) + +UninstallCommand() diff --git a/vendor/pip-1.2.1/pip/commands/unzip.py b/vendor/pip-1.2.1/pip/commands/unzip.py new file mode 100644 index 0000000..f83e182 --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/unzip.py @@ -0,0 +1,9 @@ +from pip.commands.zip import ZipCommand + + +class UnzipCommand(ZipCommand): + name = 'unzip' + summary = 'Unzip individual packages' + + +UnzipCommand() diff --git a/vendor/pip-1.2.1/pip/commands/zip.py b/vendor/pip-1.2.1/pip/commands/zip.py new file mode 100644 index 0000000..ebe1d79 --- /dev/null +++ b/vendor/pip-1.2.1/pip/commands/zip.py @@ -0,0 +1,346 @@ +import sys +import re +import fnmatch +import os +import shutil +import zipfile +from pip.util import display_path, backup_dir, rmtree +from pip.log import logger +from pip.exceptions import InstallationError +from pip.basecommand import Command + + +class ZipCommand(Command): + name = 'zip' + usage = '%prog [OPTIONS] PACKAGE_NAMES...' + summary = 'Zip individual packages' + + def __init__(self): + super(ZipCommand, self).__init__() + if self.name == 'zip': + self.parser.add_option( + '--unzip', + action='store_true', + dest='unzip', + help='Unzip (rather than zip) a package') + else: + self.parser.add_option( + '--zip', + action='store_false', + dest='unzip', + default=True, + help='Zip (rather than unzip) a package') + self.parser.add_option( + '--no-pyc', + action='store_true', + dest='no_pyc', + help='Do not include .pyc files in zip files (useful on Google App Engine)') + self.parser.add_option( + '-l', '--list', + action='store_true', + dest='list', + help='List the packages available, and their zip status') + self.parser.add_option( + '--sort-files', + action='store_true', + dest='sort_files', + help='With --list, sort packages according to how many files they contain') + self.parser.add_option( + '--path', + action='append', + dest='paths', + help='Restrict operations to the given paths (may include wildcards)') + self.parser.add_option( + '-n', '--simulate', + action='store_true', + help='Do not actually perform the zip/unzip operation') + + def paths(self): + """All the entries of sys.path, possibly restricted by --path""" + if not self.select_paths: + return sys.path + result = [] + match_any = set() + for path in sys.path: + path = os.path.normcase(os.path.abspath(path)) + for match in self.select_paths: + match = os.path.normcase(os.path.abspath(match)) + if '*' in match: + if re.search(fnmatch.translate(match+'*'), path): + result.append(path) + match_any.add(match) + break + else: + if path.startswith(match): + result.append(path) + match_any.add(match) + break + else: + logger.debug("Skipping path %s because it doesn't match %s" + % (path, ', '.join(self.select_paths))) + for match in self.select_paths: + if match not in match_any and '*' not in match: + result.append(match) + logger.debug("Adding path %s because it doesn't match anything already on sys.path" + % match) + return result + + def run(self, options, args): + self.select_paths = options.paths + self.simulate = options.simulate + if options.list: + return self.list(options, args) + if not args: + raise InstallationError( + 'You must give at least one package to zip or unzip') + packages = [] + for arg in args: + module_name, filename = self.find_package(arg) + if options.unzip and os.path.isdir(filename): + raise InstallationError( + 'The module %s (in %s) is not a zip file; cannot be unzipped' + % (module_name, filename)) + elif not options.unzip and not os.path.isdir(filename): + raise InstallationError( + 'The module %s (in %s) is not a directory; cannot be zipped' + % (module_name, filename)) + packages.append((module_name, filename)) + last_status = None + for module_name, filename in packages: + if options.unzip: + last_status = self.unzip_package(module_name, filename) + else: + last_status = self.zip_package(module_name, filename, options.no_pyc) + return last_status + + def unzip_package(self, module_name, filename): + zip_filename = os.path.dirname(filename) + if not os.path.isfile(zip_filename) and zipfile.is_zipfile(zip_filename): + raise InstallationError( + 'Module %s (in %s) isn\'t located in a zip file in %s' + % (module_name, filename, zip_filename)) + package_path = os.path.dirname(zip_filename) + if not package_path in self.paths(): + logger.warn( + 'Unpacking %s into %s, but %s is not on sys.path' + % (display_path(zip_filename), display_path(package_path), + display_path(package_path))) + logger.notify('Unzipping %s (in %s)' % (module_name, display_path(zip_filename))) + if self.simulate: + logger.notify('Skipping remaining operations because of --simulate') + return + logger.indent += 2 + try: + ## FIXME: this should be undoable: + zip = zipfile.ZipFile(zip_filename) + to_save = [] + for name in zip.namelist(): + if name.startswith(module_name + os.path.sep): + content = zip.read(name) + dest = os.path.join(package_path, name) + if not os.path.exists(os.path.dirname(dest)): + os.makedirs(os.path.dirname(dest)) + if not content and dest.endswith(os.path.sep): + if not os.path.exists(dest): + os.makedirs(dest) + else: + f = open(dest, 'wb') + f.write(content) + f.close() + else: + to_save.append((name, zip.read(name))) + zip.close() + if not to_save: + logger.info('Removing now-empty zip file %s' % display_path(zip_filename)) + os.unlink(zip_filename) + self.remove_filename_from_pth(zip_filename) + else: + logger.info('Removing entries in %s/ from zip file %s' % (module_name, display_path(zip_filename))) + zip = zipfile.ZipFile(zip_filename, 'w') + for name, content in to_save: + zip.writestr(name, content) + zip.close() + finally: + logger.indent -= 2 + + def zip_package(self, module_name, filename, no_pyc): + orig_filename = filename + logger.notify('Zip %s (in %s)' % (module_name, display_path(filename))) + logger.indent += 2 + if filename.endswith('.egg'): + dest_filename = filename + else: + dest_filename = filename + '.zip' + try: + ## FIXME: I think this needs to be undoable: + if filename == dest_filename: + filename = backup_dir(orig_filename) + logger.notify('Moving %s aside to %s' % (orig_filename, filename)) + if not self.simulate: + shutil.move(orig_filename, filename) + try: + logger.info('Creating zip file in %s' % display_path(dest_filename)) + if not self.simulate: + zip = zipfile.ZipFile(dest_filename, 'w') + zip.writestr(module_name + '/', '') + for dirpath, dirnames, filenames in os.walk(filename): + if no_pyc: + filenames = [f for f in filenames + if not f.lower().endswith('.pyc')] + for fns, is_dir in [(dirnames, True), (filenames, False)]: + for fn in fns: + full = os.path.join(dirpath, fn) + dest = os.path.join(module_name, dirpath[len(filename):].lstrip(os.path.sep), fn) + if is_dir: + zip.writestr(dest+'/', '') + else: + zip.write(full, dest) + zip.close() + logger.info('Removing old directory %s' % display_path(filename)) + if not self.simulate: + rmtree(filename) + except: + ## FIXME: need to do an undo here + raise + ## FIXME: should also be undone: + self.add_filename_to_pth(dest_filename) + finally: + logger.indent -= 2 + + def remove_filename_from_pth(self, filename): + for pth in self.pth_files(): + f = open(pth, 'r') + lines = f.readlines() + f.close() + new_lines = [ + l for l in lines if l.strip() != filename] + if lines != new_lines: + logger.info('Removing reference to %s from .pth file %s' + % (display_path(filename), display_path(pth))) + if not [line for line in new_lines if line]: + logger.info('%s file would be empty: deleting' % display_path(pth)) + if not self.simulate: + os.unlink(pth) + else: + if not self.simulate: + f = open(pth, 'wb') + f.writelines(new_lines) + f.close() + return + logger.warn('Cannot find a reference to %s in any .pth file' % display_path(filename)) + + def add_filename_to_pth(self, filename): + path = os.path.dirname(filename) + dest = os.path.join(path, filename + '.pth') + if path not in self.paths(): + logger.warn('Adding .pth file %s, but it is not on sys.path' % display_path(dest)) + if not self.simulate: + if os.path.exists(dest): + f = open(dest) + lines = f.readlines() + f.close() + if lines and not lines[-1].endswith('\n'): + lines[-1] += '\n' + lines.append(filename+'\n') + else: + lines = [filename + '\n'] + f = open(dest, 'wb') + f.writelines(lines) + f.close() + + def pth_files(self): + for path in self.paths(): + if not os.path.exists(path) or not os.path.isdir(path): + continue + for filename in os.listdir(path): + if filename.endswith('.pth'): + yield os.path.join(path, filename) + + def find_package(self, package): + for path in self.paths(): + full = os.path.join(path, package) + if os.path.exists(full): + return package, full + if not os.path.isdir(path) and zipfile.is_zipfile(path): + zip = zipfile.ZipFile(path, 'r') + try: + zip.read(os.path.join(package, '__init__.py')) + except KeyError: + pass + else: + zip.close() + return package, full + zip.close() + ## FIXME: need special error for package.py case: + raise InstallationError( + 'No package with the name %s found' % package) + + def list(self, options, args): + if args: + raise InstallationError( + 'You cannot give an argument with --list') + for path in sorted(self.paths()): + if not os.path.exists(path): + continue + basename = os.path.basename(path.rstrip(os.path.sep)) + if os.path.isfile(path) and zipfile.is_zipfile(path): + if os.path.dirname(path) not in self.paths(): + logger.notify('Zipped egg: %s' % display_path(path)) + continue + if (basename != 'site-packages' and basename != 'dist-packages' + and not path.replace('\\', '/').endswith('lib/python')): + continue + logger.notify('In %s:' % display_path(path)) + logger.indent += 2 + zipped = [] + unzipped = [] + try: + for filename in sorted(os.listdir(path)): + ext = os.path.splitext(filename)[1].lower() + if ext in ('.pth', '.egg-info', '.egg-link'): + continue + if ext == '.py': + logger.info('Not displaying %s: not a package' % display_path(filename)) + continue + full = os.path.join(path, filename) + if os.path.isdir(full): + unzipped.append((filename, self.count_package(full))) + elif zipfile.is_zipfile(full): + zipped.append(filename) + else: + logger.info('Unknown file: %s' % display_path(filename)) + if zipped: + logger.notify('Zipped packages:') + logger.indent += 2 + try: + for filename in zipped: + logger.notify(filename) + finally: + logger.indent -= 2 + else: + logger.notify('No zipped packages.') + if unzipped: + if options.sort_files: + unzipped.sort(key=lambda x: -x[1]) + logger.notify('Unzipped packages:') + logger.indent += 2 + try: + for filename, count in unzipped: + logger.notify('%s (%i files)' % (filename, count)) + finally: + logger.indent -= 2 + else: + logger.notify('No unzipped packages.') + finally: + logger.indent -= 2 + + def count_package(self, path): + total = 0 + for dirpath, dirnames, filenames in os.walk(path): + filenames = [f for f in filenames + if not f.lower().endswith('.pyc')] + total += len(filenames) + return total + + +ZipCommand() diff --git a/vendor/pip-1.2.1/pip/download.py b/vendor/pip-1.2.1/pip/download.py new file mode 100644 index 0000000..a31e5d6 --- /dev/null +++ b/vendor/pip-1.2.1/pip/download.py @@ -0,0 +1,481 @@ +import cgi +import getpass +import mimetypes +import os +import re +import shutil +import sys +import tempfile +from pip.backwardcompat import (md5, copytree, xmlrpclib, urllib, urllib2, + urlparse, string_types, HTTPError) +from pip.exceptions import InstallationError +from pip.util import (splitext, rmtree, format_size, display_path, + backup_dir, ask, ask_path_exists, unpack_file, + create_download_cache_folder, cache_download) +from pip.vcs import vcs +from pip.log import logger + + +__all__ = ['xmlrpclib_transport', 'get_file_content', 'urlopen', + 'is_url', 'url_to_path', 'path_to_url', 'path_to_url2', + 'geturl', 'is_archive_file', 'unpack_vcs_link', + 'unpack_file_url', 'is_vcs_url', 'is_file_url', 'unpack_http_url'] + + +xmlrpclib_transport = xmlrpclib.Transport() + + +def get_file_content(url, comes_from=None): + """Gets the content of a file; it may be a filename, file: URL, or + http: URL. Returns (location, content)""" + match = _scheme_re.search(url) + if match: + scheme = match.group(1).lower() + if (scheme == 'file' and comes_from + and comes_from.startswith('http')): + raise InstallationError( + 'Requirements file %s references URL %s, which is local' + % (comes_from, url)) + if scheme == 'file': + path = url.split(':', 1)[1] + path = path.replace('\\', '/') + match = _url_slash_drive_re.match(path) + if match: + path = match.group(1) + ':' + path.split('|', 1)[1] + path = urllib.unquote(path) + if path.startswith('/'): + path = '/' + path.lstrip('/') + url = path + else: + ## FIXME: catch some errors + resp = urlopen(url) + return geturl(resp), resp.read() + try: + f = open(url) + content = f.read() + except IOError: + e = sys.exc_info()[1] + raise InstallationError('Could not open requirements file: %s' % str(e)) + else: + f.close() + return url, content + + +_scheme_re = re.compile(r'^(http|https|file):', re.I) +_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I) + + +class URLOpener(object): + """ + pip's own URL helper that adds HTTP auth and proxy support + """ + def __init__(self): + self.passman = urllib2.HTTPPasswordMgrWithDefaultRealm() + + def __call__(self, url): + """ + If the given url contains auth info or if a normal request gets a 401 + response, an attempt is made to fetch the resource using basic HTTP + auth. + + """ + url, username, password = self.extract_credentials(url) + if username is None: + try: + response = urllib2.urlopen(self.get_request(url)) + except urllib2.HTTPError: + e = sys.exc_info()[1] + if e.code != 401: + raise + response = self.get_response(url) + else: + response = self.get_response(url, username, password) + return response + + def get_request(self, url): + """ + Wraps the URL to retrieve to protects against "creative" + interpretation of the RFC: http://bugs.python.org/issue8732 + """ + if isinstance(url, string_types): + url = urllib2.Request(url, headers={'Accept-encoding': 'identity'}) + return url + + def get_response(self, url, username=None, password=None): + """ + does the dirty work of actually getting the rsponse object using urllib2 + and its HTTP auth builtins. + """ + scheme, netloc, path, query, frag = urlparse.urlsplit(url) + req = self.get_request(url) + + stored_username, stored_password = self.passman.find_user_password(None, netloc) + # see if we have a password stored + if stored_username is None: + if username is None and self.prompting: + username = urllib.quote(raw_input('User for %s: ' % netloc)) + password = urllib.quote(getpass.getpass('Password: ')) + if username and password: + self.passman.add_password(None, netloc, username, password) + stored_username, stored_password = self.passman.find_user_password(None, netloc) + authhandler = urllib2.HTTPBasicAuthHandler(self.passman) + opener = urllib2.build_opener(authhandler) + # FIXME: should catch a 401 and offer to let the user reenter credentials + return opener.open(req) + + def setup(self, proxystr='', prompting=True): + """ + Sets the proxy handler given the option passed on the command + line. If an empty string is passed it looks at the HTTP_PROXY + environment variable. + """ + self.prompting = prompting + proxy = self.get_proxy(proxystr) + if proxy: + proxy_support = urllib2.ProxyHandler({"http": proxy, "ftp": proxy, "https": proxy}) + opener = urllib2.build_opener(proxy_support, urllib2.CacheFTPHandler) + urllib2.install_opener(opener) + + def parse_credentials(self, netloc): + if "@" in netloc: + userinfo = netloc.rsplit("@", 1)[0] + if ":" in userinfo: + return userinfo.split(":", 1) + return userinfo, None + return None, None + + def extract_credentials(self, url): + """ + Extracts user/password from a url. + + Returns a tuple: + (url-without-auth, username, password) + """ + if isinstance(url, urllib2.Request): + result = urlparse.urlsplit(url.get_full_url()) + else: + result = urlparse.urlsplit(url) + scheme, netloc, path, query, frag = result + + username, password = self.parse_credentials(netloc) + if username is None: + return url, None, None + elif password is None and self.prompting: + # remove the auth credentials from the url part + netloc = netloc.replace('%s@' % username, '', 1) + # prompt for the password + prompt = 'Password for %s@%s: ' % (username, netloc) + password = urllib.quote(getpass.getpass(prompt)) + else: + # remove the auth credentials from the url part + netloc = netloc.replace('%s:%s@' % (username, password), '', 1) + + target_url = urlparse.urlunsplit((scheme, netloc, path, query, frag)) + return target_url, username, password + + def get_proxy(self, proxystr=''): + """ + Get the proxy given the option passed on the command line. + If an empty string is passed it looks at the HTTP_PROXY + environment variable. + """ + if not proxystr: + proxystr = os.environ.get('HTTP_PROXY', '') + if proxystr: + if '@' in proxystr: + user_password, server_port = proxystr.split('@', 1) + if ':' in user_password: + user, password = user_password.split(':', 1) + else: + user = user_password + prompt = 'Password for %s@%s: ' % (user, server_port) + password = urllib.quote(getpass.getpass(prompt)) + return '%s:%s@%s' % (user, password, server_port) + else: + return proxystr + else: + return None + +urlopen = URLOpener() + + +def is_url(name): + """Returns true if the name looks like a URL""" + if ':' not in name: + return False + scheme = name.split(':', 1)[0].lower() + return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes + + +def url_to_path(url): + """ + Convert a file: URL to a path. + """ + assert url.startswith('file:'), ( + "You can only turn file: urls into filenames (not %r)" % url) + path = url[len('file:'):].lstrip('/') + path = urllib.unquote(path) + if _url_drive_re.match(path): + path = path[0] + ':' + path[2:] + else: + path = '/' + path + return path + + +_drive_re = re.compile('^([a-z]):', re.I) +_url_drive_re = re.compile('^([a-z])[:|]', re.I) + + +def path_to_url(path): + """ + Convert a path to a file: URL. The path will be made absolute. + """ + path = os.path.normcase(os.path.abspath(path)) + if _drive_re.match(path): + path = path[0] + '|' + path[2:] + url = urllib.quote(path) + url = url.replace(os.path.sep, '/') + url = url.lstrip('/') + return 'file:///' + url + + +def path_to_url2(path): + """ + Convert a path to a file: URL. The path will be made absolute and have + quoted path parts. + """ + path = os.path.normpath(os.path.abspath(path)) + drive, path = os.path.splitdrive(path) + filepath = path.split(os.path.sep) + url = '/'.join([urllib.quote(part) for part in filepath]) + if not drive: + url = url.lstrip('/') + return 'file:///' + drive + url + + +def geturl(urllib2_resp): + """ + Use instead of urllib.addinfourl.geturl(), which appears to have + some issues with dropping the double slash for certain schemes + (e.g. file://). This implementation is probably over-eager, as it + always restores '://' if it is missing, and it appears some url + schemata aren't always followed by '//' after the colon, but as + far as I know pip doesn't need any of those. + The URI RFC can be found at: http://tools.ietf.org/html/rfc1630 + + This function assumes that + scheme:/foo/bar + is the same as + scheme:///foo/bar + """ + url = urllib2_resp.geturl() + scheme, rest = url.split(':', 1) + if rest.startswith('//'): + return url + else: + # FIXME: write a good test to cover it + return '%s://%s' % (scheme, rest) + + +def is_archive_file(name): + """Return True if `name` is a considered as an archive file.""" + archives = ('.zip', '.tar.gz', '.tar.bz2', '.tgz', '.tar', '.pybundle') + ext = splitext(name)[1].lower() + if ext in archives: + return True + return False + + +def unpack_vcs_link(link, location, only_download=False): + vcs_backend = _get_used_vcs_backend(link) + if only_download: + vcs_backend.export(location) + else: + vcs_backend.unpack(location) + + +def unpack_file_url(link, location): + source = url_to_path(link.url) + content_type = mimetypes.guess_type(source)[0] + if os.path.isdir(source): + # delete the location since shutil will create it again :( + if os.path.isdir(location): + rmtree(location) + copytree(source, location) + else: + unpack_file(source, location, content_type, link) + + +def _get_used_vcs_backend(link): + for backend in vcs.backends: + if link.scheme in backend.schemes: + vcs_backend = backend(link.url) + return vcs_backend + + +def is_vcs_url(link): + return bool(_get_used_vcs_backend(link)) + + +def is_file_url(link): + return link.url.lower().startswith('file:') + + +def _check_md5(download_hash, link): + download_hash = download_hash.hexdigest() + if download_hash != link.md5_hash: + logger.fatal("MD5 hash of the package %s (%s) doesn't match the expected hash %s!" + % (link, download_hash, link.md5_hash)) + raise InstallationError('Bad MD5 hash for package %s' % link) + + +def _get_md5_from_file(target_file, link): + download_hash = md5() + fp = open(target_file, 'rb') + while True: + chunk = fp.read(4096) + if not chunk: + break + download_hash.update(chunk) + fp.close() + return download_hash + + +def _download_url(resp, link, temp_location): + fp = open(temp_location, 'wb') + download_hash = None + if link.md5_hash: + download_hash = md5() + try: + total_length = int(resp.info()['content-length']) + except (ValueError, KeyError, TypeError): + total_length = 0 + downloaded = 0 + show_progress = total_length > 40*1000 or not total_length + show_url = link.show_url + try: + if show_progress: + ## FIXME: the URL can get really long in this message: + if total_length: + logger.start_progress('Downloading %s (%s): ' % (show_url, format_size(total_length))) + else: + logger.start_progress('Downloading %s (unknown size): ' % show_url) + else: + logger.notify('Downloading %s' % show_url) + logger.debug('Downloading from URL %s' % link) + + while True: + chunk = resp.read(4096) + if not chunk: + break + downloaded += len(chunk) + if show_progress: + if not total_length: + logger.show_progress('%s' % format_size(downloaded)) + else: + logger.show_progress('%3i%% %s' % (100*downloaded/total_length, format_size(downloaded))) + if link.md5_hash: + download_hash.update(chunk) + fp.write(chunk) + fp.close() + finally: + if show_progress: + logger.end_progress('%s downloaded' % format_size(downloaded)) + return download_hash + + +def _copy_file(filename, location, content_type, link): + copy = True + download_location = os.path.join(location, link.filename) + if os.path.exists(download_location): + response = ask_path_exists( + 'The file %s exists. (i)gnore, (w)ipe, (b)ackup ' % + display_path(download_location), ('i', 'w', 'b')) + if response == 'i': + copy = False + elif response == 'w': + logger.warn('Deleting %s' % display_path(download_location)) + os.remove(download_location) + elif response == 'b': + dest_file = backup_dir(download_location) + logger.warn('Backing up %s to %s' + % (display_path(download_location), display_path(dest_file))) + shutil.move(download_location, dest_file) + if copy: + shutil.copy(filename, download_location) + logger.indent -= 2 + logger.notify('Saved %s' % display_path(download_location)) + + +def unpack_http_url(link, location, download_cache, download_dir=None): + temp_dir = tempfile.mkdtemp('-unpack', 'pip-') + target_url = link.url.split('#', 1)[0] + target_file = None + download_hash = None + if download_cache: + target_file = os.path.join(download_cache, + urllib.quote(target_url, '')) + if not os.path.isdir(download_cache): + create_download_cache_folder(download_cache) + if (target_file + and os.path.exists(target_file) + and os.path.exists(target_file + '.content-type')): + fp = open(target_file+'.content-type') + content_type = fp.read().strip() + fp.close() + if link.md5_hash: + download_hash = _get_md5_from_file(target_file, link) + temp_location = target_file + logger.notify('Using download cache from %s' % target_file) + else: + resp = _get_response_from_url(target_url, link) + content_type = resp.info()['content-type'] + filename = link.filename # fallback + # Have a look at the Content-Disposition header for a better guess + content_disposition = resp.info().get('content-disposition') + if content_disposition: + type, params = cgi.parse_header(content_disposition) + # We use ``or`` here because we don't want to use an "empty" value + # from the filename param. + filename = params.get('filename') or filename + ext = splitext(filename)[1] + if not ext: + ext = mimetypes.guess_extension(content_type) + if ext: + filename += ext + if not ext and link.url != geturl(resp): + ext = os.path.splitext(geturl(resp))[1] + if ext: + filename += ext + temp_location = os.path.join(temp_dir, filename) + download_hash = _download_url(resp, link, temp_location) + if link.md5_hash: + _check_md5(download_hash, link) + if download_dir: + _copy_file(temp_location, download_dir, content_type, link) + unpack_file(temp_location, location, content_type, link) + if target_file and target_file != temp_location: + cache_download(target_file, temp_location, content_type) + if target_file is None: + os.unlink(temp_location) + os.rmdir(temp_dir) + + +def _get_response_from_url(target_url, link): + try: + resp = urlopen(target_url) + except urllib2.HTTPError: + e = sys.exc_info()[1] + logger.fatal("HTTP error %s while getting %s" % (e.code, link)) + raise + except IOError: + e = sys.exc_info()[1] + # Typically an FTP error + logger.fatal("Error %s while getting %s" % (e, link)) + raise + return resp + + +class Urllib2HeadRequest(urllib2.Request): + def get_method(self): + return "HEAD" diff --git a/vendor/pip-1.2.1/pip/exceptions.py b/vendor/pip-1.2.1/pip/exceptions.py new file mode 100644 index 0000000..22f554a --- /dev/null +++ b/vendor/pip-1.2.1/pip/exceptions.py @@ -0,0 +1,27 @@ +"""Exceptions used throughout package""" + + +class InstallationError(Exception): + """General exception during installation""" + + +class UninstallationError(Exception): + """General exception during uninstallation""" + + +class DistributionNotFound(InstallationError): + """Raised when a distribution cannot be found to satisfy a requirement""" + + +class BestVersionAlreadyInstalled(Exception): + """Raised when the most up-to-date version of a package is already + installed. + """ + + +class BadCommand(Exception): + """Raised when virtualenv or a command is not found""" + + +class CommandError(Exception): + """Raised when there is an error in command-line arguments""" diff --git a/vendor/pip-1.2.1/pip/index.py b/vendor/pip-1.2.1/pip/index.py new file mode 100644 index 0000000..8e53e44 --- /dev/null +++ b/vendor/pip-1.2.1/pip/index.py @@ -0,0 +1,708 @@ +"""Routines related to PyPI, indexes""" + +import sys +import os +import re +import gzip +import mimetypes +try: + import threading +except ImportError: + import dummy_threading as threading +import posixpath +import pkg_resources +import random +import socket +import string +import zlib +from pip.log import logger +from pip.util import Inf +from pip.util import normalize_name, splitext +from pip.exceptions import DistributionNotFound, BestVersionAlreadyInstalled +from pip.backwardcompat import (WindowsError, BytesIO, + Queue, httplib, urlparse, + URLError, HTTPError, u, + product, url2pathname) +from pip.backwardcompat import Empty as QueueEmpty +from pip.download import urlopen, path_to_url2, url_to_path, geturl, Urllib2HeadRequest + +__all__ = ['PackageFinder'] + + +DEFAULT_MIRROR_URL = "last.pypi.python.org" + + +class PackageFinder(object): + """This finds packages. + + This is meant to match easy_install's technique for looking for + packages, by reading pages and looking for appropriate links + """ + + def __init__(self, find_links, index_urls, + use_mirrors=False, mirrors=None, main_mirror_url=None): + self.find_links = find_links + self.index_urls = index_urls + self.dependency_links = [] + self.cache = PageCache() + # These are boring links that have already been logged somehow: + self.logged_links = set() + if use_mirrors: + self.mirror_urls = self._get_mirror_urls(mirrors, main_mirror_url) + logger.info('Using PyPI mirrors: %s' % ', '.join(self.mirror_urls)) + else: + self.mirror_urls = [] + + def add_dependency_links(self, links): + ## FIXME: this shouldn't be global list this, it should only + ## apply to requirements of the package that specifies the + ## dependency_links value + ## FIXME: also, we should track comes_from (i.e., use Link) + self.dependency_links.extend(links) + + @staticmethod + def _sort_locations(locations): + """ + Sort locations into "files" (archives) and "urls", and return + a pair of lists (files,urls) + """ + files = [] + urls = [] + + # puts the url for the given file path into the appropriate + # list + def sort_path(path): + url = path_to_url2(path) + if mimetypes.guess_type(url, strict=False)[0] == 'text/html': + urls.append(url) + else: + files.append(url) + + for url in locations: + if url.startswith('file:'): + path = url_to_path(url) + if os.path.isdir(path): + path = os.path.realpath(path) + for item in os.listdir(path): + sort_path(os.path.join(path, item)) + elif os.path.isfile(path): + sort_path(path) + else: + urls.append(url) + return files, urls + + def find_requirement(self, req, upgrade): + url_name = req.url_name + # Only check main index if index URL is given: + main_index_url = None + if self.index_urls: + # Check that we have the url_name correctly spelled: + main_index_url = Link(posixpath.join(self.index_urls[0], url_name)) + # This will also cache the page, so it's okay that we get it again later: + page = self._get_page(main_index_url, req) + if page is None: + url_name = self._find_url_name(Link(self.index_urls[0]), url_name, req) or req.url_name + + # Combine index URLs with mirror URLs here to allow + # adding more index URLs from requirements files + all_index_urls = self.index_urls + self.mirror_urls + + def mkurl_pypi_url(url): + loc = posixpath.join(url, url_name) + # For maximum compatibility with easy_install, ensure the path + # ends in a trailing slash. Although this isn't in the spec + # (and PyPI can handle it without the slash) some other index + # implementations might break if they relied on easy_install's behavior. + if not loc.endswith('/'): + loc = loc + '/' + return loc + if url_name is not None: + locations = [ + mkurl_pypi_url(url) + for url in all_index_urls] + self.find_links + else: + locations = list(self.find_links) + locations.extend(self.dependency_links) + for version in req.absolute_versions: + if url_name is not None and main_index_url is not None: + locations = [ + posixpath.join(main_index_url.url, version)] + locations + + file_locations, url_locations = self._sort_locations(locations) + + locations = [Link(url) for url in url_locations] + logger.debug('URLs to search for versions for %s:' % req) + for location in locations: + logger.debug('* %s' % location) + found_versions = [] + found_versions.extend( + self._package_versions( + [Link(url, '-f') for url in self.find_links], req.name.lower())) + page_versions = [] + for page in self._get_pages(locations, req): + logger.debug('Analyzing links from page %s' % page.url) + logger.indent += 2 + try: + page_versions.extend(self._package_versions(page.links, req.name.lower())) + finally: + logger.indent -= 2 + dependency_versions = list(self._package_versions( + [Link(url) for url in self.dependency_links], req.name.lower())) + if dependency_versions: + logger.info('dependency_links found: %s' % ', '.join([link.url for parsed, link, version in dependency_versions])) + file_versions = list(self._package_versions( + [Link(url) for url in file_locations], req.name.lower())) + if not found_versions and not page_versions and not dependency_versions and not file_versions: + logger.fatal('Could not find any downloads that satisfy the requirement %s' % req) + raise DistributionNotFound('No distributions at all found for %s' % req) + if req.satisfied_by is not None: + found_versions.append((req.satisfied_by.parsed_version, Inf, req.satisfied_by.version)) + if file_versions: + file_versions.sort(reverse=True) + logger.info('Local files found: %s' % ', '.join([url_to_path(link.url) for parsed, link, version in file_versions])) + found_versions = file_versions + found_versions + all_versions = found_versions + page_versions + dependency_versions + applicable_versions = [] + for (parsed_version, link, version) in all_versions: + if version not in req.req: + logger.info("Ignoring link %s, version %s doesn't match %s" + % (link, version, ','.join([''.join(s) for s in req.req.specs]))) + continue + applicable_versions.append((link, version)) + applicable_versions = sorted(applicable_versions, key=lambda v: pkg_resources.parse_version(v[1]), reverse=True) + existing_applicable = bool([link for link, version in applicable_versions if link is Inf]) + if not upgrade and existing_applicable: + if applicable_versions[0][1] is Inf: + logger.info('Existing installed version (%s) is most up-to-date and satisfies requirement' + % req.satisfied_by.version) + raise BestVersionAlreadyInstalled + else: + logger.info('Existing installed version (%s) satisfies requirement (most up-to-date version is %s)' + % (req.satisfied_by.version, applicable_versions[0][1])) + return None + if not applicable_versions: + logger.fatal('Could not find a version that satisfies the requirement %s (from versions: %s)' + % (req, ', '.join([version for parsed_version, link, version in found_versions]))) + raise DistributionNotFound('No distributions matching the version for %s' % req) + if applicable_versions[0][0] is Inf: + # We have an existing version, and its the best version + logger.info('Installed version (%s) is most up-to-date (past versions: %s)' + % (req.satisfied_by.version, ', '.join([version for link, version in applicable_versions[1:]]) or 'none')) + raise BestVersionAlreadyInstalled + if len(applicable_versions) > 1: + logger.info('Using version %s (newest of versions: %s)' % + (applicable_versions[0][1], ', '.join([version for link, version in applicable_versions]))) + return applicable_versions[0][0] + + def _find_url_name(self, index_url, url_name, req): + """Finds the true URL name of a package, when the given name isn't quite correct. + This is usually used to implement case-insensitivity.""" + if not index_url.url.endswith('/'): + # Vaguely part of the PyPI API... weird but true. + ## FIXME: bad to modify this? + index_url.url += '/' + page = self._get_page(index_url, req) + if page is None: + logger.fatal('Cannot fetch index base URL %s' % index_url) + return + norm_name = normalize_name(req.url_name) + for link in page.links: + base = posixpath.basename(link.path.rstrip('/')) + if norm_name == normalize_name(base): + logger.notify('Real name of requirement %s is %s' % (url_name, base)) + return base + return None + + def _get_pages(self, locations, req): + """Yields (page, page_url) from the given locations, skipping + locations that have errors, and adding download/homepage links""" + pending_queue = Queue() + for location in locations: + pending_queue.put(location) + done = [] + seen = set() + threads = [] + for i in range(min(10, len(locations))): + t = threading.Thread(target=self._get_queued_page, args=(req, pending_queue, done, seen)) + t.setDaemon(True) + threads.append(t) + t.start() + for t in threads: + t.join() + return done + + _log_lock = threading.Lock() + + def _get_queued_page(self, req, pending_queue, done, seen): + while 1: + try: + location = pending_queue.get(False) + except QueueEmpty: + return + if location in seen: + continue + seen.add(location) + page = self._get_page(location, req) + if page is None: + continue + done.append(page) + for link in page.rel_links(): + pending_queue.put(link) + + _egg_fragment_re = re.compile(r'#egg=([^&]*)') + _egg_info_re = re.compile(r'([a-z0-9_.]+)-([a-z0-9_.-]+)', re.I) + _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') + + def _sort_links(self, links): + "Returns elements of links in order, non-egg links first, egg links second, while eliminating duplicates" + eggs, no_eggs = [], [] + seen = set() + for link in links: + if link not in seen: + seen.add(link) + if link.egg_fragment: + eggs.append(link) + else: + no_eggs.append(link) + return no_eggs + eggs + + def _package_versions(self, links, search_name): + for link in self._sort_links(links): + for v in self._link_package_versions(link, search_name): + yield v + + def _link_package_versions(self, link, search_name): + """ + Return an iterable of triples (pkg_resources_version_key, + link, python_version) that can be extracted from the given + link. + + Meant to be overridden by subclasses, not called by clients. + """ + if link.egg_fragment: + egg_info = link.egg_fragment + else: + egg_info, ext = link.splitext() + if not ext: + if link not in self.logged_links: + logger.debug('Skipping link %s; not a file' % link) + self.logged_links.add(link) + return [] + if egg_info.endswith('.tar'): + # Special double-extension case: + egg_info = egg_info[:-4] + ext = '.tar' + ext + if ext not in ('.tar.gz', '.tar.bz2', '.tar', '.tgz', '.zip'): + if link not in self.logged_links: + logger.debug('Skipping link %s; unknown archive format: %s' % (link, ext)) + self.logged_links.add(link) + return [] + if "macosx10" in link.path and ext == '.zip': + if link not in self.logged_links: + logger.debug('Skipping link %s; macosx10 one' % (link)) + self.logged_links.add(link) + return [] + version = self._egg_info_matches(egg_info, search_name, link) + if version is None: + logger.debug('Skipping link %s; wrong project name (not %s)' % (link, search_name)) + return [] + match = self._py_version_re.search(version) + if match: + version = version[:match.start()] + py_version = match.group(1) + if py_version != sys.version[:3]: + logger.debug('Skipping %s because Python version is incorrect' % link) + return [] + logger.debug('Found link %s, version: %s' % (link, version)) + return [(pkg_resources.parse_version(version), + link, + version)] + + def _egg_info_matches(self, egg_info, search_name, link): + match = self._egg_info_re.search(egg_info) + if not match: + logger.debug('Could not parse version from link: %s' % link) + return None + name = match.group(0).lower() + # To match the "safe" name that pkg_resources creates: + name = name.replace('_', '-') + if name.startswith(search_name.lower()): + return match.group(0)[len(search_name):].lstrip('-') + else: + return None + + def _get_page(self, link, req): + return HTMLPage.get_page(link, req, cache=self.cache) + + def _get_mirror_urls(self, mirrors=None, main_mirror_url=None): + """Retrieves a list of URLs from the main mirror DNS entry + unless a list of mirror URLs are passed. + """ + if not mirrors: + mirrors = get_mirrors(main_mirror_url) + # Should this be made "less random"? E.g. netselect like? + random.shuffle(mirrors) + + mirror_urls = set() + for mirror_url in mirrors: + # Make sure we have a valid URL + if not ("http://" or "https://" or "file://") in mirror_url: + mirror_url = "http://%s" % mirror_url + if not mirror_url.endswith("/simple"): + mirror_url = "%s/simple/" % mirror_url + mirror_urls.add(mirror_url) + + return list(mirror_urls) + + +class PageCache(object): + """Cache of HTML pages""" + + failure_limit = 3 + + def __init__(self): + self._failures = {} + self._pages = {} + self._archives = {} + + def too_many_failures(self, url): + return self._failures.get(url, 0) >= self.failure_limit + + def get_page(self, url): + return self._pages.get(url) + + def is_archive(self, url): + return self._archives.get(url, False) + + def set_is_archive(self, url, value=True): + self._archives[url] = value + + def add_page_failure(self, url, level): + self._failures[url] = self._failures.get(url, 0)+level + + def add_page(self, urls, page): + for url in urls: + self._pages[url] = page + + +class HTMLPage(object): + """Represents one page, along with its URL""" + + ## FIXME: these regexes are horrible hacks: + _homepage_re = re.compile(r'\s*home\s*page', re.I) + _download_re = re.compile(r'\s*download\s+url', re.I) + ## These aren't so aweful: + _rel_re = re.compile("""<[^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*>""", re.I) + _href_re = re.compile('href=(?:"([^"]*)"|\'([^\']*)\'|([^>\\s\\n]*))', re.I|re.S) + _base_re = re.compile(r"""]+)""", re.I) + + def __init__(self, content, url, headers=None): + self.content = content + self.url = url + self.headers = headers + + def __str__(self): + return self.url + + @classmethod + def get_page(cls, link, req, cache=None, skip_archives=True): + url = link.url + url = url.split('#', 1)[0] + if cache.too_many_failures(url): + return None + + # Check for VCS schemes that do not support lookup as web pages. + from pip.vcs import VcsSupport + for scheme in VcsSupport.schemes: + if url.lower().startswith(scheme) and url[len(scheme)] in '+:': + logger.debug('Cannot look at %(scheme)s URL %(link)s' % locals()) + return None + + if cache is not None: + inst = cache.get_page(url) + if inst is not None: + return inst + try: + if skip_archives: + if cache is not None: + if cache.is_archive(url): + return None + filename = link.filename + for bad_ext in ['.tar', '.tar.gz', '.tar.bz2', '.tgz', '.zip']: + if filename.endswith(bad_ext): + content_type = cls._get_content_type(url) + if content_type.lower().startswith('text/html'): + break + else: + logger.debug('Skipping page %s because of Content-Type: %s' % (link, content_type)) + if cache is not None: + cache.set_is_archive(url) + return None + logger.debug('Getting page %s' % url) + + # Tack index.html onto file:// URLs that point to directories + (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url) + if scheme == 'file' and os.path.isdir(url2pathname(path)): + # add trailing slash if not present so urljoin doesn't trim final segment + if not url.endswith('/'): + url += '/' + url = urlparse.urljoin(url, 'index.html') + logger.debug(' file: URL is directory, getting %s' % url) + + resp = urlopen(url) + + real_url = geturl(resp) + headers = resp.info() + contents = resp.read() + encoding = headers.get('Content-Encoding', None) + #XXX need to handle exceptions and add testing for this + if encoding is not None: + if encoding == 'gzip': + contents = gzip.GzipFile(fileobj=BytesIO(contents)).read() + if encoding == 'deflate': + contents = zlib.decompress(contents) + inst = cls(u(contents), real_url, headers) + except (HTTPError, URLError, socket.timeout, socket.error, OSError, WindowsError): + e = sys.exc_info()[1] + desc = str(e) + if isinstance(e, socket.timeout): + log_meth = logger.info + level =1 + desc = 'timed out' + elif isinstance(e, URLError): + log_meth = logger.info + if hasattr(e, 'reason') and isinstance(e.reason, socket.timeout): + desc = 'timed out' + level = 1 + else: + level = 2 + elif isinstance(e, HTTPError) and e.code == 404: + ## FIXME: notify? + log_meth = logger.info + level = 2 + else: + log_meth = logger.info + level = 1 + log_meth('Could not fetch URL %s: %s' % (link, desc)) + log_meth('Will skip URL %s when looking for download links for %s' % (link.url, req)) + if cache is not None: + cache.add_page_failure(url, level) + return None + if cache is not None: + cache.add_page([url, real_url], inst) + return inst + + @staticmethod + def _get_content_type(url): + """Get the Content-Type of the given url, using a HEAD request""" + scheme, netloc, path, query, fragment = urlparse.urlsplit(url) + if not scheme in ('http', 'https', 'ftp', 'ftps'): + ## FIXME: some warning or something? + ## assertion error? + return '' + req = Urllib2HeadRequest(url, headers={'Host': netloc}) + resp = urlopen(req) + try: + if hasattr(resp, 'code') and resp.code != 200 and scheme not in ('ftp', 'ftps'): + ## FIXME: doesn't handle redirects + return '' + return resp.info().get('content-type', '') + finally: + resp.close() + + @property + def base_url(self): + if not hasattr(self, "_base_url"): + match = self._base_re.search(self.content) + if match: + self._base_url = match.group(1) + else: + self._base_url = self.url + return self._base_url + + @property + def links(self): + """Yields all links in the page""" + for match in self._href_re.finditer(self.content): + url = match.group(1) or match.group(2) or match.group(3) + url = self.clean_link(urlparse.urljoin(self.base_url, url)) + yield Link(url, self) + + def rel_links(self): + for url in self.explicit_rel_links(): + yield url + for url in self.scraped_rel_links(): + yield url + + def explicit_rel_links(self, rels=('homepage', 'download')): + """Yields all links with the given relations""" + for match in self._rel_re.finditer(self.content): + found_rels = match.group(1).lower().split() + for rel in rels: + if rel in found_rels: + break + else: + continue + match = self._href_re.search(match.group(0)) + if not match: + continue + url = match.group(1) or match.group(2) or match.group(3) + url = self.clean_link(urlparse.urljoin(self.base_url, url)) + yield Link(url, self) + + def scraped_rel_links(self): + for regex in (self._homepage_re, self._download_re): + match = regex.search(self.content) + if not match: + continue + href_match = self._href_re.search(self.content, pos=match.end()) + if not href_match: + continue + url = href_match.group(1) or href_match.group(2) or href_match.group(3) + if not url: + continue + url = self.clean_link(urlparse.urljoin(self.base_url, url)) + yield Link(url, self) + + _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) + + def clean_link(self, url): + """Makes sure a link is fully encoded. That is, if a ' ' shows up in + the link, it will be rewritten to %20 (while not over-quoting + % or other characters).""" + return self._clean_re.sub( + lambda match: '%%%2x' % ord(match.group(0)), url) + + +class Link(object): + + def __init__(self, url, comes_from=None): + self.url = url + self.comes_from = comes_from + + def __str__(self): + if self.comes_from: + return '%s (from %s)' % (self.url, self.comes_from) + else: + return self.url + + def __repr__(self): + return '' % self + + def __eq__(self, other): + return self.url == other.url + + def __hash__(self): + return hash(self.url) + + @property + def filename(self): + url = self.url_fragment + name = posixpath.basename(url) + assert name, ('URL %r produced no filename' % url) + return name + + @property + def scheme(self): + return urlparse.urlsplit(self.url)[0] + + @property + def path(self): + return urlparse.urlsplit(self.url)[2] + + def splitext(self): + return splitext(posixpath.basename(self.path.rstrip('/'))) + + @property + def url_fragment(self): + url = self.url + url = url.split('#', 1)[0] + url = url.split('?', 1)[0] + url = url.rstrip('/') + return url + + _egg_fragment_re = re.compile(r'#egg=([^&]*)') + + @property + def egg_fragment(self): + match = self._egg_fragment_re.search(self.url) + if not match: + return None + return match.group(1) + + _md5_re = re.compile(r'md5=([a-f0-9]+)') + + @property + def md5_hash(self): + match = self._md5_re.search(self.url) + if match: + return match.group(1) + return None + + @property + def show_url(self): + return posixpath.basename(self.url.split('#', 1)[0].split('?', 1)[0]) + + +def get_requirement_from_url(url): + """Get a requirement from the URL, if possible. This looks for #egg + in the URL""" + link = Link(url) + egg_info = link.egg_fragment + if not egg_info: + egg_info = splitext(link.filename)[0] + return package_to_requirement(egg_info) + + +def package_to_requirement(package_name): + """Translate a name like Foo-1.2 to Foo==1.3""" + match = re.search(r'^(.*?)-(dev|\d.*)', package_name) + if match: + name = match.group(1) + version = match.group(2) + else: + name = package_name + version = '' + if version: + return '%s==%s' % (name, version) + else: + return name + + +def get_mirrors(hostname=None): + """Return the list of mirrors from the last record found on the DNS + entry:: + + >>> from pip.index import get_mirrors + >>> get_mirrors() + ['a.pypi.python.org', 'b.pypi.python.org', 'c.pypi.python.org', + 'd.pypi.python.org'] + + Originally written for the distutils2 project by Alexis Metaireau. + """ + if hostname is None: + hostname = DEFAULT_MIRROR_URL + + # return the last mirror registered on PyPI. + try: + hostname = socket.gethostbyname_ex(hostname)[0] + except socket.gaierror: + return [] + end_letter = hostname.split(".", 1) + + # determine the list from the last one. + return ["%s.%s" % (s, end_letter[1]) for s in string_range(end_letter[0])] + + +def string_range(last): + """Compute the range of string between "a" and last. + + This works for simple "a to z" lists, but also for "a to zz" lists. + """ + for k in range(len(last)): + for x in product(string.ascii_lowercase, repeat=k+1): + result = ''.join(x) + yield result + if result == last: + return + diff --git a/vendor/pip-1.2.1/pip/locations.py b/vendor/pip-1.2.1/pip/locations.py new file mode 100644 index 0000000..34c6dbb --- /dev/null +++ b/vendor/pip-1.2.1/pip/locations.py @@ -0,0 +1,52 @@ +"""Locations where we look for configs, install stuff, etc""" + +import sys +import os +from pip.backwardcompat import get_python_lib + + +def running_under_virtualenv(): + """ + Return True if we're running inside a virtualenv, False otherwise. + + """ + return hasattr(sys, 'real_prefix') + + +if running_under_virtualenv(): + ## FIXME: is build/ a good name? + build_prefix = os.path.join(sys.prefix, 'build') + src_prefix = os.path.join(sys.prefix, 'src') +else: + ## FIXME: this isn't a very good default + build_prefix = os.path.join(os.getcwd(), 'build') + src_prefix = os.path.join(os.getcwd(), 'src') + +# under Mac OS X + virtualenv sys.prefix is not properly resolved +# it is something like /path/to/python/bin/.. +build_prefix = os.path.abspath(build_prefix) +src_prefix = os.path.abspath(src_prefix) + +# FIXME doesn't account for venv linked to global site-packages + +site_packages = get_python_lib() +user_dir = os.path.expanduser('~') +if sys.platform == 'win32': + bin_py = os.path.join(sys.prefix, 'Scripts') + # buildout uses 'bin' on Windows too? + if not os.path.exists(bin_py): + bin_py = os.path.join(sys.prefix, 'bin') + user_dir = os.environ.get('APPDATA', user_dir) # Use %APPDATA% for roaming + default_storage_dir = os.path.join(user_dir, 'pip') + default_config_file = os.path.join(default_storage_dir, 'pip.ini') + default_log_file = os.path.join(default_storage_dir, 'pip.log') +else: + bin_py = os.path.join(sys.prefix, 'bin') + default_storage_dir = os.path.join(user_dir, '.pip') + default_config_file = os.path.join(default_storage_dir, 'pip.conf') + default_log_file = os.path.join(default_storage_dir, 'pip.log') + # Forcing to use /usr/local/bin for standard Mac OS X framework installs + # Also log to ~/Library/Logs/ for use with the Console.app log viewer + if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': + bin_py = '/usr/local/bin' + default_log_file = os.path.join(user_dir, 'Library/Logs/pip.log') diff --git a/vendor/pip-1.2.1/pip/log.py b/vendor/pip-1.2.1/pip/log.py new file mode 100644 index 0000000..63541a1 --- /dev/null +++ b/vendor/pip-1.2.1/pip/log.py @@ -0,0 +1,188 @@ +"""Logging +""" + +import sys +import logging + +import pip.backwardcompat + + +class Logger(object): + + """ + Logging object for use in command-line script. Allows ranges of + levels, to avoid some redundancy of displayed information. + """ + + VERBOSE_DEBUG = logging.DEBUG-1 + DEBUG = logging.DEBUG + INFO = logging.INFO + NOTIFY = (logging.INFO+logging.WARN)/2 + WARN = WARNING = logging.WARN + ERROR = logging.ERROR + FATAL = logging.FATAL + + LEVELS = [VERBOSE_DEBUG, DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] + + def __init__(self): + self.consumers = [] + self.indent = 0 + self.explicit_levels = False + self.in_progress = None + self.in_progress_hanging = False + + def debug(self, msg, *args, **kw): + self.log(self.DEBUG, msg, *args, **kw) + + def info(self, msg, *args, **kw): + self.log(self.INFO, msg, *args, **kw) + + def notify(self, msg, *args, **kw): + self.log(self.NOTIFY, msg, *args, **kw) + + def warn(self, msg, *args, **kw): + self.log(self.WARN, msg, *args, **kw) + + def error(self, msg, *args, **kw): + self.log(self.WARN, msg, *args, **kw) + + def fatal(self, msg, *args, **kw): + self.log(self.FATAL, msg, *args, **kw) + + def log(self, level, msg, *args, **kw): + if args: + if kw: + raise TypeError( + "You may give positional or keyword arguments, not both") + args = args or kw + rendered = None + for consumer_level, consumer in self.consumers: + if self.level_matches(level, consumer_level): + if (self.in_progress_hanging + and consumer in (sys.stdout, sys.stderr)): + self.in_progress_hanging = False + sys.stdout.write('\n') + sys.stdout.flush() + if rendered is None: + if args: + rendered = msg % args + else: + rendered = msg + rendered = ' '*self.indent + rendered + if self.explicit_levels: + ## FIXME: should this be a name, not a level number? + rendered = '%02i %s' % (level, rendered) + if hasattr(consumer, 'write'): + rendered += '\n' + pip.backwardcompat.fwrite(consumer, rendered) + else: + consumer(rendered) + + def _show_progress(self): + """Should we display download progress?""" + return (self.stdout_level_matches(self.NOTIFY) and sys.stdout.isatty()) + + def start_progress(self, msg): + assert not self.in_progress, ( + "Tried to start_progress(%r) while in_progress %r" + % (msg, self.in_progress)) + if self._show_progress(): + sys.stdout.write(' '*self.indent + msg) + sys.stdout.flush() + self.in_progress_hanging = True + else: + self.in_progress_hanging = False + self.in_progress = msg + self.last_message = None + + def end_progress(self, msg='done.'): + assert self.in_progress, ( + "Tried to end_progress without start_progress") + if self._show_progress(): + if not self.in_progress_hanging: + # Some message has been printed out since start_progress + sys.stdout.write('...' + self.in_progress + msg + '\n') + sys.stdout.flush() + else: + # These erase any messages shown with show_progress (besides .'s) + logger.show_progress('') + logger.show_progress('') + sys.stdout.write(msg + '\n') + sys.stdout.flush() + self.in_progress = None + self.in_progress_hanging = False + + def show_progress(self, message=None): + """If we are in a progress scope, and no log messages have been + shown, write out another '.'""" + if self.in_progress_hanging: + if message is None: + sys.stdout.write('.') + sys.stdout.flush() + else: + if self.last_message: + padding = ' ' * max(0, len(self.last_message)-len(message)) + else: + padding = '' + sys.stdout.write('\r%s%s%s%s' % (' '*self.indent, self.in_progress, message, padding)) + sys.stdout.flush() + self.last_message = message + + def stdout_level_matches(self, level): + """Returns true if a message at this level will go to stdout""" + return self.level_matches(level, self._stdout_level()) + + def _stdout_level(self): + """Returns the level that stdout runs at""" + for level, consumer in self.consumers: + if consumer is sys.stdout: + return level + return self.FATAL + + def level_matches(self, level, consumer_level): + """ + >>> l = Logger() + >>> l.level_matches(3, 4) + False + >>> l.level_matches(3, 2) + True + >>> l.level_matches(slice(None, 3), 3) + False + >>> l.level_matches(slice(None, 3), 2) + True + >>> l.level_matches(slice(1, 3), 1) + True + >>> l.level_matches(slice(2, 3), 1) + False + """ + if isinstance(level, slice): + start, stop = level.start, level.stop + if start is not None and start > consumer_level: + return False + if stop is not None or stop <= consumer_level: + return False + return True + else: + return level >= consumer_level + + @classmethod + def level_for_integer(cls, level): + levels = cls.LEVELS + if level < 0: + return levels[0] + if level >= len(levels): + return levels[-1] + return levels[level] + + def move_stdout_to_stderr(self): + to_remove = [] + to_add = [] + for consumer_level, consumer in self.consumers: + if consumer == sys.stdout: + to_remove.append((consumer_level, consumer)) + to_add.append((consumer_level, sys.stderr)) + for item in to_remove: + self.consumers.remove(item) + self.consumers.extend(to_add) + +logger = Logger() diff --git a/vendor/pip-1.2.1/pip/req.py b/vendor/pip-1.2.1/pip/req.py new file mode 100644 index 0000000..a1a6959 --- /dev/null +++ b/vendor/pip-1.2.1/pip/req.py @@ -0,0 +1,1517 @@ +import sys +import os +import shutil +import re +import zipfile +import pkg_resources +import tempfile +from pip.locations import bin_py, running_under_virtualenv +from pip.exceptions import (InstallationError, UninstallationError, + BestVersionAlreadyInstalled) +from pip.vcs import vcs +from pip.log import logger +from pip.util import display_path, rmtree +from pip.util import ask, ask_path_exists, backup_dir +from pip.util import is_installable_dir, is_local, dist_is_local +from pip.util import renames, normalize_path, egg_link_path +from pip.util import make_path_relative +from pip import call_subprocess +from pip.backwardcompat import (any, copytree, urlparse, urllib, + ConfigParser, string_types, HTTPError, + FeedParser, get_python_version, + b) +from pip.index import Link +from pip.locations import build_prefix +from pip.download import (get_file_content, is_url, url_to_path, + path_to_url, is_archive_file, + unpack_vcs_link, is_vcs_url, is_file_url, + unpack_file_url, unpack_http_url) + + +PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt' + + +class InstallRequirement(object): + + def __init__(self, req, comes_from, source_dir=None, editable=False, + url=None, update=True): + self.extras = () + if isinstance(req, string_types): + req = pkg_resources.Requirement.parse(req) + self.extras = req.extras + self.req = req + self.comes_from = comes_from + self.source_dir = source_dir + self.editable = editable + self.url = url + self._egg_info_path = None + # This holds the pkg_resources.Distribution object if this requirement + # is already available: + self.satisfied_by = None + # This hold the pkg_resources.Distribution object if this requirement + # conflicts with another installed distribution: + self.conflicts_with = None + self._temp_build_dir = None + self._is_bundle = None + # True if the editable should be updated: + self.update = update + # Set to True after successful installation + self.install_succeeded = None + # UninstallPathSet of uninstalled distribution (for possible rollback) + self.uninstalled = None + + @classmethod + def from_editable(cls, editable_req, comes_from=None, default_vcs=None): + name, url = parse_editable(editable_req, default_vcs) + if url.startswith('file:'): + source_dir = url_to_path(url) + else: + source_dir = None + return cls(name, comes_from, source_dir=source_dir, editable=True, url=url) + + @classmethod + def from_line(cls, name, comes_from=None): + """Creates an InstallRequirement from a name, which might be a + requirement, directory containing 'setup.py', filename, or URL. + """ + url = None + name = name.strip() + req = None + path = os.path.normpath(os.path.abspath(name)) + link = None + + if is_url(name): + link = Link(name) + elif os.path.isdir(path) and (os.path.sep in name or name.startswith('.')): + if not is_installable_dir(path): + raise InstallationError("Directory %r is not installable. File 'setup.py' not found.", name) + link = Link(path_to_url(name)) + elif is_archive_file(path): + if not os.path.isfile(path): + logger.warn('Requirement %r looks like a filename, but the file does not exist', name) + link = Link(path_to_url(name)) + + # If the line has an egg= definition, but isn't editable, pull the requirement out. + # Otherwise, assume the name is the req for the non URL/path/archive case. + if link and req is None: + url = link.url_fragment + req = link.egg_fragment + + # Handle relative file URLs + if link.scheme == 'file' and re.search(r'\.\./', url): + url = path_to_url(os.path.normpath(os.path.abspath(link.path))) + + else: + req = name + + return cls(req, comes_from, url=url) + + def __str__(self): + if self.req: + s = str(self.req) + if self.url: + s += ' from %s' % self.url + else: + s = self.url + if self.satisfied_by is not None: + s += ' in %s' % display_path(self.satisfied_by.location) + if self.comes_from: + if isinstance(self.comes_from, string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += ' (from %s)' % comes_from + return s + + def from_path(self): + if self.req is None: + return None + s = str(self.req) + if self.comes_from: + if isinstance(self.comes_from, string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += '->' + comes_from + return s + + def build_location(self, build_dir, unpack=True): + if self._temp_build_dir is not None: + return self._temp_build_dir + if self.req is None: + self._temp_build_dir = tempfile.mkdtemp('-build', 'pip-') + self._ideal_build_dir = build_dir + return self._temp_build_dir + if self.editable: + name = self.name.lower() + else: + name = self.name + # FIXME: Is there a better place to create the build_dir? (hg and bzr need this) + if not os.path.exists(build_dir): + _make_build_dir(build_dir) + return os.path.join(build_dir, name) + + def correct_build_location(self): + """If the build location was a temporary directory, this will move it + to a new more permanent location""" + if self.source_dir is not None: + return + assert self.req is not None + assert self._temp_build_dir + old_location = self._temp_build_dir + new_build_dir = self._ideal_build_dir + del self._ideal_build_dir + if self.editable: + name = self.name.lower() + else: + name = self.name + new_location = os.path.join(new_build_dir, name) + if not os.path.exists(new_build_dir): + logger.debug('Creating directory %s' % new_build_dir) + _make_build_dir(new_build_dir) + if os.path.exists(new_location): + raise InstallationError( + 'A package already exists in %s; please remove it to continue' + % display_path(new_location)) + logger.debug('Moving package %s from %s to new location %s' + % (self, display_path(old_location), display_path(new_location))) + shutil.move(old_location, new_location) + self._temp_build_dir = new_location + self.source_dir = new_location + self._egg_info_path = None + + @property + def name(self): + if self.req is None: + return None + return self.req.project_name + + @property + def url_name(self): + if self.req is None: + return None + return urllib.quote(self.req.unsafe_name) + + @property + def setup_py(self): + return os.path.join(self.source_dir, 'setup.py') + + def run_egg_info(self, force_root_egg_info=False): + assert self.source_dir + if self.name: + logger.notify('Running setup.py egg_info for package %s' % self.name) + else: + logger.notify('Running setup.py egg_info for package from %s' % self.url) + logger.indent += 2 + try: + script = self._run_setup_py + script = script.replace('__SETUP_PY__', repr(self.setup_py)) + script = script.replace('__PKG_NAME__', repr(self.name)) + # We can't put the .egg-info files at the root, because then the source code will be mistaken + # for an installed egg, causing problems + if self.editable or force_root_egg_info: + egg_base_option = [] + else: + egg_info_dir = os.path.join(self.source_dir, 'pip-egg-info') + if not os.path.exists(egg_info_dir): + os.makedirs(egg_info_dir) + egg_base_option = ['--egg-base', 'pip-egg-info'] + call_subprocess( + [sys.executable, '-c', script, 'egg_info'] + egg_base_option, + cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False, + command_level=logger.VERBOSE_DEBUG, + command_desc='python setup.py egg_info') + finally: + logger.indent -= 2 + if not self.req: + self.req = pkg_resources.Requirement.parse( + "%(Name)s==%(Version)s" % self.pkg_info()) + self.correct_build_location() + + ## FIXME: This is a lame hack, entirely for PasteScript which has + ## a self-provided entry point that causes this awkwardness + _run_setup_py = """ +__file__ = __SETUP_PY__ +from setuptools.command import egg_info +def replacement_run(self): + self.mkpath(self.egg_info) + installer = self.distribution.fetch_build_egg + for ep in egg_info.iter_entry_points('egg_info.writers'): + # require=False is the change we're making: + writer = ep.load(require=False) + if writer: + writer(self, ep.name, egg_info.os.path.join(self.egg_info,ep.name)) + self.find_sources() +egg_info.egg_info.run = replacement_run +exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec')) +""" + + def egg_info_data(self, filename): + if self.satisfied_by is not None: + if not self.satisfied_by.has_metadata(filename): + return None + return self.satisfied_by.get_metadata(filename) + assert self.source_dir + filename = self.egg_info_path(filename) + if not os.path.exists(filename): + return None + fp = open(filename, 'r') + data = fp.read() + fp.close() + return data + + def egg_info_path(self, filename): + if self._egg_info_path is None: + if self.editable: + base = self.source_dir + else: + base = os.path.join(self.source_dir, 'pip-egg-info') + filenames = os.listdir(base) + if self.editable: + filenames = [] + for root, dirs, files in os.walk(base): + for dir in vcs.dirnames: + if dir in dirs: + dirs.remove(dir) + for dir in dirs: + # Don't search in anything that looks like a virtualenv environment + if (os.path.exists(os.path.join(root, dir, 'bin', 'python')) + or os.path.exists(os.path.join(root, dir, 'Scripts', 'Python.exe'))): + dirs.remove(dir) + # Also don't search through tests + if dir == 'test' or dir == 'tests': + dirs.remove(dir) + filenames.extend([os.path.join(root, dir) + for dir in dirs]) + filenames = [f for f in filenames if f.endswith('.egg-info')] + + if not filenames: + raise InstallationError('No files/directores in %s (from %s)' % (base, filename)) + assert filenames, "No files/directories in %s (from %s)" % (base, filename) + + # if we have more than one match, we pick the toplevel one. This can + # easily be the case if there is a dist folder which contains an + # extracted tarball for testing purposes. + if len(filenames) > 1: + filenames.sort(key=lambda x: x.count(os.path.sep) + + (os.path.altsep and + x.count(os.path.altsep) or 0)) + self._egg_info_path = os.path.join(base, filenames[0]) + return os.path.join(self._egg_info_path, filename) + + def egg_info_lines(self, filename): + data = self.egg_info_data(filename) + if not data: + return [] + result = [] + for line in data.splitlines(): + line = line.strip() + if not line or line.startswith('#'): + continue + result.append(line) + return result + + def pkg_info(self): + p = FeedParser() + data = self.egg_info_data('PKG-INFO') + if not data: + logger.warn('No PKG-INFO file found in %s' % display_path(self.egg_info_path('PKG-INFO'))) + p.feed(data or '') + return p.close() + + @property + def dependency_links(self): + return self.egg_info_lines('dependency_links.txt') + + _requirements_section_re = re.compile(r'\[(.*?)\]') + + def requirements(self, extras=()): + in_extra = None + for line in self.egg_info_lines('requires.txt'): + match = self._requirements_section_re.match(line.lower()) + if match: + in_extra = match.group(1) + continue + if in_extra and in_extra not in extras: + logger.debug('skipping extra %s' % in_extra) + # Skip requirement for an extra we aren't requiring + continue + yield line + + @property + def absolute_versions(self): + for qualifier, version in self.req.specs: + if qualifier == '==': + yield version + + @property + def installed_version(self): + return self.pkg_info()['version'] + + def assert_source_matches_version(self): + assert self.source_dir + version = self.installed_version + if version not in self.req: + logger.warn('Requested %s, but installing version %s' % (self, self.installed_version)) + else: + logger.debug('Source in %s has version %s, which satisfies requirement %s' + % (display_path(self.source_dir), version, self)) + + def update_editable(self, obtain=True): + if not self.url: + logger.info("Cannot update repository at %s; repository location is unknown" % self.source_dir) + return + assert self.editable + assert self.source_dir + if self.url.startswith('file:'): + # Static paths don't get updated + return + assert '+' in self.url, "bad url: %r" % self.url + if not self.update: + return + vc_type, url = self.url.split('+', 1) + backend = vcs.get_backend(vc_type) + if backend: + vcs_backend = backend(self.url) + if obtain: + vcs_backend.obtain(self.source_dir) + else: + vcs_backend.export(self.source_dir) + else: + assert 0, ( + 'Unexpected version control type (in %s): %s' + % (self.url, vc_type)) + + def uninstall(self, auto_confirm=False): + """ + Uninstall the distribution currently satisfying this requirement. + + Prompts before removing or modifying files unless + ``auto_confirm`` is True. + + Refuses to delete or modify files outside of ``sys.prefix`` - + thus uninstallation within a virtual environment can only + modify that virtual environment, even if the virtualenv is + linked to global site-packages. + + """ + if not self.check_if_exists(): + raise UninstallationError("Cannot uninstall requirement %s, not installed" % (self.name,)) + dist = self.satisfied_by or self.conflicts_with + + paths_to_remove = UninstallPathSet(dist) + + pip_egg_info_path = os.path.join(dist.location, + dist.egg_name()) + '.egg-info' + # workaround for http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=618367 + debian_egg_info_path = pip_egg_info_path.replace( + '-py%s' % pkg_resources.PY_MAJOR, '') + easy_install_egg = dist.egg_name() + '.egg' + develop_egg_link = egg_link_path(dist) + + pip_egg_info_exists = os.path.exists(pip_egg_info_path) + debian_egg_info_exists = os.path.exists(debian_egg_info_path) + if pip_egg_info_exists or debian_egg_info_exists: + # package installed by pip + if pip_egg_info_exists: + egg_info_path = pip_egg_info_path + else: + egg_info_path = debian_egg_info_path + paths_to_remove.add(egg_info_path) + if dist.has_metadata('installed-files.txt'): + for installed_file in dist.get_metadata('installed-files.txt').splitlines(): + path = os.path.normpath(os.path.join(egg_info_path, installed_file)) + paths_to_remove.add(path) + if dist.has_metadata('top_level.txt'): + if dist.has_metadata('namespace_packages.txt'): + namespaces = dist.get_metadata('namespace_packages.txt') + else: + namespaces = [] + for top_level_pkg in [p for p + in dist.get_metadata('top_level.txt').splitlines() + if p and p not in namespaces]: + path = os.path.join(dist.location, top_level_pkg) + paths_to_remove.add(path) + paths_to_remove.add(path + '.py') + paths_to_remove.add(path + '.pyc') + + elif dist.location.endswith(easy_install_egg): + # package installed by easy_install + paths_to_remove.add(dist.location) + easy_install_pth = os.path.join(os.path.dirname(dist.location), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) + + elif os.path.isfile(develop_egg_link): + # develop egg + fh = open(develop_egg_link, 'r') + link_pointer = os.path.normcase(fh.readline().strip()) + fh.close() + assert (link_pointer == dist.location), 'Egg-link %s does not match installed location of %s (at %s)' % (link_pointer, self.name, dist.location) + paths_to_remove.add(develop_egg_link) + easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, dist.location) + + # find distutils scripts= scripts + if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): + for script in dist.metadata_listdir('scripts'): + paths_to_remove.add(os.path.join(bin_py, script)) + if sys.platform == 'win32': + paths_to_remove.add(os.path.join(bin_py, script) + '.bat') + + # find console_scripts + if dist.has_metadata('entry_points.txt'): + config = ConfigParser.SafeConfigParser() + config.readfp(FakeFile(dist.get_metadata_lines('entry_points.txt'))) + if config.has_section('console_scripts'): + for name, value in config.items('console_scripts'): + paths_to_remove.add(os.path.join(bin_py, name)) + if sys.platform == 'win32': + paths_to_remove.add(os.path.join(bin_py, name) + '.exe') + paths_to_remove.add(os.path.join(bin_py, name) + '.exe.manifest') + paths_to_remove.add(os.path.join(bin_py, name) + '-script.py') + + paths_to_remove.remove(auto_confirm) + self.uninstalled = paths_to_remove + + def rollback_uninstall(self): + if self.uninstalled: + self.uninstalled.rollback() + else: + logger.error("Can't rollback %s, nothing uninstalled." + % (self.project_name,)) + + def commit_uninstall(self): + if self.uninstalled: + self.uninstalled.commit() + else: + logger.error("Can't commit %s, nothing uninstalled." + % (self.project_name,)) + + def archive(self, build_dir): + assert self.source_dir + create_archive = True + archive_name = '%s-%s.zip' % (self.name, self.installed_version) + archive_path = os.path.join(build_dir, archive_name) + if os.path.exists(archive_path): + response = ask_path_exists( + 'The file %s exists. (i)gnore, (w)ipe, (b)ackup ' % + display_path(archive_path), ('i', 'w', 'b')) + if response == 'i': + create_archive = False + elif response == 'w': + logger.warn('Deleting %s' % display_path(archive_path)) + os.remove(archive_path) + elif response == 'b': + dest_file = backup_dir(archive_path) + logger.warn('Backing up %s to %s' + % (display_path(archive_path), display_path(dest_file))) + shutil.move(archive_path, dest_file) + if create_archive: + zip = zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED) + dir = os.path.normcase(os.path.abspath(self.source_dir)) + for dirpath, dirnames, filenames in os.walk(dir): + if 'pip-egg-info' in dirnames: + dirnames.remove('pip-egg-info') + for dirname in dirnames: + dirname = os.path.join(dirpath, dirname) + name = self._clean_zip_name(dirname, dir) + zipdir = zipfile.ZipInfo(self.name + '/' + name + '/') + zipdir.external_attr = 0x1ED << 16 # 0o755 + zip.writestr(zipdir, '') + for filename in filenames: + if filename == PIP_DELETE_MARKER_FILENAME: + continue + filename = os.path.join(dirpath, filename) + name = self._clean_zip_name(filename, dir) + zip.write(filename, self.name + '/' + name) + zip.close() + logger.indent -= 2 + logger.notify('Saved %s' % display_path(archive_path)) + + def _clean_zip_name(self, name, prefix): + assert name.startswith(prefix+os.path.sep), ( + "name %r doesn't start with prefix %r" % (name, prefix)) + name = name[len(prefix)+1:] + name = name.replace(os.path.sep, '/') + return name + + def install(self, install_options, global_options=()): + if self.editable: + self.install_editable(install_options, global_options) + return + temp_location = tempfile.mkdtemp('-record', 'pip-') + record_filename = os.path.join(temp_location, 'install-record.txt') + try: + install_args = [ + sys.executable, '-c', + "import setuptools;__file__=%r;"\ + "exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))" % self.setup_py] +\ + list(global_options) + [ + 'install', + '--single-version-externally-managed', + '--record', record_filename] + + if running_under_virtualenv(): + ## FIXME: I'm not sure if this is a reasonable location; probably not + ## but we can't put it in the default location, as that is a virtualenv symlink that isn't writable + install_args += ['--install-headers', + os.path.join(sys.prefix, 'include', 'site', + 'python' + get_python_version())] + logger.notify('Running setup.py install for %s' % self.name) + logger.indent += 2 + try: + call_subprocess(install_args + install_options, + cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False) + finally: + logger.indent -= 2 + if not os.path.exists(record_filename): + logger.notify('Record file %s not found' % record_filename) + return + self.install_succeeded = True + f = open(record_filename) + for line in f: + line = line.strip() + if line.endswith('.egg-info'): + egg_info_dir = line + break + else: + logger.warn('Could not find .egg-info directory in install record for %s' % self) + ## FIXME: put the record somewhere + ## FIXME: should this be an error? + return + f.close() + new_lines = [] + f = open(record_filename) + for line in f: + filename = line.strip() + if os.path.isdir(filename): + filename += os.path.sep + new_lines.append(make_path_relative(filename, egg_info_dir)) + f.close() + f = open(os.path.join(egg_info_dir, 'installed-files.txt'), 'w') + f.write('\n'.join(new_lines)+'\n') + f.close() + finally: + if os.path.exists(record_filename): + os.remove(record_filename) + os.rmdir(temp_location) + + def remove_temporary_source(self): + """Remove the source files from this requirement, if they are marked + for deletion""" + if self.is_bundle or os.path.exists(self.delete_marker_filename): + logger.info('Removing source in %s' % self.source_dir) + if self.source_dir: + rmtree(self.source_dir) + self.source_dir = None + if self._temp_build_dir and os.path.exists(self._temp_build_dir): + rmtree(self._temp_build_dir) + self._temp_build_dir = None + + def install_editable(self, install_options, global_options=()): + logger.notify('Running setup.py develop for %s' % self.name) + logger.indent += 2 + try: + ## FIXME: should we do --install-headers here too? + call_subprocess( + [sys.executable, '-c', + "import setuptools; __file__=%r; exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))" % self.setup_py] + + list(global_options) + ['develop', '--no-deps'] + list(install_options), + + cwd=self.source_dir, filter_stdout=self._filter_install, + show_stdout=False) + finally: + logger.indent -= 2 + self.install_succeeded = True + + def _filter_install(self, line): + level = logger.NOTIFY + for regex in [r'^running .*', r'^writing .*', '^creating .*', '^[Cc]opying .*', + r'^reading .*', r"^removing .*\.egg-info' \(and everything under it\)$", + r'^byte-compiling ', + # Not sure what this warning is, but it seems harmless: + r"^warning: manifest_maker: standard file '-c' not found$"]: + if re.search(regex, line.strip()): + level = logger.INFO + break + return (level, line) + + def check_if_exists(self): + """Find an installed distribution that satisfies or conflicts + with this requirement, and set self.satisfied_by or + self.conflicts_with appropriately.""" + if self.req is None: + return False + try: + self.satisfied_by = pkg_resources.get_distribution(self.req) + except pkg_resources.DistributionNotFound: + return False + except pkg_resources.VersionConflict: + self.conflicts_with = pkg_resources.get_distribution(self.req.project_name) + return True + + @property + def is_bundle(self): + if self._is_bundle is not None: + return self._is_bundle + base = self._temp_build_dir + if not base: + ## FIXME: this doesn't seem right: + return False + self._is_bundle = (os.path.exists(os.path.join(base, 'pip-manifest.txt')) + or os.path.exists(os.path.join(base, 'pyinstall-manifest.txt'))) + return self._is_bundle + + def bundle_requirements(self): + for dest_dir in self._bundle_editable_dirs: + package = os.path.basename(dest_dir) + ## FIXME: svnism: + for vcs_backend in vcs.backends: + url = rev = None + vcs_bundle_file = os.path.join( + dest_dir, vcs_backend.bundle_file) + if os.path.exists(vcs_bundle_file): + vc_type = vcs_backend.name + fp = open(vcs_bundle_file) + content = fp.read() + fp.close() + url, rev = vcs_backend().parse_vcs_bundle_file(content) + break + if url: + url = '%s+%s@%s' % (vc_type, url, rev) + else: + url = None + yield InstallRequirement( + package, self, editable=True, url=url, + update=False, source_dir=dest_dir) + for dest_dir in self._bundle_build_dirs: + package = os.path.basename(dest_dir) + yield InstallRequirement( + package, self, + source_dir=dest_dir) + + def move_bundle_files(self, dest_build_dir, dest_src_dir): + base = self._temp_build_dir + assert base + src_dir = os.path.join(base, 'src') + build_dir = os.path.join(base, 'build') + bundle_build_dirs = [] + bundle_editable_dirs = [] + for source_dir, dest_dir, dir_collection in [ + (src_dir, dest_src_dir, bundle_editable_dirs), + (build_dir, dest_build_dir, bundle_build_dirs)]: + if os.path.exists(source_dir): + for dirname in os.listdir(source_dir): + dest = os.path.join(dest_dir, dirname) + dir_collection.append(dest) + if os.path.exists(dest): + logger.warn('The directory %s (containing package %s) already exists; cannot move source from bundle %s' + % (dest, dirname, self)) + continue + if not os.path.exists(dest_dir): + logger.info('Creating directory %s' % dest_dir) + os.makedirs(dest_dir) + shutil.move(os.path.join(source_dir, dirname), dest) + if not os.listdir(source_dir): + os.rmdir(source_dir) + self._temp_build_dir = None + self._bundle_build_dirs = bundle_build_dirs + self._bundle_editable_dirs = bundle_editable_dirs + + @property + def delete_marker_filename(self): + assert self.source_dir + return os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME) + + +DELETE_MARKER_MESSAGE = '''\ +This file is placed here by pip to indicate the source was put +here by pip. + +Once this package is successfully installed this source code will be +deleted (unless you remove this file). +''' + + +class Requirements(object): + + def __init__(self): + self._keys = [] + self._dict = {} + + def keys(self): + return self._keys + + def values(self): + values_list = [] + for key in self._keys: + values_list.append(self._dict[key]) + return values_list + + def __contains__(self, item): + return item in self._keys + + def __setitem__(self, key, value): + if key not in self._keys: + self._keys.append(key) + self._dict[key] = value + + def __getitem__(self, key): + return self._dict[key] + + def __repr__(self): + values = ['%s: %s' % (repr(k), repr(self[k])) for k in self.keys()] + return 'Requirements({%s})' % ', '.join(values) + + +class RequirementSet(object): + + def __init__(self, build_dir, src_dir, download_dir, download_cache=None, + upgrade=False, ignore_installed=False, + ignore_dependencies=False, force_reinstall=False): + self.build_dir = build_dir + self.src_dir = src_dir + self.download_dir = download_dir + self.download_cache = download_cache + self.upgrade = upgrade + self.ignore_installed = ignore_installed + self.force_reinstall = force_reinstall + self.requirements = Requirements() + # Mapping of alias: real_name + self.requirement_aliases = {} + self.unnamed_requirements = [] + self.ignore_dependencies = ignore_dependencies + self.successfully_downloaded = [] + self.successfully_installed = [] + self.reqs_to_cleanup = [] + + def __str__(self): + reqs = [req for req in self.requirements.values() + if not req.comes_from] + reqs.sort(key=lambda req: req.name.lower()) + return ' '.join([str(req.req) for req in reqs]) + + def add_requirement(self, install_req): + name = install_req.name + if not name: + self.unnamed_requirements.append(install_req) + else: + if self.has_requirement(name): + raise InstallationError( + 'Double requirement given: %s (aready in %s, name=%r)' + % (install_req, self.get_requirement(name), name)) + self.requirements[name] = install_req + ## FIXME: what about other normalizations? E.g., _ vs. -? + if name.lower() != name: + self.requirement_aliases[name.lower()] = name + + def has_requirement(self, project_name): + for name in project_name, project_name.lower(): + if name in self.requirements or name in self.requirement_aliases: + return True + return False + + @property + def has_requirements(self): + return list(self.requirements.values()) or self.unnamed_requirements + + @property + def has_editables(self): + if any(req.editable for req in self.requirements.values()): + return True + if any(req.editable for req in self.unnamed_requirements): + return True + return False + + @property + def is_download(self): + if self.download_dir: + self.download_dir = os.path.expanduser(self.download_dir) + if os.path.exists(self.download_dir): + return True + else: + logger.fatal('Could not find download directory') + raise InstallationError( + "Could not find or access download directory '%s'" + % display_path(self.download_dir)) + return False + + def get_requirement(self, project_name): + for name in project_name, project_name.lower(): + if name in self.requirements: + return self.requirements[name] + if name in self.requirement_aliases: + return self.requirements[self.requirement_aliases[name]] + raise KeyError("No project with the name %r" % project_name) + + def uninstall(self, auto_confirm=False): + for req in self.requirements.values(): + req.uninstall(auto_confirm=auto_confirm) + req.commit_uninstall() + + def locate_files(self): + ## FIXME: duplicates code from install_files; relevant code should + ## probably be factored out into a separate method + unnamed = list(self.unnamed_requirements) + reqs = list(self.requirements.values()) + while reqs or unnamed: + if unnamed: + req_to_install = unnamed.pop(0) + else: + req_to_install = reqs.pop(0) + install_needed = True + if not self.ignore_installed and not req_to_install.editable: + req_to_install.check_if_exists() + if req_to_install.satisfied_by: + if self.upgrade: + req_to_install.conflicts_with = req_to_install.satisfied_by + req_to_install.satisfied_by = None + else: + install_needed = False + if req_to_install.satisfied_by: + logger.notify('Requirement already satisfied ' + '(use --upgrade to upgrade): %s' + % req_to_install) + + if req_to_install.editable: + if req_to_install.source_dir is None: + req_to_install.source_dir = req_to_install.build_location(self.src_dir) + elif install_needed: + req_to_install.source_dir = req_to_install.build_location(self.build_dir, not self.is_download) + + if req_to_install.source_dir is not None and not os.path.isdir(req_to_install.source_dir): + raise InstallationError('Could not install requirement %s ' + 'because source folder %s does not exist ' + '(perhaps --no-download was used without first running ' + 'an equivalent install with --no-install?)' + % (req_to_install, req_to_install.source_dir)) + + def prepare_files(self, finder, force_root_egg_info=False, bundle=False): + """Prepare process. Create temp directories, download and/or unpack files.""" + unnamed = list(self.unnamed_requirements) + reqs = list(self.requirements.values()) + while reqs or unnamed: + if unnamed: + req_to_install = unnamed.pop(0) + else: + req_to_install = reqs.pop(0) + install = True + best_installed = False + if not self.ignore_installed and not req_to_install.editable: + req_to_install.check_if_exists() + if req_to_install.satisfied_by: + if self.upgrade: + if not self.force_reinstall: + try: + url = finder.find_requirement( + req_to_install, self.upgrade) + except BestVersionAlreadyInstalled: + best_installed = True + install = False + else: + # Avoid the need to call find_requirement again + req_to_install.url = url.url + + if not best_installed: + req_to_install.conflicts_with = req_to_install.satisfied_by + req_to_install.satisfied_by = None + else: + install = False + if req_to_install.satisfied_by: + if best_installed: + logger.notify('Requirement already up-to-date: %s' + % req_to_install) + else: + logger.notify('Requirement already satisfied ' + '(use --upgrade to upgrade): %s' + % req_to_install) + if req_to_install.editable: + logger.notify('Obtaining %s' % req_to_install) + elif install: + if req_to_install.url and req_to_install.url.lower().startswith('file:'): + logger.notify('Unpacking %s' % display_path(url_to_path(req_to_install.url))) + else: + logger.notify('Downloading/unpacking %s' % req_to_install) + logger.indent += 2 + try: + is_bundle = False + if req_to_install.editable: + if req_to_install.source_dir is None: + location = req_to_install.build_location(self.src_dir) + req_to_install.source_dir = location + else: + location = req_to_install.source_dir + if not os.path.exists(self.build_dir): + _make_build_dir(self.build_dir) + req_to_install.update_editable(not self.is_download) + if self.is_download: + req_to_install.run_egg_info() + req_to_install.archive(self.download_dir) + else: + req_to_install.run_egg_info() + elif install: + ##@@ if filesystem packages are not marked + ##editable in a req, a non deterministic error + ##occurs when the script attempts to unpack the + ##build directory + + location = req_to_install.build_location(self.build_dir, not self.is_download) + ## FIXME: is the existance of the checkout good enough to use it? I don't think so. + unpack = True + url = None + if not os.path.exists(os.path.join(location, 'setup.py')): + ## FIXME: this won't upgrade when there's an existing package unpacked in `location` + if req_to_install.url is None: + url = finder.find_requirement(req_to_install, upgrade=self.upgrade) + else: + ## FIXME: should req_to_install.url already be a link? + url = Link(req_to_install.url) + assert url + if url: + try: + self.unpack_url(url, location, self.is_download) + except HTTPError: + e = sys.exc_info()[1] + logger.fatal('Could not install requirement %s because of error %s' + % (req_to_install, e)) + raise InstallationError( + 'Could not install requirement %s because of HTTP error %s for URL %s' + % (req_to_install, e, url)) + else: + unpack = False + if unpack: + is_bundle = req_to_install.is_bundle + if is_bundle: + req_to_install.move_bundle_files(self.build_dir, self.src_dir) + for subreq in req_to_install.bundle_requirements(): + reqs.append(subreq) + self.add_requirement(subreq) + elif self.is_download: + req_to_install.source_dir = location + req_to_install.run_egg_info() + if url and url.scheme in vcs.all_schemes: + req_to_install.archive(self.download_dir) + else: + req_to_install.source_dir = location + req_to_install.run_egg_info() + if force_root_egg_info: + # We need to run this to make sure that the .egg-info/ + # directory is created for packing in the bundle + req_to_install.run_egg_info(force_root_egg_info=True) + req_to_install.assert_source_matches_version() + #@@ sketchy way of identifying packages not grabbed from an index + if bundle and req_to_install.url: + self.copy_to_build_dir(req_to_install) + install = False + # req_to_install.req is only avail after unpack for URL pkgs + # repeat check_if_exists to uninstall-on-upgrade (#14) + req_to_install.check_if_exists() + if req_to_install.satisfied_by: + if self.upgrade or self.ignore_installed: + req_to_install.conflicts_with = req_to_install.satisfied_by + req_to_install.satisfied_by = None + else: + install = False + if not is_bundle: + ## FIXME: shouldn't be globally added: + finder.add_dependency_links(req_to_install.dependency_links) + if (req_to_install.extras): + logger.notify("Installing extra requirements: %r" % ','.join(req_to_install.extras)) + if not self.ignore_dependencies: + for req in req_to_install.requirements(req_to_install.extras): + try: + name = pkg_resources.Requirement.parse(req).project_name + except ValueError: + e = sys.exc_info()[1] + ## FIXME: proper warning + logger.error('Invalid requirement: %r (%s) in requirement %s' % (req, e, req_to_install)) + continue + if self.has_requirement(name): + ## FIXME: check for conflict + continue + subreq = InstallRequirement(req, req_to_install) + reqs.append(subreq) + self.add_requirement(subreq) + if req_to_install.name not in self.requirements: + self.requirements[req_to_install.name] = req_to_install + if self.is_download: + self.reqs_to_cleanup.append(req_to_install) + else: + self.reqs_to_cleanup.append(req_to_install) + + if install: + self.successfully_downloaded.append(req_to_install) + if bundle and (req_to_install.url and req_to_install.url.startswith('file:///')): + self.copy_to_build_dir(req_to_install) + finally: + logger.indent -= 2 + + def cleanup_files(self, bundle=False): + """Clean up files, remove builds.""" + logger.notify('Cleaning up...') + logger.indent += 2 + for req in self.reqs_to_cleanup: + req.remove_temporary_source() + + remove_dir = [] + if self._pip_has_created_build_dir(): + remove_dir.append(self.build_dir) + + # The source dir of a bundle can always be removed. + # FIXME: not if it pre-existed the bundle! + if bundle: + remove_dir.append(self.src_dir) + + for dir in remove_dir: + if os.path.exists(dir): + logger.info('Removing temporary dir %s...' % dir) + rmtree(dir) + + logger.indent -= 2 + + def _pip_has_created_build_dir(self): + return (self.build_dir == build_prefix and + os.path.exists(os.path.join(self.build_dir, PIP_DELETE_MARKER_FILENAME))) + + def copy_to_build_dir(self, req_to_install): + target_dir = req_to_install.editable and self.src_dir or self.build_dir + logger.info("Copying %s to %s" % (req_to_install.name, target_dir)) + dest = os.path.join(target_dir, req_to_install.name) + copytree(req_to_install.source_dir, dest) + call_subprocess(["python", "%s/setup.py" % dest, "clean"], cwd=dest, + command_desc='python setup.py clean') + + def unpack_url(self, link, location, only_download=False): + if only_download: + loc = self.download_dir + else: + loc = location + if is_vcs_url(link): + return unpack_vcs_link(link, loc, only_download) + elif is_file_url(link): + return unpack_file_url(link, loc) + else: + if self.download_cache: + self.download_cache = os.path.expanduser(self.download_cache) + retval = unpack_http_url(link, location, self.download_cache, self.download_dir) + if only_download: + _write_delete_marker_message(os.path.join(location, PIP_DELETE_MARKER_FILENAME)) + return retval + + def install(self, install_options, global_options=()): + """Install everything in this set (after having downloaded and unpacked the packages)""" + to_install = [r for r in self.requirements.values() + if not r.satisfied_by] + + if to_install: + logger.notify('Installing collected packages: %s' % ', '.join([req.name for req in to_install])) + logger.indent += 2 + try: + for requirement in to_install: + if requirement.conflicts_with: + logger.notify('Found existing installation: %s' + % requirement.conflicts_with) + logger.indent += 2 + try: + requirement.uninstall(auto_confirm=True) + finally: + logger.indent -= 2 + try: + requirement.install(install_options, global_options) + except: + # if install did not succeed, rollback previous uninstall + if requirement.conflicts_with and not requirement.install_succeeded: + requirement.rollback_uninstall() + raise + else: + if requirement.conflicts_with and requirement.install_succeeded: + requirement.commit_uninstall() + requirement.remove_temporary_source() + finally: + logger.indent -= 2 + self.successfully_installed = to_install + + def create_bundle(self, bundle_filename): + ## FIXME: can't decide which is better; zip is easier to read + ## random files from, but tar.bz2 is smaller and not as lame a + ## format. + + ## FIXME: this file should really include a manifest of the + ## packages, maybe some other metadata files. It would make + ## it easier to detect as well. + zip = zipfile.ZipFile(bundle_filename, 'w', zipfile.ZIP_DEFLATED) + vcs_dirs = [] + for dir, basename in (self.build_dir, 'build'), (self.src_dir, 'src'): + dir = os.path.normcase(os.path.abspath(dir)) + for dirpath, dirnames, filenames in os.walk(dir): + for backend in vcs.backends: + vcs_backend = backend() + vcs_url = vcs_rev = None + if vcs_backend.dirname in dirnames: + for vcs_dir in vcs_dirs: + if dirpath.startswith(vcs_dir): + # vcs bundle file already in parent directory + break + else: + vcs_url, vcs_rev = vcs_backend.get_info( + os.path.join(dir, dirpath)) + vcs_dirs.append(dirpath) + vcs_bundle_file = vcs_backend.bundle_file + vcs_guide = vcs_backend.guide % {'url': vcs_url, + 'rev': vcs_rev} + dirnames.remove(vcs_backend.dirname) + break + if 'pip-egg-info' in dirnames: + dirnames.remove('pip-egg-info') + for dirname in dirnames: + dirname = os.path.join(dirpath, dirname) + name = self._clean_zip_name(dirname, dir) + zip.writestr(basename + '/' + name + '/', '') + for filename in filenames: + if filename == PIP_DELETE_MARKER_FILENAME: + continue + filename = os.path.join(dirpath, filename) + name = self._clean_zip_name(filename, dir) + zip.write(filename, basename + '/' + name) + if vcs_url: + name = os.path.join(dirpath, vcs_bundle_file) + name = self._clean_zip_name(name, dir) + zip.writestr(basename + '/' + name, vcs_guide) + + zip.writestr('pip-manifest.txt', self.bundle_requirements()) + zip.close() + + BUNDLE_HEADER = '''\ +# This is a pip bundle file, that contains many source packages +# that can be installed as a group. You can install this like: +# pip this_file.zip +# The rest of the file contains a list of all the packages included: +''' + + def bundle_requirements(self): + parts = [self.BUNDLE_HEADER] + for req in [req for req in self.requirements.values() + if not req.comes_from]: + parts.append('%s==%s\n' % (req.name, req.installed_version)) + parts.append('# These packages were installed to satisfy the above requirements:\n') + for req in [req for req in self.requirements.values() + if req.comes_from]: + parts.append('%s==%s\n' % (req.name, req.installed_version)) + ## FIXME: should we do something with self.unnamed_requirements? + return ''.join(parts) + + def _clean_zip_name(self, name, prefix): + assert name.startswith(prefix+os.path.sep), ( + "name %r doesn't start with prefix %r" % (name, prefix)) + name = name[len(prefix)+1:] + name = name.replace(os.path.sep, '/') + return name + + +def _make_build_dir(build_dir): + os.makedirs(build_dir) + _write_delete_marker_message(os.path.join(build_dir, PIP_DELETE_MARKER_FILENAME)) + + +def _write_delete_marker_message(filepath): + marker_fp = open(filepath, 'w') + marker_fp.write(DELETE_MARKER_MESSAGE) + marker_fp.close() + + +_scheme_re = re.compile(r'^(http|https|file):', re.I) + + +def parse_requirements(filename, finder=None, comes_from=None, options=None): + skip_match = None + skip_regex = options.skip_requirements_regex + if skip_regex: + skip_match = re.compile(skip_regex) + filename, content = get_file_content(filename, comes_from=comes_from) + for line_number, line in enumerate(content.splitlines()): + line_number += 1 + line = line.strip() + if not line or line.startswith('#'): + continue + if skip_match and skip_match.search(line): + continue + if line.startswith('-r') or line.startswith('--requirement'): + if line.startswith('-r'): + req_url = line[2:].strip() + else: + req_url = line[len('--requirement'):].strip().strip('=') + if _scheme_re.search(filename): + # Relative to a URL + req_url = urlparse.urljoin(filename, req_url) + elif not _scheme_re.search(req_url): + req_url = os.path.join(os.path.dirname(filename), req_url) + for item in parse_requirements(req_url, finder, comes_from=filename, options=options): + yield item + elif line.startswith('-Z') or line.startswith('--always-unzip'): + # No longer used, but previously these were used in + # requirement files, so we'll ignore. + pass + elif line.startswith('-f') or line.startswith('--find-links'): + if line.startswith('-f'): + line = line[2:].strip() + else: + line = line[len('--find-links'):].strip().lstrip('=') + ## FIXME: it would be nice to keep track of the source of + ## the find_links: + if finder: + finder.find_links.append(line) + elif line.startswith('-i') or line.startswith('--index-url'): + if line.startswith('-i'): + line = line[2:].strip() + else: + line = line[len('--index-url'):].strip().lstrip('=') + if finder: + finder.index_urls = [line] + elif line.startswith('--extra-index-url'): + line = line[len('--extra-index-url'):].strip().lstrip('=') + if finder: + finder.index_urls.append(line) + else: + comes_from = '-r %s (line %s)' % (filename, line_number) + if line.startswith('-e') or line.startswith('--editable'): + if line.startswith('-e'): + line = line[2:].strip() + else: + line = line[len('--editable'):].strip().lstrip('=') + req = InstallRequirement.from_editable( + line, comes_from=comes_from, default_vcs=options.default_vcs) + else: + req = InstallRequirement.from_line(line, comes_from) + yield req + + +def parse_editable(editable_req, default_vcs=None): + """Parses svn+http://blahblah@rev#egg=Foobar into a requirement + (Foobar) and a URL""" + url = editable_req + if os.path.isdir(url) and os.path.exists(os.path.join(url, 'setup.py')): + # Treating it as code that has already been checked out + url = path_to_url(url) + if url.lower().startswith('file:'): + return None, url + for version_control in vcs: + if url.lower().startswith('%s:' % version_control): + url = '%s+%s' % (version_control, url) + if '+' not in url: + if default_vcs: + url = default_vcs + '+' + url + else: + raise InstallationError( + '--editable=%s should be formatted with svn+URL, git+URL, hg+URL or bzr+URL' % editable_req) + vc_type = url.split('+', 1)[0].lower() + if not vcs.get_backend(vc_type): + raise InstallationError( + 'For --editable=%s only svn (svn+URL), Git (git+URL), Mercurial (hg+URL) and Bazaar (bzr+URL) is currently supported' % editable_req) + match = re.search(r'(?:#|#.*?&)egg=([^&]*)', editable_req) + if (not match or not match.group(1)) and vcs.get_backend(vc_type): + parts = [p for p in editable_req.split('#', 1)[0].split('/') if p] + if parts[-2] in ('tags', 'branches', 'tag', 'branch'): + req = parts[-3] + elif parts[-1] == 'trunk': + req = parts[-2] + else: + raise InstallationError( + '--editable=%s is not the right format; it must have #egg=Package' + % editable_req) + else: + req = match.group(1) + ## FIXME: use package_to_requirement? + match = re.search(r'^(.*?)(?:-dev|-\d.*)$', req) + if match: + # Strip off -dev, -0.2, etc. + req = match.group(1) + return req, url + + +class UninstallPathSet(object): + """A set of file paths to be removed in the uninstallation of a + requirement.""" + def __init__(self, dist): + self.paths = set() + self._refuse = set() + self.pth = {} + self.dist = dist + self.save_dir = None + self._moved_paths = [] + + def _permitted(self, path): + """ + Return True if the given path is one we are permitted to + remove/modify, False otherwise. + + """ + return is_local(path) + + def _can_uninstall(self): + if not dist_is_local(self.dist): + logger.notify("Not uninstalling %s at %s, outside environment %s" + % (self.dist.project_name, normalize_path(self.dist.location), sys.prefix)) + return False + return True + + def add(self, path): + path = normalize_path(path) + if not os.path.exists(path): + return + if self._permitted(path): + self.paths.add(path) + else: + self._refuse.add(path) + + def add_pth(self, pth_file, entry): + pth_file = normalize_path(pth_file) + if self._permitted(pth_file): + if pth_file not in self.pth: + self.pth[pth_file] = UninstallPthEntries(pth_file) + self.pth[pth_file].add(entry) + else: + self._refuse.add(pth_file) + + def compact(self, paths): + """Compact a path set to contain the minimal number of paths + necessary to contain all paths in the set. If /a/path/ and + /a/path/to/a/file.txt are both in the set, leave only the + shorter path.""" + short_paths = set() + for path in sorted(paths, key=len): + if not any([(path.startswith(shortpath) and + path[len(shortpath.rstrip(os.path.sep))] == os.path.sep) + for shortpath in short_paths]): + short_paths.add(path) + return short_paths + + def _stash(self, path): + return os.path.join( + self.save_dir, os.path.splitdrive(path)[1].lstrip(os.path.sep)) + + def remove(self, auto_confirm=False): + """Remove paths in ``self.paths`` with confirmation (unless + ``auto_confirm`` is True).""" + if not self._can_uninstall(): + return + logger.notify('Uninstalling %s:' % self.dist.project_name) + logger.indent += 2 + paths = sorted(self.compact(self.paths)) + try: + if auto_confirm: + response = 'y' + else: + for path in paths: + logger.notify(path) + response = ask('Proceed (y/n)? ', ('y', 'n')) + if self._refuse: + logger.notify('Not removing or modifying (outside of prefix):') + for path in self.compact(self._refuse): + logger.notify(path) + if response == 'y': + self.save_dir = tempfile.mkdtemp(suffix='-uninstall', + prefix='pip-') + for path in paths: + new_path = self._stash(path) + logger.info('Removing file or directory %s' % path) + self._moved_paths.append(path) + renames(path, new_path) + for pth in self.pth.values(): + pth.remove() + logger.notify('Successfully uninstalled %s' % self.dist.project_name) + + finally: + logger.indent -= 2 + + def rollback(self): + """Rollback the changes previously made by remove().""" + if self.save_dir is None: + logger.error("Can't roll back %s; was not uninstalled" % self.dist.project_name) + return False + logger.notify('Rolling back uninstall of %s' % self.dist.project_name) + for path in self._moved_paths: + tmp_path = self._stash(path) + logger.info('Replacing %s' % path) + renames(tmp_path, path) + for pth in self.pth: + pth.rollback() + + def commit(self): + """Remove temporary save dir: rollback will no longer be possible.""" + if self.save_dir is not None: + rmtree(self.save_dir) + self.save_dir = None + self._moved_paths = [] + + +class UninstallPthEntries(object): + def __init__(self, pth_file): + if not os.path.isfile(pth_file): + raise UninstallationError("Cannot remove entries from nonexistent file %s" % pth_file) + self.file = pth_file + self.entries = set() + self._saved_lines = None + + def add(self, entry): + entry = os.path.normcase(entry) + # On Windows, os.path.normcase converts the entry to use + # backslashes. This is correct for entries that describe absolute + # paths outside of site-packages, but all the others use forward + # slashes. + if sys.platform == 'win32' and not os.path.splitdrive(entry)[0]: + entry = entry.replace('\\', '/') + self.entries.add(entry) + + def remove(self): + logger.info('Removing pth entries from %s:' % self.file) + fh = open(self.file, 'rb') + # windows uses '\r\n' with py3k, but uses '\n' with py2.x + lines = fh.readlines() + self._saved_lines = lines + fh.close() + if any(b('\r\n') in line for line in lines): + endline = '\r\n' + else: + endline = '\n' + for entry in self.entries: + try: + logger.info('Removing entry: %s' % entry) + lines.remove(b(entry + endline)) + except ValueError: + pass + fh = open(self.file, 'wb') + fh.writelines(lines) + fh.close() + + def rollback(self): + if self._saved_lines is None: + logger.error('Cannot roll back changes to %s, none were made' % self.file) + return False + logger.info('Rolling %s back to previous state' % self.file) + fh = open(self.file, 'wb') + fh.writelines(self._saved_lines) + fh.close() + return True + + +class FakeFile(object): + """Wrap a list of lines in an object with readline() to make + ConfigParser happy.""" + def __init__(self, lines): + self._gen = (l for l in lines) + + def readline(self): + try: + try: + return next(self._gen) + except NameError: + return self._gen.next() + except StopIteration: + return '' + + def __iter__(self): + return self._gen diff --git a/vendor/pip-1.2.1/pip/runner.py b/vendor/pip-1.2.1/pip/runner.py new file mode 100644 index 0000000..be830ad --- /dev/null +++ b/vendor/pip-1.2.1/pip/runner.py @@ -0,0 +1,18 @@ +import sys +import os + + +def run(): + base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + ## FIXME: this is kind of crude; if we could create a fake pip + ## module, then exec into it and update pip.__path__ properly, we + ## wouldn't have to update sys.path: + sys.path.insert(0, base) + import pip + return pip.main() + + +if __name__ == '__main__': + exit = run() + if exit: + sys.exit(exit) diff --git a/vendor/pip-1.2.1/pip/status_codes.py b/vendor/pip-1.2.1/pip/status_codes.py new file mode 100644 index 0000000..b6208e9 --- /dev/null +++ b/vendor/pip-1.2.1/pip/status_codes.py @@ -0,0 +1,5 @@ +SUCCESS = 0 +ERROR = 1 +UNKNOWN_ERROR = 2 +VIRTUALENV_NOT_FOUND = 3 +NO_MATCHES_FOUND = 23 diff --git a/vendor/pip-1.2.1/pip/util.py b/vendor/pip-1.2.1/pip/util.py new file mode 100644 index 0000000..e5ad6df --- /dev/null +++ b/vendor/pip-1.2.1/pip/util.py @@ -0,0 +1,509 @@ +import sys +import shutil +import os +import stat +import re +import posixpath +import pkg_resources +import zipfile +import tarfile +from pip.exceptions import InstallationError, BadCommand +from pip.backwardcompat import WindowsError, string_types, raw_input +from pip.locations import site_packages, running_under_virtualenv +from pip.log import logger + +__all__ = ['rmtree', 'display_path', 'backup_dir', + 'find_command', 'ask', 'Inf', + 'normalize_name', 'splitext', + 'format_size', 'is_installable_dir', + 'is_svn_page', 'file_contents', + 'split_leading_dir', 'has_leading_dir', + 'make_path_relative', 'normalize_path', + 'renames', 'get_terminal_size', + 'unzip_file', 'untar_file', 'create_download_cache_folder', + 'cache_download', 'unpack_file'] + + +def rmtree(dir, ignore_errors=False): + shutil.rmtree(dir, ignore_errors=ignore_errors, + onerror=rmtree_errorhandler) + + +def rmtree_errorhandler(func, path, exc_info): + """On Windows, the files in .svn are read-only, so when rmtree() tries to + remove them, an exception is thrown. We catch that here, remove the + read-only attribute, and hopefully continue without problems.""" + exctype, value = exc_info[:2] + # On Python 2.4, it will be OSError number 13 + # On all more recent Pythons, it'll be WindowsError number 5 + if not ((exctype is WindowsError and value.args[0] == 5) or + (exctype is OSError and value.args[0] == 13)): + raise + # file type should currently be read only + if ((os.stat(path).st_mode & stat.S_IREAD) != stat.S_IREAD): + raise + # convert to read/write + os.chmod(path, stat.S_IWRITE) + # use the original function to repeat the operation + func(path) + + +def display_path(path): + """Gives the display value for a given path, making it relative to cwd + if possible.""" + path = os.path.normcase(os.path.abspath(path)) + if path.startswith(os.getcwd() + os.path.sep): + path = '.' + path[len(os.getcwd()):] + return path + + +def backup_dir(dir, ext='.bak'): + """Figure out the name of a directory to back up the given dir to + (adding .bak, .bak2, etc)""" + n = 1 + extension = ext + while os.path.exists(dir + extension): + n += 1 + extension = ext + str(n) + return dir + extension + + +def find_command(cmd, paths=None, pathext=None): + """Searches the PATH for the given command and returns its path""" + if paths is None: + paths = os.environ.get('PATH', '').split(os.pathsep) + if isinstance(paths, string_types): + paths = [paths] + # check if there are funny path extensions for executables, e.g. Windows + if pathext is None: + pathext = get_pathext() + pathext = [ext for ext in pathext.lower().split(os.pathsep)] + # don't use extensions if the command ends with one of them + if os.path.splitext(cmd)[1].lower() in pathext: + pathext = [''] + # check if we find the command on PATH + for path in paths: + # try without extension first + cmd_path = os.path.join(path, cmd) + for ext in pathext: + # then including the extension + cmd_path_ext = cmd_path + ext + if os.path.isfile(cmd_path_ext): + return cmd_path_ext + if os.path.isfile(cmd_path): + return cmd_path + raise BadCommand('Cannot find command %r' % cmd) + + +def get_pathext(default_pathext=None): + """Returns the path extensions from environment or a default""" + if default_pathext is None: + default_pathext = os.pathsep.join(['.COM', '.EXE', '.BAT', '.CMD']) + pathext = os.environ.get('PATHEXT', default_pathext) + return pathext + + +def ask_path_exists(message, options): + for action in os.environ.get('PIP_EXISTS_ACTION', ''): + if action in options: + return action + return ask(message, options) + + +def ask(message, options): + """Ask the message interactively, with the given possible responses""" + while 1: + if os.environ.get('PIP_NO_INPUT'): + raise Exception('No input was expected ($PIP_NO_INPUT set); question: %s' % message) + response = raw_input(message) + response = response.strip().lower() + if response not in options: + print('Your response (%r) was not one of the expected responses: %s' % ( + response, ', '.join(options))) + else: + return response + + +class _Inf(object): + """I am bigger than everything!""" + def __cmp__(self, a): + if self is a: + return 0 + return 1 + + def __repr__(self): + return 'Inf' + +Inf = _Inf() +del _Inf + + +_normalize_re = re.compile(r'[^a-z]', re.I) + + +def normalize_name(name): + return _normalize_re.sub('-', name.lower()) + + +def format_size(bytes): + if bytes > 1000*1000: + return '%.1fMb' % (bytes/1000.0/1000) + elif bytes > 10*1000: + return '%iKb' % (bytes/1000) + elif bytes > 1000: + return '%.1fKb' % (bytes/1000.0) + else: + return '%ibytes' % bytes + + +def is_installable_dir(path): + """Return True if `path` is a directory containing a setup.py file.""" + if not os.path.isdir(path): + return False + setup_py = os.path.join(path, 'setup.py') + if os.path.isfile(setup_py): + return True + return False + + +def is_svn_page(html): + """Returns true if the page appears to be the index page of an svn repository""" + return (re.search(r'[^<]*Revision \d+:', html) + and re.search(r'Powered by (?:<a[^>]*?>)?Subversion', html, re.I)) + + +def file_contents(filename): + fp = open(filename, 'rb') + try: + return fp.read().decode('utf-8') + finally: + fp.close() + + +def split_leading_dir(path): + path = str(path) + path = path.lstrip('/').lstrip('\\') + if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) + or '\\' not in path): + return path.split('/', 1) + elif '\\' in path: + return path.split('\\', 1) + else: + return path, '' + + +def has_leading_dir(paths): + """Returns true if all the paths have the same leading path name + (i.e., everything is in one subdirectory in an archive)""" + common_prefix = None + for path in paths: + prefix, rest = split_leading_dir(path) + if not prefix: + return False + elif common_prefix is None: + common_prefix = prefix + elif prefix != common_prefix: + return False + return True + + +def make_path_relative(path, rel_to): + """ + Make a filename relative, where the filename path, and it is + relative to rel_to + + >>> make_relative_path('/usr/share/something/a-file.pth', + ... '/usr/share/another-place/src/Directory') + '../../../something/a-file.pth' + >>> make_relative_path('/usr/share/something/a-file.pth', + ... '/home/user/src/Directory') + '../../../usr/share/something/a-file.pth' + >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') + 'a-file.pth' + """ + path_filename = os.path.basename(path) + path = os.path.dirname(path) + path = os.path.normpath(os.path.abspath(path)) + rel_to = os.path.normpath(os.path.abspath(rel_to)) + path_parts = path.strip(os.path.sep).split(os.path.sep) + rel_to_parts = rel_to.strip(os.path.sep).split(os.path.sep) + while path_parts and rel_to_parts and path_parts[0] == rel_to_parts[0]: + path_parts.pop(0) + rel_to_parts.pop(0) + full_parts = ['..']*len(rel_to_parts) + path_parts + [path_filename] + if full_parts == ['']: + return '.' + os.path.sep + return os.path.sep.join(full_parts) + + +def normalize_path(path): + """ + Convert a path to its canonical, case-normalized, absolute version. + + """ + return os.path.normcase(os.path.realpath(path)) + + +def splitext(path): + """Like os.path.splitext, but take off .tar too""" + base, ext = posixpath.splitext(path) + if base.lower().endswith('.tar'): + ext = base[-4:] + ext + base = base[:-4] + return base, ext + + +def renames(old, new): + """Like os.renames(), but handles renaming across devices.""" + # Implementation borrowed from os.renames(). + head, tail = os.path.split(new) + if head and tail and not os.path.exists(head): + os.makedirs(head) + + shutil.move(old, new) + + head, tail = os.path.split(old) + if head and tail: + try: + os.removedirs(head) + except OSError: + pass + + +def is_local(path): + """ + Return True if path is within sys.prefix, if we're running in a virtualenv. + + If we're not in a virtualenv, all paths are considered "local." + + """ + if not running_under_virtualenv(): + return True + return normalize_path(path).startswith(normalize_path(sys.prefix)) + + +def dist_is_local(dist): + """ + Return True if given Distribution object is installed locally + (i.e. within current virtualenv). + + Always True if we're not in a virtualenv. + + """ + return is_local(dist_location(dist)) + + +def get_installed_distributions(local_only=True, skip=('setuptools', 'pip', 'python')): + """ + Return a list of installed Distribution objects. + + If ``local_only`` is True (default), only return installations + local to the current virtualenv, if in a virtualenv. + + ``skip`` argument is an iterable of lower-case project names to + ignore; defaults to ('setuptools', 'pip', 'python'). [FIXME also + skip virtualenv?] + + """ + if local_only: + local_test = dist_is_local + else: + local_test = lambda d: True + return [d for d in pkg_resources.working_set if local_test(d) and d.key not in skip] + + +def egg_link_path(dist): + """ + Return the path where we'd expect to find a .egg-link file for + this distribution. (There doesn't seem to be any metadata in the + Distribution object for a develop egg that points back to its + .egg-link and easy-install.pth files). + + This won't find a globally-installed develop egg if we're in a + virtualenv. + + """ + return os.path.join(site_packages, dist.project_name) + '.egg-link' + + +def dist_location(dist): + """ + Get the site-packages location of this distribution. Generally + this is dist.location, except in the case of develop-installed + packages, where dist.location is the source code location, and we + want to know where the egg-link file is. + + """ + egg_link = egg_link_path(dist) + if os.path.exists(egg_link): + return egg_link + return dist.location + + +def get_terminal_size(): + """Returns a tuple (x, y) representing the width(x) and the height(x) + in characters of the terminal window.""" + def ioctl_GWINSZ(fd): + try: + import fcntl + import termios + import struct + cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, + '1234')) + except: + return None + if cr == (0, 0): + return None + if cr == (0, 0): + return None + return cr + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + cr = ioctl_GWINSZ(fd) + os.close(fd) + except: + pass + if not cr: + cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) + return int(cr[1]), int(cr[0]) + + +def unzip_file(filename, location, flatten=True): + """Unzip the file (zip file located at filename) to the destination + location""" + if not os.path.exists(location): + os.makedirs(location) + zipfp = open(filename, 'rb') + try: + zip = zipfile.ZipFile(zipfp) + leading = has_leading_dir(zip.namelist()) and flatten + for name in zip.namelist(): + data = zip.read(name) + fn = name + if leading: + fn = split_leading_dir(name)[1] + fn = os.path.join(location, fn) + dir = os.path.dirname(fn) + if not os.path.exists(dir): + os.makedirs(dir) + if fn.endswith('/') or fn.endswith('\\'): + # A directory + if not os.path.exists(fn): + os.makedirs(fn) + else: + fp = open(fn, 'wb') + try: + fp.write(data) + finally: + fp.close() + finally: + zipfp.close() + + +def untar_file(filename, location): + """Untar the file (tar file located at filename) to the destination location""" + if not os.path.exists(location): + os.makedirs(location) + if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): + mode = 'r:gz' + elif filename.lower().endswith('.bz2') or filename.lower().endswith('.tbz'): + mode = 'r:bz2' + elif filename.lower().endswith('.tar'): + mode = 'r' + else: + logger.warn('Cannot determine compression type for file %s' % filename) + mode = 'r:*' + tar = tarfile.open(filename, mode) + try: + # note: python<=2.5 doesnt seem to know about pax headers, filter them + leading = has_leading_dir([ + member.name for member in tar.getmembers() + if member.name != 'pax_global_header' + ]) + for member in tar.getmembers(): + fn = member.name + if fn == 'pax_global_header': + continue + if leading: + fn = split_leading_dir(fn)[1] + path = os.path.join(location, fn) + if member.isdir(): + if not os.path.exists(path): + os.makedirs(path) + elif member.issym(): + try: + tar._extract_member(member, path) + except: + e = sys.exc_info()[1] + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warn( + 'In the tar file %s the member %s is invalid: %s' + % (filename, member.name, e)) + continue + else: + try: + fp = tar.extractfile(member) + except (KeyError, AttributeError): + e = sys.exc_info()[1] + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warn( + 'In the tar file %s the member %s is invalid: %s' + % (filename, member.name, e)) + continue + if not os.path.exists(os.path.dirname(path)): + os.makedirs(os.path.dirname(path)) + destfp = open(path, 'wb') + try: + shutil.copyfileobj(fp, destfp) + finally: + destfp.close() + fp.close() + finally: + tar.close() + + +def create_download_cache_folder(folder): + logger.indent -= 2 + logger.notify('Creating supposed download cache at %s' % folder) + logger.indent += 2 + os.makedirs(folder) + + +def cache_download(target_file, temp_location, content_type): + logger.notify('Storing download in cache at %s' % display_path(target_file)) + shutil.copyfile(temp_location, target_file) + fp = open(target_file+'.content-type', 'w') + fp.write(content_type) + fp.close() + os.unlink(temp_location) + + +def unpack_file(filename, location, content_type, link): + filename = os.path.realpath(filename) + if (content_type == 'application/zip' + or filename.endswith('.zip') + or filename.endswith('.pybundle') + or zipfile.is_zipfile(filename)): + unzip_file(filename, location, flatten=not filename.endswith('.pybundle')) + elif (content_type == 'application/x-gzip' + or tarfile.is_tarfile(filename) + or splitext(filename)[1].lower() in ('.tar', '.tar.gz', '.tar.bz2', '.tgz', '.tbz')): + untar_file(filename, location) + elif (content_type and content_type.startswith('text/html') + and is_svn_page(file_contents(filename))): + # We don't really care about this + from pip.vcs.subversion import Subversion + Subversion('svn+' + link.url).unpack(location) + else: + ## FIXME: handle? + ## FIXME: magic signatures? + logger.fatal('Cannot unpack file %s (downloaded from %s, content-type: %s); cannot detect archive format' + % (filename, location, content_type)) + raise InstallationError('Cannot determine archive format of %s' % location) + + + diff --git a/vendor/pip-1.2.1/pip/vcs/__init__.py b/vendor/pip-1.2.1/pip/vcs/__init__.py new file mode 100644 index 0000000..a2137e9 --- /dev/null +++ b/vendor/pip-1.2.1/pip/vcs/__init__.py @@ -0,0 +1,244 @@ +"""Handles all VCS (version control) support""" + +import os +import shutil + +from pip.backwardcompat import urlparse, urllib +from pip.log import logger +from pip.util import (display_path, backup_dir, find_command, + ask, rmtree, ask_path_exists) + + +__all__ = ['vcs', 'get_src_requirement'] + + +class VcsSupport(object): + _registry = {} + schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] + + def __init__(self): + # Register more schemes with urlparse for various version control systems + urlparse.uses_netloc.extend(self.schemes) + urlparse.uses_fragment.extend(self.schemes) + super(VcsSupport, self).__init__() + + def __iter__(self): + return self._registry.__iter__() + + @property + def backends(self): + return list(self._registry.values()) + + @property + def dirnames(self): + return [backend.dirname for backend in self.backends] + + @property + def all_schemes(self): + schemes = [] + for backend in self.backends: + schemes.extend(backend.schemes) + return schemes + + def register(self, cls): + if not hasattr(cls, 'name'): + logger.warn('Cannot register VCS %s' % cls.__name__) + return + if cls.name not in self._registry: + self._registry[cls.name] = cls + + def unregister(self, cls=None, name=None): + if name in self._registry: + del self._registry[name] + elif cls in self._registry.values(): + del self._registry[cls.name] + else: + logger.warn('Cannot unregister because no class or name given') + + def get_backend_name(self, location): + """ + Return the name of the version control backend if found at given + location, e.g. vcs.get_backend_name('/path/to/vcs/checkout') + """ + for vc_type in self._registry.values(): + path = os.path.join(location, vc_type.dirname) + if os.path.exists(path): + return vc_type.name + return None + + def get_backend(self, name): + name = name.lower() + if name in self._registry: + return self._registry[name] + + def get_backend_from_location(self, location): + vc_type = self.get_backend_name(location) + if vc_type: + return self.get_backend(vc_type) + return None + + +vcs = VcsSupport() + + +class VersionControl(object): + name = '' + dirname = '' + + def __init__(self, url=None, *args, **kwargs): + self.url = url + self._cmd = None + super(VersionControl, self).__init__(*args, **kwargs) + + def _filter(self, line): + return (logger.INFO, line) + + def _is_local_repository(self, repo): + """ + posix absolute paths start with os.path.sep, + win32 ones ones start with drive (like c:\\folder) + """ + drive, tail = os.path.splitdrive(repo) + return repo.startswith(os.path.sep) or drive + + @property + def cmd(self): + if self._cmd is not None: + return self._cmd + command = find_command(self.name) + logger.info('Found command %r at %r' % (self.name, command)) + self._cmd = command + return command + + def get_url_rev(self): + """ + Returns the correct repository URL and revision by parsing the given + repository URL + """ + url = self.url.split('+', 1)[1] + scheme, netloc, path, query, frag = urlparse.urlsplit(url) + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + url = urlparse.urlunsplit((scheme, netloc, path, query, '')) + return url, rev + + def get_info(self, location): + """ + Returns (url, revision), where both are strings + """ + assert not location.rstrip('/').endswith(self.dirname), 'Bad directory: %s' % location + return self.get_url(location), self.get_revision(location) + + def normalize_url(self, url): + """ + Normalize a URL for comparison by unquoting it and removing any trailing slash. + """ + return urllib.unquote(url).rstrip('/') + + def compare_urls(self, url1, url2): + """ + Compare two repo URLs for identity, ignoring incidental differences. + """ + return (self.normalize_url(url1) == self.normalize_url(url2)) + + def parse_vcs_bundle_file(self, content): + """ + Takes the contents of the bundled text file that explains how to revert + the stripped off version control data of the given package and returns + the URL and revision of it. + """ + raise NotImplementedError + + def obtain(self, dest): + """ + Called when installing or updating an editable package, takes the + source path of the checkout. + """ + raise NotImplementedError + + def switch(self, dest, url, rev_options): + """ + Switch the repo at ``dest`` to point to ``URL``. + """ + raise NotImplemented + + def update(self, dest, rev_options): + """ + Update an already-existing repo to the given ``rev_options``. + """ + raise NotImplementedError + + def check_destination(self, dest, url, rev_options, rev_display): + """ + Prepare a location to receive a checkout/clone. + + Return True if the location is ready for (and requires) a + checkout/clone, False otherwise. + """ + checkout = True + prompt = False + if os.path.exists(dest): + checkout = False + if os.path.exists(os.path.join(dest, self.dirname)): + existing_url = self.get_url(dest) + if self.compare_urls(existing_url, url): + logger.info('%s in %s exists, and has correct URL (%s)' % + (self.repo_name.title(), display_path(dest), + url)) + logger.notify('Updating %s %s%s' % + (display_path(dest), self.repo_name, + rev_display)) + self.update(dest, rev_options) + else: + logger.warn('%s %s in %s exists with URL %s' % + (self.name, self.repo_name, + display_path(dest), existing_url)) + prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', + ('s', 'i', 'w', 'b')) + else: + logger.warn('Directory %s already exists, ' + 'and is not a %s %s.' % + (dest, self.name, self.repo_name)) + prompt = ('(i)gnore, (w)ipe, (b)ackup ', ('i', 'w', 'b')) + if prompt: + logger.warn('The plan is to install the %s repository %s' % + (self.name, url)) + response = ask_path_exists('What to do? %s' % prompt[0], + prompt[1]) + + if response == 's': + logger.notify('Switching %s %s to %s%s' % + (self.repo_name, display_path(dest), url, + rev_display)) + self.switch(dest, url, rev_options) + elif response == 'i': + # do nothing + pass + elif response == 'w': + logger.warn('Deleting %s' % display_path(dest)) + rmtree(dest) + checkout = True + elif response == 'b': + dest_dir = backup_dir(dest) + logger.warn('Backing up %s to %s' + % (display_path(dest), dest_dir)) + shutil.move(dest, dest_dir) + checkout = True + return checkout + + def unpack(self, location): + if os.path.exists(location): + rmtree(location) + self.obtain(location) + + def get_src_requirement(self, dist, location, find_tags=False): + raise NotImplementedError + + +def get_src_requirement(dist, location, find_tags): + version_control = vcs.get_backend_from_location(location) + if version_control: + return version_control().get_src_requirement(dist, location, find_tags) + logger.warn('cannot determine version of editable source in %s (is not SVN checkout, Git clone, Mercurial clone or Bazaar branch)' % location) + return dist.as_requirement() diff --git a/vendor/pip-1.2.1/pip/vcs/bazaar.py b/vendor/pip-1.2.1/pip/vcs/bazaar.py new file mode 100644 index 0000000..5d52777 --- /dev/null +++ b/vendor/pip-1.2.1/pip/vcs/bazaar.py @@ -0,0 +1,129 @@ +import os +import tempfile +import re +from pip import call_subprocess +from pip.backwardcompat import urlparse +from pip.log import logger +from pip.util import rmtree, display_path +from pip.vcs import vcs, VersionControl +from pip.download import path_to_url2 + + +class Bazaar(VersionControl): + name = 'bzr' + dirname = '.bzr' + repo_name = 'branch' + bundle_file = 'bzr-branch.txt' + schemes = ('bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', 'bzr+lp') + guide = ('# This was a Bazaar branch; to make it a branch again run:\n' + 'bzr branch -r %(rev)s %(url)s .\n') + + def __init__(self, url=None, *args, **kwargs): + super(Bazaar, self).__init__(url, *args, **kwargs) + urlparse.non_hierarchical.extend(['lp']) + urlparse.uses_fragment.extend(['lp']) + + def parse_vcs_bundle_file(self, content): + url = rev = None + for line in content.splitlines(): + if not line.strip() or line.strip().startswith('#'): + continue + match = re.search(r'^bzr\s*branch\s*-r\s*(\d*)', line) + if match: + rev = match.group(1).strip() + url = line[match.end():].strip().split(None, 1)[0] + if url and rev: + return url, rev + return None, None + + def export(self, location): + """Export the Bazaar repository at the url to the destination location""" + temp_dir = tempfile.mkdtemp('-export', 'pip-') + self.unpack(temp_dir) + if os.path.exists(location): + # Remove the location to make sure Bazaar can export it correctly + rmtree(location) + try: + call_subprocess([self.cmd, 'export', location], cwd=temp_dir, + filter_stdout=self._filter, show_stdout=False) + finally: + rmtree(temp_dir) + + def switch(self, dest, url, rev_options): + call_subprocess([self.cmd, 'switch', url], cwd=dest) + + def update(self, dest, rev_options): + call_subprocess( + [self.cmd, 'pull', '-q'] + rev_options, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + if rev: + rev_options = ['-r', rev] + rev_display = ' (to revision %s)' % rev + else: + rev_options = [] + rev_display = '' + if self.check_destination(dest, url, rev_options, rev_display): + logger.notify('Checking out %s%s to %s' + % (url, rev_display, display_path(dest))) + call_subprocess( + [self.cmd, 'branch', '-q'] + rev_options + [url, dest]) + + def get_url_rev(self): + # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it + url, rev = super(Bazaar, self).get_url_rev() + if url.startswith('ssh://'): + url = 'bzr+' + url + return url, rev + + def get_url(self, location): + urls = call_subprocess( + [self.cmd, 'info'], show_stdout=False, cwd=location) + for line in urls.splitlines(): + line = line.strip() + for x in ('checkout of branch: ', + 'parent branch: '): + if line.startswith(x): + repo = line.split(x)[1] + if self._is_local_repository(repo): + return path_to_url2(repo) + return repo + return None + + def get_revision(self, location): + revision = call_subprocess( + [self.cmd, 'revno'], show_stdout=False, cwd=location) + return revision.splitlines()[-1] + + def get_tag_revs(self, location): + tags = call_subprocess( + [self.cmd, 'tags'], show_stdout=False, cwd=location) + tag_revs = [] + for line in tags.splitlines(): + tags_match = re.search(r'([.\w-]+)\s*(.*)$', line) + if tags_match: + tag = tags_match.group(1) + rev = tags_match.group(2) + tag_revs.append((rev.strip(), tag.strip())) + return dict(tag_revs) + + def get_src_requirement(self, dist, location, find_tags): + repo = self.get_url(location) + if not repo.lower().startswith('bzr:'): + repo = 'bzr+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev = self.get_revision(location) + tag_revs = self.get_tag_revs(location) + + if current_rev in tag_revs: + # It's a tag + full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev]) + else: + full_egg_name = '%s-dev_r%s' % (dist.egg_name(), current_rev) + return '%s@%s#egg=%s' % (repo, current_rev, full_egg_name) + + +vcs.register(Bazaar) diff --git a/vendor/pip-1.2.1/pip/vcs/git.py b/vendor/pip-1.2.1/pip/vcs/git.py new file mode 100644 index 0000000..ecaf19f --- /dev/null +++ b/vendor/pip-1.2.1/pip/vcs/git.py @@ -0,0 +1,206 @@ +import tempfile +import re +from pip import call_subprocess +from pip.util import display_path, rmtree +from pip.vcs import vcs, VersionControl +from pip.log import logger +from pip.backwardcompat import url2pathname, urlparse +urlsplit = urlparse.urlsplit +urlunsplit = urlparse.urlunsplit + + +class Git(VersionControl): + name = 'git' + dirname = '.git' + repo_name = 'clone' + schemes = ('git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file') + bundle_file = 'git-clone.txt' + guide = ('# This was a Git repo; to make it a repo again run:\n' + 'git init\ngit remote add origin %(url)s -f\ngit checkout %(rev)s\n') + + def __init__(self, url=None, *args, **kwargs): + + # Works around an apparent Git bug + # (see http://article.gmane.org/gmane.comp.version-control.git/146500) + if url: + scheme, netloc, path, query, fragment = urlsplit(url) + if scheme.endswith('file'): + initial_slashes = path[:-len(path.lstrip('/'))] + newpath = initial_slashes + url2pathname(path).replace('\\', '/').lstrip('/') + url = urlunsplit((scheme, netloc, newpath, query, fragment)) + after_plus = scheme.find('+')+1 + url = scheme[:after_plus]+ urlunsplit((scheme[after_plus:], netloc, newpath, query, fragment)) + + super(Git, self).__init__(url, *args, **kwargs) + + def parse_vcs_bundle_file(self, content): + url = rev = None + for line in content.splitlines(): + if not line.strip() or line.strip().startswith('#'): + continue + url_match = re.search(r'git\s*remote\s*add\s*origin(.*)\s*-f', line) + if url_match: + url = url_match.group(1).strip() + rev_match = re.search(r'^git\s*checkout\s*-q\s*(.*)\s*', line) + if rev_match: + rev = rev_match.group(1).strip() + if url and rev: + return url, rev + return None, None + + def export(self, location): + """Export the Git repository at the url to the destination location""" + temp_dir = tempfile.mkdtemp('-export', 'pip-') + self.unpack(temp_dir) + try: + if not location.endswith('/'): + location = location + '/' + call_subprocess( + [self.cmd, 'checkout-index', '-a', '-f', '--prefix', location], + filter_stdout=self._filter, show_stdout=False, cwd=temp_dir) + finally: + rmtree(temp_dir) + + def check_rev_options(self, rev, dest, rev_options): + """Check the revision options before checkout to compensate that tags + and branches may need origin/ as a prefix. + Returns the SHA1 of the branch or tag if found. + """ + revisions = self.get_tag_revs(dest) + revisions.update(self.get_branch_revs(dest)) + + origin_rev = 'origin/%s' % rev + if origin_rev in revisions: + # remote branch + return [revisions[origin_rev]] + elif rev in revisions: + # a local tag or branch name + return [revisions[rev]] + else: + logger.warn("Could not find a tag or branch '%s', assuming commit." % rev) + return rev_options + + def switch(self, dest, url, rev_options): + call_subprocess( + [self.cmd, 'config', 'remote.origin.url', url], cwd=dest) + call_subprocess( + [self.cmd, 'checkout', '-q'] + rev_options, cwd=dest) + + def update(self, dest, rev_options): + # First fetch changes from the default remote + call_subprocess([self.cmd, 'fetch', '-q'], cwd=dest) + # Then reset to wanted revision (maby even origin/master) + if rev_options: + rev_options = self.check_rev_options(rev_options[0], dest, rev_options) + call_subprocess([self.cmd, 'reset', '--hard', '-q'] + rev_options, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + if rev: + rev_options = [rev] + rev_display = ' (to %s)' % rev + else: + rev_options = ['origin/master'] + rev_display = '' + if self.check_destination(dest, url, rev_options, rev_display): + logger.notify('Cloning %s%s to %s' % (url, rev_display, display_path(dest))) + call_subprocess([self.cmd, 'clone', '-q', url, dest]) + if rev: + rev_options = self.check_rev_options(rev, dest, rev_options) + # Only do a checkout if rev_options differs from HEAD + if not self.get_revision(dest).startswith(rev_options[0]): + call_subprocess([self.cmd, 'checkout', '-q'] + rev_options, cwd=dest) + + def get_url(self, location): + url = call_subprocess( + [self.cmd, 'config', 'remote.origin.url'], + show_stdout=False, cwd=location) + return url.strip() + + def get_revision(self, location): + current_rev = call_subprocess( + [self.cmd, 'rev-parse', 'HEAD'], show_stdout=False, cwd=location) + return current_rev.strip() + + def get_tag_revs(self, location): + tags = self._get_all_tag_names(location) + tag_revs = {} + for line in tags.splitlines(): + tag = line.strip() + rev = self._get_revision_from_rev_parse(tag, location) + tag_revs[tag] = rev.strip() + return tag_revs + + def get_branch_revs(self, location): + branches = self._get_all_branch_names(location) + branch_revs = {} + for line in branches.splitlines(): + if '(no branch)' in line: + continue + line = line.split('->')[0].strip() + # actual branch case + branch = "".join(b for b in line.split() if b != '*') + rev = self._get_revision_from_rev_parse(branch, location) + branch_revs[branch] = rev.strip() + return branch_revs + + def get_src_requirement(self, dist, location, find_tags): + repo = self.get_url(location) + if not repo.lower().startswith('git:'): + repo = 'git+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev = self.get_revision(location) + tag_revs = self.get_tag_revs(location) + branch_revs = self.get_branch_revs(location) + + if current_rev in tag_revs: + # It's a tag + full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev]) + elif (current_rev in branch_revs and + branch_revs[current_rev] != 'origin/master'): + # It's the head of a branch + full_egg_name = '%s-%s' % (egg_project_name, + branch_revs[current_rev].replace('origin/', '')) + else: + full_egg_name = '%s-dev' % egg_project_name + + return '%s@%s#egg=%s' % (repo, current_rev, full_egg_name) + + def get_url_rev(self): + """ + Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. + That's required because although they use SSH they sometimes doesn't + work with a ssh:// scheme (e.g. Github). But we need a scheme for + parsing. Hence we remove it again afterwards and return it as a stub. + """ + if not '://' in self.url: + assert not 'file:' in self.url + self.url = self.url.replace('git+', 'git+ssh://') + url, rev = super(Git, self).get_url_rev() + url = url.replace('ssh://', '') + else: + url, rev = super(Git, self).get_url_rev() + + return url, rev + + def _get_all_tag_names(self, location): + return call_subprocess([self.cmd, 'tag', '-l'], + show_stdout=False, + raise_on_returncode=False, + cwd=location) + + def _get_all_branch_names(self, location): + remote_branches = call_subprocess([self.cmd, 'branch', '-r'], + show_stdout=False, cwd=location) + local_branches = call_subprocess([self.cmd, 'branch', '-l'], + show_stdout=False, cwd=location) + return remote_branches + local_branches + + def _get_revision_from_rev_parse(self, name, location): + return call_subprocess([self.cmd, 'rev-parse', name], + show_stdout=False, cwd=location) + + +vcs.register(Git) diff --git a/vendor/pip-1.2.1/pip/vcs/mercurial.py b/vendor/pip-1.2.1/pip/vcs/mercurial.py new file mode 100644 index 0000000..fbafccc --- /dev/null +++ b/vendor/pip-1.2.1/pip/vcs/mercurial.py @@ -0,0 +1,151 @@ +import os +import tempfile +import re +import sys +from pip import call_subprocess +from pip.util import display_path, rmtree +from pip.log import logger +from pip.vcs import vcs, VersionControl +from pip.download import path_to_url2 +from pip.backwardcompat import ConfigParser + + +class Mercurial(VersionControl): + name = 'hg' + dirname = '.hg' + repo_name = 'clone' + schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http') + bundle_file = 'hg-clone.txt' + guide = ('# This was a Mercurial repo; to make it a repo again run:\n' + 'hg init\nhg pull %(url)s\nhg update -r %(rev)s\n') + + def parse_vcs_bundle_file(self, content): + url = rev = None + for line in content.splitlines(): + if not line.strip() or line.strip().startswith('#'): + continue + url_match = re.search(r'hg\s*pull\s*(.*)\s*', line) + if url_match: + url = url_match.group(1).strip() + rev_match = re.search(r'^hg\s*update\s*-r\s*(.*)\s*', line) + if rev_match: + rev = rev_match.group(1).strip() + if url and rev: + return url, rev + return None, None + + def export(self, location): + """Export the Hg repository at the url to the destination location""" + temp_dir = tempfile.mkdtemp('-export', 'pip-') + self.unpack(temp_dir) + try: + call_subprocess( + [self.cmd, 'archive', location], + filter_stdout=self._filter, show_stdout=False, cwd=temp_dir) + finally: + rmtree(temp_dir) + + def switch(self, dest, url, rev_options): + repo_config = os.path.join(dest, self.dirname, 'hgrc') + config = ConfigParser.SafeConfigParser() + try: + config.read(repo_config) + config.set('paths', 'default', url) + config_file = open(repo_config, 'w') + config.write(config_file) + config_file.close() + except (OSError, ConfigParser.NoSectionError): + e = sys.exc_info()[1] + logger.warn( + 'Could not switch Mercurial repository to %s: %s' + % (url, e)) + else: + call_subprocess([self.cmd, 'update', '-q'] + rev_options, cwd=dest) + + def update(self, dest, rev_options): + call_subprocess([self.cmd, 'pull', '-q'], cwd=dest) + call_subprocess( + [self.cmd, 'update', '-q'] + rev_options, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + if rev: + rev_options = [rev] + rev_display = ' (to revision %s)' % rev + else: + rev_options = [] + rev_display = '' + if self.check_destination(dest, url, rev_options, rev_display): + logger.notify('Cloning hg %s%s to %s' + % (url, rev_display, display_path(dest))) + call_subprocess([self.cmd, 'clone', '--noupdate', '-q', url, dest]) + call_subprocess([self.cmd, 'update', '-q'] + rev_options, cwd=dest) + + def get_url(self, location): + url = call_subprocess( + [self.cmd, 'showconfig', 'paths.default'], + show_stdout=False, cwd=location).strip() + if self._is_local_repository(url): + url = path_to_url2(url) + return url.strip() + + def get_tag_revs(self, location): + tags = call_subprocess( + [self.cmd, 'tags'], show_stdout=False, cwd=location) + tag_revs = [] + for line in tags.splitlines(): + tags_match = re.search(r'([\w\d\.-]+)\s*([\d]+):.*$', line) + if tags_match: + tag = tags_match.group(1) + rev = tags_match.group(2) + if "tip" != tag: + tag_revs.append((rev.strip(), tag.strip())) + return dict(tag_revs) + + def get_branch_revs(self, location): + branches = call_subprocess( + [self.cmd, 'branches'], show_stdout=False, cwd=location) + branch_revs = [] + for line in branches.splitlines(): + branches_match = re.search(r'([\w\d\.-]+)\s*([\d]+):.*$', line) + if branches_match: + branch = branches_match.group(1) + rev = branches_match.group(2) + if "default" != branch: + branch_revs.append((rev.strip(), branch.strip())) + return dict(branch_revs) + + def get_revision(self, location): + current_revision = call_subprocess( + [self.cmd, 'parents', '--template={rev}'], + show_stdout=False, cwd=location).strip() + return current_revision + + def get_revision_hash(self, location): + current_rev_hash = call_subprocess( + [self.cmd, 'parents', '--template={node}'], + show_stdout=False, cwd=location).strip() + return current_rev_hash + + def get_src_requirement(self, dist, location, find_tags): + repo = self.get_url(location) + if not repo.lower().startswith('hg:'): + repo = 'hg+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev = self.get_revision(location) + current_rev_hash = self.get_revision_hash(location) + tag_revs = self.get_tag_revs(location) + branch_revs = self.get_branch_revs(location) + if current_rev in tag_revs: + # It's a tag + full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev]) + elif current_rev in branch_revs: + # It's the tip of a branch + full_egg_name = '%s-%s' % (egg_project_name, branch_revs[current_rev]) + else: + full_egg_name = '%s-dev' % egg_project_name + return '%s@%s#egg=%s' % (repo, current_rev_hash, full_egg_name) + +vcs.register(Mercurial) diff --git a/vendor/pip-1.2.1/pip/vcs/subversion.py b/vendor/pip-1.2.1/pip/vcs/subversion.py new file mode 100644 index 0000000..f54eee6 --- /dev/null +++ b/vendor/pip-1.2.1/pip/vcs/subversion.py @@ -0,0 +1,272 @@ +import os +import re +from pip.backwardcompat import urlparse +from pip import call_subprocess, InstallationError +from pip.index import Link +from pip.util import rmtree, display_path +from pip.log import logger +from pip.vcs import vcs, VersionControl + +_svn_xml_url_re = re.compile('url="([^"]+)"') +_svn_rev_re = re.compile('committed-rev="(\d+)"') +_svn_url_re = re.compile(r'URL: (.+)') +_svn_revision_re = re.compile(r'Revision: (.+)') +_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') +_svn_info_xml_url_re = re.compile(r'<url>(.*)</url>') + + +class Subversion(VersionControl): + name = 'svn' + dirname = '.svn' + repo_name = 'checkout' + schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') + bundle_file = 'svn-checkout.txt' + guide = ('# This was an svn checkout; to make it a checkout again run:\n' + 'svn checkout --force -r %(rev)s %(url)s .\n') + + def get_info(self, location): + """Returns (url, revision), where both are strings""" + assert not location.rstrip('/').endswith(self.dirname), 'Bad directory: %s' % location + output = call_subprocess( + [self.cmd, 'info', location], show_stdout=False, extra_environ={'LANG': 'C'}) + match = _svn_url_re.search(output) + if not match: + logger.warn('Cannot determine URL of svn checkout %s' % display_path(location)) + logger.info('Output that cannot be parsed: \n%s' % output) + return None, None + url = match.group(1).strip() + match = _svn_revision_re.search(output) + if not match: + logger.warn('Cannot determine revision of svn checkout %s' % display_path(location)) + logger.info('Output that cannot be parsed: \n%s' % output) + return url, None + return url, match.group(1) + + def parse_vcs_bundle_file(self, content): + for line in content.splitlines(): + if not line.strip() or line.strip().startswith('#'): + continue + match = re.search(r'^-r\s*([^ ])?', line) + if not match: + return None, None + rev = match.group(1) + rest = line[match.end():].strip().split(None, 1)[0] + return rest, rev + return None, None + + def export(self, location): + """Export the svn repository at the url to the destination location""" + url, rev = self.get_url_rev() + rev_options = get_rev_options(url, rev) + logger.notify('Exporting svn repository %s to %s' % (url, location)) + logger.indent += 2 + try: + if os.path.exists(location): + # Subversion doesn't like to check out over an existing directory + # --force fixes this, but was only added in svn 1.5 + rmtree(location) + call_subprocess( + [self.cmd, 'export'] + rev_options + [url, location], + filter_stdout=self._filter, show_stdout=False) + finally: + logger.indent -= 2 + + def switch(self, dest, url, rev_options): + call_subprocess( + [self.cmd, 'switch'] + rev_options + [url, dest]) + + def update(self, dest, rev_options): + call_subprocess( + [self.cmd, 'update'] + rev_options + [dest]) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = get_rev_options(url, rev) + if rev: + rev_display = ' (to revision %s)' % rev + else: + rev_display = '' + if self.check_destination(dest, url, rev_options, rev_display): + logger.notify('Checking out %s%s to %s' + % (url, rev_display, display_path(dest))) + call_subprocess( + [self.cmd, 'checkout', '-q'] + rev_options + [url, dest]) + + def get_location(self, dist, dependency_links): + for url in dependency_links: + egg_fragment = Link(url).egg_fragment + if not egg_fragment: + continue + if '-' in egg_fragment: + ## FIXME: will this work when a package has - in the name? + key = '-'.join(egg_fragment.split('-')[:-1]).lower() + else: + key = egg_fragment + if key == dist.key: + return url.split('#', 1)[0] + return None + + def get_revision(self, location): + """ + Return the maximum revision for all files under a given location + """ + # Note: taken from setuptools.command.egg_info + revision = 0 + + for base, dirs, files in os.walk(location): + if self.dirname not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove(self.dirname) + entries_fn = os.path.join(base, self.dirname, 'entries') + if not os.path.exists(entries_fn): + ## FIXME: should we warn? + continue + + dirurl, localrev = self._get_svn_url_rev(base) + + if base == location: + base_url = dirurl+'/' # save the root url + elif not dirurl or not dirurl.startswith(base_url): + dirs[:] = [] + continue # not part of the same svn tree, skip it + revision = max(revision, localrev) + return revision + + def get_url_rev(self): + # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it + url, rev = super(Subversion, self).get_url_rev() + if url.startswith('ssh://'): + url = 'svn+' + url + return url, rev + + def get_url(self, location): + # In cases where the source is in a subdirectory, not alongside setup.py + # we have to look up in the location until we find a real setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without finding setup.py + logger.warn("Could not find setup.py for directory %s (tried all parent directories)" + % orig_location) + return None + + return self._get_svn_url_rev(location)[0] + + def _get_svn_url_rev(self, location): + f = open(os.path.join(location, self.dirname, 'entries')) + data = f.read() + f.close() + if data.startswith('8') or data.startswith('9') or data.startswith('10'): + data = list(map(str.splitlines, data.split('\n\x0c\n'))) + del data[0][0] # get rid of the '8' + url = data[0][3] + revs = [int(d[9]) for d in data if len(d)>9 and d[9]]+[0] + elif data.startswith('<?xml'): + match = _svn_xml_url_re.search(data) + if not match: + raise ValueError('Badly formatted data: %r' % data) + url = match.group(1) # get repository URL + revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)]+[0] + else: + try: + # subversion >= 1.7 + xml = call_subprocess([self.cmd, 'info', '--xml', location], show_stdout=False) + url = _svn_info_xml_url_re.search(xml).group(1) + revs = [int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml)] + except InstallationError: + url, revs = None, [] + + if revs: + rev = max(revs) + else: + rev = 0 + + return url, rev + + def get_tag_revs(self, svn_tag_url): + stdout = call_subprocess( + [self.cmd, 'ls', '-v', svn_tag_url], show_stdout=False) + results = [] + for line in stdout.splitlines(): + parts = line.split() + rev = int(parts[0]) + tag = parts[-1].strip('/') + results.append((tag, rev)) + return results + + def find_tag_match(self, rev, tag_revs): + best_match_rev = None + best_tag = None + for tag, tag_rev in tag_revs: + if (tag_rev > rev and + (best_match_rev is None or best_match_rev > tag_rev)): + # FIXME: Is best_match > tag_rev really possible? + # or is it a sign something is wacky? + best_match_rev = tag_rev + best_tag = tag + return best_tag + + def get_src_requirement(self, dist, location, find_tags=False): + repo = self.get_url(location) + if repo is None: + return None + parts = repo.split('/') + ## FIXME: why not project name? + egg_project_name = dist.egg_name().split('-', 1)[0] + rev = self.get_revision(location) + if parts[-2] in ('tags', 'tag'): + # It's a tag, perfect! + full_egg_name = '%s-%s' % (egg_project_name, parts[-1]) + elif parts[-2] in ('branches', 'branch'): + # It's a branch :( + full_egg_name = '%s-%s-r%s' % (dist.egg_name(), parts[-1], rev) + elif parts[-1] == 'trunk': + # Trunk :-/ + full_egg_name = '%s-dev_r%s' % (dist.egg_name(), rev) + if find_tags: + tag_url = '/'.join(parts[:-1]) + '/tags' + tag_revs = self.get_tag_revs(tag_url) + match = self.find_tag_match(rev, tag_revs) + if match: + logger.notify('trunk checkout %s seems to be equivalent to tag %s' % match) + repo = '%s/%s' % (tag_url, match) + full_egg_name = '%s-%s' % (egg_project_name, match) + else: + # Don't know what it is + logger.warn('svn URL does not fit normal structure (tags/branches/trunk): %s' % repo) + full_egg_name = '%s-dev_r%s' % (egg_project_name, rev) + return 'svn+%s@%s#egg=%s' % (repo, rev, full_egg_name) + + +def get_rev_options(url, rev): + if rev: + rev_options = ['-r', rev] + else: + rev_options = [] + + r = urlparse.urlsplit(url) + if hasattr(r, 'username'): + # >= Python-2.5 + username, password = r.username, r.password + else: + netloc = r[1] + if '@' in netloc: + auth = netloc.split('@')[0] + if ':' in auth: + username, password = auth.split(':', 1) + else: + username, password = auth, None + else: + username, password = None, None + + if username: + rev_options += ['--username', username] + if password: + rev_options += ['--password', password] + return rev_options + + +vcs.register(Subversion) diff --git a/vendor/pip-1.2.1/setup.cfg b/vendor/pip-1.2.1/setup.cfg new file mode 100644 index 0000000..ce26f6a --- /dev/null +++ b/vendor/pip-1.2.1/setup.cfg @@ -0,0 +1,2 @@ +[nosetests] +where=tests diff --git a/vendor/pip-1.2.1/setup.py b/vendor/pip-1.2.1/setup.py new file mode 100644 index 0000000..3227621 --- /dev/null +++ b/vendor/pip-1.2.1/setup.py @@ -0,0 +1,55 @@ +import sys +import os +from setuptools import setup + +# If you change this version, change it also in docs/conf.py +version = "1.1" + +doc_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "docs") +index_filename = os.path.join(doc_dir, "index.txt") +news_filename = os.path.join(doc_dir, "news.txt") +long_description = """ + +The main website for pip is `www.pip-installer.org +<http://www.pip-installer.org>`_. You can also install +the `in-development version <https://github.com/pypa/pip/tarball/develop#egg=pip-dev>`_ +of pip with ``easy_install pip==dev``. + +""" +f = open(index_filename) +# remove the toctree from sphinx index, as it breaks long_description +parts = f.read().split("split here", 2) +long_description = parts[0] + long_description + parts[2] +f.close() +f = open(news_filename) +long_description += "\n\n" + f.read() +f.close() + +setup(name="pip", + version=version, + description="pip installs packages. Python packages. An easy_install replacement", + long_description=long_description, + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Topic :: Software Development :: Build Tools', + 'Programming Language :: Python :: 2', + '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', + ], + keywords='easy_install distutils setuptools egg virtualenv', + author='The pip developers', + author_email='python-virtualenv@groups.google.com', + url='http://www.pip-installer.org', + license='MIT', + packages=['pip', 'pip.commands', 'pip.vcs'], + entry_points=dict(console_scripts=['pip=pip:main', 'pip-%s=pip:main' % sys.version[:3]]), + test_suite='nose.collector', + tests_require=['nose', 'virtualenv>=1.7', 'scripttest>=1.1.1', 'mock'], + zip_safe=False) diff --git a/vendor/virtualenv-1.8.4/virtualenv_support/__init__.py b/vendor/pip-1.2.1/tests/__init__.py similarity index 100% rename from vendor/virtualenv-1.8.4/virtualenv_support/__init__.py rename to vendor/pip-1.2.1/tests/__init__.py diff --git a/vendor/pip-1.2.1/tests/in dex/FSPkg/FSPkg-0.1dev.tar.gz b/vendor/pip-1.2.1/tests/in dex/FSPkg/FSPkg-0.1dev.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7fa7c10c2398d841d046838fa08b19188951cb90 GIT binary patch literal 1034 zcmV+l1oitLiwFREN#aWY1MQmcZ{ju>$NSoUg+(=SHv!Erf`o*&({{a0-Dq{)Z7;ei z@`#~Uox~R#uH0XLj+0P`D0C`Gwefsjki?IFC6B+h^Mv#3tNYp6Nv&9xHR$)TIr{lg zQy%jR+ja+*=Xrh4!ItgVwta&8^>!;~E)_|2S3<I&yYhXxqm=KkZ{8F>Y$xmE-1vVg zMUA82+5UG2u5bMBI!+(_-vqh;&2Nv+W?dFflS2=Lf1`iLv9$m7G~k2(n;`eUq-rjD zlj*FMHuUrGJ#UBqeYdLrf$N@NtCrqWICB5rXwe6m=x>oCv*4dO;~^g5kS@%%T*N_2 z7fiAw*2yZJQ}o(h1`f!&{>8GMHumV>c0IeQf8X&y|4lGWlL#C4t0dtPvq&VV%2PUc z%Hl8(WO7etRHD+hlpUN%gcdX{=7qM^v)c%nQg31s(NWtBtab-sLy>h<9Lwa8%1O$E z%1o_u#%Wf$q7hb9DqJ+&Ds%HBo&_64TCKm)lf_!Af)h@pWK*UaAKlz`@G1U4^?j(6 z#WRV`Be+va4A0KQQZTIpb(h4wB%PV-AHH+nk%?)LGpT~L+KT$`>GDgGhH}&vOqfo{ z)t!^Mt}Hc{N?Jf8!nm>gm<SpRPGXt0y2>|CwYlsW6TR)ZIGfN|>PNmxDLppY@ZTHy zFyZr%j&9oYYhZlU?%+0kAd%oyX6Jd=Z{L;`vDlO-s|Z4($mkEf2$UJVG7(5JrK5Ag zC4DTWMa8*ZIX=%>s{3(M7&1<A_xmn>|DaNWiwqHsl^ka2MZVjzCT&QUfk>FnkhvRe z)R7r+Zd@<D=J~g<TJ2`*{y(I8poKJ^ECbHsd)ZSD>IH4=-Tztk=KkNYd>iKfMgV;r zH(T|;KI^_v`x$%n@Aa$tw>)_NYlLSlsIT2gpf<MZKTcFv@9etS&h7whJbV3Lz5fj? zs}K5b0$Bf#o2~l4y7<ujb$ot#pf>jD->dHb?Y{5&p#LWLohp*O)p!5QBQry6_bfCf z5glSPD$vSc_3SJxd_9jMk}kFRiNFi`C5dQP=(8byDtLk3nGnbjYfEw7HQ^AGvKbCR zzvTgrA^tSJ7+?N1Mn6BsfOd4_qKL|vD)Xoey5dAllQep)>$M&5%52sD_2s9JKfS*` zz}DZePyeptRrK$Bt_}Kcg4LHlRDJ_MPb>!2^tC}!HEoL@Rr6HeF{}3VJ!sXY5)p8^ zpxhM9|GW?cEM_VQYWs@u|75HFH=ggy+t|PV_bd7zI0K0PHG&b(u`hy0%=-Vo>Y76L z>))xo|My)7_WzA=3fcz%0000000000000000000000000000000QgVx4Nr6VZvapL E0GQk!n*aa+ literal 0 HcmV?d00001 diff --git a/vendor/pip-1.2.1/tests/in dex/FSPkg/index.html b/vendor/pip-1.2.1/tests/in dex/FSPkg/index.html new file mode 100644 index 0000000..cf4f404 --- /dev/null +++ b/vendor/pip-1.2.1/tests/in dex/FSPkg/index.html @@ -0,0 +1,3 @@ +<html><head><title>Links for FSPkg

    Links for FSPkg

    FSPkg-0.1dev.tar.gz
    +Source
    + diff --git a/vendor/pip-1.2.1/tests/in dex/README.txt b/vendor/pip-1.2.1/tests/in dex/README.txt new file mode 100644 index 0000000..d26726f --- /dev/null +++ b/vendor/pip-1.2.1/tests/in dex/README.txt @@ -0,0 +1,2 @@ +This directory has the odd space in its name in order to test urlquoting and +dequoting of file:// scheme index URLs. diff --git a/vendor/pip-1.2.1/tests/local_repos.py b/vendor/pip-1.2.1/tests/local_repos.py new file mode 100644 index 0000000..4a1a171 --- /dev/null +++ b/vendor/pip-1.2.1/tests/local_repos.py @@ -0,0 +1,75 @@ +import os +import subprocess +from pip.vcs import subversion, git, bazaar, mercurial +from pip.backwardcompat import urlretrieve +from tests.test_pip import path_to_url +from tests.pypi_server import PyPIProxy + + +if hasattr(subprocess, "check_call"): + subprocess_call = subprocess.check_call +else: + subprocess_call = subprocess.call + + +def _create_initools_repository(): + subprocess_call('svnadmin create INITools'.split(), cwd=_get_vcs_folder()) + + +def _dump_initools_repository(): + filename, _ = urlretrieve('http://bitbucket.org/hltbra/pip-initools-dump/raw/8b55c908a320/INITools_modified.dump') + initools_folder = os.path.join(_get_vcs_folder(), 'INITools') + devnull = open(os.devnull, 'w') + dump = open(filename) + subprocess_call(['svnadmin', 'load', initools_folder], stdin=dump, stdout=devnull) + dump.close() + devnull.close() + os.remove(filename) + + +def _create_svn_repository_for_initools(): + tests_cache = _get_vcs_folder() + if not os.path.exists(os.path.join(tests_cache, 'INITools')): + _create_initools_repository() + _dump_initools_repository() + + +def _get_vcs_folder(): + folder_name = PyPIProxy.CACHE_PATH + if not os.path.exists(folder_name): + os.mkdir(folder_name) + return folder_name + + +def _get_vcs_and_checkout_url(remote_repository): + tests_cache = _get_vcs_folder() + vcs_classes = {'svn': subversion.Subversion, + 'git': git.Git, + 'bzr': bazaar.Bazaar, + 'hg': mercurial.Mercurial} + default_vcs = 'svn' + if '+' not in remote_repository: + remote_repository = '%s+%s' % (default_vcs, remote_repository) + vcs, repository_path = remote_repository.split('+', 1) + vcs_class = vcs_classes[vcs] + branch = '' + if vcs == 'svn': + branch = os.path.basename(remote_repository) + repository_name = os.path.basename(remote_repository[:-len(branch)-1]) # remove the slash + else: + repository_name = os.path.basename(remote_repository) + + destination_path = os.path.join(tests_cache, repository_name) + if not os.path.exists(destination_path): + vcs_class(remote_repository).obtain(destination_path) + return '%s+%s' % (vcs, path_to_url('/'.join([tests_cache, repository_name, branch]))) + + +def local_checkout(remote_repo): + if remote_repo.startswith('svn'): + _create_svn_repository_for_initools() + return _get_vcs_and_checkout_url(remote_repo) + + +def local_repo(remote_repo): + return local_checkout(remote_repo).split('+', 1)[1] diff --git a/vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/broken.py b/vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/broken.py new file mode 100644 index 0000000..e69de29 diff --git a/vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/setup.py b/vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/setup.py new file mode 100644 index 0000000..989cc2a --- /dev/null +++ b/vendor/pip-1.2.1/tests/packages/BrokenEmitsUTF8/setup.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +from distutils.core import setup +import sys + +class FakeError(Exception): + pass + +if sys.argv[1] == 'install': + if hasattr(sys.stdout, 'buffer'): + sys.stdout.buffer.write('\nThis package prints out UTF-8 stuff like:\n'.encode('utf-8')) + sys.stdout.buffer.write('* return type of ‘main’ is not ‘int’\n'.encode('utf-8')) + sys.stdout.buffer.write('* Björk Guðmundsdóttir [ˈpjœr̥k ˈkvʏðmʏntsˌtoʊhtɪr]'.encode('utf-8')) + else: + pass + sys.stdout.write('\nThis package prints out UTF-8 stuff like:\n') + sys.stdout.write('* return type of \xe2\x80\x98main\xe2\x80\x99 is not \xe2\x80\x98int\xe2\x80\x99\n') + sys.stdout.write('* Bj\xc3\xb6rk Gu\xc3\xb0mundsd\xc3\xb3ttir [\xcb\x88pj\xc5\x93r\xcc\xa5k \xcb\x88kv\xca\x8f\xc3\xb0m\xca\x8fnts\xcb\x8cto\xca\x8aht\xc9\xaar]\n') + + raise FakeError('this package designed to fail on install') + +setup(name='broken', + version='0.2broken', + py_modules=['broken'], + ) diff --git a/vendor/pip-1.2.1/tests/packages/FSPkg/fspkg/__init__.py b/vendor/pip-1.2.1/tests/packages/FSPkg/fspkg/__init__.py new file mode 100644 index 0000000..792d600 --- /dev/null +++ b/vendor/pip-1.2.1/tests/packages/FSPkg/fspkg/__init__.py @@ -0,0 +1 @@ +# diff --git a/vendor/pip-1.2.1/tests/packages/FSPkg/setup.cfg b/vendor/pip-1.2.1/tests/packages/FSPkg/setup.cfg new file mode 100644 index 0000000..01bb954 --- /dev/null +++ b/vendor/pip-1.2.1/tests/packages/FSPkg/setup.cfg @@ -0,0 +1,3 @@ +[egg_info] +tag_build = dev +tag_svn_revision = true diff --git a/vendor/pip-1.2.1/tests/packages/FSPkg/setup.py b/vendor/pip-1.2.1/tests/packages/FSPkg/setup.py new file mode 100644 index 0000000..c94ead9 --- /dev/null +++ b/vendor/pip-1.2.1/tests/packages/FSPkg/setup.py @@ -0,0 +1,25 @@ +from setuptools import setup, find_packages + +version = '0.1' + +setup(name='FSPkg', + version=version, + description="File system test package", + long_description="""\ +File system test package""", + classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers + keywords='pip tests', + author='pip', + author_email='pip@openplans.org', + url='http://pip.openplans.org', + license='', + packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), + include_package_data=True, + zip_safe=False, + install_requires=[ + # -*- Extra requirements: -*- + ], + entry_points=""" + # -*- Entry points: -*- + """, + ) diff --git a/vendor/pip-1.2.1/tests/packages/LineEndings/setup.py b/vendor/pip-1.2.1/tests/packages/LineEndings/setup.py new file mode 100644 index 0000000..d65ccfb --- /dev/null +++ b/vendor/pip-1.2.1/tests/packages/LineEndings/setup.py @@ -0,0 +1,3 @@ +from distutils.core import setup + +setup() diff --git a/vendor/pip-1.2.1/tests/packages/README.txt b/vendor/pip-1.2.1/tests/packages/README.txt new file mode 100644 index 0000000..b6ecde6 --- /dev/null +++ b/vendor/pip-1.2.1/tests/packages/README.txt @@ -0,0 +1,6 @@ +This package exists for testing uninstall-rollback. + +Version 0.2broken has a setup.py crafted to fail on install (and only on +install). If any earlier step would fail (i.e. egg-info-generation), the +already-installed version would never be uninstalled, so uninstall-rollback +would not come into play. diff --git a/vendor/pip-1.2.1/tests/packages/broken-0.1.tar.gz b/vendor/pip-1.2.1/tests/packages/broken-0.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3298fce4e02f29bdfa28fed577be86c49e859bec GIT binary patch literal 407 zcmV;I0cidoiwFqyGUQ4E17dP-Yh`XNFfK7JbYXG;?bgq0gD?~aaL@TGa_a`u8LbKh z4}<+G-E3J|cNk-&Hr?Eekt7cK-_I)6QYbqqE45vw2yE-8)&yv4hfnUoKv|O;pb=)O%$Iy0RGCq?X>@Y z+u)b^-)=+xd$729nvbUu4srDnhjak|000000000000000003~pegWz+1e*XT003F< B!S(a$uJ(MyOM@h91f-A>4@&P9WM-{G^BADr?E%FIF1t!M&1e3#xf1yIm(<#zUf>DAMH_yCg$_@Z=g zxhVX0nr6cAy={E^D2!X2ui1*jf*Y|a`2wthB@+dx61w&0gfvfeRx-&aew(uXr)F1x zC$5cqn2Ep3=G{=W`6Jb$F1VT8cgr5SLAR^-zj{&s*H_cxt88|ck?%_KpmOEgcYUet zqtb`>0hg|(``#ZS=cUT1Xwiz0)Sy~!M+??^tQ`!*P z=gKNs0mEd&m|a?)74BUij}`7jz8GdLjv5x&mOZ7^MR*u;=;7lk+)skeY-h9E8l(vDu8$2}1+qL2yj= zIxX^{ux}cIGQ+N(t((!I^y<9BJNaJy0s)nzAmt;VlzrQ*CzGHXUnN;+UCPR95)6>f5c+Gfi|BUoiKM{?nG; zp=sbNNhFd>azpt0WJi>xezA{RzdnbsEF5Zg3Ku{=ZPjf}nDMmGK z3Cvxp4iVfE%?6Ssu-T4$k}WDU_X6g5jpQj{Vv;?yRExmZLs-D584Q%9VgM(G`6Wb_ zi{WM}u8#o(978Gys9A-Hb0Y}lfnqnJq2k#}$7U_j6^KF^q?qRr6@w3M@X5fr*8@S%fAvd)cNB*z{LjViw6zVoWf@6sHgyFl?)HX~a$(gyn-AYjaP%6XJa@ z);#`u|Eh(lOfik9t7HU&B~}os2GS==I))|CYDRO7hWW7AnWa8NSejiI>u)@g=7rFZ zX-ZRDrn9yT1Zl~aGKkJoVFtKs76h?nVYfnvsW>r+T%cAJ%>s%@)J8+Z6bnRakZD^@ zuw+;1rs^D+U4?WFz%m$5CrRq84P7W+gBeg+#WU~NO!9y@G6m&e$;H5Fmg!ERB){VB MNT&)C8X@bApnJ9Se*gdg literal 0 HcmV?d00001 diff --git a/vendor/pip-1.2.1/tests/packages/pkgwithmpkg-1.0-py2.7-macosx10.7.mpkg.zip b/vendor/pip-1.2.1/tests/packages/pkgwithmpkg-1.0-py2.7-macosx10.7.mpkg.zip new file mode 100644 index 0000000..e69de29 diff --git a/vendor/pip-1.2.1/tests/packages/pkgwithmpkg-1.0.tar.gz b/vendor/pip-1.2.1/tests/packages/pkgwithmpkg-1.0.tar.gz new file mode 100644 index 0000000..e69de29 diff --git a/vendor/pip-1.2.1/tests/path.py b/vendor/pip-1.2.1/tests/path.py new file mode 100644 index 0000000..fc72448 --- /dev/null +++ b/vendor/pip-1.2.1/tests/path.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +# Author: Aziz Köksal +import os +import sys +import shutil + +if sys.version_info >= (3,): + unicode = str + u = str +else: + unicode = unicode + u = lambda s: s.decode('utf-8') + +_base = os.path.supports_unicode_filenames and unicode or str + +from pip.util import rmtree + + +class Path(_base): + """ Models a path in an object oriented way. """ + + sep = os.sep # File system path separator: '/' or '\'. + pathsep = os.pathsep # Separator in the PATH environment variable. + string = _base + + def __new__(cls, *paths): + if len(paths): + return _base.__new__(cls, os.path.join(*paths)) + return _base.__new__(cls) + + def __div__(self, path): + """ Joins this path with another path. """ + """ path_obj / 'bc.d' """ + """ path_obj / path_obj2 """ + return Path(self, path) + + __truediv__ = __div__ + + def __rdiv__(self, path): + """ Joins this path with another path. """ + """ "/home/a" / path_obj """ + return Path(path, self) + + __rtruediv__ = __rdiv__ + + def __idiv__(self, path): + """ Like __div__ but also assigns to the variable. """ + """ path_obj /= 'bc.d' """ + return Path(self, path) + + __itruediv__ = __idiv__ + + def __floordiv__(self, paths): + """ Returns a list of paths prefixed with 'self'. """ + """ '/home/a' // [bc.d, ef.g] -> [/home/a/bc.d, /home/a/ef.g] """ + return [Path(self, path) for path in paths] + + def __sub__(self, path): + """ Makes this path relative to another path. """ + """ path_obj - '/home/a' """ + """ path_obj - path_obj2 """ + return Path(os.path.relpath(self, path)) + + def __rsub__(self, path): + """ Returns path relative to this path. """ + """ "/home/a" - path_obj """ + return Path(os.path.relpath(path, self)) + + def __add__(self, path): + """ Path('/home/a') + 'bc.d' -> '/home/abc.d' """ + return Path(_base(self) + path) + + def __radd__(self, path): + """ '/home/a' + Path('bc.d') -> '/home/abc.d' """ + return Path(path + _base(self)) + + def __repr__(self): + return u("Path(%s)" % _base.__repr__(self)) + + def __hash__(self): + return _base.__hash__(self) + + @property + def name(self): + """ '/home/a/bc.d' -> 'bc.d' """ + return os.path.basename(self) + + @property + def namebase(self): + """ '/home/a/bc.d' -> 'bc' """ + return self.noext.name + + @property + def noext(self): + """ '/home/a/bc.d' -> '/home/a/bc' """ + return Path(os.path.splitext(self)[0]) + + @property + def ext(self): + """ '/home/a/bc.d' -> '.d' """ + return Path(os.path.splitext(self)[1]) + + @property + def abspath(self): + """ './a/bc.d' -> '/home/a/bc.d' """ + return Path(os.path.abspath(self)) + + @property + def realpath(self): + """ Resolves symbolic links. """ + return Path(os.path.realpath(self)) + + @property + def normpath(self): + """ '/home/x/.././a//bc.d' -> '/home/a/bc.d' """ + return Path(os.path.normpath(self)) + + @property + def normcase(self): + """ Deals with case-insensitive filesystems """ + return Path(os.path.normcase(self)) + + @property + def folder(self): + """ Returns the folder of this path. """ + """ '/home/a/bc.d' -> '/home/a' """ + """ '/home/a/' -> '/home/a' """ + """ '/home/a' -> '/home' """ + return Path(os.path.dirname(self)) + + @property + def exists(self): + """ Returns True if the path exists. """ + return os.path.exists(self) + + @property + def atime(self): + """ Returns last accessed time. """ + return os.path.getatime(self) + + @property + def mtime(self): + """ Returns last modified time. """ + return os.path.getmtime(self) + + @property + def ctime(self): + """ Returns last changed time. """ + return os.path.getctime(self) + + @classmethod + def supports_unicode(self): + """ Returns True if the system can handle Unicode file names. """ + return os.path.supports_unicode_filenames() + + def walk(self, **kwargs): + """ Returns a generator that walks through a directory tree. """ + if "followlinks" in kwargs: + from sys import version_info as vi + if vi[0]*10+vi[1] < 26: # Only Python 2.6 or newer supports followlinks + del kwargs["followlinks"] + return os.walk(self, **kwargs) + + def mkdir(self, mode=0x1FF): # 0o777 + """ Creates a directory, if it doesn't exist already. """ + if not self.exists: + os.mkdir(self, mode) + + def makedirs(self, mode=0x1FF): # 0o777 + """ Like mkdir(), but also creates parent directories. """ + if not self.exists: + os.makedirs(self, mode) + + def remove(self): + """ Removes a file. """ + os.remove(self) + rm = remove # Alias. + + def rmdir(self): + """ Removes a directory. """ + return os.rmdir(self) + + def rmtree(self, noerrors=True): + """ Removes a directory tree. Ignores errors by default. """ + return rmtree(self, ignore_errors=noerrors) + + def copy(self, to): + shutil.copy(self, to) + + def copytree(self, to): + """ Copies a directory tree to another path. """ + shutil.copytree(self, to) + + def move(self, to): + """ Moves a file or directory to another path. """ + shutil.move(self, to) + + def rename(self, to): + """ Renames a file or directory. May throw an OSError. """ + os.rename(self, to) + + def renames(self, to): + os.renames(self, to) + + def glob(self, pattern): + from glob import glob + return list(map(Path, glob(_base(self/pattern)))) + +curdir = Path(os.path.curdir) diff --git a/vendor/pip-1.2.1/tests/pypi_server.py b/vendor/pip-1.2.1/tests/pypi_server.py new file mode 100644 index 0000000..e05f944 --- /dev/null +++ b/vendor/pip-1.2.1/tests/pypi_server.py @@ -0,0 +1,129 @@ +import os +import pip.backwardcompat +from pip.backwardcompat import urllib, string_types, b, u, emailmessage + + +urlopen_original = pip.backwardcompat.urllib2.urlopen + + +class CachedResponse(object): + """ + CachedResponse always cache url access and returns the cached response. + It returns an object compatible with ``urllib.addinfourl``, + it means the object is like the result of a call like:: + + >>> response = urllib2.urlopen('http://example.com') + """ + + def __init__(self, url, folder): + self.headers = emailmessage.Message() + self.code = 500 + self.msg = 'Internal Server Error' + # url can be a simple string, or a urllib2.Request object + if isinstance(url, string_types): + self.url = url + else: + self.url = url.get_full_url() + for key, value in url.headers.items(): + self.headers[key] = value + self._body = b('') + self._set_all_fields(folder) + + def _set_all_fields(self, folder): + filename = os.path.join(folder, urllib.quote(self.url, '')) + if not os.path.exists(filename): + self._cache_url(filename) + fp = open(filename, 'rb') + try: + line = fp.readline().strip() + self.code, self.msg = line.split(None, 1) + except ValueError: + raise ValueError('Bad field line: %r' % line) + self.code = int(self.code) + self.msg = u(self.msg) + for line in fp: + if line == b('\n'): + break + key, value = line.split(b(': '), 1) + self.headers[u(key)] = u(value.strip()) + for line in fp: + self._body += line + fp.close() + + def getcode(self): + return self.code + + def geturl(self): + return self.url + + def info(self): + return self.headers + + def read(self, bytes=None): + """ + it can read a chunk of bytes or everything + """ + if bytes: + result = self._body[:bytes] + self._body = self._body[bytes:] + return result + return self._body + + def close(self): + pass + + def _cache_url(self, filepath): + response = urlopen_original(self.url) + fp = open(filepath, 'wb') + # when it uses file:// scheme, code is None and there is no msg attr + # but it has been successfully opened + status = b('%s %s' % (getattr(response, 'code', 200) or 200, getattr(response, 'msg', 'OK'))) + headers = [b('%s: %s' % (key, value)) for key, value in list(response.headers.items())] + body = response.read() + fp.write(b('\n').join([status] + headers + [b(''), body])) + fp.close() + + +class PyPIProxy(object): + + CACHE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tests_cache") + + @classmethod + def setup(cls): + instance = cls() + instance._create_cache_folder() + instance._monkey_patch_urllib2_to_cache_everything() + + def _monkey_patch_urllib2_to_cache_everything(self): + def urlopen(url): + return CachedResponse(url, self.CACHE_PATH) + pip.backwardcompat.urllib2.urlopen = urlopen + + def _create_cache_folder(self): + if not os.path.exists(self.CACHE_PATH): + os.mkdir(self.CACHE_PATH) + + +def assert_equal(a, b): + assert a == b, "\nexpected:\n%r\ngot:\n%r" % (b, a) + + +def test_cache_proxy(): + url = 'http://example.com' + here = os.path.dirname(os.path.abspath(__file__)) + filepath = os.path.join(here, urllib.quote(url, '')) + if os.path.exists(filepath): + os.remove(filepath) + response = pip.backwardcompat.urllib2.urlopen(url) + r = CachedResponse(url, here) + try: + assert_equal(r.code, response.code) + assert_equal(r.msg, response.msg) + assert_equal(r.read(), response.read()) + assert_equal(r.url, response.url) + assert_equal(r.geturl(), response.geturl()) + assert_equal(set(r.headers.keys()), set(response.headers.keys())) + assert_equal(set(r.info().keys()), set(response.info().keys())) + assert_equal(r.headers['content-length'], response.headers['content-length']) + finally: + os.remove(filepath) diff --git a/vendor/pip-1.2.1/tests/test_all_pip.py b/vendor/pip-1.2.1/tests/test_all_pip.py new file mode 100644 index 0000000..f2f1ea1 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_all_pip.py @@ -0,0 +1,118 @@ +import os +import re +import sys +import subprocess +import shutil +from os.path import dirname, abspath + +from pip.backwardcompat import urllib +from pip.util import rmtree + + +src_folder = dirname(dirname(abspath(__file__))) + + +def all_projects(): + data = urllib.urlopen('http://pypi.python.org/simple/').read() + projects = [m.group(1) for m in re.finditer(r'(.+)', data)] + return projects + + +def main(args=None): + if args is None: + args = sys.argv[1:] + if not args: + print('Usage: test_all_pip.py ') + sys.exit(1) + output = os.path.abspath(args[0]) + if not os.path.exists(output): + print('Creating %s' % output) + os.makedirs(output) + pending_fn = os.path.join(output, 'pending.txt') + if not os.path.exists(pending_fn): + print('Downloading pending list') + projects = all_projects() + print('Found %s projects' % len(projects)) + f = open(pending_fn, 'w') + for name in projects: + f.write(name + '\n') + f.close() + print('Starting testing...') + while os.stat(pending_fn).st_size: + _test_packages(output, pending_fn) + print('Finished all pending!') + + +def _test_packages(output, pending_fn): + package = get_last_item(pending_fn) + print('Testing package %s' % package) + dest_dir = os.path.join(output, package) + print('Creating virtualenv in %s' % dest_dir) + create_venv(dest_dir) + print('Uninstalling actual pip') + code = subprocess.check_call([os.path.join(dest_dir, 'bin', 'pip'), + 'uninstall', '-y', 'pip']) + assert not code, 'pip uninstallation failed' + print('Installing development pip') + code = subprocess.check_call([os.path.join(dest_dir, 'bin', 'python'), + 'setup.py', 'install'], + cwd=src_folder) + assert not code, 'pip installation failed' + print('Trying installation of %s' % dest_dir) + code = subprocess.check_call([os.path.join(dest_dir, 'bin', 'pip'), + 'install', package]) + if code: + print('Installation of %s failed' % package) + print('Now checking easy_install...') + create_venv(dest_dir) + code = subprocess.check_call([os.path.join(dest_dir, 'bin', 'easy_install'), + package]) + if code: + print('easy_install also failed') + add_package(os.path.join(output, 'easy-failure.txt'), package) + else: + print('easy_install succeeded') + add_package(os.path.join(output, 'failure.txt'), package) + pop_last_item(pending_fn, package) + else: + print('Installation of %s succeeded' % package) + add_package(os.path.join(output, 'success.txt'), package) + pop_last_item(pending_fn, package) + rmtree(dest_dir) + + +def create_venv(dest_dir): + if os.path.exists(dest_dir): + rmtree(dest_dir) + print('Creating virtualenv in %s' % dest_dir) + code = subprocess.check_call(['virtualenv', '--no-site-packages', dest_dir]) + assert not code, "virtualenv failed" + + +def get_last_item(fn): + f = open(fn, 'r') + lines = f.readlines() + f.close() + return lines[-1].strip() + + +def pop_last_item(fn, line=None): + f = open(fn, 'r') + lines = f.readlines() + f.close() + if line: + assert lines[-1].strip() == line.strip() + lines.pop() + f = open(fn, 'w') + f.writelines(lines) + f.close() + + +def add_package(filename, package): + f = open(filename, 'a') + f.write(package + '\n') + f.close() + + +if __name__ == '__main__': + main() diff --git a/vendor/pip-1.2.1/tests/test_basic.py b/vendor/pip-1.2.1/tests/test_basic.py new file mode 100644 index 0000000..8bdce97 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_basic.py @@ -0,0 +1,603 @@ +import re +import os +import filecmp +import textwrap +import sys +from os.path import abspath, join, curdir, pardir + +from nose import SkipTest +from nose.tools import assert_raises +from mock import patch + +from pip.util import rmtree, find_command +from pip.exceptions import BadCommand + +from tests.test_pip import (here, reset_env, run_pip, pyversion, mkdir, + src_folder, write_file) +from tests.local_repos import local_checkout +from tests.path import Path + + +def test_correct_pip_version(): + """ + Check we are running proper version of pip in run_pip. + """ + reset_env() + + # output is like: + # pip PIPVERSION from PIPDIRECTORY (python PYVERSION) + result = run_pip('--version') + + # compare the directory tree of the invoked pip with that of this source distribution + dir = re.match(r'pip \d(\.[\d])+(\.(pre|post)\d+)? from (.*) \(python \d(.[\d])+\)$', + result.stdout).group(4) + pip_folder = join(src_folder, 'pip') + pip_folder_outputed = join(dir, 'pip') + + diffs = filecmp.dircmp(pip_folder, pip_folder_outputed) + + # If any non-matching .py files exist, we have a problem: run_pip + # is picking up some other version! N.B. if this project acquires + # primary resources other than .py files, this code will need + # maintenance + mismatch_py = [x for x in diffs.left_only + diffs.right_only + diffs.diff_files if x.endswith('.py')] + assert not mismatch_py, 'mismatched source files in %r and %r'% (pip_folder, pip_folder_outputed) + + +def test_pip_second_command_line_interface_works(): + """ + Check if ``pip-`` commands behaves equally + """ + e = reset_env() + result = e.run('pip-%s' % pyversion, 'install', 'INITools==0.2') + egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion + initools_folder = e.site_packages / 'initools' + assert egg_info_folder in result.files_created, str(result) + assert initools_folder in result.files_created, str(result) + + +#def test_distutils_configuration_setting(): +# """ +# Test the distutils-configuration-setting command (which is distinct from other commands). +# """ + #print run_pip('-vv', '--distutils-cfg=easy_install:index_url:http://download.zope.org/ppix/', expect_error=True) + #Script result: python ../../poacheggs.py -E .../poacheggs-tests/test-scratch -vv --distutils-cfg=easy_install:index_url:http://download.zope.org/ppix/ + #-- stdout: -------------------- + #Distutils config .../poacheggs-tests/test-scratch/lib/python.../distutils/distutils.cfg is writable + #Replaced setting index_url + #Updated .../poacheggs-tests/test-scratch/lib/python.../distutils/distutils.cfg + # + #-- updated: ------------------- + # lib/python2.4/distutils/distutils.cfg (346 bytes) + + +def test_install_from_pypi(): + """ + Test installing a package from PyPI. + """ + e = reset_env() + result = run_pip('install', '-vvv', 'INITools==0.2') + egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion + initools_folder = e.site_packages / 'initools' + assert egg_info_folder in result.files_created, str(result) + assert initools_folder in result.files_created, str(result) + + +def test_install_from_mirrors(): + """ + Test installing a package from the PyPI mirrors. + """ + e = reset_env() + result = run_pip('install', '-vvv', '--use-mirrors', '--no-index', 'INITools==0.2') + egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion + initools_folder = e.site_packages / 'initools' + assert egg_info_folder in result.files_created, str(result) + assert initools_folder in result.files_created, str(result) + + +def test_install_from_mirrors_with_specific_mirrors(): + """ + Test installing a package from a specific PyPI mirror. + """ + e = reset_env() + result = run_pip('install', '-vvv', '--use-mirrors', '--mirrors', "http://d.pypi.python.org/", '--no-index', 'INITools==0.2') + egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion + initools_folder = e.site_packages / 'initools' + assert egg_info_folder in result.files_created, str(result) + assert initools_folder in result.files_created, str(result) + + +def test_editable_install(): + """ + Test editable installation. + """ + reset_env() + result = run_pip('install', '-e', 'INITools==0.2', expect_error=True) + assert "--editable=INITools==0.2 should be formatted with svn+URL" in result.stdout + assert len(result.files_created) == 1, result.files_created + assert not result.files_updated, result.files_updated + + +def test_install_editable_from_svn(): + """ + Test checking out from svn. + """ + reset_env() + result = run_pip('install', + '-e', + '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk')) + result.assert_installed('INITools', with_files=['.svn']) + + +def test_download_editable_to_custom_path(): + """ + Test downloading an editable using a relative custom src folder. + """ + reset_env() + mkdir('customdl') + result = run_pip('install', + '-e', + '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), + '--src', + 'customsrc', + '--download', + 'customdl') + customsrc = Path('scratch')/'customsrc'/'initools' + assert customsrc in result.files_created, sorted(result.files_created.keys()) + assert customsrc/'setup.py' in result.files_created, sorted(result.files_created.keys()) + + customdl = Path('scratch')/'customdl'/'initools' + customdl_files_created = [filename for filename in result.files_created + if filename.startswith(customdl)] + assert customdl_files_created + + +def test_editable_no_install_followed_by_no_download(): + """ + Test installing an editable in two steps (first with --no-install, then with --no-download). + """ + reset_env() + + result = run_pip('install', + '-e', + '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), + '--no-install', expect_error=True) + result.assert_installed('INITools', without_egg_link=True, with_files=['.svn']) + + result = run_pip('install', + '-e', + '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), + '--no-download', expect_error=True) + result.assert_installed('INITools', without_files=[curdir, '.svn']) + + +def test_no_install_followed_by_no_download(): + """ + Test installing in two steps (first with --no-install, then with --no-download). + """ + env = reset_env() + + egg_info_folder = env.site_packages/'INITools-0.2-py%s.egg-info' % pyversion + initools_folder = env.site_packages/'initools' + build_dir = env.venv/'build'/'INITools' + + result1 = run_pip('install', 'INITools==0.2', '--no-install', expect_error=True) + assert egg_info_folder not in result1.files_created, str(result1) + assert initools_folder not in result1.files_created, sorted(result1.files_created) + assert build_dir in result1.files_created, result1.files_created + assert build_dir/'INITools.egg-info' in result1.files_created + + result2 = run_pip('install', 'INITools==0.2', '--no-download', expect_error=True) + assert egg_info_folder in result2.files_created, str(result2) + assert initools_folder in result2.files_created, sorted(result2.files_created) + assert build_dir not in result2.files_created + assert build_dir/'INITools.egg-info' not in result2.files_created + + +def test_bad_install_with_no_download(): + """ + Test that --no-download behaves sensibly if the package source can't be found. + """ + reset_env() + result = run_pip('install', 'INITools==0.2', '--no-download', expect_error=True) + assert "perhaps --no-download was used without first running "\ + "an equivalent install with --no-install?" in result.stdout + + +def test_install_dev_version_from_pypi(): + """ + Test using package==dev. + """ + e = reset_env() + result = run_pip('install', 'INITools==dev', expect_error=True) + assert (e.site_packages / 'initools') in result.files_created, str(result.stdout) + + +def test_install_editable_from_git(): + """ + Test cloning from Git. + """ + reset_env() + args = ['install'] + args.extend(['-e', + '%s#egg=pip-test-package' % + local_checkout('git+http://github.com/pypa/pip-test-package.git')]) + result = run_pip(*args, **{"expect_error": True}) + result.assert_installed('pip-test-package', with_files=['.git']) + + +def test_install_editable_from_hg(): + """ + Test cloning from Mercurial. + """ + reset_env() + result = run_pip('install', '-e', + '%s#egg=django-registration' % + local_checkout('hg+http://bitbucket.org/ubernostrum/django-registration'), + expect_error=True) + result.assert_installed('django-registration', with_files=['.hg']) + + +def test_vcs_url_final_slash_normalization(): + """ + Test that presence or absence of final slash in VCS URL is normalized. + """ + reset_env() + result = run_pip('install', '-e', + '%s/#egg=django-registration' % + local_checkout('hg+http://bitbucket.org/ubernostrum/django-registration'), + expect_error=True) + assert 'pip-log.txt' not in result.files_created, result.files_created['pip-log.txt'].bytes + + +def test_install_editable_from_bazaar(): + """ + Test checking out from Bazaar. + """ + reset_env() + result = run_pip('install', '-e', + '%s/@174#egg=django-wikiapp' % + local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1'), + expect_error=True) + result.assert_installed('django-wikiapp', with_files=['.bzr']) + + +def test_vcs_url_urlquote_normalization(): + """ + Test that urlquoted characters are normalized for repo URL comparison. + """ + reset_env() + result = run_pip('install', '-e', + '%s/#egg=django-wikiapp' % + local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1'), + expect_error=True) + assert 'pip-log.txt' not in result.files_created, result.files_created['pip-log.txt'].bytes + + +def test_install_from_local_directory(): + """ + Test installing from a local directory. + """ + env = reset_env() + to_install = abspath(join(here, 'packages', 'FSPkg')) + result = run_pip('install', to_install, expect_error=False) + fspkg_folder = env.site_packages/'fspkg' + egg_info_folder = env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion + assert fspkg_folder in result.files_created, str(result.stdout) + assert egg_info_folder in result.files_created, str(result) + + +def test_install_from_local_directory_with_no_setup_py(): + """ + Test installing from a local directory with no 'setup.py'. + """ + reset_env() + result = run_pip('install', here, expect_error=True) + assert len(result.files_created) == 1, result.files_created + assert 'pip-log.txt' in result.files_created, result.files_created + assert "is not installable. File 'setup.py' not found." in result.stdout + + +def test_install_curdir(): + """ + Test installing current directory ('.'). + """ + env = reset_env() + run_from = abspath(join(here, 'packages', 'FSPkg')) + # Python 2.4 Windows balks if this exists already + egg_info = join(run_from, "FSPkg.egg-info") + if os.path.isdir(egg_info): + rmtree(egg_info) + result = run_pip('install', curdir, cwd=run_from, expect_error=False) + fspkg_folder = env.site_packages/'fspkg' + egg_info_folder = env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion + assert fspkg_folder in result.files_created, str(result.stdout) + assert egg_info_folder in result.files_created, str(result) + + +def test_install_curdir_usersite_fails_in_old_python(): + """ + Test --user option on older Python versions (pre 2.6) fails intelligibly + """ + if sys.version_info >= (2, 6): + raise SkipTest() + reset_env() + run_from = abspath(join(here, 'packages', 'FSPkg')) + result = run_pip('install', '--user', curdir, cwd=run_from, expect_error=True) + assert '--user is only supported in Python version 2.6 and newer' in result.stdout + + +def test_install_curdir_usersite(): + """ + Test installing current directory ('.') into usersite + """ + if sys.version_info < (2, 6): + raise SkipTest() + # FIXME distutils --user option seems to be broken in pypy + if hasattr(sys, "pypy_version_info"): + raise SkipTest() + env = reset_env(use_distribute=True) + run_from = abspath(join(here, 'packages', 'FSPkg')) + result = run_pip('install', '--user', curdir, cwd=run_from, expect_error=False) + fspkg_folder = env.user_site/'fspkg' + egg_info_folder = env.user_site/'FSPkg-0.1dev-py%s.egg-info' % pyversion + assert fspkg_folder in result.files_created, str(result.stdout) + + assert egg_info_folder in result.files_created, str(result) + + +def test_install_subversion_usersite_editable_with_distribute(): + """ + Test installing current directory ('.') into usersite after installing distribute + """ + if sys.version_info < (2, 6): + raise SkipTest() + # FIXME distutils --user option seems to be broken in pypy + if hasattr(sys, "pypy_version_info"): + raise SkipTest() + env = reset_env(use_distribute=True) + (env.lib_path/'no-global-site-packages.txt').rm() # this one reenables user_site + + result = run_pip('install', '--user', '-e', + '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk')) + result.assert_installed('INITools', use_user_site=True) + + +def test_install_subversion_usersite_editable_with_setuptools_fails(): + """ + Test installing current directory ('.') into usersite using setuptools fails + """ + # --user only works on 2.6 or higher + if sys.version_info < (2, 6): + raise SkipTest() + # We don't try to use setuptools for 3.X. + elif sys.version_info >= (3,): + raise SkipTest() + env = reset_env(use_distribute=False) + no_site_packages = env.lib_path/'no-global-site-packages.txt' + if os.path.isfile(no_site_packages): + no_site_packages.rm() # this re-enables user_site + + result = run_pip('install', '--user', '-e', + '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), + expect_error=True) + assert '--user --editable not supported with setuptools, use distribute' in result.stdout + + +def test_install_pardir(): + """ + Test installing parent directory ('..'). + """ + env = reset_env() + run_from = abspath(join(here, 'packages', 'FSPkg', 'fspkg')) + result = run_pip('install', pardir, cwd=run_from, expect_error=False) + fspkg_folder = env.site_packages/'fspkg' + egg_info_folder = env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion + assert fspkg_folder in result.files_created, str(result.stdout) + assert egg_info_folder in result.files_created, str(result) + + +def test_install_global_option(): + """ + Test using global distutils options. + (In particular those that disable the actual install action) + """ + reset_env() + result = run_pip('install', '--global-option=--version', "INITools==0.1") + assert '0.1\n' in result.stdout + + +def test_install_with_pax_header(): + """ + test installing from a tarball with pax header for python<2.6 + """ + reset_env() + run_from = abspath(join(here, 'packages')) + run_pip('install', 'paxpkg.tar.bz2', cwd=run_from) + + +def test_install_using_install_option_and_editable(): + """ + Test installing a tool using -e and --install-option + """ + env = reset_env() + folder = 'script_folder' + mkdir(folder) + url = 'git+git://github.com/pypa/virtualenv' + result = run_pip('install', '-e', '%s#egg=virtualenv' % + local_checkout(url), + '--install-option=--script-dir=%s' % folder) + virtualenv_bin = env.venv/'src'/'virtualenv'/folder/'virtualenv'+env.exe + assert virtualenv_bin in result.files_created + + +def test_install_global_option_using_editable(): + """ + Test using global distutils options, but in an editable installation + """ + reset_env() + url = 'hg+http://bitbucket.org/runeh/anyjson' + result = run_pip('install', '--global-option=--version', + '-e', '%s@0.2.5#egg=anyjson' % + local_checkout(url)) + assert '0.2.5\n' in result.stdout + + +def test_install_package_with_same_name_in_curdir(): + """ + Test installing a package with the same name of a local folder + """ + env = reset_env() + mkdir('mock==0.6') + result = run_pip('install', 'mock==0.6') + egg_folder = env.site_packages / 'mock-0.6.0-py%s.egg-info' % pyversion + assert egg_folder in result.files_created, str(result) + + +mock100_setup_py = textwrap.dedent('''\ + from setuptools import setup + setup(name='mock', + version='100.1')''') + + +def test_install_folder_using_dot_slash(): + """ + Test installing a folder using pip install ./foldername + """ + env = reset_env() + mkdir('mock') + pkg_path = env.scratch_path/'mock' + write_file('setup.py', mock100_setup_py, pkg_path) + result = run_pip('install', './mock') + egg_folder = env.site_packages / 'mock-100.1-py%s.egg-info' % pyversion + assert egg_folder in result.files_created, str(result) + + +def test_install_folder_using_slash_in_the_end(): + r""" + Test installing a folder using pip install foldername/ or foldername\ + """ + env = reset_env() + mkdir('mock') + pkg_path = env.scratch_path/'mock' + write_file('setup.py', mock100_setup_py, pkg_path) + result = run_pip('install', 'mock' + os.path.sep) + egg_folder = env.site_packages / 'mock-100.1-py%s.egg-info' % pyversion + assert egg_folder in result.files_created, str(result) + + +def test_install_folder_using_relative_path(): + """ + Test installing a folder using pip install folder1/folder2 + """ + env = reset_env() + mkdir('initools') + mkdir(Path('initools')/'mock') + pkg_path = env.scratch_path/'initools'/'mock' + write_file('setup.py', mock100_setup_py, pkg_path) + result = run_pip('install', Path('initools')/'mock') + egg_folder = env.site_packages / 'mock-100.1-py%s.egg-info' % pyversion + assert egg_folder in result.files_created, str(result) + + +def test_install_package_which_contains_dev_in_name(): + """ + Test installing package from pypi which contains 'dev' in name + """ + env = reset_env() + result = run_pip('install', 'django-devserver==0.0.4') + devserver_folder = env.site_packages/'devserver' + egg_info_folder = env.site_packages/'django_devserver-0.0.4-py%s.egg-info' % pyversion + assert devserver_folder in result.files_created, str(result.stdout) + assert egg_info_folder in result.files_created, str(result) + + +def test_install_package_with_target(): + """ + Test installing a package using pip install --target + """ + env = reset_env() + target_dir = env.scratch_path/'target' + result = run_pip('install', '-t', target_dir, "initools==0.1") + assert Path('scratch')/'target'/'initools' in result.files_created, str(result) + + +def test_find_command_folder_in_path(): + """ + If a folder named e.g. 'git' is in PATH, and find_command is looking for + the 'git' executable, it should not match the folder, but rather keep + looking. + """ + env = reset_env() + mkdir('path_one') + path_one = env.scratch_path/'path_one' + mkdir(path_one/'foo') + mkdir('path_two') + path_two = env.scratch_path/'path_two' + write_file(path_two/'foo', '# nothing') + found_path = find_command('foo', map(str, [path_one, path_two])) + assert found_path == path_two/'foo' + + +def test_does_not_find_command_because_there_is_no_path(): + """ + Test calling `pip.utils.find_command` when there is no PATH env variable + """ + environ_before = os.environ + os.environ = {} + try: + try: + find_command('anycommand') + except BadCommand: + e = sys.exc_info()[1] + assert e.args == ("Cannot find command 'anycommand'",) + else: + raise AssertionError("`find_command` should raise `BadCommand`") + finally: + os.environ = environ_before + + +@patch('os.pathsep', ':') +@patch('pip.util.get_pathext') +@patch('os.path.isfile') +def test_find_command_trys_all_pathext(mock_isfile, getpath_mock): + """ + If no pathext should check default list of extensions, if file does not + exist. + """ + mock_isfile.return_value = False + + getpath_mock.return_value = os.pathsep.join([".COM", ".EXE"]) + + paths = [os.path.join('path_one', f) for f in ['foo.com', 'foo.exe', 'foo']] + expected = [((p,),) for p in paths] + + assert_raises(BadCommand, find_command, 'foo', 'path_one') + assert mock_isfile.call_args_list == expected, "Actual: %s\nExpected %s" % (mock_isfile.call_args_list, expected) + assert getpath_mock.called, "Should call get_pathext" + + +@patch('os.pathsep', ':') +@patch('pip.util.get_pathext') +@patch('os.path.isfile') +def test_find_command_trys_supplied_pathext(mock_isfile, getpath_mock): + """ + If pathext supplied find_command should use all of its list of extensions to find file. + """ + mock_isfile.return_value = False + getpath_mock.return_value = ".FOO" + + pathext = os.pathsep.join([".RUN", ".CMD"]) + + paths = [os.path.join('path_one', f) for f in ['foo.run', 'foo.cmd', 'foo']] + expected = [((p,),) for p in paths] + + assert_raises(BadCommand, find_command, 'foo', 'path_one', pathext) + assert mock_isfile.call_args_list == expected, "Actual: %s\nExpected %s" % (mock_isfile.call_args_list, expected) + assert not getpath_mock.called, "Should not call get_pathext" diff --git a/vendor/pip-1.2.1/tests/test_bundle.py b/vendor/pip-1.2.1/tests/test_bundle.py new file mode 100644 index 0000000..cf5c563 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_bundle.py @@ -0,0 +1,33 @@ +import zipfile +import textwrap +from os.path import join +from pip.download import path_to_url2 +from tests.test_pip import here, reset_env, run_pip, write_file +from tests.path import Path +from tests.local_repos import local_checkout + + +def test_create_bundle(): + """ + Test making a bundle. We'll grab one package from the filesystem + (the FSPkg dummy package), one from vcs (initools) and one from an + index (pip itself). + + """ + env = reset_env() + fspkg = path_to_url2(Path(here)/'packages'/'FSPkg') + run_pip('install', '-e', fspkg) + pkg_lines = textwrap.dedent('''\ + -e %s + -e %s#egg=initools-dev + pip''' % (fspkg, local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'))) + write_file('bundle-req.txt', pkg_lines) + # Create a bundle in env.scratch_path/ test.pybundle + result = run_pip('bundle', '-r', env.scratch_path/ 'bundle-req.txt', env.scratch_path/ 'test.pybundle') + bundle = result.files_after.get(join('scratch', 'test.pybundle'), None) + assert bundle is not None + + files = zipfile.ZipFile(bundle.full).namelist() + assert 'src/FSPkg/' in files + assert 'src/initools/' in files + assert 'build/pip/' in files diff --git a/vendor/pip-1.2.1/tests/test_cleanup.py b/vendor/pip-1.2.1/tests/test_cleanup.py new file mode 100644 index 0000000..15a0508 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_cleanup.py @@ -0,0 +1,114 @@ +import os +import textwrap +from os.path import abspath, exists, join +from tests.test_pip import (here, reset_env, run_pip, write_file, mkdir) +from tests.local_repos import local_checkout +from tests.path import Path + + +def test_cleanup_after_install_from_pypi(): + """ + Test clean up after installing a package from PyPI. + + """ + env = reset_env() + run_pip('install', 'INITools==0.2', expect_error=True) + build = env.scratch_path/"build" + src = env.scratch_path/"src" + assert not exists(build), "build/ dir still exists: %s" % build + assert not exists(src), "unexpected src/ dir exists: %s" % src + + +def test_cleanup_after_install_editable_from_hg(): + """ + Test clean up after cloning from Mercurial. + + """ + env = reset_env() + run_pip('install', + '-e', + '%s#egg=django-registration' % + local_checkout('hg+http://bitbucket.org/ubernostrum/django-registration'), + expect_error=True) + build = env.venv_path/'build' + src = env.venv_path/'src' + assert not exists(build), "build/ dir still exists: %s" % build + assert exists(src), "expected src/ dir doesn't exist: %s" % src + + +def test_cleanup_after_install_from_local_directory(): + """ + Test clean up after installing from a local directory. + + """ + env = reset_env() + to_install = abspath(join(here, 'packages', 'FSPkg')) + run_pip('install', to_install, expect_error=False) + build = env.venv_path/'build' + src = env.venv_path/'src' + assert not exists(build), "unexpected build/ dir exists: %s" % build + assert not exists(src), "unexpected src/ dir exist: %s" % src + + +def test_cleanup_after_create_bundle(): + """ + Test clean up after making a bundle. Make sure (build|src)-bundle/ dirs are removed but not src/. + + """ + env = reset_env() + # Install an editable to create a src/ dir. + args = ['install'] + args.extend(['-e', + '%s#egg=pip-test-package' % + local_checkout('git+http://github.com/pypa/pip-test-package.git')]) + run_pip(*args) + build = env.venv_path/"build" + src = env.venv_path/"src" + assert not exists(build), "build/ dir still exists: %s" % build + assert exists(src), "expected src/ dir doesn't exist: %s" % src + + # Make the bundle. + fspkg = 'file://%s/FSPkg' %join(here, 'packages') + pkg_lines = textwrap.dedent('''\ + -e %s + -e %s#egg=initools-dev + pip''' % (fspkg, local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'))) + write_file('bundle-req.txt', pkg_lines) + run_pip('bundle', '-r', 'bundle-req.txt', 'test.pybundle') + build_bundle = env.scratch_path/"build-bundle" + src_bundle = env.scratch_path/"src-bundle" + assert not exists(build_bundle), "build-bundle/ dir still exists: %s" % build_bundle + assert not exists(src_bundle), "src-bundle/ dir still exists: %s" % src_bundle + + # Make sure previously created src/ from editable still exists + assert exists(src), "expected src dir doesn't exist: %s" % src + + +def test_no_install_and_download_should_not_leave_build_dir(): + """ + It should remove build/ dir if it was pip that created + """ + env = reset_env() + mkdir('downloaded_packages') + assert not os.path.exists(env.venv_path/'/build') + result = run_pip('install', '--no-install', 'INITools==0.2', '-d', 'downloaded_packages') + assert Path('scratch')/'downloaded_packages/build' not in result.files_created, 'pip should not leave build/ dir' + assert not os.path.exists(env.venv_path/'/build'), "build/ dir should be deleted" + + +def test_download_should_not_delete_existing_build_dir(): + """ + It should not delete build/ if existing before run the command + """ + env = reset_env() + mkdir(env.venv_path/'build') + f = open(env.venv_path/'build'/'somefile.txt', 'w') + f.write('I am not empty!') + f.close() + run_pip('install', '--no-install', 'INITools==0.2', '-d', '.') + f = open(env.venv_path/'build'/'somefile.txt') + content = f.read() + f.close() + assert os.path.exists(env.venv_path/'build'), "build/ should be left if it exists before pip run" + assert content == 'I am not empty!', "it should not affect build/ and its content" + assert ['somefile.txt'] == os.listdir(env.venv_path/'build') diff --git a/vendor/pip-1.2.1/tests/test_compat.py b/vendor/pip-1.2.1/tests/test_compat.py new file mode 100644 index 0000000..611d3f9 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_compat.py @@ -0,0 +1,56 @@ +""" +Tests for compatibility workarounds. + +""" +import os +from tests.test_pip import (here, reset_env, run_pip, pyversion, + assert_all_changes) + + +def test_debian_egg_name_workaround(): + """ + We can uninstall packages installed with the pyversion removed from the + egg-info metadata directory name. + + Refs: + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=618367 + https://bugs.launchpad.net/ubuntu/+source/distribute/+bug/725178 + https://bitbucket.org/ianb/pip/issue/104/pip-uninstall-on-ubuntu-linux + + """ + env = reset_env() + result = run_pip('install', 'INITools==0.2', expect_error=True) + + egg_info = os.path.join( + env.site_packages, "INITools-0.2-py%s.egg-info" % pyversion) + + # Debian only removes pyversion for global installs, not inside a venv + # so even if this test runs on a Debian/Ubuntu system with broken setuptools, + # since our test runs inside a venv we'll still have the normal .egg-info + assert egg_info in result.files_created, "Couldn't find %s" % egg_info + + # The Debian no-pyversion version of the .egg-info + mangled = os.path.join(env.site_packages, "INITools-0.2.egg-info") + assert mangled not in result.files_created, "Found unexpected %s" % mangled + + # Simulate a Debian install by copying the .egg-info to their name for it + full_egg_info = os.path.join(env.root_path, egg_info) + assert os.path.isdir(full_egg_info) + full_mangled = os.path.join(env.root_path, mangled) + os.renames(full_egg_info, full_mangled) + assert os.path.isdir(full_mangled) + + # Try the uninstall and verify that everything is removed. + result2 = run_pip("uninstall", "INITools", "-y") + assert_all_changes(result, result2, [env.venv/'build', 'cache']) + + +def test_setup_py_with_dos_line_endings(): + """ + It doesn't choke on a setup.py file that uses DOS line endings (\\r\\n). + + Refs https://github.com/pypa/pip/issues/237 + """ + reset_env() + to_install = os.path.abspath(os.path.join(here, 'packages', 'LineEndings')) + run_pip('install', to_install, expect_error=False) diff --git a/vendor/pip-1.2.1/tests/test_completion.py b/vendor/pip-1.2.1/tests/test_completion.py new file mode 100644 index 0000000..9381cf1 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_completion.py @@ -0,0 +1,95 @@ +import os +from tests.test_pip import reset_env, run_pip, get_env + + +def test_completion_for_bash(): + """ + Test getting completion for bash shell + """ + reset_env() + bash_completion = """\ +_pip_completion() +{ + COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 ) ) +} +complete -o default -F _pip_completion pip""" + + result = run_pip('completion', '--bash') + assert bash_completion in result.stdout, 'bash completion is wrong' + + +def test_completion_for_zsh(): + """ + Test getting completion for zsh shell + """ + reset_env() + zsh_completion = """\ +function _pip_completion { + local words cword + read -Ac words + read -cn cword + reply=( $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$(( cword-1 )) \\ + PIP_AUTO_COMPLETE=1 $words[1] ) ) +} +compctl -K _pip_completion pip""" + + result = run_pip('completion', '--zsh') + assert zsh_completion in result.stdout, 'zsh completion is wrong' + + +def test_completion_for_unknown_shell(): + """ + Test getting completion for an unknown shell + """ + reset_env() + error_msg = 'error: no such option: --myfooshell' + result = run_pip('completion', '--myfooshell', expect_error=True) + assert error_msg in result.stderr, 'tests for an unknown shell failed' + + +def test_completion_alone(): + """ + Test getting completion for none shell, just pip completion + """ + reset_env() + result = run_pip('completion', expect_error=True) + assert 'ERROR: You must pass --bash or --zsh' in result.stderr,\ + 'completion alone failed -- ' + result.stderr + + +def test_completion_for_un_snippet(): + """ + Test getting completion for ``un`` should return + uninstall and unzip + """ + environ = os.environ.copy() + reset_env(environ) + environ['PIP_AUTO_COMPLETE'] = '1' + environ['COMP_WORDS'] = 'pip un' + environ['COMP_CWORD'] = '1' + env = get_env() + # expect_error is True because autocomplete exists with 1 status code + result = env.run('python', '-c', 'import pip;pip.autocomplete()', + expect_error=True) + assert result.stdout.strip().split() == ['unzip', 'uninstall'],\ + "autocomplete function could not complete ``un`` snippet" + + +def test_completion_for_default_parameters(): + """ + Test getting completion for ``--`` should contain --help + """ + environ = os.environ.copy() + reset_env(environ) + environ['PIP_AUTO_COMPLETE'] = '1' + environ['COMP_WORDS'] = 'pip --' + environ['COMP_CWORD'] = '1' + env = get_env() + # expect_error is True because autocomplete exists with 1 status code + result = env.run('python', '-c', 'import pip;pip.autocomplete()', + expect_error=True) + assert '--help' in result.stdout,\ + "autocomplete function could not complete ``--``" diff --git a/vendor/pip-1.2.1/tests/test_config.py b/vendor/pip-1.2.1/tests/test_config.py new file mode 100644 index 0000000..477f868 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_config.py @@ -0,0 +1,152 @@ +import os +import tempfile +import textwrap +from tests.test_pip import reset_env, run_pip, clear_environ, write_file + + +def test_options_from_env_vars(): + """ + Test if ConfigOptionParser reads env vars (e.g. not using PyPI here) + + """ + environ = clear_environ(os.environ.copy()) + environ['PIP_NO_INDEX'] = '1' + reset_env(environ) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "Ignoring indexes:" in result.stdout, str(result) + assert "DistributionNotFound: No distributions at all found for INITools" in result.stdout + + +def test_command_line_options_override_env_vars(): + """ + Test that command line options override environmental variables. + + """ + environ = clear_environ(os.environ.copy()) + environ['PIP_INDEX_URL'] = 'http://b.pypi.python.org/simple/' + reset_env(environ) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "Getting page http://b.pypi.python.org/simple/INITools" in result.stdout + reset_env(environ) + result = run_pip('install', '-vvv', '--index-url', 'http://download.zope.org/ppix', 'INITools', expect_error=True) + assert "b.pypi.python.org" not in result.stdout + assert "Getting page http://download.zope.org/ppix" in result.stdout + + +def test_env_vars_override_config_file(): + """ + Test that environmental variables override settings in config files. + + """ + fd, config_file = tempfile.mkstemp('-pip.cfg', 'test-') + try: + _test_env_vars_override_config_file(config_file) + finally: + # `os.close` is a workaround for a bug in subprocess + # http://bugs.python.org/issue3210 + os.close(fd) + os.remove(config_file) + + +def _test_env_vars_override_config_file(config_file): + environ = clear_environ(os.environ.copy()) + environ['PIP_CONFIG_FILE'] = config_file # set this to make pip load it + reset_env(environ) + # It's important that we test this particular config value ('no-index') + # because their is/was a bug which only shows up in cases in which + # 'config-item' and 'config_item' hash to the same value modulo the size + # of the config dictionary. + write_file(config_file, textwrap.dedent("""\ + [global] + no-index = 1 + """)) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "DistributionNotFound: No distributions at all found for INITools" in result.stdout + environ['PIP_NO_INDEX'] = '0' + reset_env(environ) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "Successfully installed INITools" in result.stdout + + +def test_command_line_append_flags(): + """ + Test command line flags that append to defaults set by environmental variables. + + """ + environ = clear_environ(os.environ.copy()) + environ['PIP_FIND_LINKS'] = 'http://pypi.pinaxproject.com' + reset_env(environ) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "Analyzing links from page http://pypi.pinaxproject.com" in result.stdout + reset_env(environ) + result = run_pip('install', '-vvv', '--find-links', 'http://example.com', 'INITools', expect_error=True) + assert "Analyzing links from page http://pypi.pinaxproject.com" in result.stdout + assert "Analyzing links from page http://example.com" in result.stdout + + +def test_command_line_appends_correctly(): + """ + Test multiple appending options set by environmental variables. + + """ + environ = clear_environ(os.environ.copy()) + environ['PIP_FIND_LINKS'] = 'http://pypi.pinaxproject.com http://example.com' + reset_env(environ) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + + assert "Analyzing links from page http://pypi.pinaxproject.com" in result.stdout, result.stdout + assert "Analyzing links from page http://example.com" in result.stdout, result.stdout + + +def test_config_file_override_stack(): + """ + Test config files (global, overriding a global config with a + local, overriding all with a command line flag). + + """ + fd, config_file = tempfile.mkstemp('-pip.cfg', 'test-') + try: + _test_config_file_override_stack(config_file) + finally: + # `os.close` is a workaround for a bug in subprocess + # http://bugs.python.org/issue3210 + os.close(fd) + os.remove(config_file) + + +def _test_config_file_override_stack(config_file): + environ = clear_environ(os.environ.copy()) + environ['PIP_CONFIG_FILE'] = config_file # set this to make pip load it + reset_env(environ) + write_file(config_file, textwrap.dedent("""\ + [global] + index-url = http://download.zope.org/ppix + """)) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "Getting page http://download.zope.org/ppix/INITools" in result.stdout + reset_env(environ) + write_file(config_file, textwrap.dedent("""\ + [global] + index-url = http://download.zope.org/ppix + [install] + index-url = http://pypi.appspot.com/ + """)) + result = run_pip('install', '-vvv', 'INITools', expect_error=True) + assert "Getting page http://pypi.appspot.com/INITools" in result.stdout + result = run_pip('install', '-vvv', '--index-url', 'http://pypi.python.org/simple', 'INITools', expect_error=True) + assert "Getting page http://download.zope.org/ppix/INITools" not in result.stdout + assert "Getting page http://pypi.appspot.com/INITools" not in result.stdout + assert "Getting page http://pypi.python.org/simple/INITools" in result.stdout + + +def test_log_file_no_directory(): + """ + Test opening a log file with no directory name. + + """ + from pip.basecommand import open_logfile + fp = open_logfile('testpip.log') + fp.write('can write') + fp.close() + assert os.path.exists(fp.name) + os.remove(fp.name) diff --git a/vendor/pip-1.2.1/tests/test_download.py b/vendor/pip-1.2.1/tests/test_download.py new file mode 100644 index 0000000..5d4923c --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_download.py @@ -0,0 +1,43 @@ +from pip.backwardcompat import any + +import textwrap +from tests.test_pip import reset_env, run_pip, write_file +from tests.path import Path + + +def test_download_if_requested(): + """ + It should download (in the scratch path) and not install if requested. + """ + + env = reset_env() + result = run_pip('install', 'INITools==0.1', '-d', '.', expect_error=True) + assert Path('scratch')/ 'INITools-0.1.tar.gz' in result.files_created + assert env.site_packages/ 'initools' not in result.files_created + + +def test_single_download_from_requirements_file(): + """ + It should support download (in the scratch path) from PyPi from a requirements file + """ + + env = reset_env() + write_file('test-req.txt', textwrap.dedent(""" + INITools==0.1 + """)) + result = run_pip('install', '-r', env.scratch_path/ 'test-req.txt', '-d', '.', expect_error=True) + assert Path('scratch')/ 'INITools-0.1.tar.gz' in result.files_created + assert env.site_packages/ 'initools' not in result.files_created + + +def test_download_should_download_dependencies(): + """ + It should download dependencies (in the scratch path) + """ + + env = reset_env() + result = run_pip('install', 'Paste[openid]==1.7.5.1', '-d', '.', expect_error=True) + assert Path('scratch')/ 'Paste-1.7.5.1.tar.gz' in result.files_created + openid_tarball_prefix = str(Path('scratch')/ 'python-openid-') + assert any(path.startswith(openid_tarball_prefix) for path in result.files_created) + assert env.site_packages/ 'openid' not in result.files_created diff --git a/vendor/pip-1.2.1/tests/test_extras.py b/vendor/pip-1.2.1/tests/test_extras.py new file mode 100644 index 0000000..163893e --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_extras.py @@ -0,0 +1,27 @@ +from os.path import join + +from tests.test_pip import reset_env, run_pip + + +def test_simple_extras_install_from_pypi(): + """ + Test installing a package from PyPI using extras dependency Paste[openid]. + """ + e = reset_env() + result = run_pip('install', 'Paste[openid]==1.7.5.1', expect_stderr=True) + initools_folder = e.site_packages / 'openid' + assert initools_folder in result.files_created, result.files_created + + +def test_no_extras_uninstall(): + """ + No extras dependency gets uninstalled when the root package is uninstalled + """ + env = reset_env() + result = run_pip('install', 'Paste[openid]==1.7.5.1', expect_stderr=True) + assert join(env.site_packages, 'paste') in result.files_created, sorted(result.files_created.keys()) + assert join(env.site_packages, 'openid') in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('uninstall', 'Paste', '-y') + # openid should not be uninstalled + initools_folder = env.site_packages / 'openid' + assert not initools_folder in result2.files_deleted, result.files_deleted diff --git a/vendor/pip-1.2.1/tests/test_file_scheme_index.py b/vendor/pip-1.2.1/tests/test_file_scheme_index.py new file mode 100644 index 0000000..38f6654 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_file_scheme_index.py @@ -0,0 +1,16 @@ +from pip.backwardcompat import urllib +from tests.test_pip import here, reset_env, run_pip, pyversion +from tests.path import Path + +index_url = 'file://' + urllib.quote(str(Path(here).abspath/'in dex').replace('\\', '/')) + + +def test_install(): + """ + Test installing from a local index. + + """ + env = reset_env() + result = run_pip('install', '-vvv', '--index-url', index_url, 'FSPkg', expect_error=False) + assert (env.site_packages/'fspkg') in result.files_created, str(result.stdout) + assert (env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) diff --git a/vendor/pip-1.2.1/tests/test_finder.py b/vendor/pip-1.2.1/tests/test_finder.py new file mode 100644 index 0000000..4c930ed --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_finder.py @@ -0,0 +1,18 @@ +from pip.backwardcompat import urllib + +from pip.req import InstallRequirement +from pip.index import PackageFinder + +from tests.path import Path +from tests.test_pip import here + +find_links = 'file://' + urllib.quote(str(Path(here).abspath/'packages').replace('\\', '/')) + + +def test_no_mpkg(): + """Finder skips zipfiles with "macosx10" in the name.""" + finder = PackageFinder([find_links], []) + req = InstallRequirement.from_line("pkgwithmpkg") + found = finder.find_requirement(req, False) + + assert found.url.endswith("pkgwithmpkg-1.0.tar.gz"), found diff --git a/vendor/pip-1.2.1/tests/test_freeze.py b/vendor/pip-1.2.1/tests/test_freeze.py new file mode 100644 index 0000000..4412c14 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_freeze.py @@ -0,0 +1,241 @@ +import sys +import re +import textwrap +from doctest import OutputChecker, ELLIPSIS +from tests.test_pip import reset_env, run_pip, write_file, get_env, pyversion +from tests.local_repos import local_checkout, local_repo + + +distribute_re = re.compile('^distribute==[0-9.]+\n', re.MULTILINE) + + +def _check_output(result, expected): + checker = OutputChecker() + actual = str(result) + + ## FIXME! The following is a TOTAL hack. For some reason the + ## __str__ result for pkg_resources.Requirement gets downcased on + ## Windows. Since INITools is the only package we're installing + ## in this file with funky case requirements, I'm forcibly + ## upcasing it. You can also normalize everything to lowercase, + ## but then you have to remember to upcase . The right + ## thing to do in the end is probably to find out how to report + ## the proper fully-cased package name in our error message. + if sys.platform == 'win32': + actual = actual.replace('initools', 'INITools') + + # This allows our existing tests to work when run in a context + # with distribute installed. + actual = distribute_re.sub('', actual) + + def banner(msg): + return '\n========== %s ==========\n' % msg + assert checker.check_output(expected, actual, ELLIPSIS), banner('EXPECTED')+expected+banner('ACTUAL')+actual+banner(6*'=') + + +def test_freeze_basic(): + """ + Some tests of freeze, first we have to install some stuff. Note that + the test is a little crude at the end because Python 2.5+ adds egg + info to the standard library, so stuff like wsgiref will show up in + the freezing. (Probably that should be accounted for in pip, but + currently it is not). + + """ + env = reset_env() + write_file('initools-req.txt', textwrap.dedent("""\ + INITools==0.2 + # and something else to test out: + MarkupSafe<=0.12 + """)) + result = run_pip('install', '-r', env.scratch_path/'initools-req.txt') + result = run_pip('freeze', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: pip freeze + -- stdout: -------------------- + INITools==0.2 + MarkupSafe==0.12... + """) + _check_output(result, expected) + + +def test_freeze_svn(): + """Now lets try it with an svn checkout""" + env = reset_env() + result = env.run('svn', 'co', '-r10', + local_repo('svn+http://svn.colorstudy.com/INITools/trunk'), + 'initools-trunk') + result = env.run('python', 'setup.py', 'develop', + cwd=env.scratch_path/ 'initools-trunk', expect_stderr=True) + result = run_pip('freeze', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze + -- stdout: -------------------- + -e %s@10#egg=INITools-0.3.1dev...-dev_r10 + ...""" % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk')) + _check_output(result, expected) + + +def test_freeze_git_clone(): + """ + Test freezing a Git clone. + + """ + env = reset_env() + result = env.run('git', 'clone', local_repo('git+http://github.com/pypa/pip-test-package.git'), 'pip-test-package') + result = env.run('git', 'checkout', '7d654e66c8fa7149c165ddeffa5b56bc06619458', + cwd=env.scratch_path / 'pip-test-package', expect_stderr=True) + result = env.run('python', 'setup.py', 'develop', + cwd=env.scratch_path / 'pip-test-package') + result = run_pip('freeze', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze + -- stdout: -------------------- + -e %s@...#egg=pip_test_package-... + ...""" % local_checkout('git+http://github.com/pypa/pip-test-package.git')) + _check_output(result, expected) + + result = run_pip('freeze', '-f', + '%s#egg=pip_test_package' % local_checkout('git+http://github.com/pypa/pip-test-package.git'), + expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: pip freeze -f %(repo)s#egg=pip_test_package + -- stdout: -------------------- + -f %(repo)s#egg=pip_test_package + -e %(repo)s@...#egg=pip_test_package-dev + ...""" % {'repo': local_checkout('git+http://github.com/pypa/pip-test-package.git')}) + _check_output(result, expected) + + +def test_freeze_mercurial_clone(): + """ + Test freezing a Mercurial clone. + + """ + reset_env() + env = get_env() + result = env.run('hg', 'clone', + '-r', '7bc186caa7dc', + local_repo('hg+http://bitbucket.org/jezdez/django-authority'), + 'django-authority') + result = env.run('python', 'setup.py', 'develop', + cwd=env.scratch_path/'django-authority', expect_stderr=True) + result = run_pip('freeze', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze + -- stdout: -------------------- + -e %s@...#egg=django_authority-... + ...""" % local_checkout('hg+http://bitbucket.org/jezdez/django-authority')) + _check_output(result, expected) + + result = run_pip('freeze', '-f', + '%s#egg=django_authority' % local_checkout('hg+http://bitbucket.org/jezdez/django-authority'), + expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze -f %(repo)s#egg=django_authority + -- stdout: -------------------- + -f %(repo)s#egg=django_authority + -e %(repo)s@...#egg=django_authority-dev + ...""" % {'repo': local_checkout('hg+http://bitbucket.org/jezdez/django-authority')}) + _check_output(result, expected) + + +def test_freeze_bazaar_clone(): + """ + Test freezing a Bazaar clone. + + """ + reset_env() + env = get_env() + result = env.run('bzr', 'checkout', '-r', '174', + local_repo('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1'), + 'django-wikiapp') + result = env.run('python', 'setup.py', 'develop', + cwd=env.scratch_path/'django-wikiapp') + result = run_pip('freeze', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze + -- stdout: -------------------- + -e %s@...#egg=django_wikiapp-... + ...""" % local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1')) + _check_output(result, expected) + + result = run_pip('freeze', '-f', + '%s/#egg=django-wikiapp' % + local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1'), + expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze -f %(repo)s/#egg=django-wikiapp + -- stdout: -------------------- + -f %(repo)s/#egg=django-wikiapp + -e %(repo)s@...#egg=django_wikiapp-... + ...""" % {'repo': + local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1')}) + _check_output(result, expected) + + +def test_freeze_with_local_option(): + """ + Test that wsgiref (from global site-packages) is reported normally, but not with --local. + + """ + reset_env() + result = run_pip('install', 'initools==0.2') + result = run_pip('freeze', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze + -- stdout: -------------------- + INITools==0.2 + wsgiref==... + """) + + # The following check is broken (see + # http://bitbucket.org/ianb/pip/issue/110). For now we are simply + # neutering this test, but if we can't find a way to fix it, + # this whole function should be removed. + + # _check_output(result, expected) + + result = run_pip('freeze', '--local', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: ...pip freeze --local + -- stdout: -------------------- + INITools==0.2 + """) + _check_output(result, expected) + + +def test_freeze_with_requirement_option(): + """ + Test that new requirements are created correctly with --requirement hints + + """ + reset_env() + ignores = textwrap.dedent("""\ + # Unchanged requirements below this line + -r ignore.txt + --requirement ignore.txt + -Z ignore + --always-unzip ignore + -f http://ignore + -i http://ignore + --extra-index-url http://ignore + --find-links http://ignore + --index-url http://ignore + """) + write_file('hint.txt', textwrap.dedent("""\ + INITools==0.1 + NoExist==4.2 + """) + ignores) + result = run_pip('install', 'initools==0.2') + result = run_pip('install', 'MarkupSafe') + result = run_pip('freeze', '--requirement', 'hint.txt', expect_stderr=True) + expected = textwrap.dedent("""\ + Script result: pip freeze --requirement hint.txt + -- stderr: -------------------- + Requirement file contains NoExist==4.2, but that package is not installed + + -- stdout: -------------------- + INITools==0.2 + """) + ignores + "## The following requirements were added by pip --freeze:..." + _check_output(result, expected) diff --git a/vendor/pip-1.2.1/tests/test_help.py b/vendor/pip-1.2.1/tests/test_help.py new file mode 100644 index 0000000..e638963 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_help.py @@ -0,0 +1,66 @@ +from pip.exceptions import CommandError +from pip.commands.help import (HelpCommand, + SUCCESS, + ERROR,) +from mock import Mock +from nose.tools import assert_raises +from tests.test_pip import run_pip, reset_env + + +def test_run_method_should_return_sucess_when_finds_command_name(): + """ + Test HelpCommand.run for existing command + """ + options_mock = Mock() + args = ('freeze',) + help_cmd = HelpCommand() + status = help_cmd.run(options_mock, args) + assert status == SUCCESS + + +def test_run_method_should_return_sucess_when_command_name_not_specified(): + """ + Test HelpCommand.run when there are no args + """ + options_mock = Mock() + args = () + help_cmd = HelpCommand() + status = help_cmd.run(options_mock, args) + assert status == SUCCESS + + +def test_run_method_should_raise_command_error_when_command_does_not_exist(): + """ + Test HelpCommand.run for non-existing command + """ + options_mock = Mock() + args = ('mycommand',) + help_cmd = HelpCommand() + assert_raises(CommandError, help_cmd.run, options_mock, args) + + +def test_help_command_should_exit_status_ok_when_command_exists(): + """ + Test `help` command for existing command + """ + reset_env() + result = run_pip('help', 'freeze') + assert result.returncode == SUCCESS + + +def test_help_command_should_exit_status_ok_when_no_command_is_specified(): + """ + Test `help` command for no command + """ + reset_env() + result = run_pip('help') + assert result.returncode == SUCCESS + + +def test_help_command_should_exit_status_error_when_command_does_not_exist(): + """ + Test `help` command for non-existing command + """ + reset_env() + result = run_pip('help', 'mycommand', expect_error=True) + assert result.returncode == ERROR diff --git a/vendor/pip-1.2.1/tests/test_index.py b/vendor/pip-1.2.1/tests/test_index.py new file mode 100644 index 0000000..6f9d216 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_index.py @@ -0,0 +1,28 @@ +from pip.index import package_to_requirement, HTMLPage + + +def test_package_name_should_be_converted_to_requirement(): + """ + Test that it translates a name like Foo-1.2 to Foo==1.3 + """ + assert package_to_requirement('Foo-1.2') == 'Foo==1.2' + assert package_to_requirement('Foo-dev') == 'Foo==dev' + assert package_to_requirement('Foo') == 'Foo' + + +def test_html_page_should_be_able_to_scrap_rel_links(): + """ + Test scraping page looking for url in href + """ + page = HTMLPage(""" + +
  • + Home Page: + + http://supervisord.org/ +
  • """, "supervisor") + + links = list(page.scraped_rel_links()) + assert len(links) == 1 + assert links[0].url == 'http://supervisord.org/' + diff --git a/vendor/pip-1.2.1/tests/test_pip.py b/vendor/pip-1.2.1/tests/test_pip.py new file mode 100644 index 0000000..17e8f66 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_pip.py @@ -0,0 +1,618 @@ +#!/usr/bin/env python +import os +import sys +import tempfile +import shutil +import glob +import atexit +import textwrap +import site + +from scripttest import TestFileEnvironment, FoundDir +from tests.path import Path, curdir, u +from pip.util import rmtree + +pyversion = sys.version[:3] + +# the directory containing all the tests +here = Path(__file__).abspath.folder + +# the root of this pip source distribution +src_folder = here.folder +download_cache = tempfile.mkdtemp(prefix='pip-test-cache') +site_packages_suffix = site.USER_SITE[len(site.USER_BASE) + 1:] + + +def path_to_url(path): + """ + Convert a path to URI. The path will be made absolute and + will not have quoted path parts. + (adapted from pip.util) + """ + path = os.path.normpath(os.path.abspath(path)) + drive, path = os.path.splitdrive(path) + filepath = path.split(os.path.sep) + url = '/'.join(filepath) + if drive: + return 'file:///' + drive + url + return 'file://' +url + + +def demand_dirs(path): + if not os.path.exists(path): + os.makedirs(path) + + +# Tweak the path so we can find up-to-date pip sources +# (http://bitbucket.org/ianb/pip/issue/98) +sys.path = [src_folder] + sys.path + + +def create_virtualenv(where, distribute=False): + import virtualenv + if sys.version_info[0] > 2: + distribute = True + virtualenv.create_environment( + where, use_distribute=distribute, unzip_setuptools=True) + + return virtualenv.path_locations(where) + + +def relpath(root, other): + """a poor man's os.path.relpath, since we may not have Python 2.6""" + prefix = root+Path.sep + assert other.startswith(prefix) + return Path(other[len(prefix):]) + +if 'PYTHONPATH' in os.environ: + del os.environ['PYTHONPATH'] + + +try: + any +except NameError: + + def any(seq): + for item in seq: + if item: + return True + return False + + +def clear_environ(environ): + return dict(((k, v) for k, v in environ.items() + if not k.lower().startswith('pip_'))) + + +def install_setuptools(env): + easy_install = os.path.join(env.bin_path, 'easy_install') + version = 'setuptools==0.6c11' + if sys.platform != 'win32': + return env.run(easy_install, version) + + tempdir = tempfile.mkdtemp() + try: + for f in glob.glob(easy_install+'*'): + shutil.copy2(f, tempdir) + return env.run(os.path.join(tempdir, 'easy_install'), version) + finally: + rmtree(tempdir) + + +env = None + + +def reset_env(environ=None, use_distribute=None): + global env + # FastTestPipEnv reuses env, not safe if use_distribute specified + if use_distribute is None: + env = FastTestPipEnvironment(environ) + else: + env = TestPipEnvironment(environ, use_distribute=use_distribute) + return env + + +class TestFailure(AssertionError): + """ + + An "assertion" failed during testing. + + """ + pass + + +# +# This cleanup routine prevents the __del__ method that cleans up the tree of +# the last TestPipEnvironment from firing after shutil has already been +# unloaded. It also ensures that FastTestPipEnvironment doesn't leave an +# environment hanging around that might confuse the next test run. +# +def _cleanup(): + global env + del env + rmtree(download_cache, ignore_errors=True) + rmtree(fast_test_env_root, ignore_errors=True) + rmtree(fast_test_env_backup, ignore_errors=True) + +atexit.register(_cleanup) + + +class TestPipResult(object): + + def __init__(self, impl, verbose=False): + self._impl = impl + + if verbose: + print(self.stdout) + if self.stderr: + print('======= stderr ========') + print(self.stderr) + print('=======================') + + def __getattr__(self, attr): + return getattr(self._impl, attr) + + if sys.platform == 'win32': + + @property + def stdout(self): + return self._impl.stdout.replace('\r\n', '\n') + + @property + def stderr(self): + return self._impl.stderr.replace('\r\n', '\n') + + def __str__(self): + return str(self._impl).replace('\r\n', '\n') + else: + # Python doesn't automatically forward __str__ through __getattr__ + + def __str__(self): + return str(self._impl) + + def assert_installed(self, pkg_name, with_files=[], without_files=[], without_egg_link=False, use_user_site=False): + e = self.test_env + + pkg_dir = e.venv/ 'src'/ pkg_name.lower() + + if use_user_site: + egg_link_path = e.user_site / pkg_name + '.egg-link' + else: + egg_link_path = e.site_packages / pkg_name + '.egg-link' + if without_egg_link: + if egg_link_path in self.files_created: + raise TestFailure('unexpected egg link file created: '\ + '%r\n%s' % (egg_link_path, self)) + else: + if not egg_link_path in self.files_created: + raise TestFailure('expected egg link file missing: '\ + '%r\n%s' % (egg_link_path, self)) + + egg_link_file = self.files_created[egg_link_path] + + if not (# FIXME: I don't understand why there's a trailing . here + egg_link_file.bytes.endswith('.') + and egg_link_file.bytes[:-1].strip().endswith(pkg_dir)): + raise TestFailure(textwrap.dedent(u('''\ + Incorrect egg_link file %r + Expected ending: %r + ------- Actual contents ------- + %s + -------------------------------''' % ( + egg_link_file, + pkg_dir + u('\n.'), + egg_link_file.bytes)))) + + if use_user_site: + pth_file = Path.string(e.user_site / 'easy-install.pth') + else: + pth_file = Path.string(e.site_packages / 'easy-install.pth') + + if (pth_file in self.files_updated) == without_egg_link: + raise TestFailure('%r unexpectedly %supdated by install' % ( + pth_file, (not without_egg_link and 'not ' or ''))) + + if (pkg_dir in self.files_created) == (curdir in without_files): + raise TestFailure(textwrap.dedent('''\ + expected package directory %r %sto be created + actually created: + %s + ''') % ( + Path.string(pkg_dir), + (curdir in without_files and 'not ' or ''), + sorted(self.files_created.keys()))) + + for f in with_files: + if not (pkg_dir/f).normpath in self.files_created: + raise TestFailure('Package directory %r missing '\ + 'expected content %f' % (pkg_dir, f)) + + for f in without_files: + if (pkg_dir/f).normpath in self.files_created: + raise TestFailure('Package directory %r has '\ + 'unexpected content %f' % (pkg_dir, f)) + + +class TestPipEnvironment(TestFileEnvironment): + """A specialized TestFileEnvironment for testing pip""" + + # + # Attribute naming convention + # --------------------------- + # + # Instances of this class have many attributes representing paths + # in the filesystem. To keep things straight, absolute paths have + # a name of the form xxxx_path and relative paths have a name that + # does not end in '_path'. + + # The following paths are relative to the root_path, and should be + # treated by clients as instance attributes. The fact that they + # are defined in the class is an implementation detail + + # where we'll create the virtual Python installation for testing + # + # Named with a leading dot to reduce the chance of spurious + # results due to being mistaken for the virtualenv package. + venv = Path('.virtualenv') + + # The root of a directory tree to be used arbitrarily by tests + scratch = Path('scratch') + + exe = sys.platform == 'win32' and '.exe' or '' + + verbose = False + + def __init__(self, environ=None, use_distribute=None): + + self.root_path = Path(tempfile.mkdtemp('-piptest')) + + # We will set up a virtual environment at root_path. + self.scratch_path = self.root_path / self.scratch + + self.venv_path = self.root_path / self.venv + + if not environ: + environ = os.environ.copy() + environ = clear_environ(environ) + environ['PIP_DOWNLOAD_CACHE'] = str(download_cache) + + environ['PIP_NO_INPUT'] = '1' + environ['PIP_LOG_FILE'] = str(self.root_path/'pip-log.txt') + + super(TestPipEnvironment, self).__init__( + self.root_path, ignore_hidden=False, + environ=environ, split_cmd=False, start_clear=False, + cwd=self.scratch_path, capture_temp=True, assert_no_temp=True) + + demand_dirs(self.venv_path) + demand_dirs(self.scratch_path) + + if use_distribute is None: + use_distribute = os.environ.get('PIP_TEST_USE_DISTRIBUTE', False) + self.use_distribute = use_distribute + + # Create a virtualenv and remember where it's putting things. + virtualenv_paths = create_virtualenv(self.venv_path, distribute=self.use_distribute) + + assert self.venv_path == virtualenv_paths[0] # sanity check + + for id, path in zip(('venv', 'lib', 'include', 'bin'), virtualenv_paths): + setattr(self, id+'_path', Path(path)) + setattr(self, id, relpath(self.root_path, path)) + + assert self.venv == TestPipEnvironment.venv # sanity check + + self.site_packages = self.lib/'site-packages' + self.user_base_path = self.venv_path/'user' + self.user_site_path = self.venv_path/'user'/site_packages_suffix + + self.user_site = relpath(self.root_path, self.user_site_path) + demand_dirs(self.user_site_path) + self.environ["PYTHONUSERBASE"] = self.user_base_path + + # create easy-install.pth in user_site, so we always have it updated instead of created + open(self.user_site_path/'easy-install.pth', 'w').close() + + # put the test-scratch virtualenv's bin dir first on the PATH + self.environ['PATH'] = Path.pathsep.join((self.bin_path, self.environ['PATH'])) + + # test that test-scratch virtualenv creation produced sensible venv python + result = self.run('python', '-c', 'import sys; print(sys.executable)') + pythonbin = result.stdout.strip() + + if Path(pythonbin).noext != self.bin_path/'python': + raise RuntimeError( + "Oops! 'python' in our test environment runs %r" + " rather than expected %r" % (pythonbin, self.bin_path/'python')) + + # make sure we have current setuptools to avoid svn incompatibilities + if not self.use_distribute: + install_setuptools(self) + + # Uninstall whatever version of pip came with the virtualenv. + # Earlier versions of pip were incapable of + # self-uninstallation on Windows, so we use the one we're testing. + self.run('python', '-c', + '"import sys; sys.path.insert(0, %r); import pip; sys.exit(pip.main());"' % os.path.dirname(here), + 'uninstall', '-vvv', '-y', 'pip') + + # Install this version instead + self.run('python', 'setup.py', 'install', cwd=src_folder, expect_stderr=True) + self._use_cached_pypi_server() + + def _ignore_file(self, fn): + if fn.endswith('__pycache__') or fn.endswith(".pyc"): + result = True + else: + result = super(TestPipEnvironment, self)._ignore_file(fn) + return result + + def run(self, *args, **kw): + if self.verbose: + print('>> running %s %s' % (args, kw)) + cwd = kw.pop('cwd', None) + run_from = kw.pop('run_from', None) + assert not cwd or not run_from, "Don't use run_from; it's going away" + cwd = Path.string(cwd or run_from or self.cwd) + assert not isinstance(cwd, Path) + return TestPipResult(super(TestPipEnvironment, self).run(cwd=cwd, *args, **kw), verbose=self.verbose) + + def __del__(self): + rmtree(str(self.root_path), ignore_errors=True) + + def _use_cached_pypi_server(self): + site_packages = self.root_path / self.site_packages + pth = open(os.path.join(site_packages, 'pypi_intercept.pth'), 'w') + pth.write('import sys; ') + pth.write('sys.path.insert(0, %r); ' % str(here)) + pth.write('import pypi_server; pypi_server.PyPIProxy.setup(); ') + pth.write('sys.path.remove(%r); ' % str(here)) + pth.close() + + +fast_test_env_root = here / 'tests_cache' / 'test_ws' +fast_test_env_backup = here / 'tests_cache' / 'test_ws_backup' + + +class FastTestPipEnvironment(TestPipEnvironment): + def __init__(self, environ=None): + import virtualenv + + self.root_path = fast_test_env_root + self.backup_path = fast_test_env_backup + + self.scratch_path = self.root_path / self.scratch + + # We will set up a virtual environment at root_path. + self.venv_path = self.root_path / self.venv + + if not environ: + environ = os.environ.copy() + environ = clear_environ(environ) + environ['PIP_DOWNLOAD_CACHE'] = str(download_cache) + + environ['PIP_NO_INPUT'] = '1' + environ['PIP_LOG_FILE'] = str(self.root_path/'pip-log.txt') + + TestFileEnvironment.__init__(self, + self.root_path, ignore_hidden=False, + environ=environ, split_cmd=False, start_clear=False, + cwd=self.scratch_path, capture_temp=True, assert_no_temp=True) + + virtualenv_paths = virtualenv.path_locations(self.venv_path) + + for id, path in zip(('venv', 'lib', 'include', 'bin'), virtualenv_paths): + setattr(self, id+'_path', Path(path)) + setattr(self, id, relpath(self.root_path, path)) + + assert self.venv == TestPipEnvironment.venv # sanity check + + self.site_packages = self.lib/'site-packages' + self.user_base_path = self.venv_path/'user' + self.user_site_path = self.venv_path/'user'/'lib'/self.lib.name/'site-packages' + + self.user_site = relpath(self.root_path, self.user_site_path) + + self.environ["PYTHONUSERBASE"] = self.user_base_path + + # put the test-scratch virtualenv's bin dir first on the PATH + self.environ['PATH'] = Path.pathsep.join((self.bin_path, self.environ['PATH'])) + + self.use_distribute = os.environ.get('PIP_TEST_USE_DISTRIBUTE', False) + + if self.root_path.exists: + rmtree(self.root_path) + if self.backup_path.exists: + shutil.copytree(self.backup_path, self.root_path, True) + else: + demand_dirs(self.venv_path) + demand_dirs(self.scratch_path) + + # Create a virtualenv and remember where it's putting things. + create_virtualenv(self.venv_path, distribute=self.use_distribute) + + demand_dirs(self.user_site_path) + + # create easy-install.pth in user_site, so we always have it updated instead of created + open(self.user_site_path/'easy-install.pth', 'w').close() + + # test that test-scratch virtualenv creation produced sensible venv python + result = self.run('python', '-c', 'import sys; print(sys.executable)') + pythonbin = result.stdout.strip() + + if Path(pythonbin).noext != self.bin_path/'python': + raise RuntimeError( + "Oops! 'python' in our test environment runs %r" + " rather than expected %r" % (pythonbin, self.bin_path/'python')) + + # make sure we have current setuptools to avoid svn incompatibilities + if not self.use_distribute: + install_setuptools(self) + + # Uninstall whatever version of pip came with the virtualenv. + # Earlier versions of pip were incapable of + # self-uninstallation on Windows, so we use the one we're testing. + self.run('python', '-c', + '"import sys; sys.path.insert(0, %r); import pip; sys.exit(pip.main());"' % os.path.dirname(here), + 'uninstall', '-vvv', '-y', 'pip') + + # Install this version instead + self.run('python', 'setup.py', 'install', cwd=src_folder, expect_stderr=True) + shutil.copytree(self.root_path, self.backup_path, True) + self._use_cached_pypi_server() + assert self.root_path.exists + + def __del__(self): + pass # shutil.rmtree(str(self.root_path), ignore_errors=True) + + +def run_pip(*args, **kw): + result = env.run('pip', *args, **kw) + ignore = [] + for path, f in result.files_before.items(): + # ignore updated directories, often due to .pyc or __pycache__ + if (path in result.files_updated and + isinstance(result.files_updated[path], FoundDir)): + ignore.append(path) + for path in ignore: + del result.files_updated[path] + return result + + +def write_file(filename, text, dest=None): + """Write a file in the dest (default=env.scratch_path) + + """ + env = get_env() + if dest: + complete_path = dest/ filename + else: + complete_path = env.scratch_path/ filename + f = open(complete_path, 'w') + f.write(text) + f.close() + + +def mkdir(dirname): + os.mkdir(os.path.join(get_env().scratch_path, dirname)) + + +def get_env(): + if env is None: + reset_env() + return env + + +# FIXME ScriptTest does something similar, but only within a single +# ProcResult; this generalizes it so states can be compared across +# multiple commands. Maybe should be rolled into ScriptTest? +def diff_states(start, end, ignore=None): + """ + Differences two "filesystem states" as represented by dictionaries + of FoundFile and FoundDir objects. + + Returns a dictionary with following keys: + + ``deleted`` + Dictionary of files/directories found only in the start state. + + ``created`` + Dictionary of files/directories found only in the end state. + + ``updated`` + Dictionary of files whose size has changed (FIXME not entirely + reliable, but comparing contents is not possible because + FoundFile.bytes is lazy, and comparing mtime doesn't help if + we want to know if a file has been returned to its earlier + state). + + Ignores mtime and other file attributes; only presence/absence and + size are considered. + + """ + ignore = ignore or [] + + def prefix_match(path, prefix): + if path == prefix: + return True + prefix = prefix.rstrip(os.path.sep) + os.path.sep + return path.startswith(prefix) + + start_keys = set([k for k in start.keys() + if not any([prefix_match(k, i) for i in ignore])]) + end_keys = set([k for k in end.keys() + if not any([prefix_match(k, i) for i in ignore])]) + deleted = dict([(k, start[k]) for k in start_keys.difference(end_keys)]) + created = dict([(k, end[k]) for k in end_keys.difference(start_keys)]) + updated = {} + for k in start_keys.intersection(end_keys): + if (start[k].size != end[k].size): + updated[k] = end[k] + return dict(deleted=deleted, created=created, updated=updated) + + +def assert_all_changes(start_state, end_state, expected_changes): + """ + Fails if anything changed that isn't listed in the + expected_changes. + + start_state is either a dict mapping paths to + scripttest.[FoundFile|FoundDir] objects or a TestPipResult whose + files_before we'll test. end_state is either a similar dict or a + TestPipResult whose files_after we'll test. + + Note: listing a directory means anything below + that directory can be expected to have changed. + """ + start_files = start_state + end_files = end_state + if isinstance(start_state, TestPipResult): + start_files = start_state.files_before + if isinstance(end_state, TestPipResult): + end_files = end_state.files_after + + diff = diff_states(start_files, end_files, ignore=expected_changes) + if list(diff.values()) != [{}, {}, {}]: + raise TestFailure('Unexpected changes:\n' + '\n'.join( + [k + ': ' + ', '.join(v.keys()) for k, v in diff.items()])) + + # Don't throw away this potentially useful information + return diff + + +def _create_test_package(env): + mkdir('version_pkg') + version_pkg_path = env.scratch_path/'version_pkg' + write_file('version_pkg.py', textwrap.dedent('''\ + def main(): + print('0.1') + '''), version_pkg_path) + write_file('setup.py', textwrap.dedent('''\ + from setuptools import setup, find_packages + setup(name='version_pkg', + version='0.1', + packages=find_packages(), + py_modules=['version_pkg'], + entry_points=dict(console_scripts=['version_pkg=version_pkg:main'])) + '''), version_pkg_path) + env.run('git', 'init', cwd=version_pkg_path) + env.run('git', 'add', '.', cwd=version_pkg_path) + env.run('git', 'commit', '-q', + '--author', 'Pip ', + '-am', 'initial version', cwd=version_pkg_path) + return version_pkg_path + + +def _change_test_package_version(env, version_pkg_path): + write_file('version_pkg.py', textwrap.dedent('''\ + def main(): + print("some different version")'''), version_pkg_path) + env.run('git', 'commit', '-q', + '--author', 'Pip ', + '-am', 'messed version', + cwd=version_pkg_path, expect_stderr=True) + + +if __name__ == '__main__': + sys.stderr.write("Run pip's tests using nosetests. Requires virtualenv, ScriptTest, and nose.\n") + sys.exit(1) diff --git a/vendor/pip-1.2.1/tests/test_proxy.py b/vendor/pip-1.2.1/tests/test_proxy.py new file mode 100644 index 0000000..fe6e551 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_proxy.py @@ -0,0 +1,64 @@ +""" +Tests for the proxy support in pip. + +TODO shouldn't need to hack sys.path in here. + +""" + +import os +import sys +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + +import os +import pip +import getpass +from pip.basecommand import get_proxy +from tests.test_pip import here + + +def new_getpass(prompt, answer='passwd'): + print('%s%s' % (prompt, answer)) + return answer + + +def test_correct_pip_version(): + """ + Check we are importing pip from the right place. + + """ + base = os.path.dirname(here) + assert pip.__file__.startswith(base), pip.__file__ + + +def test_remove_proxy(): + """ + Test removing proxy from environ. + + """ + if 'HTTP_PROXY' in os.environ: + del os.environ['HTTP_PROXY'] + assert get_proxy() == None + os.environ['HTTP_PROXY'] = 'user:pwd@server.com:port' + assert get_proxy() == 'user:pwd@server.com:port' + del os.environ['HTTP_PROXY'] + assert get_proxy('server.com') == 'server.com' + assert get_proxy('server.com:80') == 'server.com:80' + assert get_proxy('user:passwd@server.com:3128') == 'user:passwd@server.com:3128' + + +def test_get_proxy(): + """ + Test get_proxy returns correct proxy info. + + """ + # monkeypatch getpass.getpass, to avoid asking for a password + old_getpass = getpass.getpass + getpass.getpass = new_getpass + + # Test it: + assert get_proxy('user:@server.com:3128') == 'user:@server.com:3128' + assert get_proxy('user@server.com:3128') == 'user:passwd@server.com:3128' + + # Undo monkeypatch + getpass.getpass = old_getpass + diff --git a/vendor/pip-1.2.1/tests/test_requirements.py b/vendor/pip-1.2.1/tests/test_requirements.py new file mode 100644 index 0000000..59e1347 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_requirements.py @@ -0,0 +1,108 @@ +import os.path +import textwrap +from pip.backwardcompat import urllib +from pip.req import Requirements +from tests.test_pip import reset_env, run_pip, write_file, pyversion, here, path_to_url +from tests.local_repos import local_checkout +from tests.path import Path + + +def test_requirements_file(): + """ + Test installing from a requirements file. + + """ + other_lib_name, other_lib_version = 'anyjson', '0.3' + env = reset_env() + write_file('initools-req.txt', textwrap.dedent("""\ + INITools==0.2 + # and something else to test out: + %s<=%s + """ % (other_lib_name, other_lib_version))) + result = run_pip('install', '-r', env.scratch_path / 'initools-req.txt') + assert env.site_packages/'INITools-0.2-py%s.egg-info' % pyversion in result.files_created + assert env.site_packages/'initools' in result.files_created + assert result.files_created[env.site_packages/other_lib_name].dir + fn = '%s-%s-py%s.egg-info' % (other_lib_name, other_lib_version, pyversion) + assert result.files_created[env.site_packages/fn].dir + + +def test_relative_requirements_file(): + """ + Test installing from a requirements file with a relative path with an egg= definition.. + + """ + url = path_to_url(os.path.join(here, 'packages', '..', 'packages', 'FSPkg')) + '#egg=FSPkg' + env = reset_env() + write_file('file-egg-req.txt', textwrap.dedent("""\ + %s + """ % url)) + result = run_pip('install', '-vvv', '-r', env.scratch_path / 'file-egg-req.txt') + assert (env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion) in result.files_created, str(result) + assert (env.site_packages/'fspkg') in result.files_created, str(result.stdout) + + +def test_multiple_requirements_files(): + """ + Test installing from multiple nested requirements files. + + """ + other_lib_name, other_lib_version = 'anyjson', '0.3' + env = reset_env() + write_file('initools-req.txt', textwrap.dedent("""\ + -e %s@10#egg=INITools-dev + -r %s-req.txt""" % (local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), + other_lib_name))) + write_file('%s-req.txt' % other_lib_name, textwrap.dedent("""\ + %s<=%s + """ % (other_lib_name, other_lib_version))) + result = run_pip('install', '-r', env.scratch_path / 'initools-req.txt') + assert result.files_created[env.site_packages/other_lib_name].dir + fn = '%s-%s-py%s.egg-info' % (other_lib_name, other_lib_version, pyversion) + assert result.files_created[env.site_packages/fn].dir + assert env.venv/'src'/'initools' in result.files_created + + +def test_respect_order_in_requirements_file(): + env = reset_env() + write_file('frameworks-req.txt', textwrap.dedent("""\ + bidict + ordereddict + initools + """)) + result = run_pip('install', '-r', env.scratch_path / 'frameworks-req.txt') + downloaded = [line for line in result.stdout.split('\n') + if 'Downloading/unpacking' in line] + + assert 'bidict' in downloaded[0], 'First download should ' \ + 'be "bidict" but was "%s"' % downloaded[0] + assert 'ordereddict' in downloaded[1], 'Second download should ' \ + 'be "ordereddict" but was "%s"' % downloaded[1] + assert 'initools' in downloaded[2], 'Third download should ' \ + 'be "initools" but was "%s"' % downloaded[2] + + +def test_requirements_data_structure_keeps_order(): + requirements = Requirements() + requirements['pip'] = 'pip' + requirements['nose'] = 'nose' + requirements['coverage'] = 'coverage' + + assert ['pip', 'nose', 'coverage'] == list(requirements.values()) + assert ['pip', 'nose', 'coverage'] == list(requirements.keys()) + + +def test_requirements_data_structure_implements__repr__(): + requirements = Requirements() + requirements['pip'] = 'pip' + requirements['nose'] = 'nose' + + assert "Requirements({'pip': 'pip', 'nose': 'nose'})" == repr(requirements) + + +def test_requirements_data_structure_implements__contains__(): + requirements = Requirements() + requirements['pip'] = 'pip' + + assert 'pip' in requirements + assert 'nose' not in requirements diff --git a/vendor/pip-1.2.1/tests/test_search.py b/vendor/pip-1.2.1/tests/test_search.py new file mode 100644 index 0000000..53aad53 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_search.py @@ -0,0 +1,131 @@ +import pip.download +from pip.commands.search import (compare_versions, + highest_version, + transform_hits, + SearchCommand) +from pip.status_codes import NO_MATCHES_FOUND, SUCCESS +from pip.backwardcompat import xmlrpclib, b +from mock import Mock +from tests.test_pip import run_pip, reset_env, pyversion +from tests.pypi_server import assert_equal + + +if pyversion >= '3': + VERBOSE_FALSE = False +else: + VERBOSE_FALSE = 0 + + +def test_version_compare(): + """ + Test version comparison. + + """ + assert compare_versions('1.0', '1.1') == -1 + assert compare_versions('1.1', '1.0') == 1 + assert compare_versions('1.1a1', '1.1') == -1 + assert compare_versions('1.1.1', '1.1a') == -1 + assert highest_version(['1.0', '2.0', '0.1']) == '2.0' + assert highest_version(['1.0a1', '1.0']) == '1.0' + + +def test_pypi_xml_transformation(): + """ + Test transformation of data structures (pypi xmlrpc to custom list). + + """ + pypi_hits = [{'_pypi_ordering': 100, 'name': 'foo', 'summary': 'foo summary', 'version': '1.0'}, + {'_pypi_ordering': 200, 'name': 'foo', 'summary': 'foo summary v2', 'version': '2.0'}, + {'_pypi_ordering': 50, 'name': 'bar', 'summary': 'bar summary', 'version': '1.0'}] + expected = [{'score': 200, 'versions': ['1.0', '2.0'], 'name': 'foo', 'summary': 'foo summary v2'}, + {'score': 50, 'versions': ['1.0'], 'name': 'bar', 'summary': 'bar summary'}] + assert_equal(expected, transform_hits(pypi_hits)) + + +def test_search(): + """ + End to end test of search command. + + """ + reset_env() + output = run_pip('search', 'pip') + assert 'pip installs packages' in output.stdout + + +def test_multiple_search(): + """ + Test searching for multiple packages at once. + + """ + reset_env() + output = run_pip('search', 'pip', 'INITools') + assert 'pip installs packages' in output.stdout + assert 'Tools for parsing and using INI-style files' in output.stdout + + +def test_searching_through_Search_class(): + """ + Verify if ``pip.vcs.Search`` uses tests xmlrpclib.Transport class + """ + original_xmlrpclib_transport = pip.download.xmlrpclib_transport + pip.download.xmlrpclib_transport = fake_transport = Mock() + query = 'mylittlequerythatdoesnotexists' + dumped_xmlrpc_request = b(xmlrpclib.dumps(({'name': query, 'summary': query}, 'or'), 'search')) + expected = [{'_pypi_ordering': 100, 'name': 'foo', 'summary': 'foo summary', 'version': '1.0'}] + fake_transport.request.return_value = (expected,) + pypi_searcher = SearchCommand() + result = pypi_searcher.search(query, 'http://pypi.python.org/pypi') + try: + assert expected == result, result + fake_transport.request.assert_called_with('pypi.python.org', '/pypi', dumped_xmlrpc_request, verbose=VERBOSE_FALSE) + finally: + pip.download.xmlrpclib_transport = original_xmlrpclib_transport + + +def test_search_missing_argument(): + """ + Test missing required argument for search + """ + env = reset_env(use_distribute=True) + result = run_pip('search', expect_error=True) + assert 'ERROR: Missing required argument (search query).' in result.stdout + + +def test_run_method_should_return_sucess_when_find_packages(): + """ + Test SearchCommand.run for found package + """ + options_mock = Mock() + options_mock.index = 'http://pypi.python.org/pypi' + search_cmd = SearchCommand() + status = search_cmd.run(options_mock, ('pip',)) + assert status == SUCCESS + + +def test_run_method_should_return_no_matches_found_when_does_not_find_packages(): + """ + Test SearchCommand.run for no matches + """ + options_mock = Mock() + options_mock.index = 'http://pypi.python.org/pypi' + search_cmd = SearchCommand() + status = search_cmd.run(options_mock, ('non-existant-package',)) + assert status == NO_MATCHES_FOUND, status + + +def test_search_should_exit_status_code_zero_when_find_packages(): + """ + Test search exit status code for package found + """ + env = reset_env(use_distribute=True) + result = run_pip('search', 'pip') + assert result.returncode == SUCCESS + + +def test_search_exit_status_code_when_finds_no_package(): + """ + Test search exit status code for no matches + """ + env = reset_env(use_distribute=True) + result = run_pip('search', 'non-existant-package', expect_error=True) + assert result.returncode == NO_MATCHES_FOUND diff --git a/vendor/pip-1.2.1/tests/test_unicode.py b/vendor/pip-1.2.1/tests/test_unicode.py new file mode 100644 index 0000000..d9196e7 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_unicode.py @@ -0,0 +1,25 @@ +import os +from tests.test_pip import here, reset_env, run_pip + + +def test_install_package_that_emits_unicode(): + """ + Install a package with a setup.py that emits UTF-8 output and then fails. + This works fine in Python 2, but fails in Python 3 with: + + Traceback (most recent call last): + ... + File "/Users/marc/python/virtualenvs/py3.1-phpserialize/lib/python3.2/site-packages/pip-1.0.2-py3.2.egg/pip/__init__.py", line 230, in call_subprocess + line = console_to_str(stdout.readline()) + File "/Users/marc/python/virtualenvs/py3.1-phpserialize/lib/python3.2/site-packages/pip-1.0.2-py3.2.egg/pip/backwardcompat.py", line 60, in console_to_str + return s.decode(console_encoding) + UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 17: ordinal not in range(128) + + Refs https://github.com/pypa/pip/issues/326 + """ + + env = reset_env() + to_install = os.path.abspath(os.path.join(here, 'packages', 'BrokenEmitsUTF8')) + result = run_pip('install', to_install, expect_error=True) + assert '__main__.FakeError: this package designed to fail on install' in result.stdout + assert 'UnicodeDecodeError' not in result.stdout diff --git a/vendor/pip-1.2.1/tests/test_uninstall.py b/vendor/pip-1.2.1/tests/test_uninstall.py new file mode 100644 index 0000000..c88c7a6 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_uninstall.py @@ -0,0 +1,139 @@ +import textwrap +import sys +from os.path import join +from tempfile import mkdtemp +from tests.test_pip import reset_env, run_pip, assert_all_changes, write_file +from tests.local_repos import local_repo, local_checkout + +from pip.util import rmtree + + +def test_simple_uninstall(): + """ + Test simple install and uninstall. + + """ + env = reset_env() + result = run_pip('install', 'INITools==0.2', expect_error=True) + assert join(env.site_packages, 'initools') in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('uninstall', 'INITools', '-y', expect_error=True) + assert_all_changes(result, result2, [env.venv/'build', 'cache']) + + +def test_uninstall_with_scripts(): + """ + Uninstall an easy_installed package with scripts. + + """ + env = reset_env() + result = env.run('easy_install', 'PyLogo', expect_stderr=True) + easy_install_pth = env.site_packages/ 'easy-install.pth' + pylogo = sys.platform == 'win32' and 'pylogo' or 'PyLogo' + assert(pylogo in result.files_updated[easy_install_pth].bytes) + result2 = run_pip('uninstall', 'pylogo', '-y', expect_error=True) + assert_all_changes(result, result2, [env.venv/'build', 'cache']) + + +def test_uninstall_namespace_package(): + """ + Uninstall a distribution with a namespace package without clobbering + the namespace and everything in it. + + """ + env = reset_env() + result = run_pip('install', 'pd.requires==0.0.3', expect_error=True) + assert join(env.site_packages, 'pd') in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('uninstall', 'pd.find', '-y', expect_error=True) + assert join(env.site_packages, 'pd') not in result2.files_deleted, sorted(result2.files_deleted.keys()) + assert join(env.site_packages, 'pd', 'find') in result2.files_deleted, sorted(result2.files_deleted.keys()) + + +def test_uninstall_console_scripts(): + """ + Test uninstalling a package with more files (console_script entry points, extra directories). + + """ + env = reset_env() + args = ['install'] + args.append('discover') + result = run_pip(*args, **{"expect_error": True}) + assert env.bin/'discover'+env.exe in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('uninstall', 'discover', '-y', expect_error=True) + assert_all_changes(result, result2, [env.venv/'build', 'cache']) + + +def test_uninstall_easy_installed_console_scripts(): + """ + Test uninstalling package with console_scripts that is easy_installed. + + """ + env = reset_env() + args = ['easy_install'] + args.append('discover') + result = env.run(*args, **{"expect_stderr": True}) + assert env.bin/'discover'+env.exe in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('uninstall', 'discover', '-y') + assert_all_changes(result, result2, [env.venv/'build', 'cache']) + + +def test_uninstall_editable_from_svn(): + """ + Test uninstalling an editable installation from svn. + + """ + env = reset_env() + result = run_pip('install', '-e', '%s#egg=initools-dev' % + local_checkout('svn+http://svn.colorstudy.com/INITools/trunk')) + result.assert_installed('INITools') + result2 = run_pip('uninstall', '-y', 'initools') + assert (env.venv/'src'/'initools' in result2.files_after), 'oh noes, pip deleted my sources!' + assert_all_changes(result, result2, [env.venv/'src', env.venv/'build']) + + +def test_uninstall_editable_with_source_outside_venv(): + """ + Test uninstalling editable install from existing source outside the venv. + + """ + try: + temp = mkdtemp() + tmpdir = join(temp, 'virtualenv') + _test_uninstall_editable_with_source_outside_venv(tmpdir) + finally: + rmtree(temp) + + +def _test_uninstall_editable_with_source_outside_venv(tmpdir): + env = reset_env() + result = env.run('git', 'clone', local_repo('git+git://github.com/pypa/virtualenv'), tmpdir) + result2 = run_pip('install', '-e', tmpdir) + assert (join(env.site_packages, 'virtualenv.egg-link') in result2.files_created), list(result2.files_created.keys()) + result3 = run_pip('uninstall', '-y', 'virtualenv', expect_error=True) + assert_all_changes(result, result3, [env.venv/'build']) + + +def test_uninstall_from_reqs_file(): + """ + Test uninstall from a requirements file. + + """ + env = reset_env() + write_file('test-req.txt', textwrap.dedent("""\ + -e %s#egg=initools-dev + # and something else to test out: + PyLogo<0.4 + """ % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'))) + result = run_pip('install', '-r', 'test-req.txt') + write_file('test-req.txt', textwrap.dedent("""\ + # -f, -i, and --extra-index-url should all be ignored by uninstall + -f http://www.example.com + -i http://www.example.com + --extra-index-url http://www.example.com + + -e %s#egg=initools-dev + # and something else to test out: + PyLogo<0.4 + """ % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'))) + result2 = run_pip('uninstall', '-r', 'test-req.txt', '-y') + assert_all_changes( + result, result2, [env.venv/'build', env.venv/'src', env.scratch/'test-req.txt']) diff --git a/vendor/pip-1.2.1/tests/test_upgrade.py b/vendor/pip-1.2.1/tests/test_upgrade.py new file mode 100644 index 0000000..c6b8d68 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_upgrade.py @@ -0,0 +1,192 @@ +import textwrap +from os.path import join +from tests.test_pip import (here, reset_env, run_pip, assert_all_changes, + write_file, pyversion, _create_test_package, + _change_test_package_version) + + +def test_no_upgrade_unless_requested(): + """ + No upgrade if not specifically requested. + + """ + reset_env() + run_pip('install', 'INITools==0.1', expect_error=True) + result = run_pip('install', 'INITools', expect_error=True) + assert not result.files_created, 'pip install INITools upgraded when it should not have' + + +def test_upgrade_to_specific_version(): + """ + It does upgrade to specific version requested. + + """ + env = reset_env() + run_pip('install', 'INITools==0.1', expect_error=True) + result = run_pip('install', 'INITools==0.2', expect_error=True) + assert result.files_created, 'pip install with specific version did not upgrade' + assert env.site_packages/'INITools-0.1-py%s.egg-info' % pyversion in result.files_deleted + assert env.site_packages/'INITools-0.2-py%s.egg-info' % pyversion in result.files_created + + +def test_upgrade_if_requested(): + """ + And it does upgrade if requested. + + """ + env = reset_env() + run_pip('install', 'INITools==0.1', expect_error=True) + result = run_pip('install', '--upgrade', 'INITools', expect_error=True) + assert result.files_created, 'pip install --upgrade did not upgrade' + assert env.site_packages/'INITools-0.1-py%s.egg-info' % pyversion not in result.files_created + + +def test_upgrade_with_newest_already_installed(): + """ + If the newest version of a package is already installed, the package should + not be reinstalled and the user should be informed. + """ + + env = reset_env() + run_pip('install', 'INITools') + result = run_pip('install', '--upgrade', 'INITools') + assert not result.files_created, 'pip install --upgrade INITools upgraded when it should not have' + assert 'already up-to-date' in result.stdout + + +def test_upgrade_force_reinstall_newest(): + """ + Force reinstallation of a package even if it is already at its newest + version if --force-reinstall is supplied. + """ + + env = reset_env() + result = run_pip('install', 'INITools') + assert env.site_packages/ 'initools' in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('install', '--upgrade', '--force-reinstall', 'INITools') + assert result2.files_updated, 'upgrade to INITools 0.3 failed' + result3 = run_pip('uninstall', 'initools', '-y', expect_error=True) + assert_all_changes(result, result3, [env.venv/'build', 'cache']) + + +def test_uninstall_before_upgrade(): + """ + Automatic uninstall-before-upgrade. + + """ + env = reset_env() + result = run_pip('install', 'INITools==0.2', expect_error=True) + assert env.site_packages/ 'initools' in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('install', 'INITools==0.3', expect_error=True) + assert result2.files_created, 'upgrade to INITools 0.3 failed' + result3 = run_pip('uninstall', 'initools', '-y', expect_error=True) + assert_all_changes(result, result3, [env.venv/'build', 'cache']) + + +def test_uninstall_before_upgrade_from_url(): + """ + Automatic uninstall-before-upgrade from URL. + + """ + env = reset_env() + result = run_pip('install', 'INITools==0.2', expect_error=True) + assert env.site_packages/ 'initools' in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('install', 'http://pypi.python.org/packages/source/I/INITools/INITools-0.3.tar.gz', expect_error=True) + assert result2.files_created, 'upgrade to INITools 0.3 failed' + result3 = run_pip('uninstall', 'initools', '-y', expect_error=True) + assert_all_changes(result, result3, [env.venv/'build', 'cache']) + + +def test_upgrade_to_same_version_from_url(): + """ + When installing from a URL the same version that is already installed, no + need to uninstall and reinstall if --upgrade is not specified. + + """ + env = reset_env() + result = run_pip('install', 'INITools==0.3', expect_error=True) + assert env.site_packages/ 'initools' in result.files_created, sorted(result.files_created.keys()) + result2 = run_pip('install', 'http://pypi.python.org/packages/source/I/INITools/INITools-0.3.tar.gz', expect_error=True) + assert not result2.files_updated, 'INITools 0.3 reinstalled same version' + result3 = run_pip('uninstall', 'initools', '-y', expect_error=True) + assert_all_changes(result, result3, [env.venv/'build', 'cache']) + + +def test_upgrade_from_reqs_file(): + """ + Upgrade from a requirements file. + + """ + env = reset_env() + write_file('test-req.txt', textwrap.dedent("""\ + PyLogo<0.4 + # and something else to test out: + INITools==0.3 + """)) + install_result = run_pip('install', '-r', env.scratch_path/ 'test-req.txt') + write_file('test-req.txt', textwrap.dedent("""\ + PyLogo + # and something else to test out: + INITools + """)) + run_pip('install', '--upgrade', '-r', env.scratch_path/ 'test-req.txt') + uninstall_result = run_pip('uninstall', '-r', env.scratch_path/ 'test-req.txt', '-y') + assert_all_changes(install_result, uninstall_result, [env.venv/'build', 'cache', env.scratch/'test-req.txt']) + + +def test_uninstall_rollback(): + """ + Test uninstall-rollback (using test package with a setup.py + crafted to fail on install). + + """ + env = reset_env() + find_links = 'file://' + join(here, 'packages') + result = run_pip('install', '-f', find_links, '--no-index', 'broken==0.1') + assert env.site_packages / 'broken.py' in result.files_created, list(result.files_created.keys()) + result2 = run_pip('install', '-f', find_links, '--no-index', 'broken==0.2broken', expect_error=True) + assert result2.returncode == 1, str(result2) + assert env.run('python', '-c', "import broken; print(broken.VERSION)").stdout == '0.1\n' + assert_all_changes(result.files_after, result2, [env.venv/'build', 'pip-log.txt']) + + +def test_editable_git_upgrade(): + """ + Test installing an editable git package from a repository, upgrading the repository, + installing again, and check it gets the newer version + """ + env = reset_env() + version_pkg_path = _create_test_package(env) + run_pip('install', '-e', '%s#egg=version_pkg' % ('git+file://' + version_pkg_path)) + version = env.run('version_pkg') + assert '0.1' in version.stdout + _change_test_package_version(env, version_pkg_path) + run_pip('install', '-e', '%s#egg=version_pkg' % ('git+file://' + version_pkg_path)) + version2 = env.run('version_pkg') + assert 'some different version' in version2.stdout + + +def test_should_not_install_always_from_cache(): + """ + If there is an old cached package, pip should download the newer version + Related to issue #175 + """ + env = reset_env() + run_pip('install', 'INITools==0.2', expect_error=True) + run_pip('uninstall', '-y', 'INITools') + result = run_pip('install', 'INITools==0.1', expect_error=True) + assert env.site_packages/'INITools-0.2-py%s.egg-info' % pyversion not in result.files_created + assert env.site_packages/'INITools-0.1-py%s.egg-info' % pyversion in result.files_created + + +def test_install_with_ignoreinstalled_requested(): + """ + It installs package if ignore installed is set. + + """ + env = reset_env() + run_pip('install', 'INITools==0.1', expect_error=True) + result = run_pip('install', '-I', 'INITools', expect_error=True) + assert result.files_created, 'pip install -I did not install' + assert env.site_packages/'INITools-0.1-py%s.egg-info' % pyversion not in result.files_created + diff --git a/vendor/pip-1.2.1/tests/test_vcs_backends.py b/vendor/pip-1.2.1/tests/test_vcs_backends.py new file mode 100644 index 0000000..9561254 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_vcs_backends.py @@ -0,0 +1,131 @@ +from tests.test_pip import (reset_env, run_pip, + _create_test_package, _change_test_package_version) +from tests.local_repos import local_checkout + + +def test_install_editable_from_git_with_https(): + """ + Test cloning from Git with https. + """ + reset_env() + result = run_pip('install', '-e', + '%s#egg=pip-test-package' % + local_checkout('git+https://github.com/pypa/pip-test-package.git'), + expect_error=True) + result.assert_installed('pip-test-package', with_files=['.git']) + + +def test_git_with_sha1_revisions(): + """ + Git backend should be able to install from SHA1 revisions + """ + env = reset_env() + version_pkg_path = _create_test_package(env) + _change_test_package_version(env, version_pkg_path) + sha1 = env.run('git', 'rev-parse', 'HEAD~1', cwd=version_pkg_path).stdout.strip() + run_pip('install', '-e', '%s@%s#egg=version_pkg' % ('git+file://' + version_pkg_path.abspath.replace('\\', '/'), sha1)) + version = env.run('version_pkg') + assert '0.1' in version.stdout, version.stdout + + +def test_git_with_branch_name_as_revision(): + """ + Git backend should be able to install from branch names + """ + env = reset_env() + version_pkg_path = _create_test_package(env) + env.run('git', 'checkout', '-b', 'test_branch', expect_stderr=True, cwd=version_pkg_path) + _change_test_package_version(env, version_pkg_path) + run_pip('install', '-e', '%s@test_branch#egg=version_pkg' % ('git+file://' + version_pkg_path.abspath.replace('\\', '/'))) + version = env.run('version_pkg') + assert 'some different version' in version.stdout + + +def test_git_with_tag_name_as_revision(): + """ + Git backend should be able to install from tag names + """ + env = reset_env() + version_pkg_path = _create_test_package(env) + env.run('git', 'tag', 'test_tag', expect_stderr=True, cwd=version_pkg_path) + _change_test_package_version(env, version_pkg_path) + run_pip('install', '-e', '%s@test_tag#egg=version_pkg' % ('git+file://' + version_pkg_path.abspath.replace('\\', '/'))) + version = env.run('version_pkg') + assert '0.1' in version.stdout + + +def test_git_with_tag_name_and_update(): + """ + Test cloning a git repository and updating to a different version. + """ + reset_env() + result = run_pip('install', '-e', '%s#egg=pip-test-package' % + local_checkout('git+http://github.com/pypa/pip-test-package.git'), + expect_error=True) + result.assert_installed('pip-test-package', with_files=['.git']) + result = run_pip('install', '--global-option=--version', '-e', + '%s@0.1.1#egg=pip-test-package' % + local_checkout('git+http://github.com/pypa/pip-test-package.git'), + expect_error=True) + assert '0.1.1\n' in result.stdout + + +def test_git_branch_should_not_be_changed(): + """ + Editable installations should not change branch + related to issue #32 and #161 + """ + env = reset_env() + run_pip('install', '-e', '%s#egg=pip-test-package' % + local_checkout('git+http://github.com/pypa/pip-test-package.git'), + expect_error=True) + source_dir = env.venv_path/'src'/'pip-test-package' + result = env.run('git', 'branch', cwd=source_dir) + assert '* master' in result.stdout, result.stdout + + +def test_git_with_non_editable_unpacking(): + """ + Test cloning a git repository from a non-editable URL with a given tag. + """ + reset_env() + result = run_pip('install', '--global-option=--version', local_checkout( + 'git+http://github.com/pypa/pip-test-package.git@0.1.1#egg=pip-test-package' + ), expect_error=True) + assert '0.1.1\n' in result.stdout + + +def test_git_with_editable_where_egg_contains_dev_string(): + """ + Test cloning a git repository from an editable url which contains "dev" string + """ + reset_env() + result = run_pip('install', '-e', '%s#egg=django-devserver' % + local_checkout('git+git://github.com/dcramer/django-devserver.git')) + result.assert_installed('django-devserver', with_files=['.git']) + + +def test_git_with_non_editable_where_egg_contains_dev_string(): + """ + Test cloning a git repository from a non-editable url which contains "dev" string + """ + env = reset_env() + result = run_pip('install', '%s#egg=django-devserver' % + local_checkout('git+git://github.com/dcramer/django-devserver.git')) + devserver_folder = env.site_packages/'devserver' + assert devserver_folder in result.files_created, str(result) + + +def test_git_with_ambiguous_revs(): + """ + Test git with two "names" (tag/branch) pointing to the same commit + """ + env = reset_env() + version_pkg_path = _create_test_package(env) + package_url = 'git+file://%s@0.1#egg=version_pkg' % (version_pkg_path.abspath.replace('\\', '/')) + env.run('git', 'tag', '0.1', cwd=version_pkg_path) + result = run_pip('install', '-e', package_url) + assert 'Could not find a tag or branch' not in result.stdout + # it is 'version-pkg' instead of 'version_pkg' because + # egg-link name is version-pkg.egg-link because it is a single .py module + result.assert_installed('version-pkg', with_files=['.git']) diff --git a/vendor/pip-1.2.1/tests/test_vcs_bazaar.py b/vendor/pip-1.2.1/tests/test_vcs_bazaar.py new file mode 100644 index 0000000..4e43fe5 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_vcs_bazaar.py @@ -0,0 +1,29 @@ +from tests.test_pip import pyversion +from pip.vcs.bazaar import Bazaar + +if pyversion >= '3': + VERBOSE_FALSE = False +else: + VERBOSE_FALSE = 0 + + +def test_bazaar_simple_urls(): + """ + Test bzr url support. + + SSH and launchpad have special handling. + """ + http_bzr_repo = Bazaar(url='bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject') + https_bzr_repo = Bazaar(url='bzr+https://bzr.myproject.org/MyProject/trunk/#egg=MyProject') + ssh_bzr_repo = Bazaar(url='bzr+ssh://bzr.myproject.org/MyProject/trunk/#egg=MyProject') + ftp_bzr_repo = Bazaar(url='bzr+ftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject') + sftp_bzr_repo = Bazaar(url='bzr+sftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject') + launchpad_bzr_repo = Bazaar(url='bzr+lp:MyLaunchpadProject#egg=MyLaunchpadProject') + + assert http_bzr_repo.get_url_rev() == ('http://bzr.myproject.org/MyProject/trunk/', None) + assert https_bzr_repo.get_url_rev() == ('https://bzr.myproject.org/MyProject/trunk/', None) + assert ssh_bzr_repo.get_url_rev() == ('bzr+ssh://bzr.myproject.org/MyProject/trunk/', None) + assert ftp_bzr_repo.get_url_rev() == ('ftp://bzr.myproject.org/MyProject/trunk/', None) + assert sftp_bzr_repo.get_url_rev() == ('sftp://bzr.myproject.org/MyProject/trunk/', None) + assert launchpad_bzr_repo.get_url_rev() == ('lp:MyLaunchpadProject', None) + diff --git a/vendor/pip-1.2.1/tests/test_vcs_git.py b/vendor/pip-1.2.1/tests/test_vcs_git.py new file mode 100644 index 0000000..0b3abab --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_vcs_git.py @@ -0,0 +1,77 @@ +from mock import patch +from pip.vcs.git import Git +from tests.test_pip import (reset_env, run_pip, + _create_test_package) + + +def test_get_tag_revs_should_return_tag_name_and_commit_pair(): + env = reset_env() + version_pkg_path = _create_test_package(env) + env.run('git', 'tag', '0.1', cwd=version_pkg_path) + env.run('git', 'tag', '0.2', cwd=version_pkg_path) + commit = env.run('git', 'rev-parse', 'HEAD', + cwd=version_pkg_path).stdout.strip() + git = Git() + result = git.get_tag_revs(version_pkg_path) + assert result == {'0.1': commit, '0.2': commit}, result + + +def test_get_branch_revs_should_return_branch_name_and_commit_pair(): + env = reset_env() + version_pkg_path = _create_test_package(env) + env.run('git', 'branch', 'branch0.1', cwd=version_pkg_path) + commit = env.run('git', 'rev-parse', 'HEAD', + cwd=version_pkg_path).stdout.strip() + git = Git() + result = git.get_branch_revs(version_pkg_path) + assert result == {'master': commit, 'branch0.1': commit} + + +def test_get_branch_revs_should_ignore_no_branch(): + env = reset_env() + version_pkg_path = _create_test_package(env) + env.run('git', 'branch', 'branch0.1', cwd=version_pkg_path) + commit = env.run('git', 'rev-parse', 'HEAD', + cwd=version_pkg_path).stdout.strip() + # current branch here is "* (nobranch)" + env.run('git', 'checkout', commit, + cwd=version_pkg_path, expect_stderr=True) + git = Git() + result = git.get_branch_revs(version_pkg_path) + assert result == {'master': commit, 'branch0.1': commit} + + +@patch('pip.vcs.git.Git.get_tag_revs') +@patch('pip.vcs.git.Git.get_branch_revs') +def test_check_rev_options_should_handle_branch_name(branches_revs_mock, + tags_revs_mock): + branches_revs_mock.return_value = {'master': '123456'} + tags_revs_mock.return_value = {'0.1': '123456'} + git = Git() + + result = git.check_rev_options('master', '.', []) + assert result == ['123456'] + + +@patch('pip.vcs.git.Git.get_tag_revs') +@patch('pip.vcs.git.Git.get_branch_revs') +def test_check_rev_options_should_handle_tag_name(branches_revs_mock, + tags_revs_mock): + branches_revs_mock.return_value = {'master': '123456'} + tags_revs_mock.return_value = {'0.1': '123456'} + git = Git() + + result = git.check_rev_options('0.1', '.', []) + assert result == ['123456'] + + +@patch('pip.vcs.git.Git.get_tag_revs') +@patch('pip.vcs.git.Git.get_branch_revs') +def test_check_rev_options_should_handle_ambiguous_commit(branches_revs_mock, + tags_revs_mock): + branches_revs_mock.return_value = {'master': '123456'} + tags_revs_mock.return_value = {'0.1': '123456'} + git = Git() + + result = git.check_rev_options('0.1', '.', []) + assert result == ['123456'], result diff --git a/vendor/pip-1.2.1/tests/test_vcs_subversion.py b/vendor/pip-1.2.1/tests/test_vcs_subversion.py new file mode 100644 index 0000000..2122201 --- /dev/null +++ b/vendor/pip-1.2.1/tests/test_vcs_subversion.py @@ -0,0 +1,21 @@ +from mock import patch +from pip.vcs.subversion import Subversion +from tests.test_pip import reset_env + +@patch('pip.vcs.subversion.call_subprocess') +def test_obtain_should_recognize_auth_info_in_url(call_subprocess_mock): + env = reset_env() + svn = Subversion(url='svn+http://username:password@svn.example.com/') + svn.obtain(env.scratch_path/'test') + call_subprocess_mock.assert_called_with([ + svn.cmd, 'checkout', '-q', '--username', 'username', '--password', 'password', + 'http://username:password@svn.example.com/', env.scratch_path/'test']) + +@patch('pip.vcs.subversion.call_subprocess') +def test_export_should_recognize_auth_info_in_url(call_subprocess_mock): + env = reset_env() + svn = Subversion(url='svn+http://username:password@svn.example.com/') + svn.export(env.scratch_path/'test') + assert call_subprocess_mock.call_args[0] == ([ + svn.cmd, 'export', '--username', 'username', '--password', 'password', + 'http://username:password@svn.example.com/', env.scratch_path/'test'],) diff --git a/vendor/virtualenv-1.8.4/AUTHORS.txt b/vendor/virtualenv-1.8.4/AUTHORS.txt deleted file mode 100644 index 77fb20e..0000000 --- a/vendor/virtualenv-1.8.4/AUTHORS.txt +++ /dev/null @@ -1,58 +0,0 @@ -Author ------- - -Ian Bicking - -Maintainers ------------ - -Brian Rosner -Carl Meyer -Jannis Leidel -Paul Nasrat - -Contributors ------------- - -Alex Grönholm -Anatoly Techtonik -Antonio Cuni -Armin Ronacher -Benjamin Root -Bradley Ayers -Branden Rolston -Cap Petschulat -CBWhiz -Chris McDonough -Christian Stefanescu -Christopher Nilsson -Cliff Xuan -Curt Micol -Damien Nozay -David Schoonover -Doug Hellmann -Doug Napoleone -Douglas Creager -Ethan Jucovy -Gabriel de Perthuis -Gunnlaugur Thor Briem -Greg Haskins -Jason R. Coombs -Jeff Hammel -Jeremy Orem -Jonathan Griffin -Jorge Vargas -Josh Bronson -Konstantin Zemlyak -Kumar McMillan -Lars Francke -Marc Abramowitz -Mike Hommey -Miki Tebeka -Paul Moore -Philip Jenvey -Raul Leal -Ronny Pfannschmidt -Stefano Rivera -Tarek Ziadé -Vinay Sajip diff --git a/vendor/virtualenv-1.8.4/MANIFEST.in b/vendor/virtualenv-1.8.4/MANIFEST.in deleted file mode 100644 index ce219d6..0000000 --- a/vendor/virtualenv-1.8.4/MANIFEST.in +++ /dev/null @@ -1,11 +0,0 @@ -recursive-include bin * -recursive-include docs * -recursive-include scripts * -recursive-include virtualenv_support *.egg *.tar.gz -recursive-include virtualenv_embedded * -recursive-exclude docs/_templates * -recursive-exclude docs/_build * -include virtualenv_support/__init__.py -include *.py -include AUTHORS.txt -include LICENSE.txt diff --git a/vendor/virtualenv-1.8.4/PKG-INFO b/vendor/virtualenv-1.8.4/PKG-INFO deleted file mode 100644 index 601d5fb..0000000 --- a/vendor/virtualenv-1.8.4/PKG-INFO +++ /dev/null @@ -1,1208 +0,0 @@ -Metadata-Version: 1.1 -Name: virtualenv -Version: 1.8.4 -Summary: Virtual Python Environment builder -Home-page: http://www.virtualenv.org -Author: Jannis Leidel, Carl Meyer and Brian Rosner -Author-email: python-virtualenv@groups.google.com -License: MIT -Description: - - Installation - ------------ - - You can install virtualenv with ``pip install virtualenv``, or the `latest - development version `_ - with ``pip install https://github.com/pypa/virtualenv/tarball/develop``. - - You can also use ``easy_install``, or if you have no Python package manager - available at all, you can just grab the single file `virtualenv.py`_ and run - it with ``python virtualenv.py``. - - .. _virtualenv.py: https://raw.github.com/pypa/virtualenv/master/virtualenv.py - - What It Does - ------------ - - ``virtualenv`` is a tool to create isolated Python environments. - - The basic problem being addressed is one of dependencies and versions, - and indirectly permissions. Imagine you have an application that - needs version 1 of LibFoo, but another application requires version - 2. How can you use both these applications? If you install - everything into ``/usr/lib/python2.7/site-packages`` (or whatever your - platform's standard location is), it's easy to end up in a situation - where you unintentionally upgrade an application that shouldn't be - upgraded. - - Or more generally, what if you want to install an application *and - leave it be*? If an application works, any change in its libraries or - the versions of those libraries can break the application. - - Also, what if you can't install packages into the global - ``site-packages`` directory? For instance, on a shared host. - - In all these cases, ``virtualenv`` can help you. It creates an - environment that has its own installation directories, that doesn't - share libraries with other virtualenv environments (and optionally - doesn't access the globally installed libraries either). - - Usage - ----- - - The basic usage is:: - - $ python virtualenv.py ENV - - If you install it you can also just do ``virtualenv ENV``. - - This creates ``ENV/lib/pythonX.X/site-packages``, where any libraries you - install will go. It also creates ``ENV/bin/python``, which is a Python - interpreter that uses this environment. Anytime you use that interpreter - (including when a script has ``#!/path/to/ENV/bin/python`` in it) the libraries - in that environment will be used. - - It also installs either `Setuptools - `_ or `distribute - `_ into the environment. To use - Distribute instead of setuptools, just call virtualenv like this:: - - $ python virtualenv.py --distribute ENV - - You can also set the environment variable VIRTUALENV_DISTRIBUTE. - - A new virtualenv also includes the `pip `_ - installer, so you can use ``ENV/bin/pip`` to install additional packages into - the environment. - - - activate script - ~~~~~~~~~~~~~~~ - - In a newly created virtualenv there will be a ``bin/activate`` shell - script. For Windows systems, activation scripts are provided for CMD.exe - and Powershell. - - On Posix systems you can do:: - - $ source bin/activate - - This will change your ``$PATH`` so its first entry is the virtualenv's - ``bin/`` directory. (You have to use ``source`` because it changes your - shell environment in-place.) This is all it does; it's purely a - convenience. If you directly run a script or the python interpreter - from the virtualenv's ``bin/`` directory (e.g. ``path/to/env/bin/pip`` - or ``/path/to/env/bin/python script.py``) there's no need for - activation. - - After activating an environment you can use the function ``deactivate`` to - undo the changes to your ``$PATH``. - - The ``activate`` script will also modify your shell prompt to indicate - which environment is currently active. You can disable this behavior, - which can be useful if you have your own custom prompt that already - displays the active environment name. To do so, set the - ``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty - value before running the ``activate`` script. - - On Windows you just do:: - - > \path\to\env\Scripts\activate - - And type `deactivate` to undo the changes. - - Based on your active shell (CMD.exe or Powershell.exe), Windows will use - either activate.bat or activate.ps1 (as appropriate) to activate the - virtual environment. If using Powershell, see the notes about code signing - below. - - .. note:: - - If using Powershell, the ``activate`` script is subject to the - `execution policies`_ on the system. By default on Windows 7, the system's - excution policy is set to ``Restricted``, meaning no scripts like the - ``activate`` script are allowed to be executed. But that can't stop us - from changing that slightly to allow it to be executed. - - In order to use the script, you have to relax your system's execution - policy to ``AllSigned``, meaning all scripts on the system must be - digitally signed to be executed. Since the virtualenv activation - script is signed by one of the authors (Jannis Leidel) this level of - the execution policy suffices. As an administrator run:: - - PS C:\> Set-ExecutionPolicy AllSigned - - Then you'll be asked to trust the signer, when executing the script. - You will be prompted with the following:: - - PS C:\> virtualenv .\foo - New python executable in C:\foo\Scripts\python.exe - Installing setuptools................done. - Installing pip...................done. - PS C:\> .\foo\scripts\activate - - Do you want to run software from this untrusted publisher? - File C:\foo\scripts\activate.ps1 is published by E=jannis@leidel.info, - CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0 - and is not trusted on your system. Only run scripts from trusted publishers. - [V] Never run [D] Do not run [R] Run once [A] Always run [?] Help - (default is "D"):A - (foo) PS C:\> - - If you select ``[A] Always Run``, the certificate will be added to the - Trusted Publishers of your user account, and will be trusted in this - user's context henceforth. If you select ``[R] Run Once``, the script will - be run, but you will be prometed on a subsequent invocation. Advanced users - can add the signer's certificate to the Trusted Publishers of the Computer - account to apply to all users (though this technique is out of scope of this - document). - - Alternatively, you may relax the system execution policy to allow running - of local scripts without verifying the code signature using the following:: - - PS C:\> Set-ExecutionPolicy RemoteSigned - - Since the ``activate.ps1`` script is generated locally for each virtualenv, - it is not considered a remote script and can then be executed. - - .. _`execution policies`: http://technet.microsoft.com/en-us/library/dd347641.aspx - - The ``--system-site-packages`` Option - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - If you build with ``virtualenv --system-site-packages ENV``, your virtual - environment will inherit packages from ``/usr/lib/python2.7/site-packages`` - (or wherever your global site-packages directory is). - - This can be used if you have control over the global site-packages directory, - and you want to depend on the packages there. If you want isolation from the - global system, do not use this flag. - - - Environment variables and configuration files - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - virtualenv can not only be configured by passing command line options such as - ``--distribute`` but also by two other means: - - - Environment variables - - Each command line option is automatically used to look for environment - variables with the name format ``VIRTUALENV_``. That means - the name of the command line options are capitalized and have dashes - (``'-'``) replaced with underscores (``'_'``). - - For example, to automatically install Distribute instead of setuptools - you can also set an environment variable:: - - $ export VIRTUALENV_DISTRIBUTE=true - $ python virtualenv.py ENV - - It's the same as passing the option to virtualenv directly:: - - $ python virtualenv.py --distribute ENV - - This also works for appending command line options, like ``--find-links``. - Just leave an empty space between the passsed values, e.g.:: - - $ export VIRTUALENV_EXTRA_SEARCH_DIR="/path/to/dists /path/to/other/dists" - $ virtualenv ENV - - is the same as calling:: - - $ python virtualenv.py --extra-search-dir=/path/to/dists --extra-search-dir=/path/to/other/dists ENV - - - Config files - - virtualenv also looks for a standard ini config file. On Unix and Mac OS X - that's ``$HOME/.virtualenv/virtualenv.ini`` and on Windows, it's - ``%APPDATA%\virtualenv\virtualenv.ini``. - - The names of the settings are derived from the long command line option, - e.g. the option ``--distribute`` would look like this:: - - [virtualenv] - distribute = true - - Appending options like ``--extra-search-dir`` can be written on multiple - lines:: - - [virtualenv] - extra-search-dir = - /path/to/dists - /path/to/other/dists - - Please have a look at the output of ``virtualenv --help`` for a full list - of supported options. - - Windows Notes - ~~~~~~~~~~~~~ - - Some paths within the virtualenv are slightly different on Windows: scripts and - executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and - libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``. - - To create a virtualenv under a path with spaces in it on Windows, you'll need - the `win32api `_ library installed. - - PyPy Support - ~~~~~~~~~~~~ - - Beginning with virtualenv version 1.5 `PyPy `_ is - supported. To use PyPy 1.4 or 1.4.1, you need a version of virtualenv >= 1.5. - To use PyPy 1.5, you need a version of virtualenv >= 1.6.1. - - Creating Your Own Bootstrap Scripts - ----------------------------------- - - While this creates an environment, it doesn't put anything into the - environment. Developers may find it useful to distribute a script - that sets up a particular environment, for example a script that - installs a particular web application. - - To create a script like this, call - ``virtualenv.create_bootstrap_script(extra_text)``, and write the - result to your new bootstrapping script. Here's the documentation - from the docstring: - - Creates a bootstrap script, which is like this script but with - extend_parser, adjust_options, and after_install hooks. - - This returns a string that (written to disk of course) can be used - as a bootstrap script with your own customizations. The script - will be the standard virtualenv.py script, with your extra text - added (your extra text should be Python code). - - If you include these functions, they will be called: - - ``extend_parser(optparse_parser)``: - You can add or remove options from the parser here. - - ``adjust_options(options, args)``: - You can change options here, or change the args (if you accept - different kinds of arguments, be sure you modify ``args`` so it is - only ``[DEST_DIR]``). - - ``after_install(options, home_dir)``: - - After everything is installed, this function is called. This - is probably the function you are most likely to use. An - example would be:: - - def after_install(options, home_dir): - if sys.platform == 'win32': - bin = 'Scripts' - else: - bin = 'bin' - subprocess.call([join(home_dir, bin, 'easy_install'), - 'MyPackage']) - subprocess.call([join(home_dir, bin, 'my-package-script'), - 'setup', home_dir]) - - This example immediately installs a package, and runs a setup - script from that package. - - Bootstrap Example - ~~~~~~~~~~~~~~~~~ - - Here's a more concrete example of how you could use this:: - - import virtualenv, textwrap - output = virtualenv.create_bootstrap_script(textwrap.dedent(""" - import os, subprocess - def after_install(options, home_dir): - etc = join(home_dir, 'etc') - if not os.path.exists(etc): - os.makedirs(etc) - subprocess.call([join(home_dir, 'bin', 'easy_install'), - 'BlogApplication']) - subprocess.call([join(home_dir, 'bin', 'paster'), - 'make-config', 'BlogApplication', - join(etc, 'blog.ini')]) - subprocess.call([join(home_dir, 'bin', 'paster'), - 'setup-app', join(etc, 'blog.ini')]) - """)) - f = open('blog-bootstrap.py', 'w').write(output) - - Another example is available `here - `_. - - - Using Virtualenv without ``bin/python`` - --------------------------------------- - - Sometimes you can't or don't want to use the Python interpreter - created by the virtualenv. For instance, in a `mod_python - `_ or `mod_wsgi `_ - environment, there is only one interpreter. - - Luckily, it's easy. You must use the custom Python interpreter to - *install* libraries. But to *use* libraries, you just have to be sure - the path is correct. A script is available to correct the path. You - can setup the environment like:: - - activate_this = '/path/to/env/bin/activate_this.py' - execfile(activate_this, dict(__file__=activate_this)) - - This will change ``sys.path`` and even change ``sys.prefix``, but also allow - you to use an existing interpreter. Items in your environment will show up - first on ``sys.path``, before global items. However, global items will - always be accessible (as if the ``--system-site-packages`` flag had been used - in creating the environment, whether it was or not). Also, this cannot undo - the activation of other environments, or modules that have been imported. - You shouldn't try to, for instance, activate an environment before a web - request; you should activate *one* environment as early as possible, and not - do it again in that process. - - Making Environments Relocatable - ------------------------------- - - Note: this option is somewhat experimental, and there are probably - caveats that have not yet been identified. Also this does not - currently work on Windows. - - Normally environments are tied to a specific path. That means that - you cannot move an environment around or copy it to another computer. - You can fix up an environment to make it relocatable with the - command:: - - $ virtualenv --relocatable ENV - - This will make some of the files created by setuptools or distribute - use relative paths, and will change all the scripts to use ``activate_this.py`` - instead of using the location of the Python interpreter to select the - environment. - - **Note:** you must run this after you've installed *any* packages into - the environment. If you make an environment relocatable, then - install a new package, you must run ``virtualenv --relocatable`` - again. - - Also, this **does not make your packages cross-platform**. You can - move the directory around, but it can only be used on other similar - computers. Some known environmental differences that can cause - incompatibilities: a different version of Python, when one platform - uses UCS2 for its internal unicode representation and another uses - UCS4 (a compile-time option), obvious platform changes like Windows - vs. Linux, or Intel vs. ARM, and if you have libraries that bind to C - libraries on the system, if those C libraries are located somewhere - different (either different versions, or a different filesystem - layout). - - If you use this flag to create an environment, currently, the - ``--system-site-packages`` option will be implied. - - The ``--extra-search-dir`` option - --------------------------------- - - When it creates a new environment, virtualenv installs either setuptools - or distribute, and pip. In normal operation when virtualenv is - installed, the bundled version of these packages included in the - ``virtualenv_support`` directory is used. When ``virtualenv.py`` is run - standalone and ``virtualenv_support`` is not available, the latest - releases of these packages are fetched from the `Python Package Index - `_ (PyPI). - - As an alternative, you can provide your own versions of setuptools, - distribute and/or pip on the filesystem, and tell virtualenv to use - those distributions instead of downloading them from the Internet. To - use this feature, pass one or more ``--extra-search-dir`` options to - virtualenv like this:: - - $ virtualenv --extra-search-dir=/path/to/distributions ENV - - The ``/path/to/distributions`` path should point to a directory that - contains setuptools, distribute and/or pip distributions. Setuptools - distributions must be ``.egg`` files; pip distributions should be - `.tar.gz` source distributions, and distribute distributions may be - either (if found an egg will be used preferentially). - - Virtualenv will still download these packages if no satisfactory local - distributions are found. - - If you are really concerned about virtualenv fetching these packages - from the Internet and want to ensure that it never will, you can also - provide an option ``--never-download`` like so:: - - $ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV - - If this option is provided, virtualenv will never try to download - setuptools/distribute or pip. Instead, it will exit with status code 1 - if it fails to find local distributions for any of these required - packages. The local distribution lookup is done in the following - locations, with the most recent version found used: - - #. The current directory. - #. The directory where virtualenv.py is located. - #. A ``virtualenv_support`` directory relative to the directory where - virtualenv.py is located. - #. If the file being executed is not named virtualenv.py (i.e. is a boot - script), a ``virtualenv_support`` directory relative to wherever - virtualenv.py is actually installed. - - - Compare & Contrast with Alternatives - ------------------------------------ - - There are several alternatives that create isolated environments: - - * ``workingenv`` (which I do not suggest you use anymore) is the - predecessor to this library. It used the main Python interpreter, - but relied on setting ``$PYTHONPATH`` to activate the environment. - This causes problems when running Python scripts that aren't part of - the environment (e.g., a globally installed ``hg`` or ``bzr``). It - also conflicted a lot with Setuptools. - - * `virtual-python - `_ - is also a predecessor to this library. It uses only symlinks, so it - couldn't work on Windows. It also symlinks over the *entire* - standard library and global ``site-packages``. As a result, it - won't see new additions to the global ``site-packages``. - - This script only symlinks a small portion of the standard library - into the environment, and so on Windows it is feasible to simply - copy these files over. Also, it creates a new/empty - ``site-packages`` and also adds the global ``site-packages`` to the - path, so updates are tracked separately. This script also installs - Setuptools automatically, saving a step and avoiding the need for - network access. - - * `zc.buildout `_ doesn't - create an isolated Python environment in the same style, but - achieves similar results through a declarative config file that sets - up scripts with very particular packages. As a declarative system, - it is somewhat easier to repeat and manage, but more difficult to - experiment with. ``zc.buildout`` includes the ability to setup - non-Python systems (e.g., a database server or an Apache instance). - - I *strongly* recommend anyone doing application development or - deployment use one of these tools. - - Contributing - ------------ - - Refer to the `contributing to pip`_ documentation - it applies equally to - virtualenv, except that virtualenv issues should filed on the `virtualenv - repo`_ at GitHub. - - Virtualenv's release schedule is tied to pip's -- each time there's a new pip - release, there will be a new virtualenv release that bundles the new version of - pip. - - Files in the `virtualenv_embedded/` subdirectory are embedded into - `virtualenv.py` itself as base64-encoded strings (in order to support - single-file use of `virtualenv.py` without installing it). If your patch - changes any file in `virtualenv_embedded/`, run `bin/rebuild-script.py` to - update the embedded version of that file in `virtualenv.py`; commit that and - submit it as part of your patch / pull request. - - .. _contributing to pip: http://www.pip-installer.org/en/latest/contributing.html - .. _virtualenv repo: https://github.com/pypa/virtualenv/ - - Running the tests - ~~~~~~~~~~~~~~~~~ - - Virtualenv's test suite is small and not yet at all comprehensive, but we aim - to grow it. - - The easy way to run tests (handles test dependencies automatically):: - - $ python setup.py test - - If you want to run only a selection of the tests, you'll need to run them - directly with nose instead. Create a virtualenv, and install required - packages:: - - $ pip install nose mock - - Run nosetests:: - - $ nosetests - - Or select just a single test file to run:: - - $ nosetests tests.test_virtualenv - - - Other Documentation and Links - ----------------------------- - - * James Gardner has written a tutorial on using `virtualenv with - Pylons - `_. - - * `Blog announcement - `_. - - * Doug Hellmann wrote a description of his `command-line work flow - using virtualenv (virtualenvwrapper) - `_ - including some handy scripts to make working with multiple - environments easier. He also wrote `an example of using virtualenv - to try IPython - `_. - - * Chris Perkins created a `showmedo video including virtualenv - `_. - - * `Using virtualenv with mod_wsgi - `_. - - * `virtualenv commands - `_ for some more - workflow-related tools around virtualenv. - - Status and License - ------------------ - - ``virtualenv`` is a successor to `workingenv - `_, and an extension - of `virtual-python - `_. - - It was written by Ian Bicking, sponsored by the `Open Planning - Project `_ and is now maintained by a - `group of developers `_. - It is licensed under an - `MIT-style permissive license `_. - - Changes & News - -------------- - - .. warning:: - - Python bugfix releases 2.6.8, 2.7.3, 3.1.5 and 3.2.3 include a change that - will cause "import random" to fail with "cannot import name urandom" on any - virtualenv created on a Unix host with an earlier release of Python - 2.6/2.7/3.1/3.2, if the underlying system Python is upgraded. This is due to - the fact that a virtualenv uses the system Python's standard library but - contains its own copy of the Python interpreter, so an upgrade to the system - Python results in a mismatch between the version of the Python interpreter - and the version of the standard library. It can be fixed by removing - ``$ENV/bin/python`` and re-running virtualenv on the same target directory - with the upgraded Python. - - 1.8.4 (2012-11-25) - ~~~~~~~~~~~~~~~~~~ - - * Updated distribute to 0.6.31. This fixes #359 (numpy install regression) on - UTF-8 platforms, and provides a workaround on other platforms: - ``PYTHONIOENCODING=utf8 pip install numpy``. - - * When installing virtualenv via curl, don't forget to filter out arguments - the distribute setup script won't understand. Fixes #358. - - * Added some more integration tests. - - 1.8.3 (2012-11-21) - ~~~~~~~~~~~~~~~~~~ - - * Fixed readline on OS X. Thanks minrk - - * Updated distribute to 0.6.30 (improves our error reporting, plus new - distribute features and fixes). Thanks Gabriel (g2p) - - * Added compatibility with multiarch Python (Python 3.3 for example). Added an - integration test. Thanks Gabriel (g2p) - - * Added ability to install distribute from a user-provided egg, rather than the - bundled sdist, for better speed. Thanks Paul Moore. - - * Make the creation of lib64 symlink smarter about already-existing symlink, - and more explicit about full paths. Fixes #334 and #330. Thanks Jeremy Orem. - - * Give lib64 site-dir preference over lib on 64-bit systems, to avoid wrong - 32-bit compiles in the venv. Fixes #328. Thanks Damien Nozay. - - * Fix a bug with prompt-handling in ``activate.csh`` in non-interactive csh - shells. Fixes #332. Thanks Benjamin Root for report and patch. - - * Make it possible to create a virtualenv from within a Python - 3.3. pyvenv. Thanks Chris McDonough for the report. - - * Add optional --setuptools option to be able to switch to it in case - distribute is the default (like in Debian). - - 1.8.2 (2012-09-06) - ~~~~~~~~~~~~~~~~~~ - - * Updated the included pip version to 1.2.1 to fix regressions introduced - there in 1.2. - - - 1.8.1 (2012-09-03) - ~~~~~~~~~~~~~~~~~~ - - * Fixed distribute version used with `--never-download`. Thanks michr for - report and patch. - - * Fix creating Python 3.3 based virtualenvs by unsetting the - ``__PYVENV_LAUNCHER__`` environment variable in subprocesses. - - - 1.8 (2012-09-01) - ~~~~~~~~~~~~~~~~ - - * **Dropped support for Python 2.4** The minimum supported Python version is - now Python 2.5. - - * Fix `--relocatable` on systems that use lib64. Fixes #78. Thanks Branden - Rolston. - - * Symlink some additional modules under Python 3. Fixes #194. Thanks Vinay - Sajip, Ian Clelland, and Stefan Holek for the report. - - * Fix ``--relocatable`` when a script uses ``__future__`` imports. Thanks - Branden Rolston. - - * Fix a bug in the config option parser that prevented setting negative - options with environemnt variables. Thanks Ralf Schmitt. - - * Allow setting ``--no-site-packages`` from the config file. - - * Use ``/usr/bin/multiarch-platform`` if available to figure out the include - directory. Thanks for the patch, Mika Laitio. - - * Fix ``install_name_tool`` replacement to work on Python 3.X. - - * Handle paths of users' site-packages on Mac OS X correctly when changing - the prefix. - - * Updated the embedded version of distribute to 0.6.28 and pip to 1.2. - - - 1.7.2 (2012-06-22) - ~~~~~~~~~~~~~~~~~~ - - * Updated to distribute 0.6.27. - - * Fix activate.fish on OS X. Fixes #8. Thanks David Schoonover. - - * Create a virtualenv-x.x script with the Python version when installing, so - virtualenv for multiple Python versions can be installed to the same - script location. Thanks Miki Tebeka. - - * Restored ability to create a virtualenv with a path longer than 78 - characters, without breaking creation of virtualenvs with non-ASCII paths. - Thanks, Bradley Ayers. - - * Added ability to create virtualenvs without having installed Apple's - developers tools (using an own implementation of ``install_name_tool``). - Thanks Mike Hommey. - - * Fixed PyPy and Jython support on Windows. Thanks Konstantin Zemlyak. - - * Added pydoc script to ease use. Thanks Marc Abramowitz. Fixes #149. - - * Fixed creating a bootstrap script on Python 3. Thanks Raul Leal. Fixes #280. - - * Fixed inconsistency when having set the ``PYTHONDONTWRITEBYTECODE`` env var - with the --distribute option or the ``VIRTUALENV_USE_DISTRIBUTE`` env var. - ``VIRTUALENV_USE_DISTRIBUTE`` is now considered again as a legacy alias. - - - 1.7.1.2 (2012-02-17) - ~~~~~~~~~~~~~~~~~~~~ - - * Fixed minor issue in `--relocatable`. Thanks, Cap Petschulat. - - - 1.7.1.1 (2012-02-16) - ~~~~~~~~~~~~~~~~~~~~ - - * Bumped the version string in ``virtualenv.py`` up, too. - - * Fixed rST rendering bug of long description. - - - 1.7.1 (2012-02-16) - ~~~~~~~~~~~~~~~~~~ - - * Update embedded pip to version 1.1. - - * Fix `--relocatable` under Python 3. Thanks Doug Hellmann. - - * Added environ PATH modification to activate_this.py. Thanks Doug - Napoleone. Fixes #14. - - * Support creating virtualenvs directly from a Python build directory on - Windows. Thanks CBWhiz. Fixes #139. - - * Use non-recursive symlinks to fix things up for posix_local install - scheme. Thanks michr. - - * Made activate script available for use with msys and cygwin on Windows. - Thanks Greg Haskins, Cliff Xuan, Jonathan Griffin and Doug Napoleone. - Fixes #176. - - * Fixed creation of virtualenvs on Windows when Python is not installed for - all users. Thanks Anatoly Techtonik for report and patch and Doug - Napoleone for testing and confirmation. Fixes #87. - - * Fixed creation of virtualenvs using -p in installs where some modules - that ought to be in the standard library (e.g. `readline`) are actually - installed in `site-packages` next to `virtualenv.py`. Thanks Greg Haskins - for report and fix. Fixes #167. - - * Added activation script for Powershell (signed by Jannis Leidel). Many - thanks to Jason R. Coombs. - - - 1.7 (2011-11-30) - ~~~~~~~~~~~~~~~~ - - * Gave user-provided ``--extra-search-dir`` priority over default dirs for - finding setuptools/distribute (it already had priority for finding pip). - Thanks Ethan Jucovy. - - * Updated embedded Distribute release to 0.6.24. Thanks Alex Gronholm. - - * Made ``--no-site-packages`` behavior the default behavior. The - ``--no-site-packages`` flag is still permitted, but displays a warning when - used. Thanks Chris McDonough. - - * New flag: ``--system-site-packages``; this flag should be passed to get the - previous default global-site-package-including behavior back. - - * Added ability to set command options as environment variables and options - in a ``virtualenv.ini`` file. - - * Fixed various encoding related issues with paths. Thanks Gunnlaugur Thor Briem. - - * Made ``virtualenv.py`` script executable. - - - 1.6.4 (2011-07-21) - ~~~~~~~~~~~~~~~~~~ - - * Restored ability to run on Python 2.4, too. - - - 1.6.3 (2011-07-16) - ~~~~~~~~~~~~~~~~~~ - - * Restored ability to run on Python < 2.7. - - - 1.6.2 (2011-07-16) - ~~~~~~~~~~~~~~~~~~ - - * Updated embedded distribute release to 0.6.19. - - * Updated embedded pip release to 1.0.2. - - * Fixed #141 - Be smarter about finding pkg_resources when using the - non-default Python intepreter (by using the ``-p`` option). - - * Fixed #112 - Fixed path in docs. - - * Fixed #109 - Corrected doctests of a Logger method. - - * Fixed #118 - Fixed creating virtualenvs on platforms that use the - "posix_local" install scheme, such as Ubuntu with Python 2.7. - - * Add missing library to Python 3 virtualenvs (``_dummy_thread``). - - - 1.6.1 (2011-04-30) - ~~~~~~~~~~~~~~~~~~ - - * Start to use git-flow. - - * Added support for PyPy 1.5 - - * Fixed #121 -- added sanity-checking of the -p argument. Thanks Paul Nasrat. - - * Added progress meter for pip installation as well as setuptools. Thanks Ethan - Jucovy. - - * Added --never-download and --search-dir options. Thanks Ethan Jucovy. - - - 1.6 - ~~~ - - * Added Python 3 support! Huge thanks to Vinay Sajip and Vitaly Babiy. - - * Fixed creation of virtualenvs on Mac OS X when standard library modules - (readline) are installed outside the standard library. - - * Updated bundled pip to 1.0. - - - 1.5.2 - ~~~~~ - - * Moved main repository to Github: https://github.com/pypa/virtualenv - - * Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer and Brian Rosner - - * Fixed a few more pypy related bugs. - - * Updated bundled pip to 0.8.2. - - * Handed project over to new team of maintainers. - - * Moved virtualenv to Github at https://github.com/pypa/virtualenv - - - 1.5.1 - ~~~~~ - - * Added ``_weakrefset`` requirement for Python 2.7.1. - - * Fixed Windows regression in 1.5 - - - 1.5 - ~~~ - - * Include pip 0.8.1. - - * Add support for PyPy. - - * Uses a proper temporary dir when installing environment requirements. - - * Add ``--prompt`` option to be able to override the default prompt prefix. - - * Fix an issue with ``--relocatable`` on Windows. - - * Fix issue with installing the wrong version of distribute. - - * Add fish and csh activate scripts. - - - 1.4.9 - ~~~~~ - - * Include pip 0.7.2 - - - 1.4.8 - ~~~~~ - - * Fix for Mac OS X Framework builds that use - ``--universal-archs=intel`` - - * Fix ``activate_this.py`` on Windows. - - * Allow ``$PYTHONHOME`` to be set, so long as you use ``source - bin/activate`` it will get unset; if you leave it set and do not - activate the environment it will still break the environment. - - * Include pip 0.7.1 - - - 1.4.7 - ~~~~~ - - * Include pip 0.7 - - - 1.4.6 - ~~~~~ - - * Allow ``activate.sh`` to skip updating the prompt (by setting - ``$VIRTUAL_ENV_DISABLE_PROMPT``). - - - 1.4.5 - ~~~~~ - - * Include pip 0.6.3 - - * Fix ``activate.bat`` and ``deactivate.bat`` under Windows when - ``PATH`` contained a parenthesis - - - 1.4.4 - ~~~~~ - - * Include pip 0.6.2 and Distribute 0.6.10 - - * Create the ``virtualenv`` script even when Setuptools isn't - installed - - * Fix problem with ``virtualenv --relocate`` when ``bin/`` has - subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni. - - * If you set ``$VIRTUALENV_DISTRIBUTE`` then virtualenv will use - Distribute by default (so you don't have to remember to use - ``--distribute``). - - - 1.4.3 - ~~~~~ - - * Include pip 0.6.1 - - - 1.4.2 - ~~~~~ - - * Fix pip installation on Windows - - * Fix use of stand-alone ``virtualenv.py`` (and boot scripts) - - * Exclude ~/.local (user site-packages) from environments when using - ``--no-site-packages`` - - - 1.4.1 - ~~~~~ - - * Include pip 0.6 - - - 1.4 - ~~~ - - * Updated setuptools to 0.6c11 - - * Added the --distribute option - - * Fixed packaging problem of support-files - - - 1.3.4 - ~~~~~ - - * Virtualenv now copies the actual embedded Python binary on - Mac OS X to fix a hang on Snow Leopard (10.6). - - * Fail more gracefully on Windows when ``win32api`` is not installed. - - * Fix site-packages taking precedent over Jython's ``__classpath__`` - and also specially handle the new ``__pyclasspath__`` entry in - ``sys.path``. - - * Now copies Jython's ``registry`` file to the virtualenv if it exists. - - * Better find libraries when compiling extensions on Windows. - - * Create ``Scripts\pythonw.exe`` on Windows. - - * Added support for the Debian/Ubuntu - ``/usr/lib/pythonX.Y/dist-packages`` directory. - - * Set ``distutils.sysconfig.get_config_vars()['LIBDIR']`` (based on - ``sys.real_prefix``) which is reported to help building on Windows. - - * Make ``deactivate`` work on ksh - - * Fixes for ``--python``: make it work with ``--relocatable`` and the - symlink created to the exact Python version. - - - 1.3.3 - ~~~~~ - - * Use Windows newlines in ``activate.bat``, which has been reported to help - when using non-ASCII directory names. - - * Fixed compatibility with Jython 2.5b1. - - * Added a function ``virtualenv.install_python`` for more fine-grained - access to what ``virtualenv.create_environment`` does. - - * Fix `a problem `_ - with Windows and paths that contain spaces. - - * If ``/path/to/env/.pydistutils.cfg`` exists (or - ``/path/to/env/pydistutils.cfg`` on Windows systems) then ignore - ``~/.pydistutils.cfg`` and use that other file instead. - - * Fix ` a problem - `_ picking up - some ``.so`` libraries in ``/usr/local``. - - - 1.3.2 - ~~~~~ - - * Remove the ``[install] prefix = ...`` setting from the virtualenv - ``distutils.cfg`` -- this has been causing problems for a lot of - people, in rather obscure ways. - - * If you use a boot script it will attempt to import ``virtualenv`` - and find a pre-downloaded Setuptools egg using that. - - * Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2`` - - - 1.3.1 - ~~~~~ - - * Real Python 2.6 compatibility. Backported the Python 2.6 updates to - ``site.py``, including `user directories - `_ - (this means older versions of Python will support user directories, - whether intended or not). - - * Always set ``[install] prefix`` in ``distutils.cfg`` -- previously - on some platforms where a system-wide ``distutils.cfg`` was present - with a ``prefix`` setting, packages would be installed globally - (usually in ``/usr/local/lib/pythonX.Y/site-packages``). - - * Sometimes Cygwin seems to leave ``.exe`` off ``sys.executable``; a - workaround is added. - - * Fix ``--python`` option. - - * Fixed handling of Jython environments that use a - jython-complete.jar. - - - 1.3 - ~~~ - - * Update to Setuptools 0.6c9 - * Added an option ``virtualenv --relocatable EXISTING_ENV``, which - will make an existing environment "relocatable" -- the paths will - not be absolute in scripts, ``.egg-info`` and ``.pth`` files. This - may assist in building environments that can be moved and copied. - You have to run this *after* any new packages installed. - * Added ``bin/activate_this.py``, a file you can use like - ``execfile("path_to/activate_this.py", - dict(__file__="path_to/activate_this.py"))`` -- this will activate - the environment in place, similar to what `the mod_wsgi example - does `_. - * For Mac framework builds of Python, the site-packages directory - ``/Library/Python/X.Y/site-packages`` is added to ``sys.path``, from - Andrea Rech. - * Some platform-specific modules in Macs are added to the path now - (``plat-darwin/``, ``plat-mac/``, ``plat-mac/lib-scriptpackages``), - from Andrea Rech. - * Fixed a small Bashism in the ``bin/activate`` shell script. - * Added ``__future__`` to the list of required modules, for Python - 2.3. You'll still need to backport your own ``subprocess`` module. - * Fixed the ``__classpath__`` entry in Jython's ``sys.path`` taking - precedent over virtualenv's libs. - - - 1.2 - ~~~ - - * Added a ``--python`` option to select the Python interpreter. - * Add ``warnings`` to the modules copied over, for Python 2.6 support. - * Add ``sets`` to the module copied over for Python 2.3 (though Python - 2.3 still probably doesn't work). - - - 1.1.1 - ~~~~~ - - * Added support for Jython 2.5. - - - 1.1 - ~~~ - - * Added support for Python 2.6. - * Fix a problem with missing ``DLLs/zlib.pyd`` on Windows. Create - * ``bin/python`` (or ``bin/python.exe``) even when you run virtualenv - with an interpreter named, e.g., ``python2.4`` - * Fix MacPorts Python - * Added --unzip-setuptools option - * Update to Setuptools 0.6c8 - * If the current directory is not writable, run ez_setup.py in ``/tmp`` - * Copy or symlink over the ``include`` directory so that packages will - more consistently compile. - - - 1.0 - ~~~ - - * Fix build on systems that use ``/usr/lib64``, distinct from - ``/usr/lib`` (specifically CentOS x64). - * Fixed bug in ``--clear``. - * Fixed typos in ``deactivate.bat``. - * Preserve ``$PYTHONPATH`` when calling subprocesses. - - - 0.9.2 - ~~~~~ - - * Fix include dir copying on Windows (makes compiling possible). - * Include the main ``lib-tk`` in the path. - * Patch ``distutils.sysconfig``: ``get_python_inc`` and - ``get_python_lib`` to point to the global locations. - * Install ``distutils.cfg`` before Setuptools, so that system - customizations of ``distutils.cfg`` won't effect the installation. - * Add ``bin/pythonX.Y`` to the virtualenv (in addition to - ``bin/python``). - * Fixed an issue with Mac Framework Python builds, and absolute paths - (from Ronald Oussoren). - - - 0.9.1 - ~~~~~ - - * Improve ability to create a virtualenv from inside a virtualenv. - * Fix a little bug in ``bin/activate``. - * Actually get ``distutils.cfg`` to work reliably. - - - 0.9 - ~~~ - - * Added ``lib-dynload`` and ``config`` to things that need to be - copied over in an environment. - * Copy over or symlink the ``include`` directory, so that you can - build packages that need the C headers. - * Include a ``distutils`` package, so you can locally update - ``distutils.cfg`` (in ``lib/pythonX.Y/distutils/distutils.cfg``). - * Better avoid downloading Setuptools, and hitting PyPI on environment - creation. - * Fix a problem creating a ``lib64/`` directory. - * Should work on MacOSX Framework builds (the default Python - installations on Mac). Thanks to Ronald Oussoren. - - - 0.8.4 - ~~~~~ - - * Windows installs would sometimes give errors about ``sys.prefix`` that - were inaccurate. - * Slightly prettier output. - - - 0.8.3 - ~~~~~ - - * Added support for Windows. - - - 0.8.2 - ~~~~~ - - * Give a better warning if you are on an unsupported platform (Mac - Framework Pythons, and Windows). - * Give error about running while inside a workingenv. - * Give better error message about Python 2.3. - - - 0.8.1 - ~~~~~ - - Fixed packaging of the library. - - - 0.8 - ~~~ - - Initial release. Everything is changed and new! - -Keywords: setuptools deployment installation distutils -Platform: UNKNOWN -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 2 -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 diff --git a/vendor/virtualenv-1.8.4/README.rst b/vendor/virtualenv-1.8.4/README.rst deleted file mode 100644 index 9016f31..0000000 --- a/vendor/virtualenv-1.8.4/README.rst +++ /dev/null @@ -1,7 +0,0 @@ -virtualenv -========== - -.. image:: https://secure.travis-ci.org/pypa/virtualenv.png?branch=develop - :target: http://travis-ci.org/pypa/virtualenv - -For documentation, see http://www.virtualenv.org/ diff --git a/vendor/virtualenv-1.8.4/bin/rebuild-script.py b/vendor/virtualenv-1.8.4/bin/rebuild-script.py deleted file mode 100755 index 44fb129..0000000 --- a/vendor/virtualenv-1.8.4/bin/rebuild-script.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -""" -Helper script to rebuild virtualenv.py from virtualenv_support -""" - -import re -import os -import sys - -here = os.path.dirname(__file__) -script = os.path.join(here, '..', 'virtualenv.py') - -file_regex = re.compile( - r'##file (.*?)\n([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*convert\("""(.*?)"""\)', - re.S) -file_template = '##file %(filename)s\n%(varname)s = convert("""\n%(data)s""")' - -def rebuild(): - f = open(script, 'rb') - content = f.read() - f.close() - parts = [] - last_pos = 0 - match = None - for match in file_regex.finditer(content): - parts.append(content[last_pos:match.start()]) - last_pos = match.end() - filename = match.group(1) - varname = match.group(2) - data = match.group(3) - print('Found reference to file %s' % filename) - pathname = os.path.join(here, '..', 'virtualenv_embedded', filename) - f = open(pathname, 'rb') - c = f.read() - f.close() - new_data = c.encode('zlib').encode('base64') - if new_data == data: - print(' Reference up to date (%s bytes)' % len(c)) - parts.append(match.group(0)) - continue - print(' Content changed (%s bytes -> %s bytes)' % ( - zipped_len(data), len(c))) - new_match = file_template % dict( - filename=filename, - varname=varname, - data=new_data) - parts.append(new_match) - parts.append(content[last_pos:]) - new_content = ''.join(parts) - if new_content != content: - sys.stdout.write('Content updated; overwriting... ') - f = open(script, 'wb') - f.write(new_content) - f.close() - print('done.') - else: - print('No changes in content') - if match is None: - print('No variables were matched/found') - -def zipped_len(data): - if not data: - return 'no data' - try: - return len(data.decode('base64').decode('zlib')) - except: - return 'unknown' - -if __name__ == '__main__': - rebuild() - diff --git a/vendor/virtualenv-1.8.4/bin/refresh-support-files.py b/vendor/virtualenv-1.8.4/bin/refresh-support-files.py deleted file mode 100755 index bad9419..0000000 --- a/vendor/virtualenv-1.8.4/bin/refresh-support-files.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -""" -Refresh any files in ../virtualenv_support/ that come from elsewhere -""" - -import os -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen -import sys - -here = os.path.dirname(__file__) -support_location = os.path.join(here, '..', 'virtualenv_support') -embedded_location = os.path.join(here, '..', 'virtualenv_embedded') - -embedded_files = [ - ('http://peak.telecommunity.com/dist/ez_setup.py', 'ez_setup.py'), - ('http://python-distribute.org/distribute_setup.py', 'distribute_setup.py'), -] - -support_files = [ - ('http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg', 'setuptools-0.6c11-py2.6.egg'), - ('http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c11-py2.5.egg', 'setuptools-0.6c11-py2.5.egg'), - ('http://pypi.python.org/packages/source/d/distribute/distribute-0.6.31.tar.gz', 'distribute-0.6.31.tar.gz'), - ('http://pypi.python.org/packages/source/p/pip/pip-1.2.1.tar.gz', 'pip-1.2.1.tar.gz'), -] - - -def refresh_files(files, location): - for url, filename in files: - sys.stdout.write('fetching %s ... ' % url) - sys.stdout.flush() - f = urlopen(url) - content = f.read() - f.close() - print('done.') - filename = os.path.join(location, filename) - if os.path.exists(filename): - f = open(filename, 'rb') - cur_content = f.read() - f.close() - else: - cur_content = '' - if cur_content == content: - print(' %s up-to-date' % filename) - else: - print(' overwriting %s' % filename) - f = open(filename, 'wb') - f.write(content) - f.close() - - -def main(): - refresh_files(embedded_files, embedded_location) - refresh_files(support_files, support_location) - -if __name__ == '__main__': - main() diff --git a/vendor/virtualenv-1.8.4/docs/conf.py b/vendor/virtualenv-1.8.4/docs/conf.py deleted file mode 100644 index 45a8226..0000000 --- a/vendor/virtualenv-1.8.4/docs/conf.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Paste documentation build configuration file, created by -# sphinx-quickstart on Tue Apr 22 22:08:49 2008. -# -# 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). -# -# All configuration values have a default value; values that are commented out -# serve to show the default value. - -import sys - -# If your extensions are in another directory, add it here. -#sys.path.append('some/directory') - -# 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 = ['sphinx.ext.autodoc'] - -# Add any paths that contain templates here, relative to this directory. -## FIXME: disabled for now because I haven't figured out how to use this: -#templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.txt' - -# The master toctree document. -master_doc = 'index' - -# General substitutions. -project = 'virtualenv' -copyright = '2007-2012, Ian Bicking, The Open Planning Project, The virtualenv developers' - -# The default replacements for |version| and |release|, also used in various -# other places throughout the built documents. -try: - from virtualenv import __version__ - # The short X.Y version. - version = '.'.join(__version__.split('.')[:2]) - # The full version, including alpha/beta/rc tags. - release = __version__ -except ImportError: - version = release = 'dev' - -# 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 = [] - -# 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' - - -# Options for HTML output -# ----------------------- - -# The style sheet to use for HTML and HTML Help pages. A file of that name -# must exist either in Sphinx' static/ path, or in one of the custom paths -# given in html_static_path. -#html_style = 'default.css' - -html_theme = 'nature' -html_theme_path = ['_theme'] - -# 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 - -# Content template for the index page. -#html_index = '' - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# 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 = True - -# If true, the reST sources are included in the HTML build as _sources/. -#html_copy_source = True - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Pastedoc' - - -# 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, document class [howto/manual]). -#latex_documents = [] - -# 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/virtualenv-1.8.4/docs/index.txt b/vendor/virtualenv-1.8.4/docs/index.txt deleted file mode 100644 index a65ff53..0000000 --- a/vendor/virtualenv-1.8.4/docs/index.txt +++ /dev/null @@ -1,573 +0,0 @@ -virtualenv -========== - -* `Discussion list `_ -* `Bugs `_ - -.. contents:: - -.. toctree:: - :maxdepth: 1 - - news - -.. comment: split here - -Installation ------------- - -You can install virtualenv with ``pip install virtualenv``, or the `latest -development version `_ -with ``pip install https://github.com/pypa/virtualenv/tarball/develop``. - -You can also use ``easy_install``, or if you have no Python package manager -available at all, you can just grab the single file `virtualenv.py`_ and run -it with ``python virtualenv.py``. - -.. _virtualenv.py: https://raw.github.com/pypa/virtualenv/master/virtualenv.py - -What It Does ------------- - -``virtualenv`` is a tool to create isolated Python environments. - -The basic problem being addressed is one of dependencies and versions, -and indirectly permissions. Imagine you have an application that -needs version 1 of LibFoo, but another application requires version -2. How can you use both these applications? If you install -everything into ``/usr/lib/python2.7/site-packages`` (or whatever your -platform's standard location is), it's easy to end up in a situation -where you unintentionally upgrade an application that shouldn't be -upgraded. - -Or more generally, what if you want to install an application *and -leave it be*? If an application works, any change in its libraries or -the versions of those libraries can break the application. - -Also, what if you can't install packages into the global -``site-packages`` directory? For instance, on a shared host. - -In all these cases, ``virtualenv`` can help you. It creates an -environment that has its own installation directories, that doesn't -share libraries with other virtualenv environments (and optionally -doesn't access the globally installed libraries either). - -Usage ------ - -The basic usage is:: - - $ python virtualenv.py ENV - -If you install it you can also just do ``virtualenv ENV``. - -This creates ``ENV/lib/pythonX.X/site-packages``, where any libraries you -install will go. It also creates ``ENV/bin/python``, which is a Python -interpreter that uses this environment. Anytime you use that interpreter -(including when a script has ``#!/path/to/ENV/bin/python`` in it) the libraries -in that environment will be used. - -It also installs either `Setuptools -`_ or `distribute -`_ into the environment. To use -Distribute instead of setuptools, just call virtualenv like this:: - - $ python virtualenv.py --distribute ENV - -You can also set the environment variable VIRTUALENV_DISTRIBUTE. - -A new virtualenv also includes the `pip `_ -installer, so you can use ``ENV/bin/pip`` to install additional packages into -the environment. - - -activate script -~~~~~~~~~~~~~~~ - -In a newly created virtualenv there will be a ``bin/activate`` shell -script. For Windows systems, activation scripts are provided for CMD.exe -and Powershell. - -On Posix systems you can do:: - - $ source bin/activate - -This will change your ``$PATH`` so its first entry is the virtualenv's -``bin/`` directory. (You have to use ``source`` because it changes your -shell environment in-place.) This is all it does; it's purely a -convenience. If you directly run a script or the python interpreter -from the virtualenv's ``bin/`` directory (e.g. ``path/to/env/bin/pip`` -or ``/path/to/env/bin/python script.py``) there's no need for -activation. - -After activating an environment you can use the function ``deactivate`` to -undo the changes to your ``$PATH``. - -The ``activate`` script will also modify your shell prompt to indicate -which environment is currently active. You can disable this behavior, -which can be useful if you have your own custom prompt that already -displays the active environment name. To do so, set the -``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty -value before running the ``activate`` script. - -On Windows you just do:: - - > \path\to\env\Scripts\activate - -And type `deactivate` to undo the changes. - -Based on your active shell (CMD.exe or Powershell.exe), Windows will use -either activate.bat or activate.ps1 (as appropriate) to activate the -virtual environment. If using Powershell, see the notes about code signing -below. - -.. note:: - - If using Powershell, the ``activate`` script is subject to the - `execution policies`_ on the system. By default on Windows 7, the system's - excution policy is set to ``Restricted``, meaning no scripts like the - ``activate`` script are allowed to be executed. But that can't stop us - from changing that slightly to allow it to be executed. - - In order to use the script, you have to relax your system's execution - policy to ``AllSigned``, meaning all scripts on the system must be - digitally signed to be executed. Since the virtualenv activation - script is signed by one of the authors (Jannis Leidel) this level of - the execution policy suffices. As an administrator run:: - - PS C:\> Set-ExecutionPolicy AllSigned - - Then you'll be asked to trust the signer, when executing the script. - You will be prompted with the following:: - - PS C:\> virtualenv .\foo - New python executable in C:\foo\Scripts\python.exe - Installing setuptools................done. - Installing pip...................done. - PS C:\> .\foo\scripts\activate - - Do you want to run software from this untrusted publisher? - File C:\foo\scripts\activate.ps1 is published by E=jannis@leidel.info, - CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0 - and is not trusted on your system. Only run scripts from trusted publishers. - [V] Never run [D] Do not run [R] Run once [A] Always run [?] Help - (default is "D"):A - (foo) PS C:\> - - If you select ``[A] Always Run``, the certificate will be added to the - Trusted Publishers of your user account, and will be trusted in this - user's context henceforth. If you select ``[R] Run Once``, the script will - be run, but you will be prometed on a subsequent invocation. Advanced users - can add the signer's certificate to the Trusted Publishers of the Computer - account to apply to all users (though this technique is out of scope of this - document). - - Alternatively, you may relax the system execution policy to allow running - of local scripts without verifying the code signature using the following:: - - PS C:\> Set-ExecutionPolicy RemoteSigned - - Since the ``activate.ps1`` script is generated locally for each virtualenv, - it is not considered a remote script and can then be executed. - -.. _`execution policies`: http://technet.microsoft.com/en-us/library/dd347641.aspx - -The ``--system-site-packages`` Option -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you build with ``virtualenv --system-site-packages ENV``, your virtual -environment will inherit packages from ``/usr/lib/python2.7/site-packages`` -(or wherever your global site-packages directory is). - -This can be used if you have control over the global site-packages directory, -and you want to depend on the packages there. If you want isolation from the -global system, do not use this flag. - - -Environment variables and configuration files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -virtualenv can not only be configured by passing command line options such as -``--distribute`` but also by two other means: - -- Environment variables - - Each command line option is automatically used to look for environment - variables with the name format ``VIRTUALENV_``. That means - the name of the command line options are capitalized and have dashes - (``'-'``) replaced with underscores (``'_'``). - - For example, to automatically install Distribute instead of setuptools - you can also set an environment variable:: - - $ export VIRTUALENV_DISTRIBUTE=true - $ python virtualenv.py ENV - - It's the same as passing the option to virtualenv directly:: - - $ python virtualenv.py --distribute ENV - - This also works for appending command line options, like ``--find-links``. - Just leave an empty space between the passsed values, e.g.:: - - $ export VIRTUALENV_EXTRA_SEARCH_DIR="/path/to/dists /path/to/other/dists" - $ virtualenv ENV - - is the same as calling:: - - $ python virtualenv.py --extra-search-dir=/path/to/dists --extra-search-dir=/path/to/other/dists ENV - -- Config files - - virtualenv also looks for a standard ini config file. On Unix and Mac OS X - that's ``$HOME/.virtualenv/virtualenv.ini`` and on Windows, it's - ``%APPDATA%\virtualenv\virtualenv.ini``. - - The names of the settings are derived from the long command line option, - e.g. the option ``--distribute`` would look like this:: - - [virtualenv] - distribute = true - - Appending options like ``--extra-search-dir`` can be written on multiple - lines:: - - [virtualenv] - extra-search-dir = - /path/to/dists - /path/to/other/dists - -Please have a look at the output of ``virtualenv --help`` for a full list -of supported options. - -Windows Notes -~~~~~~~~~~~~~ - -Some paths within the virtualenv are slightly different on Windows: scripts and -executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and -libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``. - -To create a virtualenv under a path with spaces in it on Windows, you'll need -the `win32api `_ library installed. - -PyPy Support -~~~~~~~~~~~~ - -Beginning with virtualenv version 1.5 `PyPy `_ is -supported. To use PyPy 1.4 or 1.4.1, you need a version of virtualenv >= 1.5. -To use PyPy 1.5, you need a version of virtualenv >= 1.6.1. - -Creating Your Own Bootstrap Scripts ------------------------------------ - -While this creates an environment, it doesn't put anything into the -environment. Developers may find it useful to distribute a script -that sets up a particular environment, for example a script that -installs a particular web application. - -To create a script like this, call -``virtualenv.create_bootstrap_script(extra_text)``, and write the -result to your new bootstrapping script. Here's the documentation -from the docstring: - -Creates a bootstrap script, which is like this script but with -extend_parser, adjust_options, and after_install hooks. - -This returns a string that (written to disk of course) can be used -as a bootstrap script with your own customizations. The script -will be the standard virtualenv.py script, with your extra text -added (your extra text should be Python code). - -If you include these functions, they will be called: - -``extend_parser(optparse_parser)``: - You can add or remove options from the parser here. - -``adjust_options(options, args)``: - You can change options here, or change the args (if you accept - different kinds of arguments, be sure you modify ``args`` so it is - only ``[DEST_DIR]``). - -``after_install(options, home_dir)``: - - After everything is installed, this function is called. This - is probably the function you are most likely to use. An - example would be:: - - def after_install(options, home_dir): - if sys.platform == 'win32': - bin = 'Scripts' - else: - bin = 'bin' - subprocess.call([join(home_dir, bin, 'easy_install'), - 'MyPackage']) - subprocess.call([join(home_dir, bin, 'my-package-script'), - 'setup', home_dir]) - - This example immediately installs a package, and runs a setup - script from that package. - -Bootstrap Example -~~~~~~~~~~~~~~~~~ - -Here's a more concrete example of how you could use this:: - - import virtualenv, textwrap - output = virtualenv.create_bootstrap_script(textwrap.dedent(""" - import os, subprocess - def after_install(options, home_dir): - etc = join(home_dir, 'etc') - if not os.path.exists(etc): - os.makedirs(etc) - subprocess.call([join(home_dir, 'bin', 'easy_install'), - 'BlogApplication']) - subprocess.call([join(home_dir, 'bin', 'paster'), - 'make-config', 'BlogApplication', - join(etc, 'blog.ini')]) - subprocess.call([join(home_dir, 'bin', 'paster'), - 'setup-app', join(etc, 'blog.ini')]) - """)) - f = open('blog-bootstrap.py', 'w').write(output) - -Another example is available `here -`_. - - -Using Virtualenv without ``bin/python`` ---------------------------------------- - -Sometimes you can't or don't want to use the Python interpreter -created by the virtualenv. For instance, in a `mod_python -`_ or `mod_wsgi `_ -environment, there is only one interpreter. - -Luckily, it's easy. You must use the custom Python interpreter to -*install* libraries. But to *use* libraries, you just have to be sure -the path is correct. A script is available to correct the path. You -can setup the environment like:: - - activate_this = '/path/to/env/bin/activate_this.py' - execfile(activate_this, dict(__file__=activate_this)) - -This will change ``sys.path`` and even change ``sys.prefix``, but also allow -you to use an existing interpreter. Items in your environment will show up -first on ``sys.path``, before global items. However, global items will -always be accessible (as if the ``--system-site-packages`` flag had been used -in creating the environment, whether it was or not). Also, this cannot undo -the activation of other environments, or modules that have been imported. -You shouldn't try to, for instance, activate an environment before a web -request; you should activate *one* environment as early as possible, and not -do it again in that process. - -Making Environments Relocatable -------------------------------- - -Note: this option is somewhat experimental, and there are probably -caveats that have not yet been identified. Also this does not -currently work on Windows. - -Normally environments are tied to a specific path. That means that -you cannot move an environment around or copy it to another computer. -You can fix up an environment to make it relocatable with the -command:: - - $ virtualenv --relocatable ENV - -This will make some of the files created by setuptools or distribute -use relative paths, and will change all the scripts to use ``activate_this.py`` -instead of using the location of the Python interpreter to select the -environment. - -**Note:** you must run this after you've installed *any* packages into -the environment. If you make an environment relocatable, then -install a new package, you must run ``virtualenv --relocatable`` -again. - -Also, this **does not make your packages cross-platform**. You can -move the directory around, but it can only be used on other similar -computers. Some known environmental differences that can cause -incompatibilities: a different version of Python, when one platform -uses UCS2 for its internal unicode representation and another uses -UCS4 (a compile-time option), obvious platform changes like Windows -vs. Linux, or Intel vs. ARM, and if you have libraries that bind to C -libraries on the system, if those C libraries are located somewhere -different (either different versions, or a different filesystem -layout). - -If you use this flag to create an environment, currently, the -``--system-site-packages`` option will be implied. - -The ``--extra-search-dir`` option ---------------------------------- - -When it creates a new environment, virtualenv installs either setuptools -or distribute, and pip. In normal operation when virtualenv is -installed, the bundled version of these packages included in the -``virtualenv_support`` directory is used. When ``virtualenv.py`` is run -standalone and ``virtualenv_support`` is not available, the latest -releases of these packages are fetched from the `Python Package Index -`_ (PyPI). - -As an alternative, you can provide your own versions of setuptools, -distribute and/or pip on the filesystem, and tell virtualenv to use -those distributions instead of downloading them from the Internet. To -use this feature, pass one or more ``--extra-search-dir`` options to -virtualenv like this:: - - $ virtualenv --extra-search-dir=/path/to/distributions ENV - -The ``/path/to/distributions`` path should point to a directory that -contains setuptools, distribute and/or pip distributions. Setuptools -distributions must be ``.egg`` files; pip distributions should be -`.tar.gz` source distributions, and distribute distributions may be -either (if found an egg will be used preferentially). - -Virtualenv will still download these packages if no satisfactory local -distributions are found. - -If you are really concerned about virtualenv fetching these packages -from the Internet and want to ensure that it never will, you can also -provide an option ``--never-download`` like so:: - - $ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV - -If this option is provided, virtualenv will never try to download -setuptools/distribute or pip. Instead, it will exit with status code 1 -if it fails to find local distributions for any of these required -packages. The local distribution lookup is done in the following -locations, with the most recent version found used: - - #. The current directory. - #. The directory where virtualenv.py is located. - #. A ``virtualenv_support`` directory relative to the directory where - virtualenv.py is located. - #. If the file being executed is not named virtualenv.py (i.e. is a boot - script), a ``virtualenv_support`` directory relative to wherever - virtualenv.py is actually installed. - - -Compare & Contrast with Alternatives ------------------------------------- - -There are several alternatives that create isolated environments: - -* ``workingenv`` (which I do not suggest you use anymore) is the - predecessor to this library. It used the main Python interpreter, - but relied on setting ``$PYTHONPATH`` to activate the environment. - This causes problems when running Python scripts that aren't part of - the environment (e.g., a globally installed ``hg`` or ``bzr``). It - also conflicted a lot with Setuptools. - -* `virtual-python - `_ - is also a predecessor to this library. It uses only symlinks, so it - couldn't work on Windows. It also symlinks over the *entire* - standard library and global ``site-packages``. As a result, it - won't see new additions to the global ``site-packages``. - - This script only symlinks a small portion of the standard library - into the environment, and so on Windows it is feasible to simply - copy these files over. Also, it creates a new/empty - ``site-packages`` and also adds the global ``site-packages`` to the - path, so updates are tracked separately. This script also installs - Setuptools automatically, saving a step and avoiding the need for - network access. - -* `zc.buildout `_ doesn't - create an isolated Python environment in the same style, but - achieves similar results through a declarative config file that sets - up scripts with very particular packages. As a declarative system, - it is somewhat easier to repeat and manage, but more difficult to - experiment with. ``zc.buildout`` includes the ability to setup - non-Python systems (e.g., a database server or an Apache instance). - -I *strongly* recommend anyone doing application development or -deployment use one of these tools. - -Contributing ------------- - -Refer to the `contributing to pip`_ documentation - it applies equally to -virtualenv, except that virtualenv issues should filed on the `virtualenv -repo`_ at GitHub. - -Virtualenv's release schedule is tied to pip's -- each time there's a new pip -release, there will be a new virtualenv release that bundles the new version of -pip. - -Files in the `virtualenv_embedded/` subdirectory are embedded into -`virtualenv.py` itself as base64-encoded strings (in order to support -single-file use of `virtualenv.py` without installing it). If your patch -changes any file in `virtualenv_embedded/`, run `bin/rebuild-script.py` to -update the embedded version of that file in `virtualenv.py`; commit that and -submit it as part of your patch / pull request. - -.. _contributing to pip: http://www.pip-installer.org/en/latest/contributing.html -.. _virtualenv repo: https://github.com/pypa/virtualenv/ - -Running the tests -~~~~~~~~~~~~~~~~~ - -Virtualenv's test suite is small and not yet at all comprehensive, but we aim -to grow it. - -The easy way to run tests (handles test dependencies automatically):: - - $ python setup.py test - -If you want to run only a selection of the tests, you'll need to run them -directly with nose instead. Create a virtualenv, and install required -packages:: - - $ pip install nose mock - -Run nosetests:: - - $ nosetests - -Or select just a single test file to run:: - - $ nosetests tests.test_virtualenv - - -Other Documentation and Links ------------------------------ - -* James Gardner has written a tutorial on using `virtualenv with - Pylons - `_. - -* `Blog announcement - `_. - -* Doug Hellmann wrote a description of his `command-line work flow - using virtualenv (virtualenvwrapper) - `_ - including some handy scripts to make working with multiple - environments easier. He also wrote `an example of using virtualenv - to try IPython - `_. - -* Chris Perkins created a `showmedo video including virtualenv - `_. - -* `Using virtualenv with mod_wsgi - `_. - -* `virtualenv commands - `_ for some more - workflow-related tools around virtualenv. - -Status and License ------------------- - -``virtualenv`` is a successor to `workingenv -`_, and an extension -of `virtual-python -`_. - -It was written by Ian Bicking, sponsored by the `Open Planning -Project `_ and is now maintained by a -`group of developers `_. -It is licensed under an -`MIT-style permissive license `_. diff --git a/vendor/virtualenv-1.8.4/docs/news.txt b/vendor/virtualenv-1.8.4/docs/news.txt deleted file mode 100644 index ef7de06..0000000 --- a/vendor/virtualenv-1.8.4/docs/news.txt +++ /dev/null @@ -1,626 +0,0 @@ -Changes & News --------------- - -.. warning:: - - Python bugfix releases 2.6.8, 2.7.3, 3.1.5 and 3.2.3 include a change that - will cause "import random" to fail with "cannot import name urandom" on any - virtualenv created on a Unix host with an earlier release of Python - 2.6/2.7/3.1/3.2, if the underlying system Python is upgraded. This is due to - the fact that a virtualenv uses the system Python's standard library but - contains its own copy of the Python interpreter, so an upgrade to the system - Python results in a mismatch between the version of the Python interpreter - and the version of the standard library. It can be fixed by removing - ``$ENV/bin/python`` and re-running virtualenv on the same target directory - with the upgraded Python. - -1.8.4 (2012-11-25) -~~~~~~~~~~~~~~~~~~ - -* Updated distribute to 0.6.31. This fixes #359 (numpy install regression) on - UTF-8 platforms, and provides a workaround on other platforms: - ``PYTHONIOENCODING=utf8 pip install numpy``. - -* When installing virtualenv via curl, don't forget to filter out arguments - the distribute setup script won't understand. Fixes #358. - -* Added some more integration tests. - -1.8.3 (2012-11-21) -~~~~~~~~~~~~~~~~~~ - -* Fixed readline on OS X. Thanks minrk - -* Updated distribute to 0.6.30 (improves our error reporting, plus new - distribute features and fixes). Thanks Gabriel (g2p) - -* Added compatibility with multiarch Python (Python 3.3 for example). Added an - integration test. Thanks Gabriel (g2p) - -* Added ability to install distribute from a user-provided egg, rather than the - bundled sdist, for better speed. Thanks Paul Moore. - -* Make the creation of lib64 symlink smarter about already-existing symlink, - and more explicit about full paths. Fixes #334 and #330. Thanks Jeremy Orem. - -* Give lib64 site-dir preference over lib on 64-bit systems, to avoid wrong - 32-bit compiles in the venv. Fixes #328. Thanks Damien Nozay. - -* Fix a bug with prompt-handling in ``activate.csh`` in non-interactive csh - shells. Fixes #332. Thanks Benjamin Root for report and patch. - -* Make it possible to create a virtualenv from within a Python - 3.3. pyvenv. Thanks Chris McDonough for the report. - -* Add optional --setuptools option to be able to switch to it in case - distribute is the default (like in Debian). - -1.8.2 (2012-09-06) -~~~~~~~~~~~~~~~~~~ - -* Updated the included pip version to 1.2.1 to fix regressions introduced - there in 1.2. - - -1.8.1 (2012-09-03) -~~~~~~~~~~~~~~~~~~ - -* Fixed distribute version used with `--never-download`. Thanks michr for - report and patch. - -* Fix creating Python 3.3 based virtualenvs by unsetting the - ``__PYVENV_LAUNCHER__`` environment variable in subprocesses. - - -1.8 (2012-09-01) -~~~~~~~~~~~~~~~~ - -* **Dropped support for Python 2.4** The minimum supported Python version is - now Python 2.5. - -* Fix `--relocatable` on systems that use lib64. Fixes #78. Thanks Branden - Rolston. - -* Symlink some additional modules under Python 3. Fixes #194. Thanks Vinay - Sajip, Ian Clelland, and Stefan Holek for the report. - -* Fix ``--relocatable`` when a script uses ``__future__`` imports. Thanks - Branden Rolston. - -* Fix a bug in the config option parser that prevented setting negative - options with environemnt variables. Thanks Ralf Schmitt. - -* Allow setting ``--no-site-packages`` from the config file. - -* Use ``/usr/bin/multiarch-platform`` if available to figure out the include - directory. Thanks for the patch, Mika Laitio. - -* Fix ``install_name_tool`` replacement to work on Python 3.X. - -* Handle paths of users' site-packages on Mac OS X correctly when changing - the prefix. - -* Updated the embedded version of distribute to 0.6.28 and pip to 1.2. - - -1.7.2 (2012-06-22) -~~~~~~~~~~~~~~~~~~ - -* Updated to distribute 0.6.27. - -* Fix activate.fish on OS X. Fixes #8. Thanks David Schoonover. - -* Create a virtualenv-x.x script with the Python version when installing, so - virtualenv for multiple Python versions can be installed to the same - script location. Thanks Miki Tebeka. - -* Restored ability to create a virtualenv with a path longer than 78 - characters, without breaking creation of virtualenvs with non-ASCII paths. - Thanks, Bradley Ayers. - -* Added ability to create virtualenvs without having installed Apple's - developers tools (using an own implementation of ``install_name_tool``). - Thanks Mike Hommey. - -* Fixed PyPy and Jython support on Windows. Thanks Konstantin Zemlyak. - -* Added pydoc script to ease use. Thanks Marc Abramowitz. Fixes #149. - -* Fixed creating a bootstrap script on Python 3. Thanks Raul Leal. Fixes #280. - -* Fixed inconsistency when having set the ``PYTHONDONTWRITEBYTECODE`` env var - with the --distribute option or the ``VIRTUALENV_USE_DISTRIBUTE`` env var. - ``VIRTUALENV_USE_DISTRIBUTE`` is now considered again as a legacy alias. - - -1.7.1.2 (2012-02-17) -~~~~~~~~~~~~~~~~~~~~ - -* Fixed minor issue in `--relocatable`. Thanks, Cap Petschulat. - - -1.7.1.1 (2012-02-16) -~~~~~~~~~~~~~~~~~~~~ - -* Bumped the version string in ``virtualenv.py`` up, too. - -* Fixed rST rendering bug of long description. - - -1.7.1 (2012-02-16) -~~~~~~~~~~~~~~~~~~ - -* Update embedded pip to version 1.1. - -* Fix `--relocatable` under Python 3. Thanks Doug Hellmann. - -* Added environ PATH modification to activate_this.py. Thanks Doug - Napoleone. Fixes #14. - -* Support creating virtualenvs directly from a Python build directory on - Windows. Thanks CBWhiz. Fixes #139. - -* Use non-recursive symlinks to fix things up for posix_local install - scheme. Thanks michr. - -* Made activate script available for use with msys and cygwin on Windows. - Thanks Greg Haskins, Cliff Xuan, Jonathan Griffin and Doug Napoleone. - Fixes #176. - -* Fixed creation of virtualenvs on Windows when Python is not installed for - all users. Thanks Anatoly Techtonik for report and patch and Doug - Napoleone for testing and confirmation. Fixes #87. - -* Fixed creation of virtualenvs using -p in installs where some modules - that ought to be in the standard library (e.g. `readline`) are actually - installed in `site-packages` next to `virtualenv.py`. Thanks Greg Haskins - for report and fix. Fixes #167. - -* Added activation script for Powershell (signed by Jannis Leidel). Many - thanks to Jason R. Coombs. - - -1.7 (2011-11-30) -~~~~~~~~~~~~~~~~ - -* Gave user-provided ``--extra-search-dir`` priority over default dirs for - finding setuptools/distribute (it already had priority for finding pip). - Thanks Ethan Jucovy. - -* Updated embedded Distribute release to 0.6.24. Thanks Alex Gronholm. - -* Made ``--no-site-packages`` behavior the default behavior. The - ``--no-site-packages`` flag is still permitted, but displays a warning when - used. Thanks Chris McDonough. - -* New flag: ``--system-site-packages``; this flag should be passed to get the - previous default global-site-package-including behavior back. - -* Added ability to set command options as environment variables and options - in a ``virtualenv.ini`` file. - -* Fixed various encoding related issues with paths. Thanks Gunnlaugur Thor Briem. - -* Made ``virtualenv.py`` script executable. - - -1.6.4 (2011-07-21) -~~~~~~~~~~~~~~~~~~ - -* Restored ability to run on Python 2.4, too. - - -1.6.3 (2011-07-16) -~~~~~~~~~~~~~~~~~~ - -* Restored ability to run on Python < 2.7. - - -1.6.2 (2011-07-16) -~~~~~~~~~~~~~~~~~~ - -* Updated embedded distribute release to 0.6.19. - -* Updated embedded pip release to 1.0.2. - -* Fixed #141 - Be smarter about finding pkg_resources when using the - non-default Python intepreter (by using the ``-p`` option). - -* Fixed #112 - Fixed path in docs. - -* Fixed #109 - Corrected doctests of a Logger method. - -* Fixed #118 - Fixed creating virtualenvs on platforms that use the - "posix_local" install scheme, such as Ubuntu with Python 2.7. - -* Add missing library to Python 3 virtualenvs (``_dummy_thread``). - - -1.6.1 (2011-04-30) -~~~~~~~~~~~~~~~~~~ - -* Start to use git-flow. - -* Added support for PyPy 1.5 - -* Fixed #121 -- added sanity-checking of the -p argument. Thanks Paul Nasrat. - -* Added progress meter for pip installation as well as setuptools. Thanks Ethan - Jucovy. - -* Added --never-download and --search-dir options. Thanks Ethan Jucovy. - - -1.6 -~~~ - -* Added Python 3 support! Huge thanks to Vinay Sajip and Vitaly Babiy. - -* Fixed creation of virtualenvs on Mac OS X when standard library modules - (readline) are installed outside the standard library. - -* Updated bundled pip to 1.0. - - -1.5.2 -~~~~~ - -* Moved main repository to Github: https://github.com/pypa/virtualenv - -* Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer and Brian Rosner - -* Fixed a few more pypy related bugs. - -* Updated bundled pip to 0.8.2. - -* Handed project over to new team of maintainers. - -* Moved virtualenv to Github at https://github.com/pypa/virtualenv - - -1.5.1 -~~~~~ - -* Added ``_weakrefset`` requirement for Python 2.7.1. - -* Fixed Windows regression in 1.5 - - -1.5 -~~~ - -* Include pip 0.8.1. - -* Add support for PyPy. - -* Uses a proper temporary dir when installing environment requirements. - -* Add ``--prompt`` option to be able to override the default prompt prefix. - -* Fix an issue with ``--relocatable`` on Windows. - -* Fix issue with installing the wrong version of distribute. - -* Add fish and csh activate scripts. - - -1.4.9 -~~~~~ - -* Include pip 0.7.2 - - -1.4.8 -~~~~~ - -* Fix for Mac OS X Framework builds that use - ``--universal-archs=intel`` - -* Fix ``activate_this.py`` on Windows. - -* Allow ``$PYTHONHOME`` to be set, so long as you use ``source - bin/activate`` it will get unset; if you leave it set and do not - activate the environment it will still break the environment. - -* Include pip 0.7.1 - - -1.4.7 -~~~~~ - -* Include pip 0.7 - - -1.4.6 -~~~~~ - -* Allow ``activate.sh`` to skip updating the prompt (by setting - ``$VIRTUAL_ENV_DISABLE_PROMPT``). - - -1.4.5 -~~~~~ - -* Include pip 0.6.3 - -* Fix ``activate.bat`` and ``deactivate.bat`` under Windows when - ``PATH`` contained a parenthesis - - -1.4.4 -~~~~~ - -* Include pip 0.6.2 and Distribute 0.6.10 - -* Create the ``virtualenv`` script even when Setuptools isn't - installed - -* Fix problem with ``virtualenv --relocate`` when ``bin/`` has - subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni. - -* If you set ``$VIRTUALENV_DISTRIBUTE`` then virtualenv will use - Distribute by default (so you don't have to remember to use - ``--distribute``). - - -1.4.3 -~~~~~ - -* Include pip 0.6.1 - - -1.4.2 -~~~~~ - -* Fix pip installation on Windows - -* Fix use of stand-alone ``virtualenv.py`` (and boot scripts) - -* Exclude ~/.local (user site-packages) from environments when using - ``--no-site-packages`` - - -1.4.1 -~~~~~ - -* Include pip 0.6 - - -1.4 -~~~ - -* Updated setuptools to 0.6c11 - -* Added the --distribute option - -* Fixed packaging problem of support-files - - -1.3.4 -~~~~~ - -* Virtualenv now copies the actual embedded Python binary on - Mac OS X to fix a hang on Snow Leopard (10.6). - -* Fail more gracefully on Windows when ``win32api`` is not installed. - -* Fix site-packages taking precedent over Jython's ``__classpath__`` - and also specially handle the new ``__pyclasspath__`` entry in - ``sys.path``. - -* Now copies Jython's ``registry`` file to the virtualenv if it exists. - -* Better find libraries when compiling extensions on Windows. - -* Create ``Scripts\pythonw.exe`` on Windows. - -* Added support for the Debian/Ubuntu - ``/usr/lib/pythonX.Y/dist-packages`` directory. - -* Set ``distutils.sysconfig.get_config_vars()['LIBDIR']`` (based on - ``sys.real_prefix``) which is reported to help building on Windows. - -* Make ``deactivate`` work on ksh - -* Fixes for ``--python``: make it work with ``--relocatable`` and the - symlink created to the exact Python version. - - -1.3.3 -~~~~~ - -* Use Windows newlines in ``activate.bat``, which has been reported to help - when using non-ASCII directory names. - -* Fixed compatibility with Jython 2.5b1. - -* Added a function ``virtualenv.install_python`` for more fine-grained - access to what ``virtualenv.create_environment`` does. - -* Fix `a problem `_ - with Windows and paths that contain spaces. - -* If ``/path/to/env/.pydistutils.cfg`` exists (or - ``/path/to/env/pydistutils.cfg`` on Windows systems) then ignore - ``~/.pydistutils.cfg`` and use that other file instead. - -* Fix ` a problem - `_ picking up - some ``.so`` libraries in ``/usr/local``. - - -1.3.2 -~~~~~ - -* Remove the ``[install] prefix = ...`` setting from the virtualenv - ``distutils.cfg`` -- this has been causing problems for a lot of - people, in rather obscure ways. - -* If you use a boot script it will attempt to import ``virtualenv`` - and find a pre-downloaded Setuptools egg using that. - -* Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2`` - - -1.3.1 -~~~~~ - -* Real Python 2.6 compatibility. Backported the Python 2.6 updates to - ``site.py``, including `user directories - `_ - (this means older versions of Python will support user directories, - whether intended or not). - -* Always set ``[install] prefix`` in ``distutils.cfg`` -- previously - on some platforms where a system-wide ``distutils.cfg`` was present - with a ``prefix`` setting, packages would be installed globally - (usually in ``/usr/local/lib/pythonX.Y/site-packages``). - -* Sometimes Cygwin seems to leave ``.exe`` off ``sys.executable``; a - workaround is added. - -* Fix ``--python`` option. - -* Fixed handling of Jython environments that use a - jython-complete.jar. - - -1.3 -~~~ - -* Update to Setuptools 0.6c9 -* Added an option ``virtualenv --relocatable EXISTING_ENV``, which - will make an existing environment "relocatable" -- the paths will - not be absolute in scripts, ``.egg-info`` and ``.pth`` files. This - may assist in building environments that can be moved and copied. - You have to run this *after* any new packages installed. -* Added ``bin/activate_this.py``, a file you can use like - ``execfile("path_to/activate_this.py", - dict(__file__="path_to/activate_this.py"))`` -- this will activate - the environment in place, similar to what `the mod_wsgi example - does `_. -* For Mac framework builds of Python, the site-packages directory - ``/Library/Python/X.Y/site-packages`` is added to ``sys.path``, from - Andrea Rech. -* Some platform-specific modules in Macs are added to the path now - (``plat-darwin/``, ``plat-mac/``, ``plat-mac/lib-scriptpackages``), - from Andrea Rech. -* Fixed a small Bashism in the ``bin/activate`` shell script. -* Added ``__future__`` to the list of required modules, for Python - 2.3. You'll still need to backport your own ``subprocess`` module. -* Fixed the ``__classpath__`` entry in Jython's ``sys.path`` taking - precedent over virtualenv's libs. - - -1.2 -~~~ - -* Added a ``--python`` option to select the Python interpreter. -* Add ``warnings`` to the modules copied over, for Python 2.6 support. -* Add ``sets`` to the module copied over for Python 2.3 (though Python - 2.3 still probably doesn't work). - - -1.1.1 -~~~~~ - -* Added support for Jython 2.5. - - -1.1 -~~~ - -* Added support for Python 2.6. -* Fix a problem with missing ``DLLs/zlib.pyd`` on Windows. Create -* ``bin/python`` (or ``bin/python.exe``) even when you run virtualenv - with an interpreter named, e.g., ``python2.4`` -* Fix MacPorts Python -* Added --unzip-setuptools option -* Update to Setuptools 0.6c8 -* If the current directory is not writable, run ez_setup.py in ``/tmp`` -* Copy or symlink over the ``include`` directory so that packages will - more consistently compile. - - -1.0 -~~~ - -* Fix build on systems that use ``/usr/lib64``, distinct from - ``/usr/lib`` (specifically CentOS x64). -* Fixed bug in ``--clear``. -* Fixed typos in ``deactivate.bat``. -* Preserve ``$PYTHONPATH`` when calling subprocesses. - - -0.9.2 -~~~~~ - -* Fix include dir copying on Windows (makes compiling possible). -* Include the main ``lib-tk`` in the path. -* Patch ``distutils.sysconfig``: ``get_python_inc`` and - ``get_python_lib`` to point to the global locations. -* Install ``distutils.cfg`` before Setuptools, so that system - customizations of ``distutils.cfg`` won't effect the installation. -* Add ``bin/pythonX.Y`` to the virtualenv (in addition to - ``bin/python``). -* Fixed an issue with Mac Framework Python builds, and absolute paths - (from Ronald Oussoren). - - -0.9.1 -~~~~~ - -* Improve ability to create a virtualenv from inside a virtualenv. -* Fix a little bug in ``bin/activate``. -* Actually get ``distutils.cfg`` to work reliably. - - -0.9 -~~~ - -* Added ``lib-dynload`` and ``config`` to things that need to be - copied over in an environment. -* Copy over or symlink the ``include`` directory, so that you can - build packages that need the C headers. -* Include a ``distutils`` package, so you can locally update - ``distutils.cfg`` (in ``lib/pythonX.Y/distutils/distutils.cfg``). -* Better avoid downloading Setuptools, and hitting PyPI on environment - creation. -* Fix a problem creating a ``lib64/`` directory. -* Should work on MacOSX Framework builds (the default Python - installations on Mac). Thanks to Ronald Oussoren. - - -0.8.4 -~~~~~ - -* Windows installs would sometimes give errors about ``sys.prefix`` that - were inaccurate. -* Slightly prettier output. - - -0.8.3 -~~~~~ - -* Added support for Windows. - - -0.8.2 -~~~~~ - -* Give a better warning if you are on an unsupported platform (Mac - Framework Pythons, and Windows). -* Give error about running while inside a workingenv. -* Give better error message about Python 2.3. - - -0.8.1 -~~~~~ - -Fixed packaging of the library. - - -0.8 -~~~ - -Initial release. Everything is changed and new! diff --git a/vendor/virtualenv-1.8.4/scripts/virtualenv b/vendor/virtualenv-1.8.4/scripts/virtualenv deleted file mode 100644 index c961dd7..0000000 --- a/vendor/virtualenv-1.8.4/scripts/virtualenv +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python -import virtualenv -virtualenv.main() diff --git a/vendor/virtualenv-1.8.4/setup.cfg b/vendor/virtualenv-1.8.4/setup.cfg deleted file mode 100644 index 861a9f5..0000000 --- a/vendor/virtualenv-1.8.4/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - diff --git a/vendor/virtualenv-1.8.4/setup.py b/vendor/virtualenv-1.8.4/setup.py deleted file mode 100644 index c9f6885..0000000 --- a/vendor/virtualenv-1.8.4/setup.py +++ /dev/null @@ -1,91 +0,0 @@ -import os -import re -import shutil -import sys - -try: - from setuptools import setup - setup_params = { - 'entry_points': { - 'console_scripts': [ - 'virtualenv=virtualenv:main', - 'virtualenv-%s.%s=virtualenv:main' % sys.version_info[:2] - ], - }, - 'zip_safe': False, - 'test_suite': 'nose.collector', - 'tests_require': ['nose', 'Mock'], - } -except ImportError: - from distutils.core import setup - if sys.platform == 'win32': - print('Note: without Setuptools installed you will have to use "python -m virtualenv ENV"') - setup_params = {} - else: - script = 'scripts/virtualenv' - script_ver = script + '-%s.%s' % sys.version_info[:2] - shutil.copy(script, script_ver) - setup_params = {'scripts': [script, script_ver]} - -here = os.path.dirname(os.path.abspath(__file__)) - -## Get long_description from index.txt: -f = open(os.path.join(here, 'docs', 'index.txt')) -long_description = f.read().strip() -long_description = long_description.split('split here', 1)[1] -f.close() -f = open(os.path.join(here, 'docs', 'news.txt')) -long_description += "\n\n" + f.read() -f.close() - - -def get_version(): - f = open(os.path.join(here, 'virtualenv.py')) - version_file = f.read() - f.close() - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - version_file, re.M) - if version_match: - return version_match.group(1) - raise RuntimeError("Unable to find version string.") - - -# Hack to prevent stupid TypeError: 'NoneType' object is not callable error on -# exit of python setup.py test # in multiprocessing/util.py _exit_function when -# running python setup.py test (see -# http://www.eby-sarna.com/pipermail/peak/2010-May/003357.html) -try: - import multiprocessing -except ImportError: - pass - -setup( - name='virtualenv', - # If you change the version here, change it in virtualenv.py and - # docs/conf.py as well - version=get_version(), - description="Virtual Python Environment builder", - long_description=long_description, - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2', - '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', - ], - keywords='setuptools deployment installation distutils', - author='Ian Bicking', - author_email='ianb@colorstudy.com', - maintainer='Jannis Leidel, Carl Meyer and Brian Rosner', - maintainer_email='python-virtualenv@groups.google.com', - url='http://www.virtualenv.org', - license='MIT', - py_modules=['virtualenv'], - packages=['virtualenv_support'], - package_data={'virtualenv_support': ['*-py%s.egg' % sys.version[:3], '*.tar.gz']}, - **setup_params) diff --git a/vendor/virtualenv-1.8.4/virtualenv.egg-info/PKG-INFO b/vendor/virtualenv-1.8.4/virtualenv.egg-info/PKG-INFO deleted file mode 100644 index 601d5fb..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.egg-info/PKG-INFO +++ /dev/null @@ -1,1208 +0,0 @@ -Metadata-Version: 1.1 -Name: virtualenv -Version: 1.8.4 -Summary: Virtual Python Environment builder -Home-page: http://www.virtualenv.org -Author: Jannis Leidel, Carl Meyer and Brian Rosner -Author-email: python-virtualenv@groups.google.com -License: MIT -Description: - - Installation - ------------ - - You can install virtualenv with ``pip install virtualenv``, or the `latest - development version `_ - with ``pip install https://github.com/pypa/virtualenv/tarball/develop``. - - You can also use ``easy_install``, or if you have no Python package manager - available at all, you can just grab the single file `virtualenv.py`_ and run - it with ``python virtualenv.py``. - - .. _virtualenv.py: https://raw.github.com/pypa/virtualenv/master/virtualenv.py - - What It Does - ------------ - - ``virtualenv`` is a tool to create isolated Python environments. - - The basic problem being addressed is one of dependencies and versions, - and indirectly permissions. Imagine you have an application that - needs version 1 of LibFoo, but another application requires version - 2. How can you use both these applications? If you install - everything into ``/usr/lib/python2.7/site-packages`` (or whatever your - platform's standard location is), it's easy to end up in a situation - where you unintentionally upgrade an application that shouldn't be - upgraded. - - Or more generally, what if you want to install an application *and - leave it be*? If an application works, any change in its libraries or - the versions of those libraries can break the application. - - Also, what if you can't install packages into the global - ``site-packages`` directory? For instance, on a shared host. - - In all these cases, ``virtualenv`` can help you. It creates an - environment that has its own installation directories, that doesn't - share libraries with other virtualenv environments (and optionally - doesn't access the globally installed libraries either). - - Usage - ----- - - The basic usage is:: - - $ python virtualenv.py ENV - - If you install it you can also just do ``virtualenv ENV``. - - This creates ``ENV/lib/pythonX.X/site-packages``, where any libraries you - install will go. It also creates ``ENV/bin/python``, which is a Python - interpreter that uses this environment. Anytime you use that interpreter - (including when a script has ``#!/path/to/ENV/bin/python`` in it) the libraries - in that environment will be used. - - It also installs either `Setuptools - `_ or `distribute - `_ into the environment. To use - Distribute instead of setuptools, just call virtualenv like this:: - - $ python virtualenv.py --distribute ENV - - You can also set the environment variable VIRTUALENV_DISTRIBUTE. - - A new virtualenv also includes the `pip `_ - installer, so you can use ``ENV/bin/pip`` to install additional packages into - the environment. - - - activate script - ~~~~~~~~~~~~~~~ - - In a newly created virtualenv there will be a ``bin/activate`` shell - script. For Windows systems, activation scripts are provided for CMD.exe - and Powershell. - - On Posix systems you can do:: - - $ source bin/activate - - This will change your ``$PATH`` so its first entry is the virtualenv's - ``bin/`` directory. (You have to use ``source`` because it changes your - shell environment in-place.) This is all it does; it's purely a - convenience. If you directly run a script or the python interpreter - from the virtualenv's ``bin/`` directory (e.g. ``path/to/env/bin/pip`` - or ``/path/to/env/bin/python script.py``) there's no need for - activation. - - After activating an environment you can use the function ``deactivate`` to - undo the changes to your ``$PATH``. - - The ``activate`` script will also modify your shell prompt to indicate - which environment is currently active. You can disable this behavior, - which can be useful if you have your own custom prompt that already - displays the active environment name. To do so, set the - ``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty - value before running the ``activate`` script. - - On Windows you just do:: - - > \path\to\env\Scripts\activate - - And type `deactivate` to undo the changes. - - Based on your active shell (CMD.exe or Powershell.exe), Windows will use - either activate.bat or activate.ps1 (as appropriate) to activate the - virtual environment. If using Powershell, see the notes about code signing - below. - - .. note:: - - If using Powershell, the ``activate`` script is subject to the - `execution policies`_ on the system. By default on Windows 7, the system's - excution policy is set to ``Restricted``, meaning no scripts like the - ``activate`` script are allowed to be executed. But that can't stop us - from changing that slightly to allow it to be executed. - - In order to use the script, you have to relax your system's execution - policy to ``AllSigned``, meaning all scripts on the system must be - digitally signed to be executed. Since the virtualenv activation - script is signed by one of the authors (Jannis Leidel) this level of - the execution policy suffices. As an administrator run:: - - PS C:\> Set-ExecutionPolicy AllSigned - - Then you'll be asked to trust the signer, when executing the script. - You will be prompted with the following:: - - PS C:\> virtualenv .\foo - New python executable in C:\foo\Scripts\python.exe - Installing setuptools................done. - Installing pip...................done. - PS C:\> .\foo\scripts\activate - - Do you want to run software from this untrusted publisher? - File C:\foo\scripts\activate.ps1 is published by E=jannis@leidel.info, - CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0 - and is not trusted on your system. Only run scripts from trusted publishers. - [V] Never run [D] Do not run [R] Run once [A] Always run [?] Help - (default is "D"):A - (foo) PS C:\> - - If you select ``[A] Always Run``, the certificate will be added to the - Trusted Publishers of your user account, and will be trusted in this - user's context henceforth. If you select ``[R] Run Once``, the script will - be run, but you will be prometed on a subsequent invocation. Advanced users - can add the signer's certificate to the Trusted Publishers of the Computer - account to apply to all users (though this technique is out of scope of this - document). - - Alternatively, you may relax the system execution policy to allow running - of local scripts without verifying the code signature using the following:: - - PS C:\> Set-ExecutionPolicy RemoteSigned - - Since the ``activate.ps1`` script is generated locally for each virtualenv, - it is not considered a remote script and can then be executed. - - .. _`execution policies`: http://technet.microsoft.com/en-us/library/dd347641.aspx - - The ``--system-site-packages`` Option - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - If you build with ``virtualenv --system-site-packages ENV``, your virtual - environment will inherit packages from ``/usr/lib/python2.7/site-packages`` - (or wherever your global site-packages directory is). - - This can be used if you have control over the global site-packages directory, - and you want to depend on the packages there. If you want isolation from the - global system, do not use this flag. - - - Environment variables and configuration files - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - virtualenv can not only be configured by passing command line options such as - ``--distribute`` but also by two other means: - - - Environment variables - - Each command line option is automatically used to look for environment - variables with the name format ``VIRTUALENV_``. That means - the name of the command line options are capitalized and have dashes - (``'-'``) replaced with underscores (``'_'``). - - For example, to automatically install Distribute instead of setuptools - you can also set an environment variable:: - - $ export VIRTUALENV_DISTRIBUTE=true - $ python virtualenv.py ENV - - It's the same as passing the option to virtualenv directly:: - - $ python virtualenv.py --distribute ENV - - This also works for appending command line options, like ``--find-links``. - Just leave an empty space between the passsed values, e.g.:: - - $ export VIRTUALENV_EXTRA_SEARCH_DIR="/path/to/dists /path/to/other/dists" - $ virtualenv ENV - - is the same as calling:: - - $ python virtualenv.py --extra-search-dir=/path/to/dists --extra-search-dir=/path/to/other/dists ENV - - - Config files - - virtualenv also looks for a standard ini config file. On Unix and Mac OS X - that's ``$HOME/.virtualenv/virtualenv.ini`` and on Windows, it's - ``%APPDATA%\virtualenv\virtualenv.ini``. - - The names of the settings are derived from the long command line option, - e.g. the option ``--distribute`` would look like this:: - - [virtualenv] - distribute = true - - Appending options like ``--extra-search-dir`` can be written on multiple - lines:: - - [virtualenv] - extra-search-dir = - /path/to/dists - /path/to/other/dists - - Please have a look at the output of ``virtualenv --help`` for a full list - of supported options. - - Windows Notes - ~~~~~~~~~~~~~ - - Some paths within the virtualenv are slightly different on Windows: scripts and - executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and - libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``. - - To create a virtualenv under a path with spaces in it on Windows, you'll need - the `win32api `_ library installed. - - PyPy Support - ~~~~~~~~~~~~ - - Beginning with virtualenv version 1.5 `PyPy `_ is - supported. To use PyPy 1.4 or 1.4.1, you need a version of virtualenv >= 1.5. - To use PyPy 1.5, you need a version of virtualenv >= 1.6.1. - - Creating Your Own Bootstrap Scripts - ----------------------------------- - - While this creates an environment, it doesn't put anything into the - environment. Developers may find it useful to distribute a script - that sets up a particular environment, for example a script that - installs a particular web application. - - To create a script like this, call - ``virtualenv.create_bootstrap_script(extra_text)``, and write the - result to your new bootstrapping script. Here's the documentation - from the docstring: - - Creates a bootstrap script, which is like this script but with - extend_parser, adjust_options, and after_install hooks. - - This returns a string that (written to disk of course) can be used - as a bootstrap script with your own customizations. The script - will be the standard virtualenv.py script, with your extra text - added (your extra text should be Python code). - - If you include these functions, they will be called: - - ``extend_parser(optparse_parser)``: - You can add or remove options from the parser here. - - ``adjust_options(options, args)``: - You can change options here, or change the args (if you accept - different kinds of arguments, be sure you modify ``args`` so it is - only ``[DEST_DIR]``). - - ``after_install(options, home_dir)``: - - After everything is installed, this function is called. This - is probably the function you are most likely to use. An - example would be:: - - def after_install(options, home_dir): - if sys.platform == 'win32': - bin = 'Scripts' - else: - bin = 'bin' - subprocess.call([join(home_dir, bin, 'easy_install'), - 'MyPackage']) - subprocess.call([join(home_dir, bin, 'my-package-script'), - 'setup', home_dir]) - - This example immediately installs a package, and runs a setup - script from that package. - - Bootstrap Example - ~~~~~~~~~~~~~~~~~ - - Here's a more concrete example of how you could use this:: - - import virtualenv, textwrap - output = virtualenv.create_bootstrap_script(textwrap.dedent(""" - import os, subprocess - def after_install(options, home_dir): - etc = join(home_dir, 'etc') - if not os.path.exists(etc): - os.makedirs(etc) - subprocess.call([join(home_dir, 'bin', 'easy_install'), - 'BlogApplication']) - subprocess.call([join(home_dir, 'bin', 'paster'), - 'make-config', 'BlogApplication', - join(etc, 'blog.ini')]) - subprocess.call([join(home_dir, 'bin', 'paster'), - 'setup-app', join(etc, 'blog.ini')]) - """)) - f = open('blog-bootstrap.py', 'w').write(output) - - Another example is available `here - `_. - - - Using Virtualenv without ``bin/python`` - --------------------------------------- - - Sometimes you can't or don't want to use the Python interpreter - created by the virtualenv. For instance, in a `mod_python - `_ or `mod_wsgi `_ - environment, there is only one interpreter. - - Luckily, it's easy. You must use the custom Python interpreter to - *install* libraries. But to *use* libraries, you just have to be sure - the path is correct. A script is available to correct the path. You - can setup the environment like:: - - activate_this = '/path/to/env/bin/activate_this.py' - execfile(activate_this, dict(__file__=activate_this)) - - This will change ``sys.path`` and even change ``sys.prefix``, but also allow - you to use an existing interpreter. Items in your environment will show up - first on ``sys.path``, before global items. However, global items will - always be accessible (as if the ``--system-site-packages`` flag had been used - in creating the environment, whether it was or not). Also, this cannot undo - the activation of other environments, or modules that have been imported. - You shouldn't try to, for instance, activate an environment before a web - request; you should activate *one* environment as early as possible, and not - do it again in that process. - - Making Environments Relocatable - ------------------------------- - - Note: this option is somewhat experimental, and there are probably - caveats that have not yet been identified. Also this does not - currently work on Windows. - - Normally environments are tied to a specific path. That means that - you cannot move an environment around or copy it to another computer. - You can fix up an environment to make it relocatable with the - command:: - - $ virtualenv --relocatable ENV - - This will make some of the files created by setuptools or distribute - use relative paths, and will change all the scripts to use ``activate_this.py`` - instead of using the location of the Python interpreter to select the - environment. - - **Note:** you must run this after you've installed *any* packages into - the environment. If you make an environment relocatable, then - install a new package, you must run ``virtualenv --relocatable`` - again. - - Also, this **does not make your packages cross-platform**. You can - move the directory around, but it can only be used on other similar - computers. Some known environmental differences that can cause - incompatibilities: a different version of Python, when one platform - uses UCS2 for its internal unicode representation and another uses - UCS4 (a compile-time option), obvious platform changes like Windows - vs. Linux, or Intel vs. ARM, and if you have libraries that bind to C - libraries on the system, if those C libraries are located somewhere - different (either different versions, or a different filesystem - layout). - - If you use this flag to create an environment, currently, the - ``--system-site-packages`` option will be implied. - - The ``--extra-search-dir`` option - --------------------------------- - - When it creates a new environment, virtualenv installs either setuptools - or distribute, and pip. In normal operation when virtualenv is - installed, the bundled version of these packages included in the - ``virtualenv_support`` directory is used. When ``virtualenv.py`` is run - standalone and ``virtualenv_support`` is not available, the latest - releases of these packages are fetched from the `Python Package Index - `_ (PyPI). - - As an alternative, you can provide your own versions of setuptools, - distribute and/or pip on the filesystem, and tell virtualenv to use - those distributions instead of downloading them from the Internet. To - use this feature, pass one or more ``--extra-search-dir`` options to - virtualenv like this:: - - $ virtualenv --extra-search-dir=/path/to/distributions ENV - - The ``/path/to/distributions`` path should point to a directory that - contains setuptools, distribute and/or pip distributions. Setuptools - distributions must be ``.egg`` files; pip distributions should be - `.tar.gz` source distributions, and distribute distributions may be - either (if found an egg will be used preferentially). - - Virtualenv will still download these packages if no satisfactory local - distributions are found. - - If you are really concerned about virtualenv fetching these packages - from the Internet and want to ensure that it never will, you can also - provide an option ``--never-download`` like so:: - - $ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV - - If this option is provided, virtualenv will never try to download - setuptools/distribute or pip. Instead, it will exit with status code 1 - if it fails to find local distributions for any of these required - packages. The local distribution lookup is done in the following - locations, with the most recent version found used: - - #. The current directory. - #. The directory where virtualenv.py is located. - #. A ``virtualenv_support`` directory relative to the directory where - virtualenv.py is located. - #. If the file being executed is not named virtualenv.py (i.e. is a boot - script), a ``virtualenv_support`` directory relative to wherever - virtualenv.py is actually installed. - - - Compare & Contrast with Alternatives - ------------------------------------ - - There are several alternatives that create isolated environments: - - * ``workingenv`` (which I do not suggest you use anymore) is the - predecessor to this library. It used the main Python interpreter, - but relied on setting ``$PYTHONPATH`` to activate the environment. - This causes problems when running Python scripts that aren't part of - the environment (e.g., a globally installed ``hg`` or ``bzr``). It - also conflicted a lot with Setuptools. - - * `virtual-python - `_ - is also a predecessor to this library. It uses only symlinks, so it - couldn't work on Windows. It also symlinks over the *entire* - standard library and global ``site-packages``. As a result, it - won't see new additions to the global ``site-packages``. - - This script only symlinks a small portion of the standard library - into the environment, and so on Windows it is feasible to simply - copy these files over. Also, it creates a new/empty - ``site-packages`` and also adds the global ``site-packages`` to the - path, so updates are tracked separately. This script also installs - Setuptools automatically, saving a step and avoiding the need for - network access. - - * `zc.buildout `_ doesn't - create an isolated Python environment in the same style, but - achieves similar results through a declarative config file that sets - up scripts with very particular packages. As a declarative system, - it is somewhat easier to repeat and manage, but more difficult to - experiment with. ``zc.buildout`` includes the ability to setup - non-Python systems (e.g., a database server or an Apache instance). - - I *strongly* recommend anyone doing application development or - deployment use one of these tools. - - Contributing - ------------ - - Refer to the `contributing to pip`_ documentation - it applies equally to - virtualenv, except that virtualenv issues should filed on the `virtualenv - repo`_ at GitHub. - - Virtualenv's release schedule is tied to pip's -- each time there's a new pip - release, there will be a new virtualenv release that bundles the new version of - pip. - - Files in the `virtualenv_embedded/` subdirectory are embedded into - `virtualenv.py` itself as base64-encoded strings (in order to support - single-file use of `virtualenv.py` without installing it). If your patch - changes any file in `virtualenv_embedded/`, run `bin/rebuild-script.py` to - update the embedded version of that file in `virtualenv.py`; commit that and - submit it as part of your patch / pull request. - - .. _contributing to pip: http://www.pip-installer.org/en/latest/contributing.html - .. _virtualenv repo: https://github.com/pypa/virtualenv/ - - Running the tests - ~~~~~~~~~~~~~~~~~ - - Virtualenv's test suite is small and not yet at all comprehensive, but we aim - to grow it. - - The easy way to run tests (handles test dependencies automatically):: - - $ python setup.py test - - If you want to run only a selection of the tests, you'll need to run them - directly with nose instead. Create a virtualenv, and install required - packages:: - - $ pip install nose mock - - Run nosetests:: - - $ nosetests - - Or select just a single test file to run:: - - $ nosetests tests.test_virtualenv - - - Other Documentation and Links - ----------------------------- - - * James Gardner has written a tutorial on using `virtualenv with - Pylons - `_. - - * `Blog announcement - `_. - - * Doug Hellmann wrote a description of his `command-line work flow - using virtualenv (virtualenvwrapper) - `_ - including some handy scripts to make working with multiple - environments easier. He also wrote `an example of using virtualenv - to try IPython - `_. - - * Chris Perkins created a `showmedo video including virtualenv - `_. - - * `Using virtualenv with mod_wsgi - `_. - - * `virtualenv commands - `_ for some more - workflow-related tools around virtualenv. - - Status and License - ------------------ - - ``virtualenv`` is a successor to `workingenv - `_, and an extension - of `virtual-python - `_. - - It was written by Ian Bicking, sponsored by the `Open Planning - Project `_ and is now maintained by a - `group of developers `_. - It is licensed under an - `MIT-style permissive license `_. - - Changes & News - -------------- - - .. warning:: - - Python bugfix releases 2.6.8, 2.7.3, 3.1.5 and 3.2.3 include a change that - will cause "import random" to fail with "cannot import name urandom" on any - virtualenv created on a Unix host with an earlier release of Python - 2.6/2.7/3.1/3.2, if the underlying system Python is upgraded. This is due to - the fact that a virtualenv uses the system Python's standard library but - contains its own copy of the Python interpreter, so an upgrade to the system - Python results in a mismatch between the version of the Python interpreter - and the version of the standard library. It can be fixed by removing - ``$ENV/bin/python`` and re-running virtualenv on the same target directory - with the upgraded Python. - - 1.8.4 (2012-11-25) - ~~~~~~~~~~~~~~~~~~ - - * Updated distribute to 0.6.31. This fixes #359 (numpy install regression) on - UTF-8 platforms, and provides a workaround on other platforms: - ``PYTHONIOENCODING=utf8 pip install numpy``. - - * When installing virtualenv via curl, don't forget to filter out arguments - the distribute setup script won't understand. Fixes #358. - - * Added some more integration tests. - - 1.8.3 (2012-11-21) - ~~~~~~~~~~~~~~~~~~ - - * Fixed readline on OS X. Thanks minrk - - * Updated distribute to 0.6.30 (improves our error reporting, plus new - distribute features and fixes). Thanks Gabriel (g2p) - - * Added compatibility with multiarch Python (Python 3.3 for example). Added an - integration test. Thanks Gabriel (g2p) - - * Added ability to install distribute from a user-provided egg, rather than the - bundled sdist, for better speed. Thanks Paul Moore. - - * Make the creation of lib64 symlink smarter about already-existing symlink, - and more explicit about full paths. Fixes #334 and #330. Thanks Jeremy Orem. - - * Give lib64 site-dir preference over lib on 64-bit systems, to avoid wrong - 32-bit compiles in the venv. Fixes #328. Thanks Damien Nozay. - - * Fix a bug with prompt-handling in ``activate.csh`` in non-interactive csh - shells. Fixes #332. Thanks Benjamin Root for report and patch. - - * Make it possible to create a virtualenv from within a Python - 3.3. pyvenv. Thanks Chris McDonough for the report. - - * Add optional --setuptools option to be able to switch to it in case - distribute is the default (like in Debian). - - 1.8.2 (2012-09-06) - ~~~~~~~~~~~~~~~~~~ - - * Updated the included pip version to 1.2.1 to fix regressions introduced - there in 1.2. - - - 1.8.1 (2012-09-03) - ~~~~~~~~~~~~~~~~~~ - - * Fixed distribute version used with `--never-download`. Thanks michr for - report and patch. - - * Fix creating Python 3.3 based virtualenvs by unsetting the - ``__PYVENV_LAUNCHER__`` environment variable in subprocesses. - - - 1.8 (2012-09-01) - ~~~~~~~~~~~~~~~~ - - * **Dropped support for Python 2.4** The minimum supported Python version is - now Python 2.5. - - * Fix `--relocatable` on systems that use lib64. Fixes #78. Thanks Branden - Rolston. - - * Symlink some additional modules under Python 3. Fixes #194. Thanks Vinay - Sajip, Ian Clelland, and Stefan Holek for the report. - - * Fix ``--relocatable`` when a script uses ``__future__`` imports. Thanks - Branden Rolston. - - * Fix a bug in the config option parser that prevented setting negative - options with environemnt variables. Thanks Ralf Schmitt. - - * Allow setting ``--no-site-packages`` from the config file. - - * Use ``/usr/bin/multiarch-platform`` if available to figure out the include - directory. Thanks for the patch, Mika Laitio. - - * Fix ``install_name_tool`` replacement to work on Python 3.X. - - * Handle paths of users' site-packages on Mac OS X correctly when changing - the prefix. - - * Updated the embedded version of distribute to 0.6.28 and pip to 1.2. - - - 1.7.2 (2012-06-22) - ~~~~~~~~~~~~~~~~~~ - - * Updated to distribute 0.6.27. - - * Fix activate.fish on OS X. Fixes #8. Thanks David Schoonover. - - * Create a virtualenv-x.x script with the Python version when installing, so - virtualenv for multiple Python versions can be installed to the same - script location. Thanks Miki Tebeka. - - * Restored ability to create a virtualenv with a path longer than 78 - characters, without breaking creation of virtualenvs with non-ASCII paths. - Thanks, Bradley Ayers. - - * Added ability to create virtualenvs without having installed Apple's - developers tools (using an own implementation of ``install_name_tool``). - Thanks Mike Hommey. - - * Fixed PyPy and Jython support on Windows. Thanks Konstantin Zemlyak. - - * Added pydoc script to ease use. Thanks Marc Abramowitz. Fixes #149. - - * Fixed creating a bootstrap script on Python 3. Thanks Raul Leal. Fixes #280. - - * Fixed inconsistency when having set the ``PYTHONDONTWRITEBYTECODE`` env var - with the --distribute option or the ``VIRTUALENV_USE_DISTRIBUTE`` env var. - ``VIRTUALENV_USE_DISTRIBUTE`` is now considered again as a legacy alias. - - - 1.7.1.2 (2012-02-17) - ~~~~~~~~~~~~~~~~~~~~ - - * Fixed minor issue in `--relocatable`. Thanks, Cap Petschulat. - - - 1.7.1.1 (2012-02-16) - ~~~~~~~~~~~~~~~~~~~~ - - * Bumped the version string in ``virtualenv.py`` up, too. - - * Fixed rST rendering bug of long description. - - - 1.7.1 (2012-02-16) - ~~~~~~~~~~~~~~~~~~ - - * Update embedded pip to version 1.1. - - * Fix `--relocatable` under Python 3. Thanks Doug Hellmann. - - * Added environ PATH modification to activate_this.py. Thanks Doug - Napoleone. Fixes #14. - - * Support creating virtualenvs directly from a Python build directory on - Windows. Thanks CBWhiz. Fixes #139. - - * Use non-recursive symlinks to fix things up for posix_local install - scheme. Thanks michr. - - * Made activate script available for use with msys and cygwin on Windows. - Thanks Greg Haskins, Cliff Xuan, Jonathan Griffin and Doug Napoleone. - Fixes #176. - - * Fixed creation of virtualenvs on Windows when Python is not installed for - all users. Thanks Anatoly Techtonik for report and patch and Doug - Napoleone for testing and confirmation. Fixes #87. - - * Fixed creation of virtualenvs using -p in installs where some modules - that ought to be in the standard library (e.g. `readline`) are actually - installed in `site-packages` next to `virtualenv.py`. Thanks Greg Haskins - for report and fix. Fixes #167. - - * Added activation script for Powershell (signed by Jannis Leidel). Many - thanks to Jason R. Coombs. - - - 1.7 (2011-11-30) - ~~~~~~~~~~~~~~~~ - - * Gave user-provided ``--extra-search-dir`` priority over default dirs for - finding setuptools/distribute (it already had priority for finding pip). - Thanks Ethan Jucovy. - - * Updated embedded Distribute release to 0.6.24. Thanks Alex Gronholm. - - * Made ``--no-site-packages`` behavior the default behavior. The - ``--no-site-packages`` flag is still permitted, but displays a warning when - used. Thanks Chris McDonough. - - * New flag: ``--system-site-packages``; this flag should be passed to get the - previous default global-site-package-including behavior back. - - * Added ability to set command options as environment variables and options - in a ``virtualenv.ini`` file. - - * Fixed various encoding related issues with paths. Thanks Gunnlaugur Thor Briem. - - * Made ``virtualenv.py`` script executable. - - - 1.6.4 (2011-07-21) - ~~~~~~~~~~~~~~~~~~ - - * Restored ability to run on Python 2.4, too. - - - 1.6.3 (2011-07-16) - ~~~~~~~~~~~~~~~~~~ - - * Restored ability to run on Python < 2.7. - - - 1.6.2 (2011-07-16) - ~~~~~~~~~~~~~~~~~~ - - * Updated embedded distribute release to 0.6.19. - - * Updated embedded pip release to 1.0.2. - - * Fixed #141 - Be smarter about finding pkg_resources when using the - non-default Python intepreter (by using the ``-p`` option). - - * Fixed #112 - Fixed path in docs. - - * Fixed #109 - Corrected doctests of a Logger method. - - * Fixed #118 - Fixed creating virtualenvs on platforms that use the - "posix_local" install scheme, such as Ubuntu with Python 2.7. - - * Add missing library to Python 3 virtualenvs (``_dummy_thread``). - - - 1.6.1 (2011-04-30) - ~~~~~~~~~~~~~~~~~~ - - * Start to use git-flow. - - * Added support for PyPy 1.5 - - * Fixed #121 -- added sanity-checking of the -p argument. Thanks Paul Nasrat. - - * Added progress meter for pip installation as well as setuptools. Thanks Ethan - Jucovy. - - * Added --never-download and --search-dir options. Thanks Ethan Jucovy. - - - 1.6 - ~~~ - - * Added Python 3 support! Huge thanks to Vinay Sajip and Vitaly Babiy. - - * Fixed creation of virtualenvs on Mac OS X when standard library modules - (readline) are installed outside the standard library. - - * Updated bundled pip to 1.0. - - - 1.5.2 - ~~~~~ - - * Moved main repository to Github: https://github.com/pypa/virtualenv - - * Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer and Brian Rosner - - * Fixed a few more pypy related bugs. - - * Updated bundled pip to 0.8.2. - - * Handed project over to new team of maintainers. - - * Moved virtualenv to Github at https://github.com/pypa/virtualenv - - - 1.5.1 - ~~~~~ - - * Added ``_weakrefset`` requirement for Python 2.7.1. - - * Fixed Windows regression in 1.5 - - - 1.5 - ~~~ - - * Include pip 0.8.1. - - * Add support for PyPy. - - * Uses a proper temporary dir when installing environment requirements. - - * Add ``--prompt`` option to be able to override the default prompt prefix. - - * Fix an issue with ``--relocatable`` on Windows. - - * Fix issue with installing the wrong version of distribute. - - * Add fish and csh activate scripts. - - - 1.4.9 - ~~~~~ - - * Include pip 0.7.2 - - - 1.4.8 - ~~~~~ - - * Fix for Mac OS X Framework builds that use - ``--universal-archs=intel`` - - * Fix ``activate_this.py`` on Windows. - - * Allow ``$PYTHONHOME`` to be set, so long as you use ``source - bin/activate`` it will get unset; if you leave it set and do not - activate the environment it will still break the environment. - - * Include pip 0.7.1 - - - 1.4.7 - ~~~~~ - - * Include pip 0.7 - - - 1.4.6 - ~~~~~ - - * Allow ``activate.sh`` to skip updating the prompt (by setting - ``$VIRTUAL_ENV_DISABLE_PROMPT``). - - - 1.4.5 - ~~~~~ - - * Include pip 0.6.3 - - * Fix ``activate.bat`` and ``deactivate.bat`` under Windows when - ``PATH`` contained a parenthesis - - - 1.4.4 - ~~~~~ - - * Include pip 0.6.2 and Distribute 0.6.10 - - * Create the ``virtualenv`` script even when Setuptools isn't - installed - - * Fix problem with ``virtualenv --relocate`` when ``bin/`` has - subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni. - - * If you set ``$VIRTUALENV_DISTRIBUTE`` then virtualenv will use - Distribute by default (so you don't have to remember to use - ``--distribute``). - - - 1.4.3 - ~~~~~ - - * Include pip 0.6.1 - - - 1.4.2 - ~~~~~ - - * Fix pip installation on Windows - - * Fix use of stand-alone ``virtualenv.py`` (and boot scripts) - - * Exclude ~/.local (user site-packages) from environments when using - ``--no-site-packages`` - - - 1.4.1 - ~~~~~ - - * Include pip 0.6 - - - 1.4 - ~~~ - - * Updated setuptools to 0.6c11 - - * Added the --distribute option - - * Fixed packaging problem of support-files - - - 1.3.4 - ~~~~~ - - * Virtualenv now copies the actual embedded Python binary on - Mac OS X to fix a hang on Snow Leopard (10.6). - - * Fail more gracefully on Windows when ``win32api`` is not installed. - - * Fix site-packages taking precedent over Jython's ``__classpath__`` - and also specially handle the new ``__pyclasspath__`` entry in - ``sys.path``. - - * Now copies Jython's ``registry`` file to the virtualenv if it exists. - - * Better find libraries when compiling extensions on Windows. - - * Create ``Scripts\pythonw.exe`` on Windows. - - * Added support for the Debian/Ubuntu - ``/usr/lib/pythonX.Y/dist-packages`` directory. - - * Set ``distutils.sysconfig.get_config_vars()['LIBDIR']`` (based on - ``sys.real_prefix``) which is reported to help building on Windows. - - * Make ``deactivate`` work on ksh - - * Fixes for ``--python``: make it work with ``--relocatable`` and the - symlink created to the exact Python version. - - - 1.3.3 - ~~~~~ - - * Use Windows newlines in ``activate.bat``, which has been reported to help - when using non-ASCII directory names. - - * Fixed compatibility with Jython 2.5b1. - - * Added a function ``virtualenv.install_python`` for more fine-grained - access to what ``virtualenv.create_environment`` does. - - * Fix `a problem `_ - with Windows and paths that contain spaces. - - * If ``/path/to/env/.pydistutils.cfg`` exists (or - ``/path/to/env/pydistutils.cfg`` on Windows systems) then ignore - ``~/.pydistutils.cfg`` and use that other file instead. - - * Fix ` a problem - `_ picking up - some ``.so`` libraries in ``/usr/local``. - - - 1.3.2 - ~~~~~ - - * Remove the ``[install] prefix = ...`` setting from the virtualenv - ``distutils.cfg`` -- this has been causing problems for a lot of - people, in rather obscure ways. - - * If you use a boot script it will attempt to import ``virtualenv`` - and find a pre-downloaded Setuptools egg using that. - - * Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2`` - - - 1.3.1 - ~~~~~ - - * Real Python 2.6 compatibility. Backported the Python 2.6 updates to - ``site.py``, including `user directories - `_ - (this means older versions of Python will support user directories, - whether intended or not). - - * Always set ``[install] prefix`` in ``distutils.cfg`` -- previously - on some platforms where a system-wide ``distutils.cfg`` was present - with a ``prefix`` setting, packages would be installed globally - (usually in ``/usr/local/lib/pythonX.Y/site-packages``). - - * Sometimes Cygwin seems to leave ``.exe`` off ``sys.executable``; a - workaround is added. - - * Fix ``--python`` option. - - * Fixed handling of Jython environments that use a - jython-complete.jar. - - - 1.3 - ~~~ - - * Update to Setuptools 0.6c9 - * Added an option ``virtualenv --relocatable EXISTING_ENV``, which - will make an existing environment "relocatable" -- the paths will - not be absolute in scripts, ``.egg-info`` and ``.pth`` files. This - may assist in building environments that can be moved and copied. - You have to run this *after* any new packages installed. - * Added ``bin/activate_this.py``, a file you can use like - ``execfile("path_to/activate_this.py", - dict(__file__="path_to/activate_this.py"))`` -- this will activate - the environment in place, similar to what `the mod_wsgi example - does `_. - * For Mac framework builds of Python, the site-packages directory - ``/Library/Python/X.Y/site-packages`` is added to ``sys.path``, from - Andrea Rech. - * Some platform-specific modules in Macs are added to the path now - (``plat-darwin/``, ``plat-mac/``, ``plat-mac/lib-scriptpackages``), - from Andrea Rech. - * Fixed a small Bashism in the ``bin/activate`` shell script. - * Added ``__future__`` to the list of required modules, for Python - 2.3. You'll still need to backport your own ``subprocess`` module. - * Fixed the ``__classpath__`` entry in Jython's ``sys.path`` taking - precedent over virtualenv's libs. - - - 1.2 - ~~~ - - * Added a ``--python`` option to select the Python interpreter. - * Add ``warnings`` to the modules copied over, for Python 2.6 support. - * Add ``sets`` to the module copied over for Python 2.3 (though Python - 2.3 still probably doesn't work). - - - 1.1.1 - ~~~~~ - - * Added support for Jython 2.5. - - - 1.1 - ~~~ - - * Added support for Python 2.6. - * Fix a problem with missing ``DLLs/zlib.pyd`` on Windows. Create - * ``bin/python`` (or ``bin/python.exe``) even when you run virtualenv - with an interpreter named, e.g., ``python2.4`` - * Fix MacPorts Python - * Added --unzip-setuptools option - * Update to Setuptools 0.6c8 - * If the current directory is not writable, run ez_setup.py in ``/tmp`` - * Copy or symlink over the ``include`` directory so that packages will - more consistently compile. - - - 1.0 - ~~~ - - * Fix build on systems that use ``/usr/lib64``, distinct from - ``/usr/lib`` (specifically CentOS x64). - * Fixed bug in ``--clear``. - * Fixed typos in ``deactivate.bat``. - * Preserve ``$PYTHONPATH`` when calling subprocesses. - - - 0.9.2 - ~~~~~ - - * Fix include dir copying on Windows (makes compiling possible). - * Include the main ``lib-tk`` in the path. - * Patch ``distutils.sysconfig``: ``get_python_inc`` and - ``get_python_lib`` to point to the global locations. - * Install ``distutils.cfg`` before Setuptools, so that system - customizations of ``distutils.cfg`` won't effect the installation. - * Add ``bin/pythonX.Y`` to the virtualenv (in addition to - ``bin/python``). - * Fixed an issue with Mac Framework Python builds, and absolute paths - (from Ronald Oussoren). - - - 0.9.1 - ~~~~~ - - * Improve ability to create a virtualenv from inside a virtualenv. - * Fix a little bug in ``bin/activate``. - * Actually get ``distutils.cfg`` to work reliably. - - - 0.9 - ~~~ - - * Added ``lib-dynload`` and ``config`` to things that need to be - copied over in an environment. - * Copy over or symlink the ``include`` directory, so that you can - build packages that need the C headers. - * Include a ``distutils`` package, so you can locally update - ``distutils.cfg`` (in ``lib/pythonX.Y/distutils/distutils.cfg``). - * Better avoid downloading Setuptools, and hitting PyPI on environment - creation. - * Fix a problem creating a ``lib64/`` directory. - * Should work on MacOSX Framework builds (the default Python - installations on Mac). Thanks to Ronald Oussoren. - - - 0.8.4 - ~~~~~ - - * Windows installs would sometimes give errors about ``sys.prefix`` that - were inaccurate. - * Slightly prettier output. - - - 0.8.3 - ~~~~~ - - * Added support for Windows. - - - 0.8.2 - ~~~~~ - - * Give a better warning if you are on an unsupported platform (Mac - Framework Pythons, and Windows). - * Give error about running while inside a workingenv. - * Give better error message about Python 2.3. - - - 0.8.1 - ~~~~~ - - Fixed packaging of the library. - - - 0.8 - ~~~ - - Initial release. Everything is changed and new! - -Keywords: setuptools deployment installation distutils -Platform: UNKNOWN -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 2 -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 diff --git a/vendor/virtualenv-1.8.4/virtualenv.egg-info/SOURCES.txt b/vendor/virtualenv-1.8.4/virtualenv.egg-info/SOURCES.txt deleted file mode 100644 index 14f9da8..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.egg-info/SOURCES.txt +++ /dev/null @@ -1,42 +0,0 @@ -AUTHORS.txt -LICENSE.txt -MANIFEST.in -README.rst -setup.py -virtualenv.py -bin/rebuild-script.py -bin/refresh-support-files.py -docs/Makefile -docs/conf.py -docs/index.txt -docs/make.bat -docs/news.txt -docs/_theme/nature/theme.conf -docs/_theme/nature/static/nature.css_t -docs/_theme/nature/static/pygments.css -scripts/virtualenv -virtualenv.egg-info/PKG-INFO -virtualenv.egg-info/SOURCES.txt -virtualenv.egg-info/dependency_links.txt -virtualenv.egg-info/entry_points.txt -virtualenv.egg-info/not-zip-safe -virtualenv.egg-info/top_level.txt -virtualenv_embedded/activate.bat -virtualenv_embedded/activate.csh -virtualenv_embedded/activate.fish -virtualenv_embedded/activate.ps1 -virtualenv_embedded/activate.sh -virtualenv_embedded/activate_this.py -virtualenv_embedded/deactivate.bat -virtualenv_embedded/distribute_from_egg.py -virtualenv_embedded/distribute_setup.py -virtualenv_embedded/distutils-init.py -virtualenv_embedded/distutils.cfg -virtualenv_embedded/ez_setup.py -virtualenv_embedded/site.py -virtualenv_support/__init__.py -virtualenv_support/distribute-0.6.31.tar.gz -virtualenv_support/pip-1.2.1.tar.gz -virtualenv_support/setuptools-0.6c11-py2.5.egg -virtualenv_support/setuptools-0.6c11-py2.6.egg -virtualenv_support/setuptools-0.6c11-py2.7.egg \ No newline at end of file diff --git a/vendor/virtualenv-1.8.4/virtualenv.egg-info/dependency_links.txt b/vendor/virtualenv-1.8.4/virtualenv.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/vendor/virtualenv-1.8.4/virtualenv.egg-info/entry_points.txt b/vendor/virtualenv-1.8.4/virtualenv.egg-info/entry_points.txt deleted file mode 100644 index 56a94e1..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.egg-info/entry_points.txt +++ /dev/null @@ -1,4 +0,0 @@ -[console_scripts] -virtualenv = virtualenv:main -virtualenv-2.7 = virtualenv:main - diff --git a/vendor/virtualenv-1.8.4/virtualenv.egg-info/not-zip-safe b/vendor/virtualenv-1.8.4/virtualenv.egg-info/not-zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/vendor/virtualenv-1.8.4/virtualenv.egg-info/top_level.txt b/vendor/virtualenv-1.8.4/virtualenv.egg-info/top_level.txt deleted file mode 100644 index 2fe6b5d..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.egg-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -virtualenv_support -virtualenv diff --git a/vendor/virtualenv-1.8.4/virtualenv.py b/vendor/virtualenv-1.8.4/virtualenv.py deleted file mode 100755 index e312aa3..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv.py +++ /dev/null @@ -1,2564 +0,0 @@ -#!/usr/bin/env python -"""Create a "virtual" Python installation -""" - -# If you change the version here, change it in setup.py -# and docs/conf.py as well. -__version__ = "1.8.4" # following best practices -virtualenv_version = __version__ # legacy, again - -import base64 -import sys -import os -import codecs -import optparse -import re -import shutil -import logging -import tempfile -import zlib -import errno -import glob -import distutils.sysconfig -from distutils.util import strtobool -import struct -import subprocess - -if sys.version_info < (2, 5): - print('ERROR: %s' % sys.exc_info()[1]) - print('ERROR: this script requires Python 2.5 or greater.') - sys.exit(101) - -try: - set -except NameError: - from sets import Set as set -try: - basestring -except NameError: - basestring = str - -try: - import ConfigParser -except ImportError: - import configparser as ConfigParser - -join = os.path.join -py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) - -is_jython = sys.platform.startswith('java') -is_pypy = hasattr(sys, 'pypy_version_info') -is_win = (sys.platform == 'win32') -is_cygwin = (sys.platform == 'cygwin') -is_darwin = (sys.platform == 'darwin') -abiflags = getattr(sys, 'abiflags', '') - -user_dir = os.path.expanduser('~') -if is_win: - default_storage_dir = os.path.join(user_dir, 'virtualenv') -else: - default_storage_dir = os.path.join(user_dir, '.virtualenv') -default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini') - -if is_pypy: - expected_exe = 'pypy' -elif is_jython: - expected_exe = 'jython' -else: - expected_exe = 'python' - - -REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath', - 'fnmatch', 'locale', 'encodings', 'codecs', - 'stat', 'UserDict', 'readline', 'copy_reg', 'types', - 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', - 'zlib'] - -REQUIRED_FILES = ['lib-dynload', 'config'] - -majver, minver = sys.version_info[:2] -if majver == 2: - if minver >= 6: - REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) - if minver >= 7: - REQUIRED_MODULES.extend(['_weakrefset']) - if minver <= 3: - REQUIRED_MODULES.extend(['sets', '__future__']) -elif majver == 3: - # Some extra modules are needed for Python 3, but different ones - # for different versions. - REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io', - '_weakrefset', 'copyreg', 'tempfile', 'random', - '__future__', 'collections', 'keyword', 'tarfile', - 'shutil', 'struct', 'copy', 'tokenize', 'token', - 'functools', 'heapq', 'bisect', 'weakref', - 'reprlib']) - if minver >= 2: - REQUIRED_FILES[-1] = 'config-%s' % majver - if minver == 3: - import sysconfig - platdir = sysconfig.get_config_var('PLATDIR') - REQUIRED_FILES.append(platdir) - # The whole list of 3.3 modules is reproduced below - the current - # uncommented ones are required for 3.3 as of now, but more may be - # added as 3.3 development continues. - REQUIRED_MODULES.extend([ - #"aifc", - #"antigravity", - #"argparse", - #"ast", - #"asynchat", - #"asyncore", - "base64", - #"bdb", - #"binhex", - #"bisect", - #"calendar", - #"cgi", - #"cgitb", - #"chunk", - #"cmd", - #"codeop", - #"code", - #"colorsys", - #"_compat_pickle", - #"compileall", - #"concurrent", - #"configparser", - #"contextlib", - #"cProfile", - #"crypt", - #"csv", - #"ctypes", - #"curses", - #"datetime", - #"dbm", - #"decimal", - #"difflib", - #"dis", - #"doctest", - #"dummy_threading", - "_dummy_thread", - #"email", - #"filecmp", - #"fileinput", - #"formatter", - #"fractions", - #"ftplib", - #"functools", - #"getopt", - #"getpass", - #"gettext", - #"glob", - #"gzip", - "hashlib", - #"heapq", - "hmac", - #"html", - #"http", - #"idlelib", - #"imaplib", - #"imghdr", - "imp", - "importlib", - #"inspect", - #"json", - #"lib2to3", - #"logging", - #"macpath", - #"macurl2path", - #"mailbox", - #"mailcap", - #"_markupbase", - #"mimetypes", - #"modulefinder", - #"multiprocessing", - #"netrc", - #"nntplib", - #"nturl2path", - #"numbers", - #"opcode", - #"optparse", - #"os2emxpath", - #"pdb", - #"pickle", - #"pickletools", - #"pipes", - #"pkgutil", - #"platform", - #"plat-linux2", - #"plistlib", - #"poplib", - #"pprint", - #"profile", - #"pstats", - #"pty", - #"pyclbr", - #"py_compile", - #"pydoc_data", - #"pydoc", - #"_pyio", - #"queue", - #"quopri", - #"reprlib", - "rlcompleter", - #"runpy", - #"sched", - #"shelve", - #"shlex", - #"smtpd", - #"smtplib", - #"sndhdr", - #"socket", - #"socketserver", - #"sqlite3", - #"ssl", - #"stringprep", - #"string", - #"_strptime", - #"subprocess", - #"sunau", - #"symbol", - #"symtable", - #"sysconfig", - #"tabnanny", - #"telnetlib", - #"test", - #"textwrap", - #"this", - #"_threading_local", - #"threading", - #"timeit", - #"tkinter", - #"tokenize", - #"token", - #"traceback", - #"trace", - #"tty", - #"turtledemo", - #"turtle", - #"unittest", - #"urllib", - #"uuid", - #"uu", - #"wave", - #"weakref", - #"webbrowser", - #"wsgiref", - #"xdrlib", - #"xml", - #"xmlrpc", - #"zipfile", - ]) - -if is_pypy: - # these are needed to correctly display the exceptions that may happen - # during the bootstrap - REQUIRED_MODULES.extend(['traceback', 'linecache']) - -class Logger(object): - - """ - Logging object for use in command-line script. Allows ranges of - levels, to avoid some redundancy of displayed information. - """ - - DEBUG = logging.DEBUG - INFO = logging.INFO - NOTIFY = (logging.INFO+logging.WARN)/2 - WARN = WARNING = logging.WARN - ERROR = logging.ERROR - FATAL = logging.FATAL - - LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] - - def __init__(self, consumers): - self.consumers = consumers - self.indent = 0 - self.in_progress = None - self.in_progress_hanging = False - - def debug(self, msg, *args, **kw): - self.log(self.DEBUG, msg, *args, **kw) - def info(self, msg, *args, **kw): - self.log(self.INFO, msg, *args, **kw) - def notify(self, msg, *args, **kw): - self.log(self.NOTIFY, msg, *args, **kw) - def warn(self, msg, *args, **kw): - self.log(self.WARN, msg, *args, **kw) - def error(self, msg, *args, **kw): - self.log(self.ERROR, msg, *args, **kw) - def fatal(self, msg, *args, **kw): - self.log(self.FATAL, msg, *args, **kw) - def log(self, level, msg, *args, **kw): - if args: - if kw: - raise TypeError( - "You may give positional or keyword arguments, not both") - args = args or kw - rendered = None - for consumer_level, consumer in self.consumers: - if self.level_matches(level, consumer_level): - if (self.in_progress_hanging - and consumer in (sys.stdout, sys.stderr)): - self.in_progress_hanging = False - sys.stdout.write('\n') - sys.stdout.flush() - if rendered is None: - if args: - rendered = msg % args - else: - rendered = msg - rendered = ' '*self.indent + rendered - if hasattr(consumer, 'write'): - consumer.write(rendered+'\n') - else: - consumer(rendered) - - def start_progress(self, msg): - assert not self.in_progress, ( - "Tried to start_progress(%r) while in_progress %r" - % (msg, self.in_progress)) - if self.level_matches(self.NOTIFY, self._stdout_level()): - sys.stdout.write(msg) - sys.stdout.flush() - self.in_progress_hanging = True - else: - self.in_progress_hanging = False - self.in_progress = msg - - def end_progress(self, msg='done.'): - assert self.in_progress, ( - "Tried to end_progress without start_progress") - if self.stdout_level_matches(self.NOTIFY): - if not self.in_progress_hanging: - # Some message has been printed out since start_progress - sys.stdout.write('...' + self.in_progress + msg + '\n') - sys.stdout.flush() - else: - sys.stdout.write(msg + '\n') - sys.stdout.flush() - self.in_progress = None - self.in_progress_hanging = False - - def show_progress(self): - """If we are in a progress scope, and no log messages have been - shown, write out another '.'""" - if self.in_progress_hanging: - sys.stdout.write('.') - sys.stdout.flush() - - def stdout_level_matches(self, level): - """Returns true if a message at this level will go to stdout""" - return self.level_matches(level, self._stdout_level()) - - def _stdout_level(self): - """Returns the level that stdout runs at""" - for level, consumer in self.consumers: - if consumer is sys.stdout: - return level - return self.FATAL - - def level_matches(self, level, consumer_level): - """ - >>> l = Logger([]) - >>> l.level_matches(3, 4) - False - >>> l.level_matches(3, 2) - True - >>> l.level_matches(slice(None, 3), 3) - False - >>> l.level_matches(slice(None, 3), 2) - True - >>> l.level_matches(slice(1, 3), 1) - True - >>> l.level_matches(slice(2, 3), 1) - False - """ - if isinstance(level, slice): - start, stop = level.start, level.stop - if start is not None and start > consumer_level: - return False - if stop is not None and stop <= consumer_level: - return False - return True - else: - return level >= consumer_level - - #@classmethod - def level_for_integer(cls, level): - levels = cls.LEVELS - if level < 0: - return levels[0] - if level >= len(levels): - return levels[-1] - return levels[level] - - level_for_integer = classmethod(level_for_integer) - -# create a silent logger just to prevent this from being undefined -# will be overridden with requested verbosity main() is called. -logger = Logger([(Logger.LEVELS[-1], sys.stdout)]) - -def mkdir(path): - if not os.path.exists(path): - logger.info('Creating %s', path) - os.makedirs(path) - else: - logger.info('Directory %s already exists', path) - -def copyfileordir(src, dest): - if os.path.isdir(src): - shutil.copytree(src, dest, True) - else: - shutil.copy2(src, dest) - -def copyfile(src, dest, symlink=True): - if not os.path.exists(src): - # Some bad symlink in the src - logger.warn('Cannot find file %s (bad symlink)', src) - return - if os.path.exists(dest): - logger.debug('File %s already exists', dest) - return - if not os.path.exists(os.path.dirname(dest)): - logger.info('Creating parent directories for %s' % os.path.dirname(dest)) - os.makedirs(os.path.dirname(dest)) - if not os.path.islink(src): - srcpath = os.path.abspath(src) - else: - srcpath = os.readlink(src) - if symlink and hasattr(os, 'symlink') and not is_win: - logger.info('Symlinking %s', dest) - try: - os.symlink(srcpath, dest) - except (OSError, NotImplementedError): - logger.info('Symlinking failed, copying to %s', dest) - copyfileordir(src, dest) - else: - logger.info('Copying to %s', dest) - copyfileordir(src, dest) - -def writefile(dest, content, overwrite=True): - if not os.path.exists(dest): - logger.info('Writing %s', dest) - f = open(dest, 'wb') - f.write(content.encode('utf-8')) - f.close() - return - else: - f = open(dest, 'rb') - c = f.read() - f.close() - if c != content.encode("utf-8"): - if not overwrite: - logger.notify('File %s exists with different content; not overwriting', dest) - return - logger.notify('Overwriting %s with new content', dest) - f = open(dest, 'wb') - f.write(content.encode('utf-8')) - f.close() - else: - logger.info('Content %s already in place', dest) - -def rmtree(dir): - if os.path.exists(dir): - logger.notify('Deleting tree %s', dir) - shutil.rmtree(dir) - else: - logger.info('Do not need to delete %s; already gone', dir) - -def make_exe(fn): - if hasattr(os, 'chmod'): - oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777 - newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777 - os.chmod(fn, newmode) - logger.info('Changed mode of %s to %s', fn, oct(newmode)) - -def _find_file(filename, dirs): - for dir in reversed(dirs): - files = glob.glob(os.path.join(dir, filename)) - if files and os.path.isfile(files[0]): - return True, files[0] - return False, filename - -def _install_req(py_executable, unzip=False, distribute=False, - search_dirs=None, never_download=False): - - if search_dirs is None: - search_dirs = file_search_dirs() - - if not distribute: - egg_path = 'setuptools-*-py%s.egg' % sys.version[:3] - found, egg_path = _find_file(egg_path, search_dirs) - project_name = 'setuptools' - bootstrap_script = EZ_SETUP_PY - tgz_path = None - else: - # Look for a distribute egg (these are not distributed by default, - # but can be made available by the user) - egg_path = 'distribute-*-py%s.egg' % sys.version[:3] - found, egg_path = _find_file(egg_path, search_dirs) - project_name = 'distribute' - if found: - tgz_path = None - bootstrap_script = DISTRIBUTE_FROM_EGG_PY - else: - # Fall back to sdist - # NB: egg_path is not None iff tgz_path is None - # iff bootstrap_script is a generic setup script accepting - # the standard arguments. - egg_path = None - tgz_path = 'distribute-*.tar.gz' - found, tgz_path = _find_file(tgz_path, search_dirs) - bootstrap_script = DISTRIBUTE_SETUP_PY - - if is_jython and os._name == 'nt': - # Jython's .bat sys.executable can't handle a command line - # argument with newlines - fd, ez_setup = tempfile.mkstemp('.py') - os.write(fd, bootstrap_script) - os.close(fd) - cmd = [py_executable, ez_setup] - else: - cmd = [py_executable, '-c', bootstrap_script] - if unzip and egg_path: - cmd.append('--always-unzip') - env = {} - remove_from_env = ['__PYVENV_LAUNCHER__'] - if logger.stdout_level_matches(logger.DEBUG) and egg_path: - cmd.append('-v') - - old_chdir = os.getcwd() - if egg_path is not None and os.path.exists(egg_path): - logger.info('Using existing %s egg: %s' % (project_name, egg_path)) - cmd.append(egg_path) - if os.environ.get('PYTHONPATH'): - env['PYTHONPATH'] = egg_path + os.path.pathsep + os.environ['PYTHONPATH'] - else: - env['PYTHONPATH'] = egg_path - elif tgz_path is not None and os.path.exists(tgz_path): - # Found a tgz source dist, let's chdir - logger.info('Using existing %s egg: %s' % (project_name, tgz_path)) - os.chdir(os.path.dirname(tgz_path)) - # in this case, we want to be sure that PYTHONPATH is unset (not - # just empty, really unset), else CPython tries to import the - # site.py that it's in virtualenv_support - remove_from_env.append('PYTHONPATH') - elif never_download: - logger.fatal("Can't find any local distributions of %s to install " - "and --never-download is set. Either re-run virtualenv " - "without the --never-download option, or place a %s " - "distribution (%s) in one of these " - "locations: %r" % (project_name, project_name, - egg_path or tgz_path, - search_dirs)) - sys.exit(1) - elif egg_path: - logger.info('No %s egg found; downloading' % project_name) - cmd.extend(['--always-copy', '-U', project_name]) - else: - logger.info('No %s tgz found; downloading' % project_name) - logger.start_progress('Installing %s...' % project_name) - logger.indent += 2 - cwd = None - if project_name == 'distribute': - env['DONT_PATCH_SETUPTOOLS'] = 'true' - - def _filter_ez_setup(line): - return filter_ez_setup(line, project_name) - - if not os.access(os.getcwd(), os.W_OK): - cwd = tempfile.mkdtemp() - if tgz_path is not None and os.path.exists(tgz_path): - # the current working dir is hostile, let's copy the - # tarball to a temp dir - target = os.path.join(cwd, os.path.split(tgz_path)[-1]) - shutil.copy(tgz_path, target) - try: - call_subprocess(cmd, show_stdout=False, - filter_stdout=_filter_ez_setup, - extra_env=env, - remove_from_env=remove_from_env, - cwd=cwd) - finally: - logger.indent -= 2 - logger.end_progress() - if cwd is not None: - shutil.rmtree(cwd) - if os.getcwd() != old_chdir: - os.chdir(old_chdir) - if is_jython and os._name == 'nt': - os.remove(ez_setup) - -def file_search_dirs(): - here = os.path.dirname(os.path.abspath(__file__)) - dirs = ['.', here, - join(here, 'virtualenv_support')] - if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv': - # Probably some boot script; just in case virtualenv is installed... - try: - import virtualenv - except ImportError: - pass - else: - dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support')) - return [d for d in dirs if os.path.isdir(d)] - -def install_setuptools(py_executable, unzip=False, - search_dirs=None, never_download=False): - _install_req(py_executable, unzip, - search_dirs=search_dirs, never_download=never_download) - -def install_distribute(py_executable, unzip=False, - search_dirs=None, never_download=False): - _install_req(py_executable, unzip, distribute=True, - search_dirs=search_dirs, never_download=never_download) - -_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I) -def install_pip(py_executable, search_dirs=None, never_download=False): - if search_dirs is None: - search_dirs = file_search_dirs() - - filenames = [] - for dir in search_dirs: - filenames.extend([join(dir, fn) for fn in os.listdir(dir) - if _pip_re.search(fn)]) - filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)] - filenames.sort() - filenames = [filename for basename, i, filename in filenames] - if not filenames: - filename = 'pip' - else: - filename = filenames[-1] - easy_install_script = 'easy_install' - if is_win: - easy_install_script = 'easy_install-script.py' - # There's two subtle issues here when invoking easy_install. - # 1. On unix-like systems the easy_install script can *only* be executed - # directly if its full filesystem path is no longer than 78 characters. - # 2. A work around to [1] is to use the `python path/to/easy_install foo` - # pattern, but that breaks if the path contains non-ASCII characters, as - # you can't put the file encoding declaration before the shebang line. - # The solution is to use Python's -x flag to skip the first line of the - # script (and any ASCII decoding errors that may have occurred in that line) - cmd = [py_executable, '-x', join(os.path.dirname(py_executable), easy_install_script), filename] - # jython and pypy don't yet support -x - if is_jython or is_pypy: - cmd.remove('-x') - if filename == 'pip': - if never_download: - logger.fatal("Can't find any local distributions of pip to install " - "and --never-download is set. Either re-run virtualenv " - "without the --never-download option, or place a pip " - "source distribution (zip/tar.gz/tar.bz2) in one of these " - "locations: %r" % search_dirs) - sys.exit(1) - logger.info('Installing pip from network...') - else: - logger.info('Installing existing %s distribution: %s' % ( - os.path.basename(filename), filename)) - logger.start_progress('Installing pip...') - logger.indent += 2 - def _filter_setup(line): - return filter_ez_setup(line, 'pip') - try: - call_subprocess(cmd, show_stdout=False, - filter_stdout=_filter_setup) - finally: - logger.indent -= 2 - logger.end_progress() - -def filter_ez_setup(line, project_name='setuptools'): - if not line.strip(): - return Logger.DEBUG - if project_name == 'distribute': - for prefix in ('Extracting', 'Now working', 'Installing', 'Before', - 'Scanning', 'Setuptools', 'Egg', 'Already', - 'running', 'writing', 'reading', 'installing', - 'creating', 'copying', 'byte-compiling', 'removing', - 'Processing'): - if line.startswith(prefix): - return Logger.DEBUG - return Logger.DEBUG - for prefix in ['Reading ', 'Best match', 'Processing setuptools', - 'Copying setuptools', 'Adding setuptools', - 'Installing ', 'Installed ']: - if line.startswith(prefix): - return Logger.DEBUG - return Logger.INFO - - -class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): - """ - Custom help formatter for use in ConfigOptionParser that updates - the defaults before expanding them, allowing them to show up correctly - in the help listing - """ - def expand_default(self, option): - if self.parser is not None: - self.parser.update_defaults(self.parser.defaults) - return optparse.IndentedHelpFormatter.expand_default(self, option) - - -class ConfigOptionParser(optparse.OptionParser): - """ - Custom option parser which updates its defaults by by checking the - configuration files and environmental variables - """ - def __init__(self, *args, **kwargs): - self.config = ConfigParser.RawConfigParser() - self.files = self.get_config_files() - self.config.read(self.files) - optparse.OptionParser.__init__(self, *args, **kwargs) - - def get_config_files(self): - config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False) - if config_file and os.path.exists(config_file): - return [config_file] - return [default_config_file] - - def update_defaults(self, defaults): - """ - Updates the given defaults with values from the config files and - the environ. Does a little special handling for certain types of - options (lists). - """ - # Then go and look for the other sources of configuration: - config = {} - # 1. config files - config.update(dict(self.get_config_section('virtualenv'))) - # 2. environmental variables - config.update(dict(self.get_environ_vars())) - # Then set the options with those values - for key, val in config.items(): - key = key.replace('_', '-') - if not key.startswith('--'): - key = '--%s' % key # only prefer long opts - option = self.get_option(key) - if option is not None: - # ignore empty values - if not val: - continue - # handle multiline configs - if option.action == 'append': - val = val.split() - else: - option.nargs = 1 - if option.action == 'store_false': - val = not strtobool(val) - elif option.action in ('store_true', 'count'): - val = strtobool(val) - try: - val = option.convert_value(key, val) - except optparse.OptionValueError: - e = sys.exc_info()[1] - print("An error occured during configuration: %s" % e) - sys.exit(3) - defaults[option.dest] = val - return defaults - - def get_config_section(self, name): - """ - Get a section of a configuration - """ - if self.config.has_section(name): - return self.config.items(name) - return [] - - def get_environ_vars(self, prefix='VIRTUALENV_'): - """ - Returns a generator with all environmental vars with prefix VIRTUALENV - """ - for key, val in os.environ.items(): - if key.startswith(prefix): - yield (key.replace(prefix, '').lower(), val) - - def get_default_values(self): - """ - Overridding to make updating the defaults after instantiation of - the option parser possible, update_defaults() does the dirty work. - """ - if not self.process_default_values: - # Old, pre-Optik 1.5 behaviour. - return optparse.Values(self.defaults) - - defaults = self.update_defaults(self.defaults.copy()) # ours - for option in self._get_all_options(): - default = defaults.get(option.dest) - if isinstance(default, basestring): - opt_str = option.get_opt_string() - defaults[option.dest] = option.check_value(opt_str, default) - return optparse.Values(defaults) - - -def main(): - parser = ConfigOptionParser( - version=virtualenv_version, - usage="%prog [OPTIONS] DEST_DIR", - formatter=UpdatingDefaultsHelpFormatter()) - - parser.add_option( - '-v', '--verbose', - action='count', - dest='verbose', - default=0, - help="Increase verbosity") - - parser.add_option( - '-q', '--quiet', - action='count', - dest='quiet', - default=0, - help='Decrease verbosity') - - parser.add_option( - '-p', '--python', - dest='python', - metavar='PYTHON_EXE', - help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 ' - 'interpreter to create the new environment. The default is the interpreter that ' - 'virtualenv was installed with (%s)' % sys.executable) - - parser.add_option( - '--clear', - dest='clear', - action='store_true', - help="Clear out the non-root install and start from scratch") - - parser.set_defaults(system_site_packages=False) - parser.add_option( - '--no-site-packages', - dest='system_site_packages', - action='store_false', - help="Don't give access to the global site-packages dir to the " - "virtual environment (default)") - - parser.add_option( - '--system-site-packages', - dest='system_site_packages', - action='store_true', - help="Give access to the global site-packages dir to the " - "virtual environment") - - parser.add_option( - '--unzip-setuptools', - dest='unzip_setuptools', - action='store_true', - help="Unzip Setuptools or Distribute when installing it") - - parser.add_option( - '--relocatable', - dest='relocatable', - action='store_true', - help='Make an EXISTING virtualenv environment relocatable. ' - 'This fixes up scripts and makes all .pth files relative') - - parser.add_option( - '--distribute', '--use-distribute', # the second option is for legacy reasons here. Hi Kenneth! - dest='use_distribute', - action='store_true', - help='Use Distribute instead of Setuptools. Set environ variable ' - 'VIRTUALENV_DISTRIBUTE to make it the default ') - - parser.add_option( - '--setuptools', - dest='use_distribute', - action='store_false', - help='Use Setuptools instead of Distribute. Set environ variable ' - 'VIRTUALENV_SETUPTOOLS to make it the default ') - - # Set this to True to use distribute by default, even in Python 2. - parser.set_defaults(use_distribute=False) - - default_search_dirs = file_search_dirs() - parser.add_option( - '--extra-search-dir', - dest="search_dirs", - action="append", - default=default_search_dirs, - help="Directory to look for setuptools/distribute/pip distributions in. " - "You can add any number of additional --extra-search-dir paths.") - - parser.add_option( - '--never-download', - dest="never_download", - action="store_true", - help="Never download anything from the network. Instead, virtualenv will fail " - "if local distributions of setuptools/distribute/pip are not present.") - - parser.add_option( - '--prompt', - dest='prompt', - help='Provides an alternative prompt prefix for this environment') - - if 'extend_parser' in globals(): - extend_parser(parser) - - options, args = parser.parse_args() - - global logger - - if 'adjust_options' in globals(): - adjust_options(options, args) - - verbosity = options.verbose - options.quiet - logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)]) - - if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): - env = os.environ.copy() - interpreter = resolve_interpreter(options.python) - if interpreter == sys.executable: - logger.warn('Already using interpreter %s' % interpreter) - else: - logger.notify('Running virtualenv with interpreter %s' % interpreter) - env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true' - file = __file__ - if file.endswith('.pyc'): - file = file[:-1] - popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env) - raise SystemExit(popen.wait()) - - # Force --distribute on Python 3, since setuptools is not available. - if majver > 2: - options.use_distribute = True - - if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute: - print( - "The PYTHONDONTWRITEBYTECODE environment variable is " - "not compatible with setuptools. Either use --distribute " - "or unset PYTHONDONTWRITEBYTECODE.") - sys.exit(2) - if not args: - print('You must provide a DEST_DIR') - parser.print_help() - sys.exit(2) - if len(args) > 1: - print('There must be only one argument: DEST_DIR (you gave %s)' % ( - ' '.join(args))) - parser.print_help() - sys.exit(2) - - home_dir = args[0] - - if os.environ.get('WORKING_ENV'): - logger.fatal('ERROR: you cannot run virtualenv while in a workingenv') - logger.fatal('Please deactivate your workingenv, then re-run this script') - sys.exit(3) - - if 'PYTHONHOME' in os.environ: - logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it') - del os.environ['PYTHONHOME'] - - if options.relocatable: - make_environment_relocatable(home_dir) - return - - create_environment(home_dir, - site_packages=options.system_site_packages, - clear=options.clear, - unzip_setuptools=options.unzip_setuptools, - use_distribute=options.use_distribute, - prompt=options.prompt, - search_dirs=options.search_dirs, - never_download=options.never_download) - if 'after_install' in globals(): - after_install(options, home_dir) - -def call_subprocess(cmd, show_stdout=True, - filter_stdout=None, cwd=None, - raise_on_returncode=True, extra_env=None, - remove_from_env=None): - cmd_parts = [] - for part in cmd: - if len(part) > 45: - part = part[:20]+"..."+part[-20:] - if ' ' in part or '\n' in part or '"' in part or "'" in part: - part = '"%s"' % part.replace('"', '\\"') - if hasattr(part, 'decode'): - try: - part = part.decode(sys.getdefaultencoding()) - except UnicodeDecodeError: - part = part.decode(sys.getfilesystemencoding()) - cmd_parts.append(part) - cmd_desc = ' '.join(cmd_parts) - if show_stdout: - stdout = None - else: - stdout = subprocess.PIPE - logger.debug("Running command %s" % cmd_desc) - if extra_env or remove_from_env: - env = os.environ.copy() - if extra_env: - env.update(extra_env) - if remove_from_env: - for varname in remove_from_env: - env.pop(varname, None) - else: - env = None - try: - proc = subprocess.Popen( - cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, - cwd=cwd, env=env) - except Exception: - e = sys.exc_info()[1] - logger.fatal( - "Error %s while executing command %s" % (e, cmd_desc)) - raise - all_output = [] - if stdout is not None: - stdout = proc.stdout - encoding = sys.getdefaultencoding() - fs_encoding = sys.getfilesystemencoding() - while 1: - line = stdout.readline() - try: - line = line.decode(encoding) - except UnicodeDecodeError: - line = line.decode(fs_encoding) - if not line: - break - line = line.rstrip() - all_output.append(line) - if filter_stdout: - level = filter_stdout(line) - if isinstance(level, tuple): - level, line = level - logger.log(level, line) - if not logger.stdout_level_matches(level): - logger.show_progress() - else: - logger.info(line) - else: - proc.communicate() - proc.wait() - if proc.returncode: - if raise_on_returncode: - if all_output: - logger.notify('Complete output from command %s:' % cmd_desc) - logger.notify('\n'.join(all_output) + '\n----------------------------------------') - raise OSError( - "Command %s failed with error code %s" - % (cmd_desc, proc.returncode)) - else: - logger.warn( - "Command %s had error code %s" - % (cmd_desc, proc.returncode)) - - -def create_environment(home_dir, site_packages=False, clear=False, - unzip_setuptools=False, use_distribute=False, - prompt=None, search_dirs=None, never_download=False): - """ - Creates a new environment in ``home_dir``. - - If ``site_packages`` is true, then the global ``site-packages/`` - directory will be on the path. - - If ``clear`` is true (default False) then the environment will - first be cleared. - """ - home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) - - py_executable = os.path.abspath(install_python( - home_dir, lib_dir, inc_dir, bin_dir, - site_packages=site_packages, clear=clear)) - - install_distutils(home_dir) - - if use_distribute: - install_distribute(py_executable, unzip=unzip_setuptools, - search_dirs=search_dirs, never_download=never_download) - else: - install_setuptools(py_executable, unzip=unzip_setuptools, - search_dirs=search_dirs, never_download=never_download) - - install_pip(py_executable, search_dirs=search_dirs, never_download=never_download) - - install_activate(home_dir, bin_dir, prompt) - -def is_executable_file(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - -def path_locations(home_dir): - """Return the path locations for the environment (where libraries are, - where scripts go, etc)""" - # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its - # prefix arg is broken: http://bugs.python.org/issue3386 - if is_win: - # Windows has lots of problems with executables with spaces in - # the name; this function will remove them (using the ~1 - # format): - mkdir(home_dir) - if ' ' in home_dir: - import ctypes - GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW - size = max(len(home_dir)+1, 256) - buf = ctypes.create_unicode_buffer(size) - try: - u = unicode - except NameError: - u = str - ret = GetShortPathName(u(home_dir), buf, size) - if not ret: - print('Error: the path "%s" has a space in it' % home_dir) - print('We could not determine the short pathname for it.') - print('Exiting.') - sys.exit(3) - home_dir = str(buf.value) - lib_dir = join(home_dir, 'Lib') - inc_dir = join(home_dir, 'Include') - bin_dir = join(home_dir, 'Scripts') - if is_jython: - lib_dir = join(home_dir, 'Lib') - inc_dir = join(home_dir, 'Include') - bin_dir = join(home_dir, 'bin') - elif is_pypy: - lib_dir = home_dir - inc_dir = join(home_dir, 'include') - bin_dir = join(home_dir, 'bin') - elif not is_win: - lib_dir = join(home_dir, 'lib', py_version) - multiarch_exec = '/usr/bin/multiarch-platform' - if is_executable_file(multiarch_exec): - # In Mageia (2) and Mandriva distros the include dir must be like: - # virtualenv/include/multiarch-x86_64-linux/python2.7 - # instead of being virtualenv/include/python2.7 - p = subprocess.Popen(multiarch_exec, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - # stdout.strip is needed to remove newline character - inc_dir = join(home_dir, 'include', stdout.strip(), py_version + abiflags) - else: - inc_dir = join(home_dir, 'include', py_version + abiflags) - bin_dir = join(home_dir, 'bin') - return home_dir, lib_dir, inc_dir, bin_dir - - -def change_prefix(filename, dst_prefix): - prefixes = [sys.prefix] - - if is_darwin: - prefixes.extend(( - os.path.join("/Library/Python", sys.version[:3], "site-packages"), - os.path.join(sys.prefix, "Extras", "lib", "python"), - os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"), - # Python 2.6 no-frameworks - os.path.join("~", ".local", "lib","python", sys.version[:3], "site-packages"), - # System Python 2.7 on OSX Mountain Lion - os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages"))) - - if hasattr(sys, 'real_prefix'): - prefixes.append(sys.real_prefix) - if hasattr(sys, 'base_prefix'): - prefixes.append(sys.base_prefix) - prefixes = list(map(os.path.expanduser, prefixes)) - prefixes = list(map(os.path.abspath, prefixes)) - # Check longer prefixes first so we don't split in the middle of a filename - prefixes = sorted(prefixes, key=len, reverse=True) - filename = os.path.abspath(filename) - for src_prefix in prefixes: - if filename.startswith(src_prefix): - _, relpath = filename.split(src_prefix, 1) - if src_prefix != os.sep: # sys.prefix == "/" - assert relpath[0] == os.sep - relpath = relpath[1:] - return join(dst_prefix, relpath) - assert False, "Filename %s does not start with any of these prefixes: %s" % \ - (filename, prefixes) - -def copy_required_modules(dst_prefix): - import imp - # If we are running under -p, we need to remove the current - # directory from sys.path temporarily here, so that we - # definitely get the modules from the site directory of - # the interpreter we are running under, not the one - # virtualenv.py is installed under (which might lead to py2/py3 - # incompatibility issues) - _prev_sys_path = sys.path - if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): - sys.path = sys.path[1:] - try: - for modname in REQUIRED_MODULES: - if modname in sys.builtin_module_names: - logger.info("Ignoring built-in bootstrap module: %s" % modname) - continue - try: - f, filename, _ = imp.find_module(modname) - except ImportError: - logger.info("Cannot import bootstrap module: %s" % modname) - else: - if f is not None: - f.close() - # special-case custom readline.so on OS X: - if modname == 'readline' and sys.platform == 'darwin' and not filename.endswith(join('lib-dynload', 'readline.so')): - dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so') - else: - dst_filename = change_prefix(filename, dst_prefix) - copyfile(filename, dst_filename) - if filename.endswith('.pyc'): - pyfile = filename[:-1] - if os.path.exists(pyfile): - copyfile(pyfile, dst_filename[:-1]) - finally: - sys.path = _prev_sys_path - - -def subst_path(prefix_path, prefix, home_dir): - prefix_path = os.path.normpath(prefix_path) - prefix = os.path.normpath(prefix) - home_dir = os.path.normpath(home_dir) - if not prefix_path.startswith(prefix): - logger.warn('Path not in prefix %r %r', prefix_path, prefix) - return - return prefix_path.replace(prefix, home_dir, 1) - - -def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear): - """Install just the base environment, no distutils patches etc""" - if sys.executable.startswith(bin_dir): - print('Please use the *system* python to run this script') - return - - if clear: - rmtree(lib_dir) - ## FIXME: why not delete it? - ## Maybe it should delete everything with #!/path/to/venv/python in it - logger.notify('Not deleting %s', bin_dir) - - if hasattr(sys, 'real_prefix'): - logger.notify('Using real prefix %r' % sys.real_prefix) - prefix = sys.real_prefix - elif hasattr(sys, 'base_prefix'): - logger.notify('Using base prefix %r' % sys.base_prefix) - prefix = sys.base_prefix - else: - prefix = sys.prefix - mkdir(lib_dir) - fix_lib64(lib_dir) - stdlib_dirs = [os.path.dirname(os.__file__)] - if is_win: - stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs')) - elif is_darwin: - stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages')) - if hasattr(os, 'symlink'): - logger.info('Symlinking Python bootstrap modules') - else: - logger.info('Copying Python bootstrap modules') - logger.indent += 2 - try: - # copy required files... - for stdlib_dir in stdlib_dirs: - if not os.path.isdir(stdlib_dir): - continue - for fn in os.listdir(stdlib_dir): - bn = os.path.splitext(fn)[0] - if fn != 'site-packages' and bn in REQUIRED_FILES: - copyfile(join(stdlib_dir, fn), join(lib_dir, fn)) - # ...and modules - copy_required_modules(home_dir) - finally: - logger.indent -= 2 - mkdir(join(lib_dir, 'site-packages')) - import site - site_filename = site.__file__ - if site_filename.endswith('.pyc'): - site_filename = site_filename[:-1] - elif site_filename.endswith('$py.class'): - site_filename = site_filename.replace('$py.class', '.py') - site_filename_dst = change_prefix(site_filename, home_dir) - site_dir = os.path.dirname(site_filename_dst) - writefile(site_filename_dst, SITE_PY) - writefile(join(site_dir, 'orig-prefix.txt'), prefix) - site_packages_filename = join(site_dir, 'no-global-site-packages.txt') - if not site_packages: - writefile(site_packages_filename, '') - - if is_pypy or is_win: - stdinc_dir = join(prefix, 'include') - else: - stdinc_dir = join(prefix, 'include', py_version + abiflags) - if os.path.exists(stdinc_dir): - copyfile(stdinc_dir, inc_dir) - else: - logger.debug('No include dir %s' % stdinc_dir) - - platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1) - if platinc_dir != stdinc_dir: - platinc_dest = distutils.sysconfig.get_python_inc( - plat_specific=1, prefix=home_dir) - if platinc_dir == platinc_dest: - # Do platinc_dest manually due to a CPython bug; - # not http://bugs.python.org/issue3386 but a close cousin - platinc_dest = subst_path(platinc_dir, prefix, home_dir) - if platinc_dest: - # PyPy's stdinc_dir and prefix are relative to the original binary - # (traversing virtualenvs), whereas the platinc_dir is relative to - # the inner virtualenv and ignores the prefix argument. - # This seems more evolved than designed. - copyfile(platinc_dir, platinc_dest) - - # pypy never uses exec_prefix, just ignore it - if sys.exec_prefix != prefix and not is_pypy: - if is_win: - exec_dir = join(sys.exec_prefix, 'lib') - elif is_jython: - exec_dir = join(sys.exec_prefix, 'Lib') - else: - exec_dir = join(sys.exec_prefix, 'lib', py_version) - for fn in os.listdir(exec_dir): - copyfile(join(exec_dir, fn), join(lib_dir, fn)) - - if is_jython: - # Jython has either jython-dev.jar and javalib/ dir, or just - # jython.jar - for name in 'jython-dev.jar', 'javalib', 'jython.jar': - src = join(prefix, name) - if os.path.exists(src): - copyfile(src, join(home_dir, name)) - # XXX: registry should always exist after Jython 2.5rc1 - src = join(prefix, 'registry') - if os.path.exists(src): - copyfile(src, join(home_dir, 'registry'), symlink=False) - copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'), - symlink=False) - - mkdir(bin_dir) - py_executable = join(bin_dir, os.path.basename(sys.executable)) - if 'Python.framework' in prefix: - # OS X framework builds cause validation to break - # https://github.com/pypa/virtualenv/issues/322 - if os.environ.get('__PYVENV_LAUNCHER__'): - os.unsetenv('__PYVENV_LAUNCHER__') - if re.search(r'/Python(?:-32|-64)*$', py_executable): - # The name of the python executable is not quite what - # we want, rename it. - py_executable = os.path.join( - os.path.dirname(py_executable), 'python') - - logger.notify('New %s executable in %s', expected_exe, py_executable) - pcbuild_dir = os.path.dirname(sys.executable) - pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth') - if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')): - logger.notify('Detected python running from build directory %s', pcbuild_dir) - logger.notify('Writing .pth file linking to build directory for *.pyd files') - writefile(pyd_pth, pcbuild_dir) - else: - pcbuild_dir = None - if os.path.exists(pyd_pth): - logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth) - os.unlink(pyd_pth) - - if sys.executable != py_executable: - ## FIXME: could I just hard link? - executable = sys.executable - if is_cygwin and os.path.exists(executable + '.exe'): - # Cygwin misreports sys.executable sometimes - executable += '.exe' - py_executable += '.exe' - logger.info('Executable actually exists in %s' % executable) - shutil.copyfile(executable, py_executable) - make_exe(py_executable) - if is_win or is_cygwin: - pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe') - if os.path.exists(pythonw): - logger.info('Also created pythonw.exe') - shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe')) - python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe') - python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe') - if os.path.exists(python_d): - logger.info('Also created python_d.exe') - shutil.copyfile(python_d, python_d_dest) - elif os.path.exists(python_d_dest): - logger.info('Removed python_d.exe as it is no longer at the source') - os.unlink(python_d_dest) - # we need to copy the DLL to enforce that windows will load the correct one. - # may not exist if we are cygwin. - py_executable_dll = 'python%s%s.dll' % ( - sys.version_info[0], sys.version_info[1]) - py_executable_dll_d = 'python%s%s_d.dll' % ( - sys.version_info[0], sys.version_info[1]) - pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll) - pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d) - pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d) - if os.path.exists(pythondll): - logger.info('Also created %s' % py_executable_dll) - shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll)) - if os.path.exists(pythondll_d): - logger.info('Also created %s' % py_executable_dll_d) - shutil.copyfile(pythondll_d, pythondll_d_dest) - elif os.path.exists(pythondll_d_dest): - logger.info('Removed %s as the source does not exist' % pythondll_d_dest) - os.unlink(pythondll_d_dest) - if is_pypy: - # make a symlink python --> pypy-c - python_executable = os.path.join(os.path.dirname(py_executable), 'python') - if sys.platform in ('win32', 'cygwin'): - python_executable += '.exe' - logger.info('Also created executable %s' % python_executable) - copyfile(py_executable, python_executable) - - if is_win: - for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll': - src = join(prefix, name) - if os.path.exists(src): - copyfile(src, join(bin_dir, name)) - - if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe: - secondary_exe = os.path.join(os.path.dirname(py_executable), - expected_exe) - py_executable_ext = os.path.splitext(py_executable)[1] - if py_executable_ext == '.exe': - # python2.4 gives an extension of '.4' :P - secondary_exe += py_executable_ext - if os.path.exists(secondary_exe): - logger.warn('Not overwriting existing %s script %s (you must use %s)' - % (expected_exe, secondary_exe, py_executable)) - else: - logger.notify('Also creating executable in %s' % secondary_exe) - shutil.copyfile(sys.executable, secondary_exe) - make_exe(secondary_exe) - - if '.framework' in prefix: - if 'Python.framework' in prefix: - logger.debug('MacOSX Python framework detected') - # Make sure we use the the embedded interpreter inside - # the framework, even if sys.executable points to - # the stub executable in ${sys.prefix}/bin - # See http://groups.google.com/group/python-virtualenv/ - # browse_thread/thread/17cab2f85da75951 - original_python = os.path.join( - prefix, 'Resources/Python.app/Contents/MacOS/Python') - if 'EPD' in prefix: - logger.debug('EPD framework detected') - original_python = os.path.join(prefix, 'bin/python') - shutil.copy(original_python, py_executable) - - # Copy the framework's dylib into the virtual - # environment - virtual_lib = os.path.join(home_dir, '.Python') - - if os.path.exists(virtual_lib): - os.unlink(virtual_lib) - copyfile( - os.path.join(prefix, 'Python'), - virtual_lib) - - # And then change the install_name of the copied python executable - try: - mach_o_change(py_executable, - os.path.join(prefix, 'Python'), - '@executable_path/../.Python') - except: - e = sys.exc_info()[1] - logger.warn("Could not call mach_o_change: %s. " - "Trying to call install_name_tool instead." % e) - try: - call_subprocess( - ["install_name_tool", "-change", - os.path.join(prefix, 'Python'), - '@executable_path/../.Python', - py_executable]) - except: - logger.fatal("Could not call install_name_tool -- you must " - "have Apple's development tools installed") - raise - - if not is_win: - # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist - py_exe_version_major = 'python%s' % sys.version_info[0] - py_exe_version_major_minor = 'python%s.%s' % ( - sys.version_info[0], sys.version_info[1]) - py_exe_no_version = 'python' - required_symlinks = [ py_exe_no_version, py_exe_version_major, - py_exe_version_major_minor ] - - py_executable_base = os.path.basename(py_executable) - - if py_executable_base in required_symlinks: - # Don't try to symlink to yourself. - required_symlinks.remove(py_executable_base) - - for pth in required_symlinks: - full_pth = join(bin_dir, pth) - if os.path.exists(full_pth): - os.unlink(full_pth) - os.symlink(py_executable_base, full_pth) - - if is_win and ' ' in py_executable: - # There's a bug with subprocess on Windows when using a first - # argument that has a space in it. Instead we have to quote - # the value: - py_executable = '"%s"' % py_executable - # NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks - cmd = [py_executable, '-c', 'import sys;out=sys.stdout;' - 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))'] - logger.info('Testing executable with %s %s "%s"' % tuple(cmd)) - try: - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE) - proc_stdout, proc_stderr = proc.communicate() - except OSError: - e = sys.exc_info()[1] - if e.errno == errno.EACCES: - logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e)) - sys.exit(100) - else: - raise e - - proc_stdout = proc_stdout.strip().decode("utf-8") - proc_stdout = os.path.normcase(os.path.abspath(proc_stdout)) - norm_home_dir = os.path.normcase(os.path.abspath(home_dir)) - if hasattr(norm_home_dir, 'decode'): - norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding()) - if proc_stdout != norm_home_dir: - logger.fatal( - 'ERROR: The executable %s is not functioning' % py_executable) - logger.fatal( - 'ERROR: It thinks sys.prefix is %r (should be %r)' - % (proc_stdout, norm_home_dir)) - logger.fatal( - 'ERROR: virtualenv is not compatible with this system or executable') - if is_win: - logger.fatal( - 'Note: some Windows users have reported this error when they ' - 'installed Python for "Only this user" or have multiple ' - 'versions of Python installed. Copying the appropriate ' - 'PythonXX.dll to the virtualenv Scripts/ directory may fix ' - 'this problem.') - sys.exit(100) - else: - logger.info('Got sys.prefix result: %r' % proc_stdout) - - pydistutils = os.path.expanduser('~/.pydistutils.cfg') - if os.path.exists(pydistutils): - logger.notify('Please make sure you remove any previous custom paths from ' - 'your %s file.' % pydistutils) - ## FIXME: really this should be calculated earlier - - fix_local_scheme(home_dir) - - if site_packages: - if os.path.exists(site_packages_filename): - logger.info('Deleting %s' % site_packages_filename) - os.unlink(site_packages_filename) - - return py_executable - - -def install_activate(home_dir, bin_dir, prompt=None): - home_dir = os.path.abspath(home_dir) - if is_win or is_jython and os._name == 'nt': - files = { - 'activate.bat': ACTIVATE_BAT, - 'deactivate.bat': DEACTIVATE_BAT, - 'activate.ps1': ACTIVATE_PS, - } - - # MSYS needs paths of the form /c/path/to/file - drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/')) - home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail) - - # Run-time conditional enables (basic) Cygwin compatibility - home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" % - (home_dir, home_dir_msys)) - files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh) - - else: - files = {'activate': ACTIVATE_SH} - - # suppling activate.fish in addition to, not instead of, the - # bash script support. - files['activate.fish'] = ACTIVATE_FISH - - # same for csh/tcsh support... - files['activate.csh'] = ACTIVATE_CSH - - files['activate_this.py'] = ACTIVATE_THIS - if hasattr(home_dir, 'decode'): - home_dir = home_dir.decode(sys.getfilesystemencoding()) - vname = os.path.basename(home_dir) - for name, content in files.items(): - content = content.replace('__VIRTUAL_PROMPT__', prompt or '') - content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname) - content = content.replace('__VIRTUAL_ENV__', home_dir) - content = content.replace('__VIRTUAL_NAME__', vname) - content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) - writefile(os.path.join(bin_dir, name), content) - -def install_distutils(home_dir): - distutils_path = change_prefix(distutils.__path__[0], home_dir) - mkdir(distutils_path) - ## FIXME: maybe this prefix setting should only be put in place if - ## there's a local distutils.cfg with a prefix setting? - home_dir = os.path.abspath(home_dir) - ## FIXME: this is breaking things, removing for now: - #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir - writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT) - writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False) - -def fix_local_scheme(home_dir): - """ - Platforms that use the "posix_local" install scheme (like Ubuntu with - Python 2.7) need to be given an additional "local" location, sigh. - """ - try: - import sysconfig - except ImportError: - pass - else: - if sysconfig._get_default_scheme() == 'posix_local': - local_path = os.path.join(home_dir, 'local') - if not os.path.exists(local_path): - os.mkdir(local_path) - for subdir_name in os.listdir(home_dir): - if subdir_name == 'local': - continue - os.symlink(os.path.abspath(os.path.join(home_dir, subdir_name)), \ - os.path.join(local_path, subdir_name)) - -def fix_lib64(lib_dir): - """ - Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y - instead of lib/pythonX.Y. If this is such a platform we'll just create a - symlink so lib64 points to lib - """ - if [p for p in distutils.sysconfig.get_config_vars().values() - if isinstance(p, basestring) and 'lib64' in p]: - logger.debug('This system uses lib64; symlinking lib64 to lib') - assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], ( - "Unexpected python lib dir: %r" % lib_dir) - lib_parent = os.path.dirname(lib_dir) - top_level = os.path.dirname(lib_parent) - lib_dir = os.path.join(top_level, 'lib') - lib64_link = os.path.join(top_level, 'lib64') - assert os.path.basename(lib_parent) == 'lib', ( - "Unexpected parent dir: %r" % lib_parent) - if os.path.lexists(lib64_link): - return - os.symlink('lib', lib64_link) - -def resolve_interpreter(exe): - """ - If the executable given isn't an absolute path, search $PATH for the interpreter - """ - if os.path.abspath(exe) != exe: - paths = os.environ.get('PATH', '').split(os.pathsep) - for path in paths: - if os.path.exists(os.path.join(path, exe)): - exe = os.path.join(path, exe) - break - if not os.path.exists(exe): - logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe)) - raise SystemExit(3) - if not is_executable(exe): - logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe)) - raise SystemExit(3) - return exe - -def is_executable(exe): - """Checks a file is executable""" - return os.access(exe, os.X_OK) - -############################################################ -## Relocating the environment: - -def make_environment_relocatable(home_dir): - """ - Makes the already-existing environment use relative paths, and takes out - the #!-based environment selection in scripts. - """ - home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) - activate_this = os.path.join(bin_dir, 'activate_this.py') - if not os.path.exists(activate_this): - logger.fatal( - 'The environment doesn\'t have a file %s -- please re-run virtualenv ' - 'on this environment to update it' % activate_this) - fixup_scripts(home_dir) - fixup_pth_and_egg_link(home_dir) - ## FIXME: need to fix up distutils.cfg - -OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3], - 'activate', 'activate.bat', 'activate_this.py'] - -def fixup_scripts(home_dir): - # This is what we expect at the top of scripts: - shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir)) - # This is what we'll put: - new_shebang = '#!/usr/bin/env python%s' % sys.version[:3] - if is_win: - bin_suffix = 'Scripts' - else: - bin_suffix = 'bin' - bin_dir = os.path.join(home_dir, bin_suffix) - home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) - for filename in os.listdir(bin_dir): - filename = os.path.join(bin_dir, filename) - if not os.path.isfile(filename): - # ignore subdirs, e.g. .svn ones. - continue - f = open(filename, 'rb') - try: - try: - lines = f.read().decode('utf-8').splitlines() - except UnicodeDecodeError: - # This is probably a binary program instead - # of a script, so just ignore it. - continue - finally: - f.close() - if not lines: - logger.warn('Script %s is an empty file' % filename) - continue - if not lines[0].strip().startswith(shebang): - if os.path.basename(filename) in OK_ABS_SCRIPTS: - logger.debug('Cannot make script %s relative' % filename) - elif lines[0].strip() == new_shebang: - logger.info('Script %s has already been made relative' % filename) - else: - logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)' - % (filename, shebang)) - continue - logger.notify('Making script %s relative' % filename) - script = relative_script([new_shebang] + lines[1:]) - f = open(filename, 'wb') - f.write('\n'.join(script).encode('utf-8')) - f.close() - -def relative_script(lines): - "Return a script that'll work in a relocatable environment." - activate = "import os; activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this" - # Find the last future statement in the script. If we insert the activation - # line before a future statement, Python will raise a SyntaxError. - activate_at = None - for idx, line in reversed(list(enumerate(lines))): - if line.split()[:3] == ['from', '__future__', 'import']: - activate_at = idx + 1 - break - if activate_at is None: - # Activate after the shebang. - activate_at = 1 - return lines[:activate_at] + ['', activate, ''] + lines[activate_at:] - -def fixup_pth_and_egg_link(home_dir, sys_path=None): - """Makes .pth and .egg-link files use relative paths""" - home_dir = os.path.normcase(os.path.abspath(home_dir)) - if sys_path is None: - sys_path = sys.path - for path in sys_path: - if not path: - path = '.' - if not os.path.isdir(path): - continue - path = os.path.normcase(os.path.abspath(path)) - if not path.startswith(home_dir): - logger.debug('Skipping system (non-environment) directory %s' % path) - continue - for filename in os.listdir(path): - filename = os.path.join(path, filename) - if filename.endswith('.pth'): - if not os.access(filename, os.W_OK): - logger.warn('Cannot write .pth file %s, skipping' % filename) - else: - fixup_pth_file(filename) - if filename.endswith('.egg-link'): - if not os.access(filename, os.W_OK): - logger.warn('Cannot write .egg-link file %s, skipping' % filename) - else: - fixup_egg_link(filename) - -def fixup_pth_file(filename): - lines = [] - prev_lines = [] - f = open(filename) - prev_lines = f.readlines() - f.close() - for line in prev_lines: - line = line.strip() - if (not line or line.startswith('#') or line.startswith('import ') - or os.path.abspath(line) != line): - lines.append(line) - else: - new_value = make_relative_path(filename, line) - if line != new_value: - logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename)) - lines.append(new_value) - if lines == prev_lines: - logger.info('No changes to .pth file %s' % filename) - return - logger.notify('Making paths in .pth file %s relative' % filename) - f = open(filename, 'w') - f.write('\n'.join(lines) + '\n') - f.close() - -def fixup_egg_link(filename): - f = open(filename) - link = f.readline().strip() - f.close() - if os.path.abspath(link) != link: - logger.debug('Link in %s already relative' % filename) - return - new_link = make_relative_path(filename, link) - logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link)) - f = open(filename, 'w') - f.write(new_link) - f.close() - -def make_relative_path(source, dest, dest_is_directory=True): - """ - Make a filename relative, where the filename is dest, and it is - being referred to from the filename source. - - >>> make_relative_path('/usr/share/something/a-file.pth', - ... '/usr/share/another-place/src/Directory') - '../another-place/src/Directory' - >>> make_relative_path('/usr/share/something/a-file.pth', - ... '/home/user/src/Directory') - '../../../home/user/src/Directory' - >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') - './' - """ - source = os.path.dirname(source) - if not dest_is_directory: - dest_filename = os.path.basename(dest) - dest = os.path.dirname(dest) - dest = os.path.normpath(os.path.abspath(dest)) - source = os.path.normpath(os.path.abspath(source)) - dest_parts = dest.strip(os.path.sep).split(os.path.sep) - source_parts = source.strip(os.path.sep).split(os.path.sep) - while dest_parts and source_parts and dest_parts[0] == source_parts[0]: - dest_parts.pop(0) - source_parts.pop(0) - full_parts = ['..']*len(source_parts) + dest_parts - if not dest_is_directory: - full_parts.append(dest_filename) - if not full_parts: - # Special case for the current directory (otherwise it'd be '') - return './' - return os.path.sep.join(full_parts) - - - -############################################################ -## Bootstrap script creation: - -def create_bootstrap_script(extra_text, python_version=''): - """ - Creates a bootstrap script, which is like this script but with - extend_parser, adjust_options, and after_install hooks. - - This returns a string that (written to disk of course) can be used - as a bootstrap script with your own customizations. The script - will be the standard virtualenv.py script, with your extra text - added (your extra text should be Python code). - - If you include these functions, they will be called: - - ``extend_parser(optparse_parser)``: - You can add or remove options from the parser here. - - ``adjust_options(options, args)``: - You can change options here, or change the args (if you accept - different kinds of arguments, be sure you modify ``args`` so it is - only ``[DEST_DIR]``). - - ``after_install(options, home_dir)``: - - After everything is installed, this function is called. This - is probably the function you are most likely to use. An - example would be:: - - def after_install(options, home_dir): - subprocess.call([join(home_dir, 'bin', 'easy_install'), - 'MyPackage']) - subprocess.call([join(home_dir, 'bin', 'my-package-script'), - 'setup', home_dir]) - - This example immediately installs a package, and runs a setup - script from that package. - - If you provide something like ``python_version='2.5'`` then the - script will start with ``#!/usr/bin/env python2.5`` instead of - ``#!/usr/bin/env python``. You can use this when the script must - be run with a particular Python version. - """ - filename = __file__ - if filename.endswith('.pyc'): - filename = filename[:-1] - f = codecs.open(filename, 'r', encoding='utf-8') - content = f.read() - f.close() - py_exe = 'python%s' % python_version - content = (('#!/usr/bin/env %s\n' % py_exe) - + '## WARNING: This file is generated\n' - + content) - return content.replace('##EXT' 'END##', extra_text) - -##EXTEND## - -def convert(s): - b = base64.b64decode(s.encode('ascii')) - return zlib.decompress(b).decode('utf-8') - -##file site.py -SITE_PY = convert(""" -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 -CP4PNIke9w== -""") - -##file ez_setup.py -EZ_SETUP_PY = convert(""" -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 -qL7+C1AkCcw= -""") - -##file distribute_from_egg.py -DISTRIBUTE_FROM_EGG_PY = convert(""" -eJw9j8tqAzEMRfcG/4MgmxQyptkGusonZBmGoGTUGYFfWPKE6dfXTkM3gqt7rh47OKP3NMF3SQFW -LlrRU1zhybpAxoKBlIqcrNnBdRjQP3GTocYfzmNrrCPQPN9iwzpxSQfQhWBi0cL3qtRtYIG/4Mv0 -KApY5hooqrOGQ05FQTaxptF9Fnx16Rq0XofjaE1XGXVxHIWK7j8P8EY/rHndLqQ1a0pe3COFgHFy -hLLdWkDbi/DeEpCjNb3u/zccT2Ob8gtnwVyI -""") - -##file distribute_setup.py -DISTRIBUTE_SETUP_PY = convert(""" -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 -""") - -##file activate.sh -ACTIVATE_SH = convert(""" -eJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+ -nfl25pvZDswCnoDPQ4QoTRQsENIEPci4CsBMZBq7CAsuLOYqvmYKTTj3YxnBgiXBudGBjUzBZUJI -BXEqgCvweIyuCjeG4eF2F5x14bcB9KQiQQWrjSddI1/oQIx6SYYeoFjzWIoIhYI1izlbhJjkKO7D -M/QEmKfO9O7WeRo/zr4P7pyHwWxkwitcgwpQ5Ej96OX+PmiFwLeVjFUOrNYKaq1Nud3nR2n8nI2m -k9H0friPTGVsUdptaxGrTEfpNVFEskxpXtUkkCkl1UNF9cgLBkx48J4EXyALuBtAwNYIjF5kcmUU -abMKmMq1ULoiRbgsDEkTSsKSGFCJ6Z8vY/2xYiSacmtyAfCDdCNTVZoVF8vSTQOoEwSnOrngBkws -MYGMBMg8/bMBLSYKS7pYEXP0PqT+ZmBT0Xuy+Pplj5yn4aM9nk72JD8/Wi+Gr98sD9eWSMOwkapD -BbUv91XSvmyVkICt2tmXR4tWmrcUCsjWOpw87YidEC8i0gdTSOFhouJUNxR+4NYBG0MftoCTD9F7 -2rTtxG3oPwY1b2HncYwhrlmj6Wq924xtGDWqfdNxap+OYxplEurnMVo9RWks+rH8qKEtx7kZT5zJ -4H7oOFclrN6uFe+d+nW2aIUsSgs/42EIPuOhXq+jEo3S6tX6w2ilNkDnIpHCWdEQhFgwj9pkk7FN -l/y5eQvRSIQ5+TrL05lewxWpt/Lbhes5cJF3mLET1MGhcKCF+40tNWnUulxrpojwDo2sObdje3Bz -N3QeHqf3D7OjEXMVV8LN3ZlvuzoWHqiUcNKHtwNd0IbvPGKYYM31nPKCgkUILw3KL+Y8l7aO1ArS -Ad37nIU0fCj5NE5gQCuC5sOSu+UdI2NeXg/lFkQIlFpdWVaWZRfvqGiirC9o6liJ9FXGYrSY9mI1 -D/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG -+n8O9H8f5vsGOWXsL1+1k3g= -""") - -##file activate.fish -ACTIVATE_FISH = convert(""" -eJyVVWFv2jAQ/c6vuBoqQVWC9nVSNVGVCaS2VC2rNLWVZZILWAs2s52wVvvxsyEJDrjbmgpK7PP5 -3bt3d22YLbmGlGcIq1wbmCPkGhPYcLMEEsGciwGLDS+YwSjlekngLFVyBe73GXSXxqw/DwbuTS8x -yyKpFr1WG15lDjETQhpQuQBuIOEKY5O9tlppLqxHKSDByjVAPwEy+mXtCq5MzjIUBTCRgEKTKwFG -gpBqxTLYXgN2myspVigMaYF92tZSowGZJf4mFExxNs9Qb614CgZtmH0BpEOn11f0cXI/+za8pnfD -2ZjA1sg9zlV/8QvcMhxbNu0QwgYokn/d+n02nt6Opzcjcnx1vXcIoN74O4ymWQXmHURfJw9jenc/ -vbmb0enj6P5+cuVhqlKm3S0u2XRtRbA2QQAhV7VhBF0rsgUX9Ur1rBUXJgVSy8O751k8mzY5OrKH -RW3eaQhYGTr8hrXO59ALhxQ83mCsDLAid3T72CCSdJhaFE+fXgicXAARUiR2WeVO37gH3oYHzFKo -9k7CaPZ1UeNwH1tWuXA4uFKYYcEa8vaKqXl7q1UpygMPhFLvlVKyNzsSM3S2km7UBOl4xweUXk5u -6e3wZmQ9leY1XE/Ili670tr9g/5POBBpGIJXCCF79L1siarl/dbESa8mD8PL61GpzqpzuMS7tqeB -1YkALrRBloBMbR9yLcVx7frQAgUqR7NZIuzkEu110gbNit1enNs82Rx5utq7Z3prU78HFRgulqNC -OTwbqJa9vkJFclQgZSjbKeBgSsUtCtt9D8OwAbIVJuewQdfvQRaoFE9wd1TmCuRG7OgJ1bVXGHc7 -z5WDL/WW36v2oi37CyVBak61+yPBA9C1qqGxzKQqZ0oPuocU9hpud0PIp8sDHkXR1HKkNlzjuUWA -a0enFUyzOWZA4yXGP+ZMI3Tdt2OuqU/SO4q64526cPE0A7ZyW2PMbWZiZ5HamIZ2RcCKLXhcDl2b -vXL+eccQoRzem80mekPDEiyiWK4GWqZmwxQOmPM0eIfgp1P9cqrBsewR2p/DPMtt+pfcYM+Ls2uh -hALufTAdmGl8B1H3VPd2af8fQAc4PgqjlIBL9cGQqNpXaAwe3LrtVn8AkZTUxg== -""") - -##file activate.csh -ACTIVATE_CSH = convert(""" -eJx9VG1P2zAQ/u5fcYQKNgTNPtN1WxlIQ4KCUEGaxuQ6yYVYSuzKdhqVX7+zk3bpy5YPUXL3PPfc -ne98DLNCWshliVDV1kGCUFvMoJGugMjq2qQIiVSxSJ1cCofD1BYRnOVGV0CfZ0N2DD91DalQSjsw -tQLpIJMGU1euvPe7QeJlkKzgWixlhnAt4aoUVsLnLBiy5NtbJWQ5THX1ZciYKKWwkOFaE04dUm6D -r/zh7pq/3D7Nnid3/HEy+wFHY/gEJydg0aFaQrBFgz1c5DG1IhTs+UZgsBC2GMFBlaeH+8dZXwcW -VPvCjXdlAvCfQsE7al0+07XjZvrSCUevR5dnkVeKlFYZmUztG4BdzL2u9KyLVabTU0bdfg7a0hgs -cSmUg6UwUiQl2iHrcbcVGNvPCiLOe7+cRwG13z9qRGgx2z6DHjfm/Op2yqeT+xvOLzs0PTKHDz2V -tkckFHoQfQRXoGJAj9el0FyJCmEMhzgMS4sB7KPOE2ExoLcSieYwDvR+cP8cg11gKkVJc2wRcm1g -QhYFlXiTaTfO2ki0fQoiFM4tLuO4aZrhOzqR4dIPcWx17hphMBY+Srwh7RTyN83XOWkcSPh1Pg/k -TXX/jbJTbMtUmcxZ+/bbqOsy82suFQg/BhdSOTRhMNBHlUarCpU7JzBhmkKmRejKOQzayQe6MWoa -n1wqWmuh6LZAaHxcdeqIlVLhIBJdO9/kbl0It2oEXQj+eGjJOuvOIR/YGRqvFhttUB2XTvLXYN2H -37CBdbW2W7j2r2+VsCn0doVWcFG1/4y1VwBjfwAyoZhD -""") - -##file activate.bat -ACTIVATE_BAT = convert(""" -eJx9UdEKgjAUfW6wfxjiIH+hEDKUFHSKLCMI7kNOEkIf9P9pTJ3OLJ/03HPPPed4Es9XS9qqwqgT -PbGKKOdXL4aAFS7A4gvAwgijuiKlqOpGlATS2NeMLE+TjJM9RkQ+SmqAXLrBo1LLIeLdiWlD6jZt -r7VNubWkndkXaxg5GO3UaOOKS6drO3luDDiO5my3iA0YAKGzPRV1ack8cOdhysI0CYzIPzjSiH5X -0QcvC8Lfaj0emsVKYF2rhL5L3fCkVjV76kShi59NHwDniAHzkgDgqBcwOgTMx+gDQQqXCw== -""") - -##file deactivate.bat -DEACTIVATE_BAT = convert(""" -eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgUliIit -KhZlqkpcnCA1WKRsuTTxWBIZ4uHv5+Hv64piEVwU3TK4BNBCmHIcKvDb6xjigWIjkI9uF1AIu7dA -akGGW7n6uXABALCXXUI= -""") - -##file activate.ps1 -ACTIVATE_PS = convert(""" -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 -QastYw== -""") - -##file distutils-init.py -DISTUTILS_INIT = convert(""" -eJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E -UXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB -C4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss -aG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT -0n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9 -oh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE -NFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c -f/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8 -p7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk -vUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw -hUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh -cbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw -buHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ -5bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh -gGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC -1vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL -MlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6 -84zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK -0/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO -kMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG -qgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h -kzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9 -GBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ= -""") - -##file distutils.cfg -DISTUTILS_CFG = convert(""" -eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH -xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg -9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= -""") - -##file activate_this.py -ACTIVATE_THIS = convert(""" -eJyNU01v2zAMvetXEB4K21jmDOstQA4dMGCHbeihlyEIDMWmG62yJEiKE//7kXKdpN2KzYBt8euR -fKSyLPs8wiEo8wh4wqZTGou4V6Hm0wJa1cSiTkJdr8+GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe -5a3p0cRKiAe2NtLADikftnDco0ko/SFEVgEZ8aRC5GLux7i3BpSJ6J1H+i7A2CjiHq9z7JRZuuQq -siwTIvpxJYCeuWaBpwZdhB+yxy/eWz+ZvVSU8C4E9FFZkyxFsvCT/ZzL8gcz9aXVE14Yyp2M+2W0 -y7n5mp0qN+avKXvbsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCZN9UzlJr+/e/iab8WfqsmPI6pWeUPd -FrMsd4H/55poeO9n54COhUs+sZNEzNtg/wanpjpuqHJaxs76HtZryI/K3H7KJ/KDIhqcbJ7kI4ar -XL+sMgXnX0D+Te2Iy5xdP8yueSlQB/x/ED2BTAtyE3K4SYUN6AMNfbO63f4lBW3bUJPbTL+mjSxS -PyRfJkZRgj+VbFv+EzHFi5pKwUEepa4JslMnwkowSRCXI+m5XvEOvtuBrxHdhLalG0JofYBok6qj -YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t -s3az+sj7eA0jfgPfeoN1 -""") - -MH_MAGIC = 0xfeedface -MH_CIGAM = 0xcefaedfe -MH_MAGIC_64 = 0xfeedfacf -MH_CIGAM_64 = 0xcffaedfe -FAT_MAGIC = 0xcafebabe -BIG_ENDIAN = '>' -LITTLE_ENDIAN = '<' -LC_LOAD_DYLIB = 0xc -maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint') - - -class fileview(object): - """ - A proxy for file-like objects that exposes a given view of a file. - Modified from macholib. - """ - - def __init__(self, fileobj, start=0, size=maxint): - if isinstance(fileobj, fileview): - self._fileobj = fileobj._fileobj - else: - self._fileobj = fileobj - self._start = start - self._end = start + size - self._pos = 0 - - def __repr__(self): - return '' % ( - self._start, self._end, self._fileobj) - - def tell(self): - return self._pos - - def _checkwindow(self, seekto, op): - if not (self._start <= seekto <= self._end): - raise IOError("%s to offset %d is outside window [%d, %d]" % ( - op, seekto, self._start, self._end)) - - def seek(self, offset, whence=0): - seekto = offset - if whence == os.SEEK_SET: - seekto += self._start - elif whence == os.SEEK_CUR: - seekto += self._start + self._pos - elif whence == os.SEEK_END: - seekto += self._end - else: - raise IOError("Invalid whence argument to seek: %r" % (whence,)) - self._checkwindow(seekto, 'seek') - self._fileobj.seek(seekto) - self._pos = seekto - self._start - - def write(self, bytes): - here = self._start + self._pos - self._checkwindow(here, 'write') - self._checkwindow(here + len(bytes), 'write') - self._fileobj.seek(here, os.SEEK_SET) - self._fileobj.write(bytes) - self._pos += len(bytes) - - def read(self, size=maxint): - assert size >= 0 - here = self._start + self._pos - self._checkwindow(here, 'read') - size = min(size, self._end - here) - self._fileobj.seek(here, os.SEEK_SET) - bytes = self._fileobj.read(size) - self._pos += len(bytes) - return bytes - - -def read_data(file, endian, num=1): - """ - Read a given number of 32-bits unsigned integers from the given file - with the given endianness. - """ - res = struct.unpack(endian + 'L' * num, file.read(num * 4)) - if len(res) == 1: - return res[0] - return res - - -def mach_o_change(path, what, value): - """ - Replace a given name (what) in any LC_LOAD_DYLIB command found in - the given binary with a new name (value), provided it's shorter. - """ - - def do_macho(file, bits, endian): - # Read Mach-O header (the magic number is assumed read by the caller) - cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6) - # 64-bits header has one more field. - if bits == 64: - read_data(file, endian) - # The header is followed by ncmds commands - for n in range(ncmds): - where = file.tell() - # Read command header - cmd, cmdsize = read_data(file, endian, 2) - if cmd == LC_LOAD_DYLIB: - # The first data field in LC_LOAD_DYLIB commands is the - # offset of the name, starting from the beginning of the - # command. - name_offset = read_data(file, endian) - file.seek(where + name_offset, os.SEEK_SET) - # Read the NUL terminated string - load = file.read(cmdsize - name_offset).decode() - load = load[:load.index('\0')] - # If the string is what is being replaced, overwrite it. - if load == what: - file.seek(where + name_offset, os.SEEK_SET) - file.write(value.encode() + '\0'.encode()) - # Seek to the next command - file.seek(where + cmdsize, os.SEEK_SET) - - def do_file(file, offset=0, size=maxint): - file = fileview(file, offset, size) - # Read magic number - magic = read_data(file, BIG_ENDIAN) - if magic == FAT_MAGIC: - # Fat binaries contain nfat_arch Mach-O binaries - nfat_arch = read_data(file, BIG_ENDIAN) - for n in range(nfat_arch): - # Read arch header - cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5) - do_file(file, offset, size) - elif magic == MH_MAGIC: - do_macho(file, 32, BIG_ENDIAN) - elif magic == MH_CIGAM: - do_macho(file, 32, LITTLE_ENDIAN) - elif magic == MH_MAGIC_64: - do_macho(file, 64, BIG_ENDIAN) - elif magic == MH_CIGAM_64: - do_macho(file, 64, LITTLE_ENDIAN) - - assert(len(what) >= len(value)) - do_file(open(path, 'r+b')) - - -if __name__ == '__main__': - main() - -## TODO: -## Copy python.exe.manifest -## Monkeypatch distutils.sysconfig diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.bat b/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.bat deleted file mode 100644 index 4c2003e..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.bat +++ /dev/null @@ -1,26 +0,0 @@ -@echo off -set "VIRTUAL_ENV=__VIRTUAL_ENV__" - -if defined _OLD_VIRTUAL_PROMPT ( - set "PROMPT=%_OLD_VIRTUAL_PROMPT%" -) else ( - if not defined PROMPT ( - set "PROMPT=$P$G" - ) - set "_OLD_VIRTUAL_PROMPT=%PROMPT%" -) -set "PROMPT=__VIRTUAL_WINPROMPT__ %PROMPT%" - -if not defined _OLD_VIRTUAL_PYTHONHOME ( - set "_OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%" -) -set PYTHONHOME= - -if defined _OLD_VIRTUAL_PATH ( - set "PATH=%_OLD_VIRTUAL_PATH%" -) else ( - set "_OLD_VIRTUAL_PATH=%PATH%" -) -set "PATH=%VIRTUAL_ENV%\__BIN_NAME__;%PATH%" - -:END diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.csh b/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.csh deleted file mode 100644 index 9db7744..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.csh +++ /dev/null @@ -1,42 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi . - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV "__VIRTUAL_ENV__" - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/__BIN_NAME__:$PATH" - - - -if ("__VIRTUAL_PROMPT__" != "") then - set env_name = "__VIRTUAL_PROMPT__" -else - if (`basename "$VIRTUAL_ENV"` == "__") then - # special case for Aspen magic directories - # see http://www.zetadev.com/software/aspen/ - set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` - else - set env_name = `basename "$VIRTUAL_ENV"` - endif -endif - -# Could be in a non-interactive environment, -# in which case, $prompt is undefined and we wouldn't -# care about the prompt anyway. -if ( $?prompt ) then - set _OLD_VIRTUAL_PROMPT="$prompt" - set prompt = "[$env_name] $prompt" -endif - -unset env_name - -alias pydoc python -m pydoc - -rehash - diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.fish b/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.fish deleted file mode 100644 index be7a2a6..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.fish +++ /dev/null @@ -1,74 +0,0 @@ -# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) -# you cannot run it directly - -function deactivate -d "Exit virtualenv and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - . ( begin - printf "function fish_prompt\n\t#" - functions _old_fish_prompt - end | psub ) - functions -e _old_fish_prompt - end - - set -e VIRTUAL_ENV - if test "$argv[1]" != "nondestructive" - # Self destruct! - functions -e deactivate - end -end - -# unset irrelevant variables -deactivate nondestructive - -set -gx VIRTUAL_ENV "__VIRTUAL_ENV__" - -set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/__BIN_NAME__" $PATH - -# unset PYTHONHOME if set -if set -q PYTHONHOME - set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME - set -e PYTHONHOME -end - -if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" - # fish uses a function instead of an env var to generate the prompt. - - # save the current fish_prompt function as the function _old_fish_prompt - . ( begin - printf "function _old_fish_prompt\n\t#" - functions fish_prompt - end | psub ) - - # with the original prompt function renamed, we can override with our own. - function fish_prompt - # Prompt override? - if test -n "__VIRTUAL_PROMPT__" - printf "%s%s%s" "__VIRTUAL_PROMPT__" (set_color normal) (_old_fish_prompt) - return - end - # ...Otherwise, prepend env - set -l _checkbase (basename "$VIRTUAL_ENV") - if test $_checkbase = "__" - # special case for Aspen magic directories - # see http://www.zetadev.com/software/aspen/ - printf "%s[%s]%s %s" (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) (_old_fish_prompt) - else - printf "%s(%s)%s%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt) - end - end - - set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" -end diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.ps1 b/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.ps1 deleted file mode 100644 index a70b08c..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.ps1 +++ /dev/null @@ -1,148 +0,0 @@ -# This file must be dot sourced from PoSh; you cannot run it -# directly. Do this: . ./activate.ps1 - -# FIXME: clean up unused vars. -$script:THIS_PATH = $myinvocation.mycommand.path -$script:BASE_DIR = split-path (resolve-path "$THIS_PATH/..") -Parent -$script:DIR_NAME = split-path $BASE_DIR -Leaf - -function global:deactivate ( [switch] $NonDestructive ){ - - if ( test-path variable:_OLD_VIRTUAL_PATH ) { - $env:PATH = $variable:_OLD_VIRTUAL_PATH - remove-variable "_OLD_VIRTUAL_PATH" -scope global - } - - if ( test-path function:_old_virtual_prompt ) { - $function:prompt = $function:_old_virtual_prompt - remove-item function:\_old_virtual_prompt - } - - if ($env:VIRTUAL_ENV) { - $old_env = split-path $env:VIRTUAL_ENV -leaf - remove-item env:VIRTUAL_ENV -erroraction silentlycontinue - } - - if ( !$NonDestructive ) { - # Self destruct! - remove-item function:deactivate - } -} - -# unset irrelevant variables -deactivate -nondestructive - -$VIRTUAL_ENV = $BASE_DIR -$env:VIRTUAL_ENV = $VIRTUAL_ENV - -$global:_OLD_VIRTUAL_PATH = $env:PATH -$env:PATH = "$env:VIRTUAL_ENV/Scripts;" + $env:PATH -function global:_old_virtual_prompt { "" } -$function:_old_virtual_prompt = $function:prompt -function global:prompt { - # Add a prefix to the current prompt, but don't discard it. - write-host "($(split-path $env:VIRTUAL_ENV -leaf)) " -nonewline - & $function:_old_virtual_prompt -} - -# SIG # Begin signature block -# MIISeAYJKoZIhvcNAQcCoIISaTCCEmUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB -# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR -# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUS5reBwSg3zOUwhXf2jPChZzf -# yPmggg6tMIIGcDCCBFigAwIBAgIBJDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQG -# EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp -# Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy -# dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjIwMTQ2WhcNMTcxMDI0MjIw -# MTQ2WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp -# BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV -# BAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgT2JqZWN0 -# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyiOLIjUemqAbPJ1J -# 0D8MlzgWKbr4fYlbRVjvhHDtfhFN6RQxq0PjTQxRgWzwFQNKJCdU5ftKoM5N4YSj -# Id6ZNavcSa6/McVnhDAQm+8H3HWoD030NVOxbjgD/Ih3HaV3/z9159nnvyxQEckR -# ZfpJB2Kfk6aHqW3JnSvRe+XVZSufDVCe/vtxGSEwKCaNrsLc9pboUoYIC3oyzWoU -# TZ65+c0H4paR8c8eK/mC914mBo6N0dQ512/bkSdaeY9YaQpGtW/h/W/FkbQRT3sC -# pttLVlIjnkuY4r9+zvqhToPjxcfDYEf+XD8VGkAqle8Aa8hQ+M1qGdQjAye8OzbV -# uUOw7wIDAQABo4IB6TCCAeUwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -# AQYwHQYDVR0OBBYEFNBOD0CZbLhLGW87KLjg44gHNKq3MB8GA1UdIwQYMBaAFE4L -# 7xqkQFulF2mHMMo0aEPQQa7yMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAoYh -# aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3J0MFsGA1UdHwRUMFIwJ6Al -# oCOGIWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDAnoCWgI4YhaHR0 -# cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMIGABgNVHSAEeTB3MHUGCysG -# AQQBgbU3AQIBMGYwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29t -# L3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t -# L2ludGVybWVkaWF0ZS5wZGYwEQYJYIZIAYb4QgEBBAQDAgABMFAGCWCGSAGG+EIB -# DQRDFkFTdGFydENvbSBDbGFzcyAyIFByaW1hcnkgSW50ZXJtZWRpYXRlIE9iamVj -# dCBTaWduaW5nIENlcnRpZmljYXRlczANBgkqhkiG9w0BAQUFAAOCAgEAcnMLA3Va -# N4OIE9l4QT5OEtZy5PByBit3oHiqQpgVEQo7DHRsjXD5H/IyTivpMikaaeRxIv95 -# baRd4hoUcMwDj4JIjC3WA9FoNFV31SMljEZa66G8RQECdMSSufgfDYu1XQ+cUKxh -# D3EtLGGcFGjjML7EQv2Iol741rEsycXwIXcryxeiMbU2TPi7X3elbwQMc4JFlJ4B -# y9FhBzuZB1DV2sN2irGVbC3G/1+S2doPDjL1CaElwRa/T0qkq2vvPxUgryAoCppU -# FKViw5yoGYC+z1GaesWWiP1eFKAL0wI7IgSvLzU3y1Vp7vsYaxOVBqZtebFTWRHt -# XjCsFrrQBngt0d33QbQRI5mwgzEp7XJ9xu5d6RVWM4TPRUsd+DDZpBHm9mszvi9g -# VFb2ZG7qRRXCSqys4+u/NLBPbXi/m/lU00cODQTlC/euwjk9HQtRrXQ/zqsBJS6U -# J+eLGw1qOfj+HVBl/ZQpfoLk7IoWlRQvRL1s7oirEaqPZUIWY/grXq9r6jDKAp3L -# ZdKQpPOnnogtqlU4f7/kLjEJhrrc98mrOWmVMK/BuFRAfQ5oDUMnVmCzAzLMjKfG -# cVW/iMew41yfhgKbwpfzm3LBr1Zv+pEBgcgW6onRLSAn3XHM0eNtz+AkxH6rRf6B -# 2mYhLEEGLapH8R1AMAo4BbVFOZR5kXcMCwowggg1MIIHHaADAgECAgIEuDANBgkq -# hkiG9w0BAQUFADCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0 -# ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx -# ODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUg -# T2JqZWN0IENBMB4XDTExMTIwMzE1MzQxOVoXDTEzMTIwMzE0NTgwN1owgYwxIDAe -# BgNVBA0TFzU4MTc5Ni1HaDd4Zkp4a3hRU0lPNEUwMQswCQYDVQQGEwJERTEPMA0G -# A1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xFjAUBgNVBAMTDUphbm5pcyBM -# ZWlkZWwxITAfBgkqhkiG9w0BCQEWEmphbm5pc0BsZWlkZWwuaW5mbzCCAiIwDQYJ -# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMcPeABYdN7nPq/AkZ/EkyUBGx/l2Yui -# Lfm8ZdLG0ulMb/kQL3fRY7sUjYPyn9S6PhqqlFnNoGHJvbbReCdUC9SIQYmOEjEA -# raHfb7MZU10NjO4U2DdGucj2zuO5tYxKizizOJF0e4yRQZVxpUGdvkW/+GLjCNK5 -# L7mIv3Z1dagxDKHYZT74HXiS4VFUwHF1k36CwfM2vsetdm46bdgSwV+BCMmZICYT -# IJAS9UQHD7kP4rik3bFWjUx08NtYYFAVOd/HwBnemUmJe4j3IhZHr0k1+eDG8hDH -# KVvPgLJIoEjC4iMFk5GWsg5z2ngk0LLu3JZMtckHsnnmBPHQK8a3opUNd8hdMNJx -# gOwKjQt2JZSGUdIEFCKVDqj0FmdnDMPfwy+FNRtpBMl1sz78dUFhSrnM0D8NXrqa -# 4rG+2FoOXlmm1rb6AFtpjAKksHRpYcPk2DPGWp/1sWB+dUQkS3gOmwFzyqeTuXpT -# 0juqd3iAxOGx1VRFQ1VHLLf3AzV4wljBau26I+tu7iXxesVucSdsdQu293jwc2kN -# xK2JyHCoZH+RyytrwS0qw8t7rMOukU9gwP8mn3X6mgWlVUODMcHTULjSiCEtvyZ/ -# aafcwjUbt4ReEcnmuZtWIha86MTCX7U7e+cnpWG4sIHPnvVTaz9rm8RyBkIxtFCB -# nQ3FnoQgyxeJAgMBAAGjggOdMIIDmTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIH -# gDAuBgNVHSUBAf8EJDAiBggrBgEFBQcDAwYKKwYBBAGCNwIBFQYKKwYBBAGCNwoD -# DTAdBgNVHQ4EFgQUWyCgrIWo8Ifvvm1/YTQIeMU9nc8wHwYDVR0jBBgwFoAU0E4P -# QJlsuEsZbzsouODjiAc0qrcwggIhBgNVHSAEggIYMIICFDCCAhAGCysGAQQBgbU3 -# AQICMIIB/zAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9s -# aWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50 -# ZXJtZWRpYXRlLnBkZjCB9wYIKwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2VydGlm -# aWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRoaXMgY2VydGlmaWNhdGUgd2FzIGlz -# c3VlZCBhY2NvcmRpbmcgdG8gdGhlIENsYXNzIDIgVmFsaWRhdGlvbiByZXF1aXJl -# bWVudHMgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25seSBm -# b3IgdGhlIGludGVuZGVkIHB1cnBvc2UgaW4gY29tcGxpYW5jZSBvZiB0aGUgcmVs -# eWluZyBwYXJ0eSBvYmxpZ2F0aW9ucy4wgZwGCCsGAQUFBwICMIGPMCcWIFN0YXJ0 -# Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MAMCAQIaZExpYWJpbGl0eSBhbmQg -# d2FycmFudGllcyBhcmUgbGltaXRlZCEgU2VlIHNlY3Rpb24gIkxlZ2FsIGFuZCBM -# aW1pdGF0aW9ucyIgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeS4wNgYDVR0fBC8w -# LTAroCmgJ4YlaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0YzItY3JsLmNybDCB -# iQYIKwYBBQUHAQEEfTB7MDcGCCsGAQUFBzABhitodHRwOi8vb2NzcC5zdGFydHNz -# bC5jb20vc3ViL2NsYXNzMi9jb2RlL2NhMEAGCCsGAQUFBzAChjRodHRwOi8vYWlh -# LnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MyLmNvZGUuY2EuY3J0MCMGA1Ud -# EgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG9w0BAQUFAAOC -# AQEAhrzEV6zwoEtKjnFRhCsjwiPykVpo5Eiye77Ve801rQDiRKgSCCiW6g3HqedL -# OtaSs65Sj2pm3Viea4KR0TECLcbCTgsdaHqw2x1yXwWBQWZEaV6EB05lIwfr94P1 -# SFpV43zkuc+bbmA3+CRK45LOcCNH5Tqq7VGTCAK5iM7tvHwFlbQRl+I6VEL2mjpF -# NsuRjDOVrv/9qw/a22YJ9R7Y1D0vUSs3IqZx2KMUaYDP7H2mSRxJO2nADQZBtriF -# gTyfD3lYV12MlIi5CQwe3QC6DrrfSMP33i5Wa/OFJiQ27WPxmScYVhiqozpImFT4 -# PU9goiBv9RKXdgTmZE1PN0NQ5jGCAzUwggMxAgEBMIGTMIGMMQswCQYDVQQGEwJJ -# TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 -# YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg -# MiBQcmltYXJ5IEludGVybWVkaWF0ZSBPYmplY3QgQ0ECAgS4MAkGBSsOAwIaBQCg -# eDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE -# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJ -# BDEWBBRVGw0FDSiaIi38dWteRUAg/9Pr6DANBgkqhkiG9w0BAQEFAASCAgCInvOZ -# FdaNFzbf6trmFDZKMojyx3UjKMCqNjHVBbuKY0qXwFC/ElYDV1ShJ2CBZbdurydO -# OQ6cIQ0KREOCwmX/xB49IlLHHUxNhEkVv7HGU3EKAFf9IBt9Yr7jikiR9cjIsfHK -# 4cjkoKJL7g28yEpLLkHt1eo37f1Ga9lDWEa5Zq3U5yX+IwXhrUBm1h8Xr033FhTR -# VEpuSz6LHtbrL/zgJnCzJ2ahjtJoYevdcWiNXffosJHFaSfYDDbiNsPRDH/1avmb -# 5j/7BhP8BcBaR6Fp8tFbNGIcWHHGcjqLMnTc4w13b7b4pDhypqElBa4+lCmwdvv9 -# GydYtRgPz8GHeoBoKj30YBlMzRIfFYaIFGIC4Ai3UEXkuH9TxYohVbGm/W0Kl4Lb -# RJ1FwiVcLcTOJdgNId2vQvKc+jtNrjcg5SP9h2v/C4aTx8tyc6tE3TOPh2f9b8DL -# S+SbVArJpuJqrPTxDDoO1QNjTgLcdVYeZDE+r/NjaGZ6cMSd8db3EaG3ijD/0bud -# SItbm/OlNVbQOFRR76D+ZNgPcU5iNZ3bmvQQIg6aSB9MHUpIE/SeCkNl9YeVk1/1 -# GFULgNMRmIYP4KLvu9ylh5Gu3hvD5VNhH6+FlXANwFy07uXks5uF8mfZVxVCnodG -# xkNCx+6PsrA5Z7WP4pXcmYnMn97npP/Q9EHJWw== -# SIG # End signature block diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.sh b/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.sh deleted file mode 100644 index e50c782..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate.sh +++ /dev/null @@ -1,80 +0,0 @@ -# This file must be used with "source bin/activate" *from bash* -# you cannot run it directly - -deactivate () { - unset pydoc - - # reset old environment variables - if [ -n "$_OLD_VIRTUAL_PATH" ] ; then - PATH="$_OLD_VIRTUAL_PATH" - export PATH - unset _OLD_VIRTUAL_PATH - fi - if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then - PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" - export PYTHONHOME - unset _OLD_VIRTUAL_PYTHONHOME - fi - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then - hash -r 2>/dev/null - fi - - if [ -n "$_OLD_VIRTUAL_PS1" ] ; then - PS1="$_OLD_VIRTUAL_PS1" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - if [ ! "$1" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV="__VIRTUAL_ENV__" -export VIRTUAL_ENV - -_OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/__BIN_NAME__:$PATH" -export PATH - -# unset PYTHONHOME if set -# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) -# could use `if (set -u; : $PYTHONHOME) ;` in bash -if [ -n "$PYTHONHOME" ] ; then - _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" - unset PYTHONHOME -fi - -if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then - _OLD_VIRTUAL_PS1="$PS1" - if [ "x__VIRTUAL_PROMPT__" != x ] ; then - PS1="__VIRTUAL_PROMPT__$PS1" - else - if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then - # special case for Aspen magic directories - # see http://www.zetadev.com/software/aspen/ - PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" - else - PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" - fi - fi - export PS1 -fi - -alias pydoc="python -m pydoc" - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then - hash -r 2>/dev/null -fi diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate_this.py b/vendor/virtualenv-1.8.4/virtualenv_embedded/activate_this.py deleted file mode 100644 index ea12c28..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/activate_this.py +++ /dev/null @@ -1,34 +0,0 @@ -"""By using execfile(this_file, dict(__file__=this_file)) you will -activate this virtualenv environment. - -This can be used when you must use an existing Python interpreter, not -the virtualenv bin/python -""" - -try: - __file__ -except NameError: - raise AssertionError( - "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") -import sys -import os - -old_os_path = os.environ['PATH'] -os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path -base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -if sys.platform == 'win32': - site_packages = os.path.join(base, 'Lib', 'site-packages') -else: - site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') -prev_sys_path = list(sys.path) -import site -site.addsitedir(site_packages) -sys.real_prefix = sys.prefix -sys.prefix = base -# Move the added items to the front of the path: -new_sys_path = [] -for item in list(sys.path): - if item not in prev_sys_path: - new_sys_path.append(item) - sys.path.remove(item) -sys.path[:0] = new_sys_path diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/deactivate.bat b/vendor/virtualenv-1.8.4/virtualenv_embedded/deactivate.bat deleted file mode 100644 index 52aabe5..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/deactivate.bat +++ /dev/null @@ -1,18 +0,0 @@ -@echo off - -if defined _OLD_VIRTUAL_PROMPT ( - set "PROMPT=%_OLD_VIRTUAL_PROMPT%" - set _OLD_VIRTUAL_PROMPT= -) - -if defined _OLD_VIRTUAL_PYTHONHOME ( - set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" - set _OLD_VIRTUAL_PYTHONHOME= -) - -if defined _OLD_VIRTUAL_PATH ( - set "PATH=%_OLD_VIRTUAL_PATH%" - set _OLD_VIRTUAL_PATH= -) - -:END diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/distribute_from_egg.py b/vendor/virtualenv-1.8.4/virtualenv_embedded/distribute_from_egg.py deleted file mode 100644 index bbbb207..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/distribute_from_egg.py +++ /dev/null @@ -1,8 +0,0 @@ -# Called from virtualenv with parameters: -# [--always-unzip] [-v] egg_name -# So, the distribute egg is always the last argument. -import sys -eggname = sys.argv[-1] -sys.path.insert(0, eggname) -from setuptools.command.easy_install import main -main(sys.argv[1:]) diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/distutils-init.py b/vendor/virtualenv-1.8.4/virtualenv_embedded/distutils-init.py deleted file mode 100644 index 29fc1da..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/distutils-init.py +++ /dev/null @@ -1,101 +0,0 @@ -import os -import sys -import warnings -import imp -import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib - # Important! To work on pypy, this must be a module that resides in the - # lib-python/modified-x.y.z directory - -dirname = os.path.dirname - -distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils') -if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)): - warnings.warn( - "The virtualenv distutils package at %s appears to be in the same location as the system distutils?") -else: - __path__.insert(0, distutils_path) - real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY)) - # Copy the relevant attributes - try: - __revision__ = real_distutils.__revision__ - except AttributeError: - pass - __version__ = real_distutils.__version__ - -from distutils import dist, sysconfig - -try: - basestring -except NameError: - basestring = str - -## patch build_ext (distutils doesn't know how to get the libs directory -## path on windows - it hardcodes the paths around the patched sys.prefix) - -if sys.platform == 'win32': - from distutils.command.build_ext import build_ext as old_build_ext - class build_ext(old_build_ext): - def finalize_options (self): - if self.library_dirs is None: - self.library_dirs = [] - elif isinstance(self.library_dirs, basestring): - self.library_dirs = self.library_dirs.split(os.pathsep) - - self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs")) - old_build_ext.finalize_options(self) - - from distutils.command import build_ext as build_ext_module - build_ext_module.build_ext = build_ext - -## distutils.dist patches: - -old_find_config_files = dist.Distribution.find_config_files -def find_config_files(self): - found = old_find_config_files(self) - system_distutils = os.path.join(distutils_path, 'distutils.cfg') - #if os.path.exists(system_distutils): - # found.insert(0, system_distutils) - # What to call the per-user config file - if os.name == 'posix': - user_filename = ".pydistutils.cfg" - else: - user_filename = "pydistutils.cfg" - user_filename = os.path.join(sys.prefix, user_filename) - if os.path.isfile(user_filename): - for item in list(found): - if item.endswith('pydistutils.cfg'): - found.remove(item) - found.append(user_filename) - return found -dist.Distribution.find_config_files = find_config_files - -## distutils.sysconfig patches: - -old_get_python_inc = sysconfig.get_python_inc -def sysconfig_get_python_inc(plat_specific=0, prefix=None): - if prefix is None: - prefix = sys.real_prefix - return old_get_python_inc(plat_specific, prefix) -sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__ -sysconfig.get_python_inc = sysconfig_get_python_inc - -old_get_python_lib = sysconfig.get_python_lib -def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None): - if standard_lib and prefix is None: - prefix = sys.real_prefix - return old_get_python_lib(plat_specific, standard_lib, prefix) -sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__ -sysconfig.get_python_lib = sysconfig_get_python_lib - -old_get_config_vars = sysconfig.get_config_vars -def sysconfig_get_config_vars(*args): - real_vars = old_get_config_vars(*args) - if sys.platform == 'win32': - lib_dir = os.path.join(sys.real_prefix, "libs") - if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars: - real_vars['LIBDIR'] = lib_dir # asked for all - elif isinstance(real_vars, list) and 'LIBDIR' in args: - real_vars = real_vars + [lib_dir] # asked for list - return real_vars -sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__ -sysconfig.get_config_vars = sysconfig_get_config_vars diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/distutils.cfg b/vendor/virtualenv-1.8.4/virtualenv_embedded/distutils.cfg deleted file mode 100644 index 1af230e..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/distutils.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# This is a config file local to this virtualenv installation -# You may include options that will be used by all distutils commands, -# and by easy_install. For instance: -# -# [easy_install] -# find_links = http://mylocalsite diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/ez_setup.py b/vendor/virtualenv-1.8.4/virtualenv_embedded/ez_setup.py deleted file mode 100644 index b74adc0..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/ez_setup.py +++ /dev/null @@ -1,284 +0,0 @@ -#!python -"""Bootstrap setuptools 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 ez_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 sys -DEFAULT_VERSION = "0.6c11" -DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] - -md5_data = { - 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', - 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', - 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', - 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', - 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', - 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', - 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', - 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', - 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', - 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', - 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', - 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', - 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', - 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', - 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', - 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', - 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', - 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', - 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', - 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', - 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', - 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', - 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', - 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', - 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', - 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', - 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', - 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', - 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', - 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', - 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', - 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', - 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', - 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', - 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', - 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', - 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', - 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', - 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', - 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', - 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', - 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', -} - -import sys, os -try: from hashlib import md5 -except ImportError: from md5 import md5 - -def _validate_md5(egg_name, data): - if egg_name in md5_data: - digest = md5(data).hexdigest() - if digest != md5_data[egg_name]: - print >>sys.stderr, ( - "md5 validation of %s failed! (Possible download problem?)" - % egg_name - ) - sys.exit(2) - return data - -def use_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - download_delay=15 -): - """Automatically find/download setuptools and make it available on sys.path - - `version` should be a valid setuptools 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 setuptools will be downloaded, if - it is not already available. If `download_delay` is specified, it should - be the number of seconds that will be paused before initiating a download, - should one be required. If an older version of setuptools is installed, - this routine will print a message to ``sys.stderr`` and raise SystemExit in - an attempt to abort the calling script. - """ - was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules - def do_download(): - egg = download_setuptools(version, download_base, to_dir, download_delay) - sys.path.insert(0, egg) - import setuptools; setuptools.bootstrap_install_from = egg - try: - import pkg_resources - except ImportError: - return do_download() - try: - pkg_resources.require("setuptools>="+version); return - except pkg_resources.VersionConflict, e: - if was_imported: - print >>sys.stderr, ( - "The required version of setuptools (>=%s) is not available, and\n" - "can't be installed while this script is running. Please install\n" - " a more recent version first, using 'easy_install -U setuptools'." - "\n\n(Currently using %r)" - ) % (version, e.args[0]) - sys.exit(2) - except pkg_resources.DistributionNotFound: - pass - - del pkg_resources, sys.modules['pkg_resources'] # reload ok - return do_download() - -def download_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - delay = 15 -): - """Download setuptools from a specified location and return its filename - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end - 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. - """ - import urllib2, shutil - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) - url = download_base + egg_name - saveto = os.path.join(to_dir, egg_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - from distutils import log - if delay: - log.warn(""" ---------------------------------------------------------------------------- -This script requires setuptools version %s to run (even to display -help). I will attempt to download it for you (from -%s), but -you may need to enable firewall access for this script first. -I will start the download in %d seconds. - -(Note: if this machine does not have network access, please obtain the file - - %s - -and place it in this directory before rerunning this script.) ----------------------------------------------------------------------------""", - version, download_base, delay, url - ); from time import sleep; sleep(delay) - log.warn("Downloading %s", url) - src = urllib2.urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = _validate_md5(egg_name, src.read()) - dst = open(saveto,"wb"); dst.write(data) - finally: - if src: src.close() - if dst: dst.close() - return os.path.realpath(saveto) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(argv, version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - try: - import setuptools - except ImportError: - egg = None - try: - egg = download_setuptools(version, delay=0) - sys.path.insert(0,egg) - from setuptools.command.easy_install import main - return main(list(argv)+[egg]) # we're done here - finally: - if egg and os.path.exists(egg): - os.unlink(egg) - else: - if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( - "You have an obsolete version of setuptools installed. Please\n" - "remove it from your system entirely before rerunning this script." - ) - sys.exit(2) - - req = "setuptools>="+version - import pkg_resources - try: - pkg_resources.require(req) - except pkg_resources.VersionConflict: - try: - from setuptools.command.easy_install import main - except ImportError: - from easy_install import main - main(list(argv)+[download_setuptools(delay=0)]) - sys.exit(0) # try to force an exit - else: - if argv: - from setuptools.command.easy_install import main - main(argv) - else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' - -def update_md5(filenames): - """Update our built-in md5 registry""" - - import re - - for name in filenames: - base = os.path.basename(name) - f = open(name,'rb') - md5_data[base] = md5(f.read()).hexdigest() - f.close() - - data = [" %r: %r,\n" % it for it in md5_data.items()] - data.sort() - repl = "".join(data) - - import inspect - srcfile = inspect.getsourcefile(sys.modules[__name__]) - f = open(srcfile, 'rb'); src = f.read(); f.close() - - match = re.search("\nmd5_data = {\n([^}]+)}", src) - if not match: - print >>sys.stderr, "Internal error!" - sys.exit(2) - - src = src[:match.start(1)] + repl + src[match.end(1):] - f = open(srcfile,'w') - f.write(src) - f.close() - - -if __name__=='__main__': - if len(sys.argv)>2 and sys.argv[1]=='--md5update': - update_md5(sys.argv[2:]) - else: - main(sys.argv[1:]) - - - - - - diff --git a/vendor/virtualenv-1.8.4/virtualenv_embedded/site.py b/vendor/virtualenv-1.8.4/virtualenv_embedded/site.py deleted file mode 100644 index 4271f43..0000000 --- a/vendor/virtualenv-1.8.4/virtualenv_embedded/site.py +++ /dev/null @@ -1,743 +0,0 @@ -"""Append module search paths for third-party packages to sys.path. - -**************************************************************** -* This module is automatically imported during initialization. * -**************************************************************** - -In earlier versions of Python (up to 1.5a3), scripts or modules that -needed to use site-specific modules would place ``import site'' -somewhere near the top of their code. Because of the automatic -import, this is no longer necessary (but code that does it still -works). - -This will append site-specific paths to the module search path. On -Unix, it starts with sys.prefix and sys.exec_prefix (if different) and -appends lib/python/site-packages as well as lib/site-python. -It also supports the Debian convention of -lib/python/dist-packages. On other platforms (mainly Mac and -Windows), it uses just sys.prefix (and sys.exec_prefix, if different, -but this is unlikely). The resulting directories, if they exist, are -appended to sys.path, and also inspected for path configuration files. - -FOR DEBIAN, this sys.path is augmented with directories in /usr/local. -Local addons go into /usr/local/lib/python/site-packages -(resp. /usr/local/lib/site-python), Debian addons install into -/usr/{lib,share}/python/dist-packages. - -A path configuration file is a file whose name has the form -.pth; its contents are additional directories (one per line) -to be added to sys.path. Non-existing directories (or -non-directories) are never added to sys.path; no directory is added to -sys.path more than once. Blank lines and lines beginning with -'#' are skipped. Lines starting with 'import' are executed. - -For example, suppose sys.prefix and sys.exec_prefix are set to -/usr/local and there is a directory /usr/local/lib/python2.X/site-packages -with three subdirectories, foo, bar and spam, and two path -configuration files, foo.pth and bar.pth. Assume foo.pth contains the -following: - - # foo package configuration - foo - bar - bletch - -and bar.pth contains: - - # bar package configuration - bar - -Then the following directories are added to sys.path, in this order: - - /usr/local/lib/python2.X/site-packages/bar - /usr/local/lib/python2.X/site-packages/foo - -Note that bletch is omitted because it doesn't exist; bar precedes foo -because bar.pth comes alphabetically before foo.pth; and spam is -omitted because it is not mentioned in either path configuration file. - -After these path manipulations, an attempt is made to import a module -named sitecustomize, which can perform arbitrary additional -site-specific customizations. If this import fails with an -ImportError exception, it is silently ignored. - -""" - -import sys -import os -try: - import __builtin__ as builtins -except ImportError: - import builtins -try: - set -except NameError: - from sets import Set as set - -# Prefixes for site-packages; add additional prefixes like /usr/local here -PREFIXES = [sys.prefix, sys.exec_prefix] -# Enable per user site-packages directory -# set it to False to disable the feature or True to force the feature -ENABLE_USER_SITE = None -# for distutils.commands.install -USER_SITE = None -USER_BASE = None - -_is_pypy = hasattr(sys, 'pypy_version_info') -_is_jython = sys.platform[:4] == 'java' -if _is_jython: - ModuleType = type(os) - -def makepath(*paths): - dir = os.path.join(*paths) - if _is_jython and (dir == '__classpath__' or - dir.startswith('__pyclasspath__')): - return dir, dir - dir = os.path.abspath(dir) - return dir, os.path.normcase(dir) - -def abs__file__(): - """Set all module' __file__ attribute to an absolute path""" - for m in sys.modules.values(): - if ((_is_jython and not isinstance(m, ModuleType)) or - hasattr(m, '__loader__')): - # only modules need the abspath in Jython. and don't mess - # with a PEP 302-supplied __file__ - continue - f = getattr(m, '__file__', None) - if f is None: - continue - m.__file__ = os.path.abspath(f) - -def removeduppaths(): - """ Remove duplicate entries from sys.path along with making them - absolute""" - # This ensures that the initial path provided by the interpreter contains - # only absolute pathnames, even if we're running from the build directory. - L = [] - known_paths = set() - for dir in sys.path: - # Filter out duplicate paths (on case-insensitive file systems also - # if they only differ in case); turn relative paths into absolute - # paths. - dir, dircase = makepath(dir) - if not dircase in known_paths: - L.append(dir) - known_paths.add(dircase) - sys.path[:] = L - return known_paths - -# XXX This should not be part of site.py, since it is needed even when -# using the -S option for Python. See http://www.python.org/sf/586680 -def addbuilddir(): - """Append ./build/lib. in case we're running in the build dir - (especially for Guido :-)""" - from distutils.util import get_platform - s = "build/lib.%s-%.3s" % (get_platform(), sys.version) - if hasattr(sys, 'gettotalrefcount'): - s += '-pydebug' - s = os.path.join(os.path.dirname(sys.path[-1]), s) - sys.path.append(s) - -def _init_pathinfo(): - """Return a set containing all existing directory entries from sys.path""" - d = set() - for dir in sys.path: - try: - if os.path.isdir(dir): - dir, dircase = makepath(dir) - d.add(dircase) - except TypeError: - continue - return d - -def addpackage(sitedir, name, known_paths): - """Add a new path to known_paths by combining sitedir and 'name' or execute - sitedir if it starts with 'import'""" - if known_paths is None: - _init_pathinfo() - reset = 1 - else: - reset = 0 - fullname = os.path.join(sitedir, name) - try: - f = open(fullname, "rU") - except IOError: - return - try: - for line in f: - if line.startswith("#"): - continue - if line.startswith("import"): - exec(line) - continue - line = line.rstrip() - dir, dircase = makepath(sitedir, line) - if not dircase in known_paths and os.path.exists(dir): - sys.path.append(dir) - known_paths.add(dircase) - finally: - f.close() - if reset: - known_paths = None - return known_paths - -def addsitedir(sitedir, known_paths=None): - """Add 'sitedir' argument to sys.path if missing and handle .pth files in - 'sitedir'""" - if known_paths is None: - known_paths = _init_pathinfo() - reset = 1 - else: - reset = 0 - sitedir, sitedircase = makepath(sitedir) - if not sitedircase in known_paths: - sys.path.append(sitedir) # Add path component - try: - names = os.listdir(sitedir) - except os.error: - return - names.sort() - for name in names: - if name.endswith(os.extsep + "pth"): - addpackage(sitedir, name, known_paths) - if reset: - known_paths = None - return known_paths - -def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_prefix): - """Add site-packages (and possibly site-python) to sys.path""" - prefixes = [os.path.join(sys_prefix, "local"), sys_prefix] - if exec_prefix != sys_prefix: - prefixes.append(os.path.join(exec_prefix, "local")) - - for prefix in prefixes: - if prefix: - if sys.platform in ('os2emx', 'riscos') or _is_jython: - sitedirs = [os.path.join(prefix, "Lib", "site-packages")] - elif _is_pypy: - sitedirs = [os.path.join(prefix, 'site-packages')] - elif sys.platform == 'darwin' and prefix == sys_prefix: - - if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python - - sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"), - os.path.join(prefix, "Extras", "lib", "python")] - - else: # any other Python distros on OSX work this way - sitedirs = [os.path.join(prefix, "lib", - "python" + sys.version[:3], "site-packages")] - - elif os.sep == '/': - sitedirs = [os.path.join(prefix, - "lib", - "python" + sys.version[:3], - "site-packages"), - os.path.join(prefix, "lib", "site-python"), - os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")] - lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages") - if (os.path.exists(lib64_dir) and - os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]): - if sys.maxsize > 2**32: - sitedirs.insert(0, lib64_dir) - else: - sitedirs.append(lib64_dir) - try: - # sys.getobjects only available in --with-pydebug build - sys.getobjects - sitedirs.insert(0, os.path.join(sitedirs[0], 'debug')) - except AttributeError: - pass - # Debian-specific dist-packages directories: - if sys.version[0] == '2': - sitedirs.append(os.path.join(prefix, "lib", - "python" + sys.version[:3], - "dist-packages")) - else: - sitedirs.append(os.path.join(prefix, "lib", - "python" + sys.version[0], - "dist-packages")) - sitedirs.append(os.path.join(prefix, "local/lib", - "python" + sys.version[:3], - "dist-packages")) - sitedirs.append(os.path.join(prefix, "lib", "dist-python")) - else: - sitedirs = [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 sitedir in sitedirs: - if os.path.isdir(sitedir): - addsitedir(sitedir, known_paths) - return None - -def check_enableusersite(): - """Check if user site directory is safe for inclusion - - The function tests for the command line flag (including environment var), - process uid/gid equal to effective uid/gid. - - None: Disabled for security reasons - False: Disabled by user (command line option) - True: Safe and enabled - """ - if hasattr(sys, 'flags') and getattr(sys.flags, 'no_user_site', False): - return False - - if hasattr(os, "getuid") and hasattr(os, "geteuid"): - # check process uid == effective uid - if os.geteuid() != os.getuid(): - return None - if hasattr(os, "getgid") and hasattr(os, "getegid"): - # check process gid == effective gid - if os.getegid() != os.getgid(): - return None - - return True - -def addusersitepackages(known_paths): - """Add a per user site-package to sys.path - - Each user has its own python directory with site-packages in the - home directory. - - USER_BASE is the root directory for all Python versions - - USER_SITE is the user specific site-packages directory - - USER_SITE/.. can be used for data. - """ - global USER_BASE, USER_SITE, ENABLE_USER_SITE - env_base = os.environ.get("PYTHONUSERBASE", None) - - def joinuser(*args): - return os.path.expanduser(os.path.join(*args)) - - #if sys.platform in ('os2emx', 'riscos'): - # # Don't know what to put here - # USER_BASE = '' - # USER_SITE = '' - if os.name == "nt": - base = os.environ.get("APPDATA") or "~" - if env_base: - USER_BASE = env_base - else: - USER_BASE = joinuser(base, "Python") - USER_SITE = os.path.join(USER_BASE, - "Python" + sys.version[0] + sys.version[2], - "site-packages") - else: - if env_base: - USER_BASE = env_base - else: - USER_BASE = joinuser("~", ".local") - USER_SITE = os.path.join(USER_BASE, "lib", - "python" + sys.version[:3], - "site-packages") - - if ENABLE_USER_SITE and os.path.isdir(USER_SITE): - addsitedir(USER_SITE, known_paths) - if ENABLE_USER_SITE: - for dist_libdir in ("lib", "local/lib"): - user_site = os.path.join(USER_BASE, dist_libdir, - "python" + sys.version[:3], - "dist-packages") - if os.path.isdir(user_site): - addsitedir(user_site, known_paths) - return known_paths - - - -def setBEGINLIBPATH(): - """The OS/2 EMX port has optional extension modules that do double duty - as DLLs (and must use the .DLL file extension) for other extensions. - The library search path needs to be amended so these will be found - during module import. Use BEGINLIBPATH so that these are at the start - of the library search path. - - """ - dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload") - libpath = os.environ['BEGINLIBPATH'].split(';') - if libpath[-1]: - libpath.append(dllpath) - else: - libpath[-1] = dllpath - os.environ['BEGINLIBPATH'] = ';'.join(libpath) - - -def setquit(): - """Define new built-ins 'quit' and 'exit'. - These are simply strings that display a hint on how to exit. - - """ - if os.sep == ':': - eof = 'Cmd-Q' - elif os.sep == '\\': - eof = 'Ctrl-Z plus Return' - else: - eof = 'Ctrl-D (i.e. EOF)' - - class Quitter(object): - def __init__(self, name): - self.name = name - def __repr__(self): - return 'Use %s() or %s to exit' % (self.name, eof) - def __call__(self, code=None): - # Shells like IDLE catch the SystemExit, but listen when their - # stdin wrapper is closed. - try: - sys.stdin.close() - except: - pass - raise SystemExit(code) - builtins.quit = Quitter('quit') - builtins.exit = Quitter('exit') - - -class _Printer(object): - """interactive prompt objects for printing the license text, a list of - contributors and the copyright notice.""" - - MAXLINES = 23 - - def __init__(self, name, data, files=(), dirs=()): - self.__name = name - self.__data = data - self.__files = files - self.__dirs = dirs - self.__lines = None - - def __setup(self): - if self.__lines: - return - data = None - for dir in self.__dirs: - for filename in self.__files: - filename = os.path.join(dir, filename) - try: - fp = open(filename, "rU") - data = fp.read() - fp.close() - break - except IOError: - pass - if data: - break - if not data: - data = self.__data - self.__lines = data.split('\n') - self.__linecnt = len(self.__lines) - - def __repr__(self): - self.__setup() - if len(self.__lines) <= self.MAXLINES: - return "\n".join(self.__lines) - else: - return "Type %s() to see the full %s text" % ((self.__name,)*2) - - def __call__(self): - self.__setup() - prompt = 'Hit Return for more, or q (and Return) to quit: ' - lineno = 0 - while 1: - try: - for i in range(lineno, lineno + self.MAXLINES): - print(self.__lines[i]) - except IndexError: - break - else: - lineno += self.MAXLINES - key = None - while key is None: - try: - key = raw_input(prompt) - except NameError: - key = input(prompt) - if key not in ('', 'q'): - key = None - if key == 'q': - break - -def setcopyright(): - """Set 'copyright' and 'credits' in __builtin__""" - builtins.copyright = _Printer("copyright", sys.copyright) - if _is_jython: - builtins.credits = _Printer( - "credits", - "Jython is maintained by the Jython developers (www.jython.org).") - elif _is_pypy: - builtins.credits = _Printer( - "credits", - "PyPy is maintained by the PyPy developers: http://codespeak.net/pypy") - else: - builtins.credits = _Printer("credits", """\ - Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands - for supporting Python development. See www.python.org for more information.""") - here = os.path.dirname(os.__file__) - builtins.license = _Printer( - "license", "See http://www.python.org/%.3s/license.html" % sys.version, - ["LICENSE.txt", "LICENSE"], - [os.path.join(here, os.pardir), here, os.curdir]) - - -class _Helper(object): - """Define the built-in 'help'. - This is a wrapper around pydoc.help (with a twist). - - """ - - def __repr__(self): - return "Type help() for interactive help, " \ - "or help(object) for help about object." - def __call__(self, *args, **kwds): - import pydoc - return pydoc.help(*args, **kwds) - -def sethelper(): - builtins.help = _Helper() - -def aliasmbcs(): - """On Windows, some default encodings are not provided by Python, - while they are always available as "mbcs" in each locale. Make - them usable by aliasing to "mbcs" in such a case.""" - if sys.platform == 'win32': - import locale, codecs - enc = locale.getdefaultlocale()[1] - if enc.startswith('cp'): # "cp***" ? - try: - codecs.lookup(enc) - except LookupError: - import encodings - encodings._cache[enc] = encodings._unknown - encodings.aliases.aliases[enc] = 'mbcs' - -def setencoding(): - """Set the string encoding used by the Unicode implementation. The - default is 'ascii', but if you're willing to experiment, you can - change this.""" - encoding = "ascii" # Default value set by _PyUnicode_Init() - if 0: - # Enable to support locale aware default string encodings. - import locale - loc = locale.getdefaultlocale() - if loc[1]: - encoding = loc[1] - if 0: - # Enable to switch off string to Unicode coercion and implicit - # Unicode to string conversion. - encoding = "undefined" - if encoding != "ascii": - # On Non-Unicode builds this will raise an AttributeError... - sys.setdefaultencoding(encoding) # Needs Python Unicode build ! - - -def execsitecustomize(): - """Run custom site specific code, if available.""" - try: - import sitecustomize - except ImportError: - pass - -def virtual_install_main_packages(): - f = open(os.path.join(os.path.dirname(__file__), 'orig-prefix.txt')) - sys.real_prefix = f.read().strip() - f.close() - pos = 2 - hardcoded_relative_dirs = [] - if sys.path[0] == '': - pos += 1 - if _is_jython: - paths = [os.path.join(sys.real_prefix, 'Lib')] - elif _is_pypy: - if sys.pypy_version_info >= (1, 5): - cpyver = '%d.%d' % sys.version_info[:2] - else: - cpyver = '%d.%d.%d' % sys.version_info[:3] - paths = [os.path.join(sys.real_prefix, 'lib_pypy'), - os.path.join(sys.real_prefix, 'lib-python', 'modified-%s' % cpyver), - os.path.join(sys.real_prefix, 'lib-python', cpyver)] - hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below - # - # This is hardcoded in the Python executable, but relative to sys.prefix: - for path in paths[:]: - plat_path = os.path.join(path, 'plat-%s' % sys.platform) - if os.path.exists(plat_path): - paths.append(plat_path) - elif sys.platform == 'win32': - paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')] - else: - paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])] - hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below - lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3]) - if os.path.exists(lib64_path): - if sys.maxsize > 2**32: - paths.insert(0, lib64_path) - else: - paths.append(lib64_path) - # This is hardcoded in the Python executable, but relative to sys.prefix: - plat_path = os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3], - 'plat-%s' % sys.platform) - if os.path.exists(plat_path): - paths.append(plat_path) - # This is hardcoded in the Python executable, but - # relative to sys.prefix, so we have to fix up: - for path in list(paths): - tk_dir = os.path.join(path, 'lib-tk') - if os.path.exists(tk_dir): - paths.append(tk_dir) - - # These are hardcoded in the Apple's Python executable, - # but relative to sys.prefix, so we have to fix them up: - if sys.platform == 'darwin': - hardcoded_paths = [os.path.join(relative_dir, module) - for relative_dir in hardcoded_relative_dirs - for module in ('plat-darwin', 'plat-mac', 'plat-mac/lib-scriptpackages')] - - for path in hardcoded_paths: - if os.path.exists(path): - paths.append(path) - - sys.path.extend(paths) - -def force_global_eggs_after_local_site_packages(): - """ - Force easy_installed eggs in the global environment to get placed - in sys.path after all packages inside the virtualenv. This - maintains the "least surprise" result that packages in the - virtualenv always mask global packages, never the other way - around. - - """ - egginsert = getattr(sys, '__egginsert', 0) - for i, path in enumerate(sys.path): - if i > egginsert and path.startswith(sys.prefix): - egginsert = i - sys.__egginsert = egginsert + 1 - -def virtual_addsitepackages(known_paths): - force_global_eggs_after_local_site_packages() - return addsitepackages(known_paths, sys_prefix=sys.real_prefix) - -def fixclasspath(): - """Adjust the special classpath sys.path entries for Jython. These - entries should follow the base virtualenv lib directories. - """ - paths = [] - classpaths = [] - for path in sys.path: - if path == '__classpath__' or path.startswith('__pyclasspath__'): - classpaths.append(path) - else: - paths.append(path) - sys.path = paths - sys.path.extend(classpaths) - -def execusercustomize(): - """Run custom user specific code, if available.""" - try: - import usercustomize - except ImportError: - pass - - -def main(): - global ENABLE_USER_SITE - virtual_install_main_packages() - abs__file__() - paths_in_sys = removeduppaths() - if (os.name == "posix" and sys.path and - os.path.basename(sys.path[-1]) == "Modules"): - addbuilddir() - if _is_jython: - fixclasspath() - GLOBAL_SITE_PACKAGES = not os.path.exists(os.path.join(os.path.dirname(__file__), 'no-global-site-packages.txt')) - if not GLOBAL_SITE_PACKAGES: - ENABLE_USER_SITE = False - if ENABLE_USER_SITE is None: - ENABLE_USER_SITE = check_enableusersite() - paths_in_sys = addsitepackages(paths_in_sys) - paths_in_sys = addusersitepackages(paths_in_sys) - if GLOBAL_SITE_PACKAGES: - paths_in_sys = virtual_addsitepackages(paths_in_sys) - if sys.platform == 'os2emx': - setBEGINLIBPATH() - setquit() - setcopyright() - sethelper() - aliasmbcs() - setencoding() - execsitecustomize() - if ENABLE_USER_SITE: - execusercustomize() - # Remove sys.setdefaultencoding() so that users cannot change the - # encoding after initialization. The test for presence is needed when - # this module is run as a script, because this code is executed twice. - if hasattr(sys, "setdefaultencoding"): - del sys.setdefaultencoding - -main() - -def _script(): - help = """\ - %s [--user-base] [--user-site] - - Without arguments print some useful information - With arguments print the value of USER_BASE and/or USER_SITE separated - by '%s'. - - Exit codes with --user-base or --user-site: - 0 - user site directory is enabled - 1 - user site directory is disabled by user - 2 - uses site directory is disabled by super user - or for security reasons - >2 - unknown error - """ - args = sys.argv[1:] - if not args: - print("sys.path = [") - for dir in sys.path: - print(" %r," % (dir,)) - print("]") - def exists(path): - if os.path.isdir(path): - return "exists" - else: - return "doesn't exist" - print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE))) - print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE))) - print("ENABLE_USER_SITE: %r" % ENABLE_USER_SITE) - sys.exit(0) - - buffer = [] - if '--user-base' in args: - buffer.append(USER_BASE) - if '--user-site' in args: - buffer.append(USER_SITE) - - if buffer: - print(os.pathsep.join(buffer)) - if ENABLE_USER_SITE: - sys.exit(0) - elif ENABLE_USER_SITE is False: - sys.exit(1) - elif ENABLE_USER_SITE is None: - sys.exit(2) - else: - sys.exit(3) - else: - import textwrap - print(textwrap.dedent(help % (sys.argv[0], os.pathsep))) - sys.exit(10) - -if __name__ == '__main__': - _script() diff --git a/vendor/virtualenv-1.8.4/virtualenv_support/distribute-0.6.31.tar.gz b/vendor/virtualenv-1.8.4/virtualenv_support/distribute-0.6.31.tar.gz deleted file mode 100644 index a8257463d46ebb665c08a61535c5397e3814a6c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 643910 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

    iqtPq6hU%Dg2uZ%B$ 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

      ~oE)OTojH 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%0DbLeEOeJ`1-8N+= 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

      c4D(B>*t~E3_pqtvx}0aZIoJ>$ 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