diff options
author | Philip Thiem <ptthiem@gmail.com> | 2013-09-28 12:33:19 -0500 |
---|---|---|
committer | Philip Thiem <ptthiem@gmail.com> | 2013-09-28 12:33:19 -0500 |
commit | 78f01306a08285e9f2abe6ad749f6ce884e12555 (patch) | |
tree | c4769869539d5ae9101a7e8e76a46e9e292b9b97 | |
parent | 30bb58f069cf1624f35cfbdb725e8e443ff64330 (diff) | |
parent | 49ce80613b7fcffd1882f7fb082e5bcc30e976f0 (diff) | |
download | external_python_setuptools-78f01306a08285e9f2abe6ad749f6ce884e12555.tar.gz external_python_setuptools-78f01306a08285e9f2abe6ad749f6ce884e12555.tar.bz2 external_python_setuptools-78f01306a08285e9f2abe6ad749f6ce884e12555.zip |
Merge with default
--HG--
extra : rebase_source : d9c70d5bebd4290f568c828c5bc3a9b93a817ff2
38 files changed, 1723 insertions, 1747 deletions
@@ -87,3 +87,16 @@ e3d70539e79f39a97f69674ab038661961a1eb43 0.8 1aef141fc968113e4c521d1edf6ea863c4ff7e00 0.9.4 88e3d6788facbb2dd6467a23c4f35529a5ce20a1 0.9.5 acc6c5d61d0f82040c237ac7ea010c0fc9e67d66 0.9.6 +19965a03c1d5231c894e0fabfaf45af1fd99f484 0.9.7 +e0a6e225ad6b28471cd42cfede6e8a334bb548fb 0.9.8 +7b91ff93a30ef78634b7bb34f4a6229a5de281ee 1.0b1 +aba16323ec9382da7bc77c633990ccb3bd58d050 1.0b2 +8a98492f0d852402c93ddbbf3f07081909a9105f 1.0b3 +c385fdf1f976fb1d2a6accc9292d8eca419180fa 1.0 +d943b67fe80dbd61326014e4acedfc488adfa1c9 1.1 +2e42e86546100c9f6845b04eb31b75c5add05f78 1.1.1 +462fe5ccd8befeb2a235e8295d6d73eb3a49cc78 1.1.2 +ddf3561d6a54087745f4bf6ea2048b86195d6fe2 1.1.3 +f94c7e4fa03077e069c1c3cef93ead735559e706 1.1.4 +d9bb58331007ee3f69d31983a180f56b15c731c3 1.1.5 +5e426bdeb46b87e299422adc419f4163b6c78d13 1.1.6 diff --git a/.travis.yml b/.travis.yml index 83efa5a4..b684935f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,6 @@ python: - 2.7 - 3.2 - 3.3 + - pypy # command to run tests script: python setup.py test diff --git a/CHANGES.txt b/CHANGES.txt index 6e993ada..f97dca3c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,6 +3,116 @@ CHANGES ======= ----- +1.1.7 +----- + +* Fixed behavior of NameError handling in 'script template (dev).py' (script + launcher for 'develop' installs). +* ``ez_setup.py`` now ensures partial downloads are cleaned up following + a failed download. + +----- +1.1.6 +----- + +* Distribute #349: ``sandbox.execfile`` now opens the target file in binary + mode, thus honoring a BOM in the file when compiled. + +----- +1.1.5 +----- + +* Issue #69: Second attempt at fix (logic was reversed). + +----- +1.1.4 +----- + +* Issue #77: Fix error in upload command (Python 2.4). + +----- +1.1.3 +----- + +* Fix NameError in previous patch. + +----- +1.1.2 +----- + +* Issue #69: Correct issue where 404 errors are returned for URLs with + fragments in them (such as #egg=). + +----- +1.1.1 +----- + +* Issue #75: Add ``--insecure`` option to ez_setup.py to accommodate + environments where a trusted SSL connection cannot be validated. +* Issue #76: Fix AttributeError in upload command with Python 2.4. + +--- +1.1 +--- + +* Issue #71 (Distribute #333): EasyInstall now puts less emphasis on the + condition when a host is blocked via ``--allow-hosts``. +* Issue #72: Restored Python 2.4 compatibility in ``ez_setup.py``. + +--- +1.0 +--- + +* Issue #60: On Windows, Setuptools supports deferring to another launcher, + such as Vinay Sajip's `pylauncher <https://bitbucket.org/pypa/pylauncher>`_ + (included with Python 3.3) to launch console and GUI scripts and not install + its own launcher executables. This experimental functionality is currently + only enabled if the ``SETUPTOOLS_LAUNCHER`` environment variable is set to + "natural". In the future, this behavior may become default, but only after + it has matured and seen substantial adoption. The ``SETUPTOOLS_LAUNCHER`` + also accepts "executable" to force the default behavior of creating launcher + executables. +* Issue #63: Bootstrap script (ez_setup.py) now prefers Powershell, curl, or + wget for retrieving the Setuptools tarball for improved security of the + install. The script will still fall back to a simple ``urlopen`` on + platforms that do not have these tools. +* Issue #65: Deprecated the ``Features`` functionality. +* Issue #52: In ``VerifyingHTTPSConn``, handle a tunnelled (proxied) + connection. + +Backward-Incompatible Changes +============================= + +This release includes a couple of backward-incompatible changes, but most if +not all users will find 1.0 a drop-in replacement for 0.9. + +* Issue #50: Normalized API of environment marker support. Specifically, + removed line number and filename from SyntaxErrors when returned from + `pkg_resources.invalid_marker`. Any clients depending on the specific + string representation of exceptions returned by that function may need to + be updated to account for this change. +* Issue #50: SyntaxErrors generated by `pkg_resources.invalid_marker` are + normalized for cross-implementation consistency. +* Removed ``--ignore-conflicts-at-my-risk`` and ``--delete-conflicting`` + options to easy_install. These options have been deprecated since 0.6a11. + +----- +0.9.8 +----- + +* Issue #53: Fix NameErrors in `_vcs_split_rev_from_url`. + +----- +0.9.7 +----- + +* Issue #49: Correct AttributeError on PyPy where a hashlib.HASH object does + not have a `.name` attribute. +* Issue #34: Documentation now refers to bootstrap script in code repository + referenced by bookmark. +* Add underscore-separated keys to environment markers (markerlib). + +----- 0.9.6 ----- @@ -739,3 +849,588 @@ easy_install * Immediately close all file handles. This closes Distribute #3. +----- +0.6c9 +----- + + * Fixed a missing files problem when using Windows source distributions on + non-Windows platforms, due to distutils not handling manifest file line + endings correctly. + + * Updated Pyrex support to work with Pyrex 0.9.6 and higher. + + * Minor changes for Jython compatibility, including skipping tests that can't + work on Jython. + + * Fixed not installing eggs in ``install_requires`` if they were also used for + ``setup_requires`` or ``tests_require``. + + * Fixed not fetching eggs in ``install_requires`` when running tests. + + * Allow ``ez_setup.use_setuptools()`` to upgrade existing setuptools + installations when called from a standalone ``setup.py``. + + * Added a warning if a namespace package is declared, but its parent package + is not also declared as a namespace. + + * Support Subversion 1.5 + + * Removed use of deprecated ``md5`` module if ``hashlib`` is available + + * Fixed ``bdist_wininst upload`` trying to upload the ``.exe`` twice + + * Fixed ``bdist_egg`` putting a ``native_libs.txt`` in the source package's + ``.egg-info``, when it should only be in the built egg's ``EGG-INFO``. + + * Ensure that _full_name is set on all shared libs before extensions are + checked for shared lib usage. (Fixes a bug in the experimental shared + library build support.) + + * Fix to allow unpacked eggs containing native libraries to fail more + gracefully under Google App Engine (with an ``ImportError`` loading the + C-based module, instead of getting a ``NameError``). + +----- +0.6c7 +----- + + * Fixed ``distutils.filelist.findall()`` crashing on broken symlinks, and + ``egg_info`` command failing on new, uncommitted SVN directories. + + * Fix import problems with nested namespace packages installed via + ``--root`` or ``--single-version-externally-managed``, due to the + parent package not having the child package as an attribute. + +----- +0.6c6 +----- + + * Added ``--egg-path`` option to ``develop`` command, allowing you to force + ``.egg-link`` files to use relative paths (allowing them to be shared across + platforms on a networked drive). + + * Fix not building binary RPMs correctly. + + * Fix "eggsecutables" (such as setuptools' own egg) only being runnable with + bash-compatible shells. + + * Fix ``#!`` parsing problems in Windows ``.exe`` script wrappers, when there + was whitespace inside a quoted argument or at the end of the ``#!`` line + (a regression introduced in 0.6c4). + + * Fix ``test`` command possibly failing if an older version of the project + being tested was installed on ``sys.path`` ahead of the test source + directory. + + * Fix ``find_packages()`` treating ``ez_setup`` and directories with ``.`` in + their names as packages. + +----- +0.6c5 +----- + + * Fix uploaded ``bdist_rpm`` packages being described as ``bdist_egg`` + packages under Python versions less than 2.5. + + * Fix uploaded ``bdist_wininst`` packages being described as suitable for + "any" version by Python 2.5, even if a ``--target-version`` was specified. + +----- +0.6c4 +----- + + * Overhauled Windows script wrapping to support ``bdist_wininst`` better. + Scripts installed with ``bdist_wininst`` will always use ``#!python.exe`` or + ``#!pythonw.exe`` as the executable name (even when built on non-Windows + platforms!), and the wrappers will look for the executable in the script's + parent directory (which should find the right version of Python). + + * Fix ``upload`` command not uploading files built by ``bdist_rpm`` or + ``bdist_wininst`` under Python 2.3 and 2.4. + + * Add support for "eggsecutable" headers: a ``#!/bin/sh`` script that is + prepended to an ``.egg`` file to allow it to be run as a script on Unix-ish + platforms. (This is mainly so that setuptools itself can have a single-file + installer on Unix, without doing multiple downloads, dealing with firewalls, + etc.) + + * Fix problem with empty revision numbers in Subversion 1.4 ``entries`` files + + * Use cross-platform relative paths in ``easy-install.pth`` when doing + ``develop`` and the source directory is a subdirectory of the installation + target directory. + + * Fix a problem installing eggs with a system packaging tool if the project + contained an implicit namespace package; for example if the ``setup()`` + listed a namespace package ``foo.bar`` without explicitly listing ``foo`` + as a namespace package. + +----- +0.6c3 +----- + + * Fixed breakages caused by Subversion 1.4's new "working copy" format + +----- +0.6c2 +----- + + * The ``ez_setup`` module displays the conflicting version of setuptools (and + its installation location) when a script requests a version that's not + available. + + * Running ``setup.py develop`` on a setuptools-using project will now install + setuptools if needed, instead of only downloading the egg. + +----- +0.6c1 +----- + + * Fixed ``AttributeError`` when trying to download a ``setup_requires`` + dependency when a distribution lacks a ``dependency_links`` setting. + + * Made ``zip-safe`` and ``not-zip-safe`` flag files contain a single byte, so + as to play better with packaging tools that complain about zero-length + files. + + * Made ``setup.py develop`` respect the ``--no-deps`` option, which it + previously was ignoring. + + * Support ``extra_path`` option to ``setup()`` when ``install`` is run in + backward-compatibility mode. + + * Source distributions now always include a ``setup.cfg`` file that explicitly + sets ``egg_info`` options such that they produce an identical version number + to the source distribution's version number. (Previously, the default + version number could be different due to the use of ``--tag-date``, or if + the version was overridden on the command line that built the source + distribution.) + +----- +0.6b4 +----- + + * Fix ``register`` not obeying name/version set by ``egg_info`` command, if + ``egg_info`` wasn't explicitly run first on the same command line. + + * Added ``--no-date`` and ``--no-svn-revision`` options to ``egg_info`` + command, to allow suppressing tags configured in ``setup.cfg``. + + * Fixed redundant warnings about missing ``README`` file(s); it should now + appear only if you are actually a source distribution. + +----- +0.6b3 +----- + + * Fix ``bdist_egg`` not including files in subdirectories of ``.egg-info``. + + * Allow ``.py`` files found by the ``include_package_data`` option to be + automatically included. Remove duplicate data file matches if both + ``include_package_data`` and ``package_data`` are used to refer to the same + files. + +----- +0.6b1 +----- + + * Strip ``module`` from the end of compiled extension modules when computing + the name of a ``.py`` loader/wrapper. (Python's import machinery ignores + this suffix when searching for an extension module.) + +------ +0.6a11 +------ + + * Added ``test_loader`` keyword to support custom test loaders + + * Added ``setuptools.file_finders`` entry point group to allow implementing + revision control plugins. + + * Added ``--identity`` option to ``upload`` command. + + * Added ``dependency_links`` to allow specifying URLs for ``--find-links``. + + * Enhanced test loader to scan packages as well as modules, and call + ``additional_tests()`` if present to get non-unittest tests. + + * Support namespace packages in conjunction with system packagers, by omitting + the installation of any ``__init__.py`` files for namespace packages, and + adding a special ``.pth`` file to create a working package in + ``sys.modules``. + + * Made ``--single-version-externally-managed`` automatic when ``--root`` is + used, so that most system packagers won't require special support for + setuptools. + + * Fixed ``setup_requires``, ``tests_require``, etc. not using ``setup.cfg`` or + other configuration files for their option defaults when installing, and + also made the install use ``--multi-version`` mode so that the project + directory doesn't need to support .pth files. + + * ``MANIFEST.in`` is now forcibly closed when any errors occur while reading + it. Previously, the file could be left open and the actual error would be + masked by problems trying to remove the open file on Windows systems. + +------ +0.6a10 +------ + + * Fixed the ``develop`` command ignoring ``--find-links``. + +----- +0.6a9 +----- + + * The ``sdist`` command no longer uses the traditional ``MANIFEST`` file to + create source distributions. ``MANIFEST.in`` is still read and processed, + as are the standard defaults and pruning. But the manifest is built inside + the project's ``.egg-info`` directory as ``SOURCES.txt``, and it is rebuilt + every time the ``egg_info`` command is run. + + * Added the ``include_package_data`` keyword to ``setup()``, allowing you to + automatically include any package data listed in revision control or + ``MANIFEST.in`` + + * Added the ``exclude_package_data`` keyword to ``setup()``, allowing you to + trim back files included via the ``package_data`` and + ``include_package_data`` options. + + * Fixed ``--tag-svn-revision`` not working when run from a source + distribution. + + * Added warning for namespace packages with missing ``declare_namespace()`` + + * Added ``tests_require`` keyword to ``setup()``, so that e.g. packages + requiring ``nose`` to run unit tests can make this dependency optional + unless the ``test`` command is run. + + * Made all commands that use ``easy_install`` respect its configuration + options, as this was causing some problems with ``setup.py install``. + + * Added an ``unpack_directory()`` driver to ``setuptools.archive_util``, so + that you can process a directory tree through a processing filter as if it + were a zipfile or tarfile. + + * Added an internal ``install_egg_info`` command to use as part of old-style + ``install`` operations, that installs an ``.egg-info`` directory with the + package. + + * Added a ``--single-version-externally-managed`` option to the ``install`` + command so that you can more easily wrap a "flat" egg in a system package. + + * Enhanced ``bdist_rpm`` so that it installs single-version eggs that + don't rely on a ``.pth`` file. The ``--no-egg`` option has been removed, + since all RPMs are now built in a more backwards-compatible format. + + * Support full roundtrip translation of eggs to and from ``bdist_wininst`` + format. Running ``bdist_wininst`` on a setuptools-based package wraps the + egg in an .exe that will safely install it as an egg (i.e., with metadata + and entry-point wrapper scripts), and ``easy_install`` can turn the .exe + back into an ``.egg`` file or directory and install it as such. + + +----- +0.6a8 +----- + + * Fixed some problems building extensions when Pyrex was installed, especially + with Python 2.4 and/or packages using SWIG. + + * Made ``develop`` command accept all the same options as ``easy_install``, + and use the ``easy_install`` command's configuration settings as defaults. + + * Made ``egg_info --tag-svn-revision`` fall back to extracting the revision + number from ``PKG-INFO`` in case it is being run on a source distribution of + a snapshot taken from a Subversion-based project. + + * Automatically detect ``.dll``, ``.so`` and ``.dylib`` files that are being + installed as data, adding them to ``native_libs.txt`` automatically. + + * Fixed some problems with fresh checkouts of projects that don't include + ``.egg-info/PKG-INFO`` under revision control and put the project's source + code directly in the project directory. If such a package had any + requirements that get processed before the ``egg_info`` command can be run, + the setup scripts would fail with a "Missing 'Version:' header and/or + PKG-INFO file" error, because the egg runtime interpreted the unbuilt + metadata in a directory on ``sys.path`` (i.e. the current directory) as + being a corrupted egg. Setuptools now monkeypatches the distribution + metadata cache to pretend that the egg has valid version information, until + it has a chance to make it actually be so (via the ``egg_info`` command). + +----- +0.6a5 +----- + + * Fixed missing gui/cli .exe files in distribution. Fixed bugs in tests. + +----- +0.6a3 +----- + + * Added ``gui_scripts`` entry point group to allow installing GUI scripts + on Windows and other platforms. (The special handling is only for Windows; + other platforms are treated the same as for ``console_scripts``.) + +----- +0.6a2 +----- + + * Added ``console_scripts`` entry point group to allow installing scripts + without the need to create separate script files. On Windows, console + scripts get an ``.exe`` wrapper so you can just type their name. On other + platforms, the scripts are written without a file extension. + +----- +0.6a1 +----- + + * Added support for building "old-style" RPMs that don't install an egg for + the target package, using a ``--no-egg`` option. + + * The ``build_ext`` command now works better when using the ``--inplace`` + option and multiple Python versions. It now makes sure that all extensions + match the current Python version, even if newer copies were built for a + different Python version. + + * The ``upload`` command no longer attaches an extra ``.zip`` when uploading + eggs, as PyPI now supports egg uploads without trickery. + + * The ``ez_setup`` script/module now displays a warning before downloading + the setuptools egg, and attempts to check the downloaded egg against an + internal MD5 checksum table. + + * Fixed the ``--tag-svn-revision`` option of ``egg_info`` not finding the + latest revision number; it was using the revision number of the directory + containing ``setup.py``, not the highest revision number in the project. + + * Added ``eager_resources`` setup argument + + * The ``sdist`` command now recognizes Subversion "deleted file" entries and + does not include them in source distributions. + + * ``setuptools`` now embeds itself more thoroughly into the distutils, so that + other distutils extensions (e.g. py2exe, py2app) will subclass setuptools' + versions of things, rather than the native distutils ones. + + * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``; + ``setup_requires`` allows you to automatically find and download packages + that are needed in order to *build* your project (as opposed to running it). + + * ``setuptools`` now finds its commands, ``setup()`` argument validators, and + metadata writers using entry points, so that they can be extended by + third-party packages. See `Creating distutils Extensions + <http://pythonhosted.org/setuptools/setuptools.html#creating-distutils-extensions>`_ + for more details. + + * The vestigial ``depends`` command has been removed. It was never finished + or documented, and never would have worked without EasyInstall - which it + pre-dated and was never compatible with. + +------ +0.5a12 +------ + + * The zip-safety scanner now checks for modules that might be used with + ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't + handle ``-m`` on zipped modules. + +------ +0.5a11 +------ + + * Fix breakage of the "develop" command that was caused by the addition of + ``--always-unzip`` to the ``easy_install`` command. + +----- +0.5a9 +----- + + * Include ``svn:externals`` directories in source distributions as well as + normal subversion-controlled files and directories. + + * Added ``exclude=patternlist`` option to ``setuptools.find_packages()`` + + * Changed --tag-svn-revision to include an "r" in front of the revision number + for better readability. + + * Added ability to build eggs without including source files (except for any + scripts, of course), using the ``--exclude-source-files`` option to + ``bdist_egg``. + + * ``setup.py install`` now automatically detects when an "unmanaged" package + or module is going to be on ``sys.path`` ahead of a package being installed, + thereby preventing the newer version from being imported. If this occurs, + a warning message is output to ``sys.stderr``, but installation proceeds + anyway. The warning message informs the user what files or directories + need deleting, and advises them they can also use EasyInstall (with the + ``--delete-conflicting`` option) to do it automatically. + + * The ``egg_info`` command now adds a ``top_level.txt`` file to the metadata + directory that lists all top-level modules and packages in the distribution. + This is used by the ``easy_install`` command to find possibly-conflicting + "unmanaged" packages when installing the distribution. + + * Added ``zip_safe`` and ``namespace_packages`` arguments to ``setup()``. + Added package analysis to determine zip-safety if the ``zip_safe`` flag + is not given, and advise the author regarding what code might need changing. + + * Fixed the swapped ``-d`` and ``-b`` options of ``bdist_egg``. + +----- +0.5a8 +----- + + * The "egg_info" command now always sets the distribution metadata to "safe" + forms of the distribution name and version, so that distribution files will + be generated with parseable names (i.e., ones that don't include '-' in the + name or version). Also, this means that if you use the various ``--tag`` + options of "egg_info", any distributions generated will use the tags in the + version, not just egg distributions. + + * Added support for defining command aliases in distutils configuration files, + under the "[aliases]" section. To prevent recursion and to allow aliases to + call the command of the same name, a given alias can be expanded only once + per command-line invocation. You can define new aliases with the "alias" + command, either for the local, global, or per-user configuration. + + * Added "rotate" command to delete old distribution files, given a set of + patterns to match and the number of files to keep. (Keeps the most + recently-modified distribution files matching each pattern.) + + * Added "saveopts" command that saves all command-line options for the current + invocation to the local, global, or per-user configuration file. Useful for + setting defaults without having to hand-edit a configuration file. + + * Added a "setopt" command that sets a single option in a specified distutils + configuration file. + +----- +0.5a7 +----- + + * Added "upload" support for egg and source distributions, including a bug + fix for "upload" and a temporary workaround for lack of .egg support in + PyPI. + +----- +0.5a6 +----- + + * Beefed up the "sdist" command so that if you don't have a MANIFEST.in, it + will include all files under revision control (CVS or Subversion) in the + current directory, and it will regenerate the list every time you create a + source distribution, not just when you tell it to. This should make the + default "do what you mean" more often than the distutils' default behavior + did, while still retaining the old behavior in the presence of MANIFEST.in. + + * Fixed the "develop" command always updating .pth files, even if you + specified ``-n`` or ``--dry-run``. + + * Slightly changed the format of the generated version when you use + ``--tag-build`` on the "egg_info" command, so that you can make tagged + revisions compare *lower* than the version specified in setup.py (e.g. by + using ``--tag-build=dev``). + +----- +0.5a5 +----- + + * Added ``develop`` command to ``setuptools``-based packages. This command + installs an ``.egg-link`` pointing to the package's source directory, and + script wrappers that ``execfile()`` the source versions of the package's + scripts. This lets you put your development checkout(s) on sys.path without + having to actually install them. (To uninstall the link, use + use ``setup.py develop --uninstall``.) + + * Added ``egg_info`` command to ``setuptools``-based packages. This command + just creates or updates the "projectname.egg-info" directory, without + building an egg. (It's used by the ``bdist_egg``, ``test``, and ``develop`` + commands.) + + * Enhanced the ``test`` command so that it doesn't install the package, but + instead builds any C extensions in-place, updates the ``.egg-info`` + metadata, adds the source directory to ``sys.path``, and runs the tests + directly on the source. This avoids an "unmanaged" installation of the + package to ``site-packages`` or elsewhere. + + * Made ``easy_install`` a standard ``setuptools`` command, moving it from + the ``easy_install`` module to ``setuptools.command.easy_install``. Note + that if you were importing or extending it, you must now change your imports + accordingly. ``easy_install.py`` is still installed as a script, but not as + a module. + +----- +0.5a4 +----- + + * Setup scripts using setuptools can now list their dependencies directly in + the setup.py file, without having to manually create a ``depends.txt`` file. + The ``install_requires`` and ``extras_require`` arguments to ``setup()`` + are used to create a dependencies file automatically. If you are manually + creating ``depends.txt`` right now, please switch to using these setup + arguments as soon as practical, because ``depends.txt`` support will be + removed in the 0.6 release cycle. For documentation on the new arguments, + see the ``setuptools.dist.Distribution`` class. + + * Setup scripts using setuptools now always install using ``easy_install`` + internally, for ease of uninstallation and upgrading. + +----- +0.5a1 +----- + + * Added support for "self-installation" bootstrapping. Packages can now + include ``ez_setup.py`` in their source distribution, and add the following + to their ``setup.py``, in order to automatically bootstrap installation of + setuptools as part of their setup process:: + + from ez_setup import use_setuptools + use_setuptools() + + from setuptools import setup + # etc... + +----- +0.4a2 +----- + + * Added ``ez_setup.py`` installer/bootstrap script to make initial setuptools + installation easier, and to allow distributions using setuptools to avoid + having to include setuptools in their source distribution. + + * All downloads are now managed by the ``PackageIndex`` class (which is now + subclassable and replaceable), so that embedders can more easily override + download logic, give download progress reports, etc. The class has also + been moved to the new ``setuptools.package_index`` module. + + * The ``Installer`` class no longer handles downloading, manages a temporary + directory, or tracks the ``zip_ok`` option. Downloading is now handled + by ``PackageIndex``, and ``Installer`` has become an ``easy_install`` + command class based on ``setuptools.Command``. + + * There is a new ``setuptools.sandbox.run_setup()`` API to invoke a setup + script in a directory sandbox, and a new ``setuptools.archive_util`` module + with an ``unpack_archive()`` API. These were split out of EasyInstall to + allow reuse by other tools and applications. + + * ``setuptools.Command`` now supports reinitializing commands using keyword + arguments to set/reset options. Also, ``Command`` subclasses can now set + their ``command_consumes_arguments`` attribute to ``True`` in order to + receive an ``args`` option containing the rest of the command line. + +----- +0.3a2 +----- + + * Added new options to ``bdist_egg`` to allow tagging the egg's version number + with a subversion revision number, the current date, or an explicit tag + value. Run ``setup.py bdist_egg --help`` to get more information. + + * Misc. bug fixes + +----- +0.3a1 +----- + + * Initial release. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index f1966505..dd0b8c7f 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -21,6 +21,7 @@ Contributors * Marc Abramowitz * Martin von Löwis * Noufal Ibrahim +* Pedro Algarvio * Pete Hollobon * Phillip J. Eby * Philip Jenvey diff --git a/docs/conf.py b/docs/conf.py index fbdb8b51..9929aaf6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,8 +14,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os -import setuptools +import setup as setup_script # 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 @@ -49,9 +48,9 @@ copyright = '2009-2013, The fellowship of the packaging' # built documents. # # The short X.Y version. -version = setuptools.__version__ +version = setup_script.setup_params['version'] # The full version, including alpha/beta/rc tags. -release = setuptools.__version__ +release = setup_script.setup_params['version'] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/development.txt b/docs/development.txt new file mode 100644 index 00000000..ba927c73 --- /dev/null +++ b/docs/development.txt @@ -0,0 +1,35 @@ +------------------------- +Development on Setuptools +------------------------- + +Setuptools is maintained by the Python community under the Python Packaging +Authority (PyPA) and led by Jason R. Coombs. + +This document describes the process by which Setuptools is developed. +This document assumes the reader has some passing familiarity with +*using* setuptools, the ``pkg_resources`` module, and EasyInstall. It +does not attempt to explain basic concepts like inter-project +dependencies, nor does it contain detailed lexical syntax for most +file formats. Neither does it explain concepts like "namespace +packages" or "resources" in any detail, as all of these subjects are +covered at length in the setuptools developer's guide and the +``pkg_resources`` reference manual. + +Instead, this is **internal** documentation for how those concepts and +features are *implemented* in concrete terms. It is intended for people +who are working on the setuptools code base, who want to be able to +troubleshoot setuptools problems, want to write code that reads the file +formats involved, or want to otherwise tinker with setuptools-generated +files and directories. + +Note, however, that these are all internal implementation details and +are therefore subject to change; stick to the published API if you don't +want to be responsible for keeping your code from breaking when +setuptools changes. You have been warned. + +.. toctree:: + :maxdepth: 1 + + formats + releases + diff --git a/docs/easy_install.txt b/docs/easy_install.txt index 12bc73ea..42a5323d 100644 --- a/docs/easy_install.txt +++ b/docs/easy_install.txt @@ -35,9 +35,8 @@ Please see the `setuptools PyPI page <https://pypi.python.org/pypi/setuptools>`_ for download links and basic installation instructions for each of the supported platforms. -You will need at least Python 2.3.5, or if you are on a 64-bit platform, Python -2.4. An ``easy_install`` script will be installed in the normal location for -Python scripts on your platform. +You will need at least 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 @@ -77,25 +76,10 @@ 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 -``ez_setup.py`` to control where ``easy_install.exe`` will be installed. - +Installing setuptools will provide an ``easy_install`` command according to +the techniques described in `Executables and Launchers`_. If the +``easy_install`` command is not available after installation, that section +provides details on how to configure Windows to make the commands available. Downloading and Installing a Package @@ -305,24 +289,80 @@ installations, so that Python won't lock us out of using anything but the most recently-installed version of the package.) +Executables and Launchers +------------------------- + +On Unix systems, scripts are installed with as natural files with a "#!" +header and no extension and they launch under the Python version indicated in +the header. + +On Windows, there is no mechanism to "execute" files without extensions, so +EasyInstall provides two techniques to mirror the Unix behavior. The behavior +is indicated by the SETUPTOOLS_LAUNCHER environment variable, which may be +"executable" (default) or "natural". + +Regardless of the technique used, the script(s) will be installed to a Scripts +directory (by default in the Python installation directory). It is recommended +for EasyInstall that you ensure this directory is in the PATH environment +variable. The easiest way to ensure the Scripts directory is in the PATH is +to run ``Tools\Scripts\win_add2path.py`` from the Python directory (requires +Python 2.6 or later). + +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 +`Command-Line Options`_ and `Configuration Files`_. During installation, +pass command line options (such as ``--script-dir``) to +``ez_setup.py`` to control where ``easy_install.exe`` will be installed. + + +Windows Executable Launcher +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the "executable" launcher is used, EasyInstall will create a '.exe' +launcher of the same name beside each installed script (including +``easy_install`` itself). These small .exe files launch the script of the +same name using the Python version indicated in the '#!' header. + +This behavior is currently default. To force +the use of executable launchers, set ``SETUPTOOLS_LAUNCHER`` to "executable". + +Natural Script Launcher +~~~~~~~~~~~~~~~~~~~~~~~ + +EasyInstall also supports deferring to an external launcher such as +`pylauncher <https://bitbucket.org/pypa/pylauncher>`_ for launching scripts. +Enable this experimental functionality by setting the +``SETUPTOOLS_LAUNCHER`` environment variable to "natural". EasyInstall will +then install scripts as simple +scripts with a .pya (or .pyw) extension appended. If these extensions are +associated with the pylauncher and listed in the PATHEXT environment variable, +these scripts can then be invoked simply and directly just like any other +executable. This behavior may become default in a future version. + +EasyInstall uses the .pya extension instead of simply +the typical '.py' extension. This distinct extension is necessary to prevent +Python +from treating the scripts as importable modules (where name conflicts exist). +Current releases of pylauncher do not yet associate with .pya files by +default, but future versions should do so. + Tips & Techniques ----------------- - Multiple Python Versions ~~~~~~~~~~~~~~~~~~~~~~~~ -As of version 0.6a11, EasyInstall installs itself under two names: +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. +used to install it. Thus, if you install EasyInstall for both Python 3.2 and +2.7, you can use the ``easy_install-3.2`` or ``easy_install-2.7`` scripts to +install packages for the respective Python version. +Setuptools also supplies easy_install as a runnable module which may be +invoked using ``python -m easy_install`` for any Python with Setuptools +installed. Restricting Downloads with ``--allow-hosts`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -532,14 +572,12 @@ 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 +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. +package to be able to function correctly. To proceed, you must manually +delete these conflicting files and directories and re-run EasyInstall. 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 @@ -783,27 +821,6 @@ Command-Line Options Added in Distribute 0.6.11 and Setuptools 0.7. -``--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 https://pypi.python.org/simple if not specified. When a package is requested diff --git a/docs/formats.txt b/docs/formats.txt index dbfc2812..ef28353e 100644 --- a/docs/formats.txt +++ b/docs/formats.txt @@ -4,26 +4,6 @@ The Internal Structure of Python Eggs STOP! This is not the first document you should read! -This document assumes you have at least some passing familiarity with -*using* setuptools, the ``pkg_resources`` module, and EasyInstall. It -does not attempt to explain basic concepts like inter-project -dependencies, nor does it contain detailed lexical syntax for most -file formats. Neither does it explain concepts like "namespace -packages" or "resources" in any detail, as all of these subjects are -covered at length in the setuptools developer's guide and the -``pkg_resources`` reference manual. - -Instead, this is **internal** documentation for how those concepts and -features are *implemented* in concrete terms. It is intended for people -who are working on the setuptools code base, who want to be able to -troubleshoot setuptools problems, want to write code that reads the file -formats involved, or want to otherwise tinker with setuptools-generated -files and directories. - -Note, however, that these are all internal implementation details and -are therefore subject to change; stick to the published API if you don't -want to be responsible for keeping your code from breaking when -setuptools changes. You have been warned. .. contents:: **Table of Contents** diff --git a/docs/index.txt b/docs/index.txt index 162a5f6f..8c68651d 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -23,3 +23,4 @@ Documentation content: setuptools easy_install pkg_resources + development diff --git a/docs/pkg_resources.txt b/docs/pkg_resources.txt index 480f9547..3aac4720 100644 --- a/docs/pkg_resources.txt +++ b/docs/pkg_resources.txt @@ -18,19 +18,31 @@ packages. 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: +introspecting, activating and using installed Python distributions. Some +of the more advanced features (notably the support for parallel installation +of multiple versions) rely specifically on the "egg" format (either as a +zip archive or subdirectory), while others (such as plugin discovery) will +work correctly so long as "egg-info" metadata directories are available for +relevant distributions. + +Eggs are a distribution format for Python modules, similar in concept to +Java's "jars" or Ruby's "gems", or the "wheel" format defined in PEP 427. +However, unlike a pure distribution format, eggs can also be installed and +added directly to ``sys.path`` as an import location. When installed in +this way, eggs are *discoverable*, meaning that they carry metadata that +unambiguously identifies their contents and dependencies. This means that +an installed egg 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". This feature allows mutually conflicting versions of +a distribution to co-exist in the same Python installation, with individual +applications activating the desired version at runtime by manipulating the +contents of ``sys.path`` (this differs from the virtual environment +approach, which involves creating isolated environments for each +application). + +The following terms are needed in order to explain the capabilities offered +by this module: project A library, framework, script, plugin, application, or collection of data @@ -79,9 +91,13 @@ eggs 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. + subdirectories. The development egg format is also used to provide a + default version of a distribution that is available to software that + doesn't use ``pkg_resources`` to request specific versions. 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 (or where the symbolic link support is + limited). (For more information about these terms and concepts, see also this `architectural overview`_ of ``pkg_resources`` and Python Eggs in general.) @@ -190,6 +206,17 @@ not provide any way to detect arbitrary changes to a list object like 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. +All distributions available directly on ``sys.path`` will be activated +automatically when ``pkg_resources`` is imported. This behaviour can cause +version conflicts for applications which require non-default versions of +those distributions. To handle this situation, ``pkg_resources`` checks for a +``__requires__`` attribute in the ``__main__`` module when initializing the +default working set, and uses this to ensure a suitable version of each +affected distribution is activated. For example:: + + __requires__ = ["CherryPy < 3"] # Must be set before pkg_resources import + import pkg_resources + Basic ``WorkingSet`` Methods ---------------------------- diff --git a/docs/releases.txt b/docs/releases.txt new file mode 100644 index 00000000..5d1419be --- /dev/null +++ b/docs/releases.txt @@ -0,0 +1,18 @@ +=============== +Release Process +=============== + +In order to allow for rapid, predictable releases, Setuptools uses a +mechanical technique for releases. The release script, ``release.py`` in the +repository, defines the details of the releases, and is executed by the +`jaraco.packaging <https://bitbucket.org/jaraco/jaraco.packaging>`_ release +module. The script does some checks (some interactive) and fully automates +the release process. + +A Setuptools release manager must have maintainer access on PyPI to the +project and administrative access to the BitBucket project. + +Release Managers +---------------- + +Currently, the project has one release manager, Jason R. Coombs. diff --git a/docs/setuptools.txt b/docs/setuptools.txt index 5d80b230..dfa9ecdd 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -20,7 +20,7 @@ package from source and doesn't have a suitable version already installed. Feature Highlights: * Automatically find/download/install/upgrade dependencies at build time using - the `EasyInstall tool <http://peak.telecommunity.com/DevCenter/EasyInstall>`_, + the `EasyInstall tool <easy_install.html>`_, 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.) @@ -72,7 +72,7 @@ is available from the `Python SVN sandbox`_, and in-development versions of the .. contents:: **Table of Contents** -.. _distribute_setup.py: `bootstrap module`_ +.. _ez_setup.py: `bootstrap module`_ ----------------- @@ -88,14 +88,14 @@ 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 +.. _EasyInstall Installation Instructions: easy_install.html#installation-instructions -.. _Custom Installation Locations: http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations +.. _Custom Installation Locations: easy_install.html#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 + ez_setup.py setuptools==dev This will download and install the latest development (i.e. unstable) version of setuptools from the Python Subversion sandbox. @@ -529,7 +529,7 @@ 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 +This feature is primarily intended to support ez_setup the installation of setuptools itself on non-Windows platforms, but may also be useful for other projects as well. @@ -652,7 +652,7 @@ 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 +If you want to 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 @@ -713,10 +713,11 @@ declare it like this, so that the "PDF" requirements are only resolved if the name="Project-A", ... entry_points = { - 'console_scripts': - ['rst2pdf = project_a.tools.pdfgen [PDF]'], - ['rst2html = project_a.tools.htmlgen'], + 'console_scripts': [ + 'rst2pdf = project_a.tools.pdfgen [PDF]', + 'rst2html = project_a.tools.htmlgen', # more script entry points ... + ], } ) @@ -1147,20 +1148,20 @@ 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`` +download `ez_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() + import ez_setup + ez_setup.use_setuptools() -That's it. The ``distribute_setup`` module will automatically download a matching +That's it. The ``ez_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 +your projects' ``ez_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 @@ -1190,7 +1191,7 @@ 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 + If your project is using ``ez_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 @@ -1266,45 +1267,6 @@ Creating System Packages 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 ----------------------------- @@ -1416,20 +1378,21 @@ 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 +Setuptools automatically calls ``declare_namespace()`` for you at runtime, +but future versions may *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 +packages work at all. In some future 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 +During the remainder of the current 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 the compatibility support is removed. +Namespace packages without declaration lines will not work +correctly once a user has upgraded to a later version, 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. @@ -1984,7 +1947,7 @@ them in a ``[develop]`` section or on the command line. ============================================ This command runs the `EasyInstall tool -<http://peak.telecommunity.com/DevCenter/EasyInstall>`_ for you. It is exactly +<easy_install.html>`_ 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 @@ -2699,8 +2662,8 @@ XXX Reusing ``setuptools`` Code =========================== -``distribute_setup`` --------------------- +``ez_setup`` +------------ XXX @@ -2722,500 +2685,6 @@ XXX 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 ============================ @@ -3226,5 +2695,5 @@ 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/ +.. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/ diff --git a/docs/using.txt b/docs/using.txt index 6f93c386..e44847d6 100644 --- a/docs/using.txt +++ b/docs/using.txt @@ -4,7 +4,7 @@ Using Setuptools in your project To use Setuptools in your project, the recommended way is to ship `ez_setup.py` alongside your `setup.py` script and call -it at the very begining of `setup.py` like this:: +it at the very beginning of `setup.py` like this:: from ez_setup import use_setuptools use_setuptools() diff --git a/ez_setup.py b/ez_setup.py index 55434eb7..c3069e7a 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -20,6 +20,7 @@ import tempfile import tarfile import optparse import subprocess +import platform from distutils import log @@ -28,13 +29,22 @@ try: except ImportError: USER_SITE = None -DEFAULT_VERSION = "0.9.7" +DEFAULT_VERSION = "1.1.7" DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" def _python_cmd(*args): args = (sys.executable,) + args return subprocess.call(args) == 0 +def _check_call_py24(cmd, *args, **kwargs): + res = subprocess.call(cmd, *args, **kwargs) + class CalledProcessError(Exception): + pass + if not res == 0: + msg = "Command '%s' return non-zero exit status %d" % (cmd, res) + raise CalledProcessError(msg) +vars(subprocess).setdefault('check_call', _check_call_py24) + def _install(tarball, install_args=()): # extracting the tarball tmpdir = tempfile.mkdtemp() @@ -141,9 +151,123 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, return _do_download(version, download_base, to_dir, download_delay) +def _clean_check(cmd, target): + """ + Run the command to download target. If the command fails, clean up before + re-raising the error. + """ + try: + subprocess.check_call(cmd) + except subprocess.CalledProcessError: + if os.access(target, os.F_OK): + os.unlink(target) + raise + +def download_file_powershell(url, target): + """ + Download the file at url to target using Powershell (which will validate + trust). Raise an exception if the command cannot complete. + """ + target = os.path.abspath(target) + cmd = [ + 'powershell', + '-Command', + "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(), + ] + _clean_check(cmd, target) + +def has_powershell(): + if platform.system() != 'Windows': + return False + cmd = ['powershell', '-Command', 'echo test'] + devnull = open(os.path.devnull, 'wb') + try: + try: + subprocess.check_call(cmd, stdout=devnull, stderr=devnull) + except: + return False + finally: + devnull.close() + return True + +download_file_powershell.viable = has_powershell + +def download_file_curl(url, target): + cmd = ['curl', url, '--silent', '--output', target] + _clean_check(cmd, target) + +def has_curl(): + cmd = ['curl', '--version'] + devnull = open(os.path.devnull, 'wb') + try: + try: + subprocess.check_call(cmd, stdout=devnull, stderr=devnull) + except: + return False + finally: + devnull.close() + return True + +download_file_curl.viable = has_curl + +def download_file_wget(url, target): + cmd = ['wget', url, '--quiet', '--output-document', target] + _clean_check(cmd, target) + +def has_wget(): + cmd = ['wget', '--version'] + devnull = open(os.path.devnull, 'wb') + try: + try: + subprocess.check_call(cmd, stdout=devnull, stderr=devnull) + except: + return False + finally: + devnull.close() + return True + +download_file_wget.viable = has_wget + +def download_file_insecure(url, target): + """ + Use Python to download the file, even though it cannot authenticate the + connection. + """ + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + src = dst = None + try: + src = urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = src.read() + dst = open(target, "wb") + dst.write(data) + finally: + if src: + src.close() + if dst: + dst.close() + +download_file_insecure.viable = lambda: True + +def get_best_downloader(): + downloaders = [ + download_file_powershell, + download_file_curl, + download_file_wget, + download_file_insecure, + ] + + for dl in downloaders: + if dl.viable(): + return dl def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, delay=15): + to_dir=os.curdir, delay=15, + downloader_factory=get_best_downloader): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available @@ -151,31 +275,19 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 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. + + ``downloader_factory`` should be a function taking no arguments and + returning a function for downloading a URL to a target. """ # making sure we use the absolute path to_dir = os.path.abspath(to_dir) - try: - from urllib.request import urlopen - except ImportError: - from urllib2 import urlopen tgz_name = "setuptools-%s.tar.gz" % version url = download_base + tgz_name saveto = os.path.join(to_dir, tgz_name) - src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads - try: - log.warn("Downloading %s", url) - src = urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = src.read() - dst = open(saveto, "wb") - dst.write(data) - finally: - if src: - src.close() - if dst: - dst.close() + log.warn("Downloading %s", url) + downloader = downloader_factory() + downloader(url, saveto) return os.path.realpath(saveto) @@ -250,6 +362,11 @@ def _parse_args(): '--download-base', dest='download_base', metavar="URL", default=DEFAULT_URL, help='alternative URL from where to download the setuptools package') + parser.add_option( + '--insecure', dest='downloader_factory', action='store_const', + const=lambda: download_file_insecure, default=get_best_downloader, + help='Use internal, non-validating downloader' + ) options, args = parser.parse_args() # positional arguments are ignored return options @@ -257,7 +374,8 @@ def _parse_args(): def main(version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" options = _parse_args() - tarball = download_setuptools(download_base=options.download_base) + tarball = download_setuptools(download_base=options.download_base, + downloader_factory=options.downloader_factory) return _install(tarball, _build_install_args(options)) if __name__ == '__main__': diff --git a/pkg_resources.py b/pkg_resources.py index 36a0e6ed..02976016 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -13,7 +13,13 @@ The package resource API is designed to work with normal filesystem packages, method. """ -import sys, os, time, re, imp, types, zipfile, zipimport +import sys +import os +import time +import re +import imp +import zipfile +import zipimport import warnings import stat try: @@ -122,8 +128,6 @@ def _sset_object(key, ob, state): _sget_none = _sset_none = lambda *args: None - - def get_supported_platform(): """Return this platform's maximum compatible version. @@ -137,7 +141,8 @@ def get_supported_platform(): If this condition occurs for any other platform with a version in its platform strings, this function should be extended accordingly. """ - plat = get_build_platform(); m = macosVersionString.match(plat) + plat = get_build_platform() + m = macosVersionString.match(plat) if m is not None and sys.platform == "darwin": try: plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) @@ -145,26 +150,6 @@ def get_supported_platform(): pass # not Mac OS X return plat - - - - - - - - - - - - - - - - - - - - __all__ = [ # Basic resource access and distribution/entry point discovery 'require', 'run_script', 'get_provider', 'get_distribution', @@ -206,6 +191,7 @@ __all__ = [ # Deprecated/backward compatibility only 'run_main', 'AvailableDistributions', ] + class ResolutionError(Exception): """Abstract base for dependency resolution errors""" def __repr__(self): @@ -222,7 +208,7 @@ class UnknownExtra(ResolutionError): _provider_factories = {} PY_MAJOR = sys.version[:3] -EGG_DIST = 3 +EGG_DIST = 3 BINARY_DIST = 2 SOURCE_DIST = 1 CHECKOUT_DIST = 0 @@ -299,11 +285,6 @@ darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") get_platform = get_build_platform # XXX backward compat - - - - - def compatible_platforms(provided,required): """Can code for the `provided` platform run on the `required` platform? @@ -329,7 +310,7 @@ def compatible_platforms(provided,required): dversion = int(provDarwin.group(1)) macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) if dversion == 7 and macosversion >= "10.3" or \ - dversion == 8 and macosversion >= "10.4": + dversion == 8 and macosversion >= "10.4": #import warnings #warnings.warn("Mac eggs should be rebuilt to " @@ -340,11 +321,9 @@ def compatible_platforms(provided,required): # are they the same major version and machine type? if provMac.group(1) != reqMac.group(1) or \ - provMac.group(3) != reqMac.group(3): + 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 @@ -410,14 +389,6 @@ class IMetadataProvider: """Execute the named script in the supplied namespace dictionary""" - - - - - - - - class IResourceProvider(IMetadataProvider): """An object that provides access to package resources""" @@ -446,19 +417,6 @@ class IResourceProvider(IMetadataProvider): """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)""" @@ -475,7 +433,6 @@ class WorkingSet(object): for entry in entries: self.add_entry(entry) - def add_entry(self, entry): """Add a path item to ``.entries``, finding any distributions on it @@ -491,15 +448,10 @@ class WorkingSet(object): 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` @@ -539,8 +491,6 @@ class WorkingSet(object): 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 @@ -633,9 +583,8 @@ class WorkingSet(object): return to_activate # return list of distros to activate - def find_plugins(self, - plugin_env, full_env=None, installer=None, fallback=True - ): + def find_plugins(self, plugin_env, full_env=None, installer=None, + fallback=True): """Find all activatable distributions in `plugin_env` Example usage:: @@ -712,10 +661,6 @@ class WorkingSet(object): return distributions, error_info - - - - def require(self, *requirements): """Ensure that distributions matching `requirements` are activated @@ -793,7 +738,7 @@ class Environment(object): """ return (self.python is None or dist.py_version is None or dist.py_version==self.python) \ - and compatible_platforms(dist.platform,self.platform) + and compatible_platforms(dist.platform,self.platform) def remove(self, dist): """Remove `dist` from the environment""" @@ -839,7 +784,6 @@ class Environment(object): 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` @@ -878,9 +822,6 @@ class Environment(object): 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): @@ -920,8 +861,6 @@ class ExtractionError(RuntimeError): """ - - class ResourceManager: """Manage resource extraction and packages""" extraction_path = None @@ -983,27 +922,13 @@ The Python egg cache directory is currently set to: 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) +""" % (old_exc, cache_path) ) - err.manager = self - err.cache_path = 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` @@ -1053,23 +978,6 @@ variable to point to an accessible directory. "PYTHON_EGG_CACHE environment variable)." % path) warnings.warn(msg, UserWarning) - - - - - - - - - - - - - - - - - def postprocess(self, tempname, filename): """Perform any platform-specific postprocessing of `tempname` @@ -1090,27 +998,6 @@ variable to point to an accessible directory. mode = ((os.stat(tempname).st_mode) | 0x16D) & 0xFFF # 0555, 07777 os.chmod(tempname, mode) - - - - - - - - - - - - - - - - - - - - - def set_extraction_path(self, path): """Set the base path where resources will be extracted to, if needed. @@ -1150,8 +1037,6 @@ variable to point to an accessible directory. """ # XXX - - def get_default_cache(): """Determine the default cache location @@ -1227,13 +1112,6 @@ def to_filename(name): """ return name.replace('-','_') - - - - - - - _marker_names = { 'os': ['name'], 'sys': ['platform'], 'platform': ['version','machine','python_implementation'], @@ -1267,12 +1145,28 @@ def _pyimp(): else: return 'CPython' +def normalize_exception(exc): + """ + Given a SyntaxError from a marker evaluation, normalize the error message: + - Remove indications of filename and line number. + - Replace platform-specific error messages with standard error messages. + """ + subs = { + 'unexpected EOF while parsing': 'invalid syntax', + 'parenthesis is never closed': 'invalid syntax', + } + exc.filename = None + exc.lineno = None + exc.msg = subs.get(exc.msg, exc.msg) + return exc + + def invalid_marker(text): """Validate text as a PEP 426 environment marker; return exception or False""" try: evaluate_marker(text) except SyntaxError: - return sys.exc_info()[1] + return normalize_exception(sys.exc_info()[1]) return False def evaluate_marker(text, extra=None, _ops={}): @@ -1289,7 +1183,9 @@ def evaluate_marker(text, extra=None, _ops={}): if not _ops: from token import NAME, STRING - import token, symbol, operator + import token + import symbol + import operator def and_test(nodelist): # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! @@ -1355,7 +1251,7 @@ def evaluate_marker(text, extra=None, _ops={}): if kind==STRING: s = nodelist[1] if s[:1] not in "'\"" or s.startswith('"""') or s.startswith("'''") \ - or '\\' in s: + or '\\' in s: raise SyntaxError( "Only plain strings allowed in environment markers") return s[1:-1] @@ -1434,7 +1330,6 @@ class NullProvider: 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)) @@ -1512,11 +1407,6 @@ class EggProvider(NullProvider): old = path path, base = os.path.split(path) - - - - - class DefaultProvider(EggProvider): """Provides access to package resources in the filesystem""" @@ -1549,9 +1439,9 @@ 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 + _get = lambda self,path: '' + _listdir = lambda self,path: [] + module_path = None def __init__(self): pass @@ -1752,28 +1642,6 @@ class ZipProvider(EggProvider): register_loader_type(zipimport.zipimporter, ZipProvider) - - - - - - - - - - - - - - - - - - - - - - class FileMetadata(EmptyProvider): """Metadata handler for standalone PKG-INFO files @@ -1804,20 +1672,6 @@ class FileMetadata(EmptyProvider): return yield_lines(self.get_metadata(name)) - - - - - - - - - - - - - - class PathMetadata(DefaultProvider): """Metadata provider for egg directories @@ -1898,8 +1752,6 @@ class ImpLoader: return mod - - def get_importer(path_item): """Retrieve a PEP 302 "importer" for the given path item @@ -1937,10 +1789,6 @@ else: del ImpLoader, ImpImporter - - - - _declare_state('dict', _distribution_finders = {}) def register_finder(importer_type, distribution_finder): @@ -2164,12 +2012,12 @@ def yield_lines(strs): 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 +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 +MODULE = re.compile(r"\w+(\.\w+)*$").match EGG_NAME = re.compile( r"(?P<name>[^-]+)" r"( -(?P<ver>[^-]+) (-py(?P<pyver>[^-]+) (-(?P<plat>.+))? )? )?", @@ -2271,8 +2119,6 @@ class EntryPoint(object): list(map(working_set.add, working_set.resolve(self.dist.requires(self.extras),env,installer))) - - #@classmethod def parse(cls, src, dist=None): """Parse a single entry point from string `src` @@ -2307,13 +2153,6 @@ class EntryPoint(object): parse = classmethod(parse) - - - - - - - #@classmethod def parse_group(cls, group, lines, dist=None): """Parse an entry point group""" @@ -2364,10 +2203,9 @@ 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 - ): + 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) @@ -2395,7 +2233,6 @@ class Distribution(object): ) from_location = classmethod(from_location) - hashcmp = property( lambda self: ( getattr(self,'parsed_version',()), @@ -2461,9 +2298,6 @@ class Distribution(object): ) version = property(version) - - - #@property def _dep_map(self): try: @@ -2503,8 +2337,6 @@ class Distribution(object): 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 @@ -2513,7 +2345,6 @@ class Distribution(object): fixup_namespace_packages(self.location) list(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" % ( @@ -2543,9 +2374,6 @@ class Distribution(object): raise AttributeError(attr) return getattr(self._provider, attr) - - - #@classmethod def from_filename(cls,filename,metadata=None, **kw): return cls.from_location( @@ -2581,12 +2409,6 @@ class Distribution(object): """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""" @@ -2627,7 +2449,6 @@ class Distribution(object): return - def check_version_conflict(self): if self.key=='setuptools': return # ignore the inevitable setuptools self-conflicts :( @@ -2636,8 +2457,7 @@ class Distribution(object): 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 - ): + or modname in _namespace_packages): continue if modname in ('pkg_resources', 'setuptools', 'site'): continue @@ -2668,9 +2488,6 @@ class Distribution(object): kw.setdefault('metadata', self._provider) return self.__class__(**kw) - - - #@property def extras(self): return [dep for dep in self._dep_map if dep] @@ -2740,9 +2557,11 @@ class DistInfoDistribution(Distribution): return dm -_distributionImpl = {'.egg': Distribution, - '.egg-info': Distribution, - '.dist-info': DistInfoDistribution } +_distributionImpl = { + '.egg': Distribution, + '.egg-info': Distribution, + '.dist-info': DistInfoDistribution, + } def issue_warning(*args,**kw): @@ -2759,27 +2578,6 @@ def issue_warning(*args,**kw): warn(stacklevel = level+1, *args, **kw) - - - - - - - - - - - - - - - - - - - - - def parse_requirements(strs): """Yield ``Requirement`` objects for each specification in `strs` @@ -2796,7 +2594,8 @@ def parse_requirements(strs): while not TERMINATOR(line,p): if CONTINUE(line,p): try: - line = next(lines); p = 0 + line = next(lines) + p = 0 except StopIteration: raise ValueError( "\\ must not appear on the last nonblank line" @@ -2847,21 +2646,6 @@ def _sort_dists(dists): 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()!""" @@ -2896,14 +2680,16 @@ class Requirement: 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 + 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 @@ -2922,12 +2708,12 @@ class Requirement: state_machine = { # =>< - '<' : '--T', - '<=': 'T-T', - '>' : 'F+F', - '>=': 'T+F', - '==': 'T..', - '!=': 'F++', + '<': '--T', + '<=': 'T-T', + '>': 'F+F', + '>=': 'T+F', + '==': 'T..', + '!=': 'F++', } @@ -3025,5 +2811,5 @@ run_main = run_script # backward compatibility # all distributions added to the working set in the future (e.g. by # calling ``require()``) will get activated as well. add_activation_listener(lambda dist: dist.activate()) -working_set.entries=[]; list(map(working_set.add_entry,sys.path)) # match order - +working_set.entries=[] +list(map(working_set.add_entry,sys.path)) # match order @@ -7,13 +7,22 @@ import re import os import subprocess +import pkg_resources + +pkg_resources.require('jaraco.packaging>=2.0') + def before_upload(): _linkify('CHANGES.txt', 'CHANGES (links).txt') - _add_bootstrap_bookmark() + BootstrapBookmark.add() + + +def after_push(): + os.remove('CHANGES (links).txt') + BootstrapBookmark.push() files_with_versions = ( - 'ez_setup.py', 'setuptools/__init__.py', + 'ez_setup.py', 'setuptools/version.py', ) test_info = "Travis-CI tests: http://travis-ci.org/#!/jaraco/setuptools" @@ -55,7 +64,21 @@ def replacer(match): url = issue_urls[key].format(**match_dict) return "`{text} <{url}>`_".format(text=text, url=url) +class BootstrapBookmark: + name = 'bootstrap' + + @classmethod + def add(cls): + cmd = ['hg', 'bookmark', '-i', cls.name, '-f'] + subprocess.Popen(cmd) -def _add_bootstrap_bookmark(): - cmd = ['hg', 'bookmark', '-i', 'bootstrap', '-f'] - subprocess.Popen(cmd) + @classmethod + def push(cls): + """ + Push the bootstrap bookmark + """ + push_command = ['hg', 'push', '-B', cls.name] + # don't use check_call here because mercurial will return a non-zero + # code even if it succeeds at pushing the bookmark (because there are + # no changesets to be pushed). !dm mercurial + subprocess.call(push_command) @@ -16,3 +16,6 @@ upload-dir = docs/build/html [sdist] formats=gztar + +[wheel] +universal=1 @@ -20,10 +20,10 @@ init_file.close() SETUP_COMMANDS = command_ns['__all__'] main_ns = {} -init_path = convert_path('setuptools/__init__.py') -init_file = open(init_path) -exec(init_file.read(), main_ns) -init_file.close() +ver_path = convert_path('setuptools/version.py') +ver_file = open(ver_path) +exec(ver_file.read(), main_ns) +ver_file.close() import setuptools from setuptools.command.build_py import build_py as _build_py diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt index 478fac7d..4a09dd1c 100644 --- a/setuptools.egg-info/entry_points.txt +++ b/setuptools.egg-info/entry_points.txt @@ -1,62 +1,62 @@ -[setuptools.installation]
-eggsecutable = setuptools.command.easy_install:bootstrap
-
-[console_scripts]
-easy_install = setuptools.command.easy_install:main
-easy_install-3.3 = setuptools.command.easy_install:main
-
-[distutils.setup_keywords]
-use_2to3 = setuptools.dist:assert_bool
-namespace_packages = setuptools.dist:check_nsp
-package_data = setuptools.dist:check_package_data
-use_2to3_exclude_fixers = setuptools.dist:assert_string_list
-dependency_links = setuptools.dist:assert_string_list
-use_2to3_fixers = setuptools.dist:assert_string_list
-test_suite = setuptools.dist:check_test_suite
-exclude_package_data = setuptools.dist:check_package_data
-extras_require = setuptools.dist:check_extras
-install_requires = setuptools.dist:check_requirements
-eager_resources = setuptools.dist:assert_string_list
-include_package_data = setuptools.dist:assert_bool
-packages = setuptools.dist:check_packages
-entry_points = setuptools.dist:check_entry_points
-zip_safe = setuptools.dist:assert_bool
-tests_require = setuptools.dist:check_requirements
-convert_2to3_doctests = setuptools.dist:assert_string_list
-test_loader = setuptools.dist:check_importable
-
-[setuptools.file_finders]
-svn_cvs = setuptools.command.sdist:_default_revctrl
-
-[egg_info.writers]
-top_level.txt = setuptools.command.egg_info:write_toplevel_names
-PKG-INFO = setuptools.command.egg_info:write_pkg_info
-eager_resources.txt = setuptools.command.egg_info:overwrite_arg
-namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
-depends.txt = setuptools.command.egg_info:warn_depends_obsolete
-dependency_links.txt = setuptools.command.egg_info:overwrite_arg
-entry_points.txt = setuptools.command.egg_info:write_entries
-requires.txt = setuptools.command.egg_info:write_requirements
-
-[distutils.commands]
-test = setuptools.command.test:test
-bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
-alias = setuptools.command.alias:alias
-sdist = setuptools.command.sdist:sdist
-develop = setuptools.command.develop:develop
-bdist_egg = setuptools.command.bdist_egg:bdist_egg
-setopt = setuptools.command.setopt:setopt
-egg_info = setuptools.command.egg_info:egg_info
-build_ext = setuptools.command.build_ext:build_ext
-upload_docs = setuptools.command.upload_docs:upload_docs
-easy_install = setuptools.command.easy_install:easy_install
-install = setuptools.command.install:install
-install_egg_info = setuptools.command.install_egg_info:install_egg_info
-bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
-install_lib = setuptools.command.install_lib:install_lib
-rotate = setuptools.command.rotate:rotate
-saveopts = setuptools.command.saveopts:saveopts
-install_scripts = setuptools.command.install_scripts:install_scripts
-build_py = setuptools.command.build_py:build_py
-register = setuptools.command.register:register
-
+[distutils.setup_keywords] +packages = setuptools.dist:check_packages +install_requires = setuptools.dist:check_requirements +eager_resources = setuptools.dist:assert_string_list +include_package_data = setuptools.dist:assert_bool +convert_2to3_doctests = setuptools.dist:assert_string_list +package_data = setuptools.dist:check_package_data +use_2to3_exclude_fixers = setuptools.dist:assert_string_list +test_suite = setuptools.dist:check_test_suite +tests_require = setuptools.dist:check_requirements +use_2to3 = setuptools.dist:assert_bool +exclude_package_data = setuptools.dist:check_package_data +test_loader = setuptools.dist:check_importable +extras_require = setuptools.dist:check_extras +use_2to3_fixers = setuptools.dist:assert_string_list +namespace_packages = setuptools.dist:check_nsp +zip_safe = setuptools.dist:assert_bool +dependency_links = setuptools.dist:assert_string_list +entry_points = setuptools.dist:check_entry_points + +[setuptools.file_finders] +svn_cvs = setuptools.command.sdist:_default_revctrl + +[egg_info.writers] +depends.txt = setuptools.command.egg_info:warn_depends_obsolete +top_level.txt = setuptools.command.egg_info:write_toplevel_names +entry_points.txt = setuptools.command.egg_info:write_entries +requires.txt = setuptools.command.egg_info:write_requirements +PKG-INFO = setuptools.command.egg_info:write_pkg_info +eager_resources.txt = setuptools.command.egg_info:overwrite_arg +dependency_links.txt = setuptools.command.egg_info:overwrite_arg +namespace_packages.txt = setuptools.command.egg_info:overwrite_arg + +[distutils.commands] +rotate = setuptools.command.rotate:rotate +bdist_egg = setuptools.command.bdist_egg:bdist_egg +install_scripts = setuptools.command.install_scripts:install_scripts +install_egg_info = setuptools.command.install_egg_info:install_egg_info +build_py = setuptools.command.build_py:build_py +build_ext = setuptools.command.build_ext:build_ext +install = setuptools.command.install:install +sdist = setuptools.command.sdist:sdist +upload_docs = setuptools.command.upload_docs:upload_docs +saveopts = setuptools.command.saveopts:saveopts +develop = setuptools.command.develop:develop +alias = setuptools.command.alias:alias +register = setuptools.command.register:register +setopt = setuptools.command.setopt:setopt +egg_info = setuptools.command.egg_info:egg_info +test = setuptools.command.test:test +easy_install = setuptools.command.easy_install:easy_install +install_lib = setuptools.command.install_lib:install_lib +bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst +bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm + +[setuptools.installation] +eggsecutable = setuptools.command.easy_install:bootstrap + +[console_scripts] +easy_install = setuptools.command.easy_install:main +easy_install-3.3 = setuptools.command.easy_install:main + diff --git a/setuptools.egg-info/requires.txt b/setuptools.egg-info/requires.txt index 221040f8..0b577c97 100644 --- a/setuptools.egg-info/requires.txt +++ b/setuptools.egg-info/requires.txt @@ -1,11 +1,11 @@ -[ssl:python_version in '2.4, 2.5'] -ssl==1.16 - [ssl:sys_platform=='win32' and python_version=='2.4'] ctypes==1.0.2 +[ssl:python_version in '2.4, 2.5'] +ssl==1.16 + [certs] certifi==0.0.8 diff --git a/setuptools/__init__.py b/setuptools/__init__.py index 18dd363d..fc9b7b93 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -1,19 +1,24 @@ """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 +import distutils.core +import distutils.filelist +from distutils.core import Command as _Command +from distutils.util import convert_path + +import setuptools.version +from setuptools.extension import Extension +from setuptools.dist import Distribution, Feature, _get_unpatched +from setuptools.depends import Require -__version__ = '0.9.7' __all__ = [ 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', 'find_packages' ] +__version__ = setuptools.version.__version__ + bootstrap_install_from = None # If we run 2to3 on .py files, should we also convert docstrings? @@ -37,10 +42,14 @@ def find_packages(where='.', exclude=()): 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+'.')) + looks_like_package = ( + '.' not in name + and os.path.isdir(fn) + and os.path.isfile(os.path.join(fn, '__init__.py')) + ) + if looks_like_package: + out.append(prefix+name) + stack.append((fn, prefix+name+'.')) for pat in list(exclude)+['ez_setup']: from fnmatch import fnmatchcase out = [item for item in out if not fnmatchcase(item,pat)] @@ -67,7 +76,6 @@ class Command(_Command): 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): @@ -83,12 +91,8 @@ def findall(dir = os.curdir): 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 +_dont_write_bytecode = getattr(sys, 'dont_write_bytecode', + bool(os.environ.get("PYTHONDONTWRITEBYTECODE"))) diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 3194644e..6ce19fa4 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -1,5 +1,6 @@ #!python -"""\ + +""" Easy Install ------------ @@ -10,6 +11,7 @@ file, or visit the `EasyInstall home page`__. __ https://pythonhosted.org/setuptools/easy_install.html """ + import sys import os import zipimport @@ -20,11 +22,16 @@ import re import stat import random import platform +import textwrap +import warnings +import site +import struct from glob import glob +from distutils import log, dir_util + import pkg_resources from setuptools import Command, _dont_write_bytecode from setuptools.sandbox import run_setup -from distutils import log, dir_util try: # Python 2.7 or >=3.2 from sysconfig import get_config_vars, get_path @@ -51,12 +58,12 @@ from setuptools.package_index import URL_SCHEME from setuptools.command import bdist_egg, egg_info from setuptools.compat import (iteritems, maxsize, xrange, basestring, unicode, reraise) -from pkg_resources import yield_lines, normalize_path, resource_string, \ - ensure_directory, get_distribution, find_distributions, \ - Environment, Requirement, Distribution, \ - PathMetadata, EggMetadata, WorkingSet, \ - DistributionNotFound, VersionConflict, \ - DEVELOP_DIST +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, +) if '__VENV_LAUNCHER__' in os.environ: sys_executable = os.environ['__VENV_LAUNCHER__'] @@ -68,22 +75,19 @@ __all__ = [ '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)) - ) +def samefile(p1, p2): + both_exist = os.path.exists(p1) and os.path.exists(p2) + use_samefile = hasattr(os.path, 'samefile') and both_exist + if use_samefile: + return os.path.samefile(p1, p2) + norm_p1 = os.path.normpath(os.path.normcase(p1)) + norm_p2 = os.path.normpath(os.path.normcase(p2)) + return norm_p1 == norm_p2 if sys.version_info <= (3,): def _to_ascii(s): @@ -120,38 +124,35 @@ class easy_install(Command): ("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]"), + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), ('record=', None, - "filename in which to record list of installed files"), + "filename in which to record list of installed files"), ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), ('site-dirs=','S',"list of directories where .pth files work"), ('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"), + ('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") + "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', + '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)) + help_msg = "install in user site-package '%s'" % site.USER_SITE + user_options.append(('user', None, help_msg)) boolean_options.append('user') - negative_opt = {'always-unzip': 'zip-ok'} create_index = PackageIndex @@ -192,8 +193,6 @@ class easy_install(Command): # 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 @@ -226,19 +225,20 @@ class easy_install(Command): 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', ''), - } + 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 @@ -336,11 +336,6 @@ class easy_install(Command): 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" @@ -351,7 +346,6 @@ class easy_install(Command): self.outputs = [] - def _expand_attrs(self, attrs): for attr in attrs: val = getattr(self, attr) @@ -406,12 +400,7 @@ class easy_install(Command): 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." - ) + pass def check_site_dir(self): """Verify that self.install_dir is .pth-capable dir, if needed""" @@ -456,7 +445,7 @@ class easy_install(Command): self.install_dir = instdir def cant_write_to_target(self): - msg = """can't create or remove files in install directory + template = """can't create or remove files in install directory The following error occurred while trying to add or remove files in the installation directory: @@ -467,7 +456,8 @@ The installation directory you specified (via --install-dir, --prefix, or the distutils default setting) was: %s -""" % (sys.exc_info()[1], self.install_dir,) +""" + msg = template % (sys.exc_info()[1], self.install_dir,) if not os.path.exists(self.install_dir): msg += """ @@ -493,9 +483,6 @@ 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 @@ -514,7 +501,8 @@ Please make the appropriate changes for your system and try again. else: try: f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,)) - f.close(); f=None + f.close() + f=None executable = sys.executable if os.name=='nt': dirname,basename = os.path.split(executable) @@ -533,9 +521,12 @@ Please make the appropriate changes for your system and try again. ) 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 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 @@ -580,11 +571,6 @@ Please make the appropriate changes for your system and try again. (spec.key, self.build_directory) ) - - - - - def easy_install(self, spec, deps=False): tmpdir = tempfile.mkdtemp(prefix="easy_install-") download = None @@ -654,7 +640,7 @@ Please make the appropriate changes for your system and try again. for dist in dists: self.process_distribution(spec, dist, deps) else: - dists = [self.check_conflicts(self.egg_distribution(download))] + dists = [self.egg_distribution(download)] self.process_distribution(spec, dists[0], deps, "Using") if spec is not None: @@ -662,8 +648,6 @@ Please make the appropriate changes for your system and try again. 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! @@ -673,9 +657,6 @@ Please make the appropriate changes for your system and try again. 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) @@ -684,7 +665,7 @@ Please make the appropriate changes for your system and try again. 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): + not self.no_find_links): self.package_index.add_find_links( dist.get_metadata_lines('dependency_links.txt') ) @@ -735,10 +716,8 @@ Please make the appropriate changes for your system and try again. 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 - ) + msg = "%r already exists in %s; build directory %s will not be kept" + log.warn(msg, spec.key, self.build_directory, setup_base) return setup_base if os.path.isdir(dist_filename): setup_base = dist_filename @@ -751,7 +730,8 @@ Please make the appropriate changes for your system and try again. 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) + ensure_directory(dst) + shutil.move(setup_base, dst) return dst def install_wrapper_scripts(self, dist): @@ -759,8 +739,6 @@ Please make the appropriate changes for your system and try again. 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()) @@ -799,14 +777,13 @@ Please make the appropriate changes for your system and try again. mask = current_umask() if not self.dry_run: ensure_directory(target) + if os.path.exists(target): + os.unlink(target) f = open(target,"w"+mode) f.write(contents) f.close() chmod(target, 0x1FF-mask) # 0777 - - - 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'): @@ -822,8 +799,7 @@ Please make the appropriate changes for your system and try again. setup_base = os.path.abspath(dist_filename) if (setup_base.startswith(tmpdir) # something we downloaded - and self.build_directory and spec is not None - ): + and self.build_directory and spec is not None): setup_base = self.maybe_move(spec, dist_filename, setup_base) # Find the setup.py file @@ -862,7 +838,6 @@ Please make the appropriate changes for your system and try again. 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) @@ -897,18 +872,19 @@ Please make the appropriate changes for your system and try again. "%s is not a valid distutils Windows .exe" % dist_filename ) # Create a dummy distribution object until we build the real distro - dist = Distribution(None, + dist = Distribution( + None, project_name=cfg.get('metadata','name'), - version=cfg.get('metadata','version'), platform=get_platform() + 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') + 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 + dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX self.exe_to_egg(dist_filename, egg_tmp) # Write EGG-INFO/PKG-INFO @@ -919,7 +895,7 @@ Please make the appropriate changes for your system and try again. if k != 'target_version': f.write('%s: %s\n' % (k.replace('_','-').title(), v)) f.close() - script_dir = os.path.join(egg_info,'scripts') + 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)] ) @@ -965,7 +941,8 @@ Please make the appropriate changes for your system and try again. 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) + 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'), @@ -979,82 +956,6 @@ Please make the appropriate changes for your system and try again. 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" @@ -1164,8 +1065,7 @@ See the setuptools documentation for the "develop" command for more info. cfg_filename = os.path.join(base, 'setup.cfg') setopt.edit_config(cfg_filename, settings) - - def update_pth(self,dist): + def update_pth(self, dist): if self.pth_file is None: return @@ -1207,9 +1107,10 @@ See the setuptools documentation for the "develop" command for more info. return dst # only unpack-and-compile skips files for dry run def unpack_and_compile(self, egg_path, destination): - to_compile = []; to_chmod = [] + to_compile = [] + to_chmod = [] - def pf(src,dst): + def pf(src, dst): if dst.endswith('.py') and not src.startswith('EGG-INFO/'): to_compile.append(dst) elif dst.endswith('.dll') or dst.endswith('.so'): @@ -1243,16 +1144,8 @@ See the setuptools documentation for the "develop" command for more info. finally: log.set_verbosity(self.verbose) # restore original verbosity - - - - - - - - def no_default_version_msg(self): - return """bad install directory or PYTHONPATH + template = """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 @@ -1279,18 +1172,8 @@ Here are some of your options for correcting the problem: https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations -Please make the appropriate changes for your system and try again.""" % ( - self.install_dir, os.environ.get('PYTHONPATH','') - ) - - - - - - - - - +Please make the appropriate changes for your system and try again.""" + return template % (self.install_dir, os.environ.get('PYTHONPATH','')) def install_site_py(self): """Make sure there's a site.py in the target dir, if needed""" @@ -1328,9 +1211,6 @@ Please make the appropriate changes for your system and try again.""" % ( self.sitepy_installed = True - - - def create_home_path(self): """Create directories under ~.""" if not self.user: @@ -1341,22 +1221,16 @@ Please make the appropriate changes for your system and try again.""" % ( self.debug_print("os.makedirs('%s', 0700)" % path) os.makedirs(path, 0x1C0) # 0700 - - - - - - INSTALL_SCHEMES = dict( posix = dict( install_dir = '$base/lib/python$py_version_short/site-packages', - script_dir = '$base/bin', + script_dir = '$base/bin', ), ) DEFAULT_SCHEME = dict( install_dir = '$base/Lib/site-packages', - script_dir = '$base/Scripts', + script_dir = '$base/Scripts', ) def _expand(self, *attrs): @@ -1380,14 +1254,6 @@ Please make the appropriate changes for your system and try again.""" % ( val = os.path.expanduser(val) setattr(self, attr, val) - - - - - - - - def get_site_dirs(): # return a list of 'site' dirs sitedirs = [_f for _f in os.environ.get('PYTHONPATH', @@ -1522,12 +1388,6 @@ def extract_wininst_cfg(dist_filename): f.close() - - - - - - def get_exe_prefixes(exe_filename): """Get exe->egg path translations for a given .exe file""" @@ -1561,7 +1421,8 @@ def get_exe_prefixes(exe_filename): finally: z.close() prefixes = [(x.lower(),y) for x, y in prefixes] - prefixes.sort(); prefixes.reverse() + prefixes.sort() + prefixes.reverse() return prefixes @@ -1582,7 +1443,8 @@ class PthDistributions(Environment): self.filename = filename self.sitedirs = list(map(normalize_path, sitedirs)) self.basedir = normalize_path(os.path.dirname(self.filename)) - self._load(); Environment.__init__(self, [], None, None) + self._load() + Environment.__init__(self, [], None, None) for path in yield_lines(self.paths): list(map(self.add, find_distributions(path, True))) @@ -1637,7 +1499,8 @@ class PthDistributions(Environment): if os.path.islink(self.filename): os.unlink(self.filename) f = open(self.filename,'wt') - f.write(data); f.close() + f.write(data) + f.close() elif os.path.exists(self.filename): log.debug("Deleting empty %s", self.filename) @@ -1645,22 +1508,22 @@ class PthDistributions(Environment): self.dirty = False - def add(self,dist): + 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 + dist.location == os.getcwd() # account for '.' being in PYTHONPATH )): self.paths.append(dist.location) self.dirty = True - Environment.add(self,dist) + Environment.add(self, dist) - def remove(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) - + 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)) @@ -1782,14 +1645,6 @@ def nt_quote_arg(arg): 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. """ @@ -1828,66 +1683,140 @@ def fix_jython_executable(executable, options): # 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.") + 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': - launcher_type = 'gui' - ext = '-script.pyw' - old = ['.pyw'] - new_header = re.sub('(?i)python.exe','pythonw.exe',header) - else: - launcher_type = 'cli' - ext = '-script.py' - old = ['.py','.pyc','.pyo'] - new_header = re.sub('(?i)pythonw.exe','python.exe',header) - if os.path.exists(new_header[2:-1].strip('"')) 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', get_win_launcher(launcher_type), - 'b' # write in binary mode - ) - if not is_64bit(): - # install a manifest for the launcher to prevent Windows - # from detecting it as an installer (which it will for - # launchers like easy_install.exe). Consider only - # adding a manifest for launchers detected as installers. - # See Distribute #143 for details. - m_name = name + '.exe.manifest' - yield (m_name, load_launcher_manifest(name), 't') - 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) +class ScriptWriter(object): + """ + Encapsulates behavior around writing entry point scripts for console and + gui apps. + """ + + template = textwrap.dedent(""" + # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r + __requires__ = %(spec)r + import sys + from pkg_resources import load_entry_point + + if __name__ == '__main__': + sys.exit( + load_entry_point(%(spec)r, %(group)r, %(name)r)() + ) + """).lstrip() + + @classmethod + def get_script_args(cls, dist, executable=sys_executable, wininst=False): + """ + Yield write_script() argument tuples for a distribution's entrypoints + """ + gen_class = cls.get_writer(wininst) + spec = str(dist.as_requirement()) + header = get_script_header("", executable, wininst) + for type_ in 'console', 'gui': + group = type_ + '_scripts' + for name, ep in dist.get_entry_map(group).items(): + script_text = gen_class.template % locals() + for res in gen_class._get_script_args(type_, name, header, + script_text): + yield res + + @classmethod + def get_writer(cls, force_windows): + if force_windows or sys.platform=='win32': + return WindowsScriptWriter.get_writer() + return cls + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + # Simply write the stub with no extension. + yield (name, header+script_text) + + +class WindowsScriptWriter(ScriptWriter): + @classmethod + def get_writer(cls): + """ + Get a script writer suitable for Windows + """ + writer_lookup = dict( + executable=WindowsExecutableLauncherWriter, + natural=cls, + ) + # for compatibility, use the executable launcher by default + launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') + return writer_lookup[launcher] + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + "For Windows, add a .py extension" + ext = dict(console='.pya', gui='.pyw')[type_] + if ext not in os.environ['PATHEXT'].lower().split(';'): + warnings.warn("%s not listed in PATHEXT; scripts will not be " + "recognized as executables." % ext, UserWarning) + old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] + old.remove(ext) + header = cls._adjust_header(type_, header) + blockers = [name+x for x in old] + yield name+ext, header+script_text, 't', blockers + + @staticmethod + def _adjust_header(type_, orig_header): + """ + Make sure 'pythonw' is used for gui and and 'python' is used for + console (regardless of what sys.executable is). + """ + pattern = 'pythonw.exe' + repl = 'python.exe' + if type_ == 'gui': + pattern, repl = repl, pattern + pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) + new_header = pattern_ob.sub(string=orig_header, repl=repl) + clean_header = new_header[2:-1].strip('"') + if sys.platform == 'win32' and not os.path.exists(clean_header): + # the adjusted version doesn't exist, so return the original + return orig_header + return new_header + + +class WindowsExecutableLauncherWriter(WindowsScriptWriter): + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + """ + For Windows, add a .py extension and an .exe launcher + """ + if type_=='gui': + launcher_type = 'gui' + ext = '-script.pyw' + old = ['.pyw'] + else: + launcher_type = 'cli' + ext = '-script.py' + old = ['.py','.pyc','.pyo'] + hdr = cls._adjust_header(type_, header) + blockers = [name+x for x in old] + yield (name+ext, hdr+script_text, 't', blockers) + yield ( + name+'.exe', get_win_launcher(launcher_type), + 'b' # write in binary mode + ) + if not is_64bit(): + # install a manifest for the launcher to prevent Windows + # from detecting it as an installer (which it will for + # launchers like easy_install.exe). Consider only + # adding a manifest for launchers detected as installers. + # See Distribute #143 for details. + m_name = name + '.exe.manifest' + yield (m_name, load_launcher_manifest(name), 't') + +# for backward-compatibility +get_script_args = ScriptWriter.get_script_args def get_win_launcher(type): """ @@ -1955,8 +1884,11 @@ def current_umask(): 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() + 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 @@ -1968,9 +1900,10 @@ 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 gen_usage(script_name): + return USAGE % dict( + script=os.path.basename(script_name), + ) def with_ei_usage(f): old_gen_usage = distutils.core.gen_usage @@ -1996,7 +1929,3 @@ usage: %(script)s [options] requirement_or_url ... distclass=DistributionWithoutHelpCommands, **kw ) ) - - - - diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index e1112ff9..6249e75c 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -1,9 +1,12 @@ +import os +import re +import sys +from glob import glob + +import pkg_resources from distutils.command.sdist import sdist as _sdist from distutils.util import convert_path from distutils import log -from glob import glob -import os, re, sys, pkg_resources -from glob import glob from setuptools import svn_utils READMES = ('README', 'README.rst', 'README.txt') @@ -37,7 +40,6 @@ class re_finder(object): #was an re_finder for calling unescape path = postproc(path) yield svn_utils.joinpath(dirname,path) - def __call__(self, dirname=''): path = svn_utils.joinpath(dirname, self.path) @@ -64,16 +66,6 @@ finders = [ - - - - - - - - - - class sdist(_sdist): """Smart sdist that finds anything supported by revision control""" @@ -128,11 +120,12 @@ class sdist(_sdist): # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle # has been fixed, so only override the method if we're using an earlier # Python. - if ( - sys.version_info < (2,7,2) - or (3,0) <= sys.version_info < (3,1,4) - or (3,2) <= sys.version_info < (3,2,1) - ): + has_leaky_handle = ( + sys.version_info < (2,7,2) + or (3,0) <= sys.version_info < (3,1,4) + or (3,2) <= sys.version_info < (3,2,1) + ) + if has_leaky_handle: read_template = __read_template_hack def add_defaults(self): @@ -197,7 +190,6 @@ class sdist(_sdist): "standard file not found: should have one of " +', '.join(READMES) ) - def make_release_tree(self, base_dir, files): _sdist.make_release_tree(self, base_dir, files) @@ -244,10 +236,3 @@ class sdist(_sdist): continue self.filelist.append(line) manifest.close() - - - - - - -# diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index 02d955ed..a6eff385 100755 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -2,10 +2,10 @@ Implements the Distutils 'upload' subcommand (upload package to PyPI).""" -from distutils.errors import * +from distutils import errors +from distutils import log from distutils.core import Command from distutils.spawn import spawn -from distutils import log try: from hashlib import md5 except ImportError: @@ -45,7 +45,7 @@ class upload(Command): def finalize_options(self): if self.identity and not self.sign: - raise DistutilsOptionError( + raise errors.DistutilsOptionError( "Must use --sign for --identity to have meaning" ) if 'HOME' in os.environ: @@ -68,7 +68,7 @@ class upload(Command): def run(self): if not self.distribution.dist_files: - raise DistutilsOptionError("No dist file created in earlier command") + raise errors.DistutilsOptionError("No dist file created in earlier command") for command, pyversion, filename in self.distribution.dist_files: self.upload_file(command, pyversion, filename) @@ -119,10 +119,10 @@ class upload(Command): boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' sep_boundary = '\n--' + boundary end_boundary = sep_boundary + '--' - body = StringIO.StringIO() + body = StringIO() for key, value in data.items(): # handle multiple entries for the same name - if type(value) != type([]): + if not isinstance(value, list): value = [value] for value in value: if type(value) is tuple: @@ -158,7 +158,6 @@ class upload(Command): raise AssertionError("unsupported schema " + schema) data = '' - loglevel = log.INFO try: http.connect() http.putrequest("POST", url) diff --git a/setuptools/compat.py b/setuptools/compat.py index 94fe23e9..bbc98d66 100644 --- a/setuptools/compat.py +++ b/setuptools/compat.py @@ -27,10 +27,10 @@ if sys.version_info[0] < 3: unichr = unichr unicode = unicode bytes = str - from urllib import url2pathname + from urllib import url2pathname, splittag import urllib2 from urllib2 import urlopen, HTTPError, URLError, unquote, splituser - from urlparse import urlparse, urlunparse, urljoin + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit xrange = xrange filterfalse = itertools.ifilterfalse @@ -74,7 +74,10 @@ else: from urllib.error import HTTPError, URLError import urllib.request as urllib2 from urllib.request import urlopen, url2pathname - from urllib.parse import urlparse, urlunparse, unquote, splituser, urljoin + from urllib.parse import ( + urlparse, urlunparse, unquote, splituser, urljoin, urlsplit, + urlunsplit, splittag, + ) xrange = range filterfalse = itertools.filterfalse @@ -83,7 +86,7 @@ else: globs = globals() if locs is None: locs = globs - f = open(fn) + f = open(fn, 'rb') try: source = f.read() finally: diff --git a/setuptools/dist.py b/setuptools/dist.py index 01889215..c5b02f99 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -1,17 +1,19 @@ __all__ = ['Distribution'] import re +import os import sys +import warnings +import distutils.log +import distutils.core +import distutils.cmd from distutils.core import Distribution as _Distribution +from distutils.errors import (DistutilsOptionError, DistutilsPlatformError, + DistutilsSetupError) + 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 setuptools.compat import numeric_types, basestring -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 +import pkg_resources def _get_unpatched(cls): """Protect against re-patching the distutils if reloaded @@ -132,38 +134,6 @@ def check_packages(dist, attr, value): "WARNING: %r not a valid package name; please use only" ".-separated package names in setup.py", pkgname ) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class Distribution(_Distribution): @@ -194,7 +164,8 @@ class Distribution(_Distribution): 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' + 'features' **deprecated** -- 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 @@ -248,10 +219,13 @@ class Distribution(_Distribution): dist._version = pkg_resources.safe_version(str(attrs['version'])) self._patched_dist = dist - def __init__ (self, attrs=None): + def __init__(self, attrs=None): have_package_data = hasattr(self, "package_data") if not have_package_data: self.package_data = {} + _attrs_dict = attrs or {} + if 'features' in _attrs_dict or 'require_features' in _attrs_dict: + Feature.warn_deprecated() self.require_features = [] self.features = {} self.dist_files = [] @@ -362,23 +336,6 @@ class Distribution(_Distribution): 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""" @@ -396,7 +353,6 @@ class Distribution(_Distribution): 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: @@ -416,10 +372,6 @@ class Distribution(_Distribution): 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) @@ -434,8 +386,8 @@ class Distribution(_Distribution): if self.feature_is_included(name)==0: descr = self.features[name].description raise DistutilsOptionError( - descr + " is required, but was excluded or is not available" - ) + descr + " is required, but was excluded or is not available" + ) self.features[name].include_in(self) self._set_feature(name,1) @@ -483,7 +435,6 @@ class Distribution(_Distribution): 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""" @@ -493,15 +444,6 @@ class Distribution(_Distribution): 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): @@ -573,17 +515,6 @@ class Distribution(_Distribution): ) list(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 @@ -610,21 +541,6 @@ class Distribution(_Distribution): return nargs - - - - - - - - - - - - - - - def get_cmdline_options(self): """Return a '{cmd: {opt:val}}' map of all command-line options @@ -665,7 +581,6 @@ class Distribution(_Distribution): return d - def iter_distribution_names(self): """Yield all packages, modules, and extension names in distribution""" @@ -684,7 +599,6 @@ class Distribution(_Distribution): 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 @@ -726,26 +640,14 @@ 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 + """ + **deprecated** -- The `Feature` facility was never completely implemented + or supported, `has reported issues + <https://bitbucket.org/pypa/setuptools/issue/58>`_ and will be removed in + a future version. + + A subset of the distribution that can be excluded if unneeded/wanted Features are created using these keyword arguments: @@ -794,9 +696,19 @@ class Feature: Aside from the methods, the only feature attributes that distributions look at are 'description' and 'optional'. """ + + @staticmethod + def warn_deprecated(): + warnings.warn( + "Features are deprecated and will be removed in a future " + "version. See http://bitbucket.org/pypa/setuptools/65.", + DeprecationWarning, + stacklevel=3, + ) + def __init__(self, description, standard=False, available=True, - optional=True, require_features=(), remove=(), **extras - ): + optional=True, require_features=(), remove=(), **extras): + self.warn_deprecated() self.description = description self.standard = standard @@ -847,8 +759,6 @@ class Feature: for f in self.require_features: dist.include_feature(f) - - def exclude_from(self,dist): """Ensure feature is excluded from distribution @@ -865,8 +775,6 @@ class Feature: for item in self.remove: dist.exclude_package(item) - - def validate(self,dist): """Verify that feature makes sense in context of distribution @@ -886,7 +794,3 @@ class Feature: " doesn't contain any packages or modules under %s" % (self.description, item, item) ) - - - - diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 47f00c00..4c9e40a7 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -1,19 +1,28 @@ """PyPI and direct package downloading""" -import sys, os.path, re, shutil, random, socket -import itertools +import sys +import os +import re +import shutil +import socket import base64 + +from pkg_resources import ( + CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST, + require, Environment, find_distributions, safe_name, safe_version, + to_filename, Requirement, DEVELOP_DIST, +) from setuptools import ssl_support -from pkg_resources import * from distutils import log from distutils.errors import DistutilsError from setuptools.compat import (urllib2, httplib, StringIO, HTTPError, urlparse, urlunparse, unquote, splituser, url2pathname, name2codepoint, - unichr, urljoin) + unichr, urljoin, urlsplit, urlunsplit) from setuptools.compat import filterfalse from fnmatch import translate from setuptools.py24compat import hashlib from setuptools.py24compat import wraps +from setuptools.py26compat import strip_fragment from setuptools.py27compat import get_all_headers EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$') @@ -105,9 +114,10 @@ def distros_for_filename(filename, metadata=None): ) -def interpret_distro_name(location, basename, metadata, - py_version=None, precedence=SOURCE_DIST, platform=None -): +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 @@ -222,6 +232,7 @@ class HashChecker(ContentChecker): ) def __init__(self, hash_name, expected): + self.hash_name = hash_name self.hash = hashlib.new(hash_name) self.expected = expected @@ -242,32 +253,18 @@ class HashChecker(ContentChecker): def is_valid(self): return self.hash.hexdigest() == self.expected - def _get_hash_name(self): - """ - Python 2.4 implementation of MD5 doesn't supply a .name attribute - so provide that name. - - When Python 2.4 is no longer required, replace invocations of this - method with simply 'self.hash.name'. - """ - try: - return self.hash.name - except AttributeError: - if 'md5' in str(type(self.hash)): - return 'md5' - raise - def report(self, reporter, template): - msg = template % self._get_hash_name() + msg = template % self.hash_name return reporter(msg) class PackageIndex(Environment): """A distribution index that scans web pages for download URLs""" - def __init__(self, index_url="https://pypi.python.org/simple", hosts=('*',), - ca_bundle=None, verify_ssl=True, *args, **kw - ): + def __init__( + self, index_url="https://pypi.python.org/simple", hosts=('*',), + ca_bundle=None, verify_ssl=True, *args, **kw + ): Environment.__init__(self,*args,**kw) self.index_url = index_url + "/"[:not index_url.endswith('/')] self.scanned_urls = {} @@ -347,7 +344,8 @@ class PackageIndex(Environment): s = URL_SCHEME(url) if (s and s.group(1).lower()=='file') or self.allows(urlparse(url)[1]): return True - msg = "\nLink to % s ***BLOCKED*** by --allow-hosts\n" + msg = ("\nNote: Bypassing %s (disallowed host; see " + "http://bit.ly/1dg9ijs for details).\n") if fatal: raise DistutilsError(msg % url) else: @@ -388,7 +386,7 @@ class PackageIndex(Environment): # process an index page into the package-page index for match in HREF.finditer(page): try: - scan( urljoin(url, htmldecode(match.group(1))) ) + scan(urljoin(url, htmldecode(match.group(1)))) except ValueError: pass @@ -411,8 +409,6 @@ class PackageIndex(Environment): 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 " @@ -443,17 +439,14 @@ class PackageIndex(Environment): self.scan_url(url) def obtain(self, requirement, installer=None): - self.prescan(); self.find_packages(requirement) + 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_hash(self, checker, filename, tfp): """ checker is a ContentChecker @@ -539,11 +532,10 @@ class PackageIndex(Environment): ) 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 - ): + 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. @@ -581,8 +573,6 @@ class PackageIndex(Environment): if dist in req and (dist.precedence<=SOURCE_DIST or not source): return dist - - if force_scan: self.prescan() self.find_packages(requirement) @@ -609,7 +599,6 @@ class PackageIndex(Environment): self.info("Best match: %s", dist) return dist.clone(location=self.download(dist.location, tmpdir)) - def fetch(self, requirement, tmpdir, force_scan=False, source=False): """Obtain a file suitable for fulfilling `requirement` @@ -623,10 +612,10 @@ class PackageIndex(Environment): return dist.location return None - def gen_setup(self, filename, fragment, tmpdir): match = EGG_FRAGMENT.match(fragment) - dists = match and [d for d in + dists = match and [ + d for d in interpret_distro_name(filename, match.group(1), None) if d.version ] or [] @@ -672,7 +661,7 @@ class PackageIndex(Environment): fp, tfp, info = None, None, None try: checker = HashChecker.from_url(url) - fp = self.open_url(url) + fp = self.open_url(strip_fragment(url)) if isinstance(fp, HTTPError): raise DistutilsError( "Can't download %s: %s %s" % (url, fp.code,fp.msg) @@ -732,9 +721,11 @@ class PackageIndex(Environment): 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)) + raise DistutilsError( + '%s returned a bad status line. The server might be ' + 'down, %s' % + (url, v.line) + ) except httplib.HTTPException: v = sys.exc_info()[1] if warning: @@ -775,7 +766,6 @@ class PackageIndex(Environment): 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(): @@ -798,21 +788,6 @@ class PackageIndex(Environment): 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 creds = '' @@ -833,7 +808,8 @@ class PackageIndex(Environment): os.system("svn checkout%s -q %s %s" % (creds, url, filename)) return filename - def _vcs_split_rev_from_url(self, url, pop_prefix=False): + @staticmethod + def _vcs_split_rev_from_url(url, pop_prefix=False): scheme, netloc, path, query, frag = urlsplit(url) scheme = scheme.split('+', 1)[-1] @@ -891,18 +867,6 @@ class PackageIndex(Environment): 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 @@ -927,20 +891,6 @@ 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): @@ -1009,15 +959,6 @@ def open_with_auth(url, opener=urllib2.urlopen): open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth) - - - - - - - - - def fix_sf_url(url): return url # backward compatibility @@ -1047,17 +988,3 @@ def local_open(url): return HTTPError(url, status, message, {'content-type':'text/html'}, StringIO(body)) - - - - - - - - - - - - - -# this line is a kludge to keep the trailing blank lines for pje's editor diff --git a/setuptools/py26compat.py b/setuptools/py26compat.py new file mode 100644 index 00000000..738b0cc4 --- /dev/null +++ b/setuptools/py26compat.py @@ -0,0 +1,19 @@ +""" +Compatibility Support for Python 2.6 and earlier +""" + +import sys + +from setuptools.compat import splittag + +def strip_fragment(url): + """ + In `Python 8280 <http://bugs.python.org/issue8280>`_, Python 2.7 and + later was patched to disregard the fragment when making URL requests. + Do the same for Python 2.6 and earlier. + """ + url, fragment = splittag(url) + return url + +if sys.version_info >= (2,7): + strip_fragment = lambda x: x diff --git a/setuptools/script template (dev).py b/setuptools/script template (dev).py index 901790e7..b3fe209e 100644 --- a/setuptools/script template (dev).py +++ b/setuptools/script template (dev).py @@ -1,9 +1,11 @@ # EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r __requires__ = """%(spec)r""" -from pkg_resources import require; require("""%(spec)r""") +import sys +from pkg_resources import require +require("""%(spec)r""") del require __file__ = """%(dev_path)r""" -try: +if sys.version_info < (3, 0): execfile(__file__) -except NameError: +else: exec(compile(open(__file__).read(), __file__, 'exec')) diff --git a/setuptools/ssl_support.py b/setuptools/ssl_support.py index f8a780a9..90359b2c 100644 --- a/setuptools/ssl_support.py +++ b/setuptools/ssl_support.py @@ -194,6 +194,12 @@ class VerifyingHTTPSConn(HTTPSConnection): sock = create_connection( (self.host, self.port), getattr(self,'source_address',None) ) + + # Handle the socket if a (proxy) tunnel is present + if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None): + self.sock = sock + self._tunnel() + self.sock = ssl.wrap_socket( sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle ) diff --git a/setuptools/tests/script-with-bom.py b/setuptools/tests/script-with-bom.py new file mode 100644 index 00000000..22dee0d2 --- /dev/null +++ b/setuptools/tests/script-with-bom.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +result = 'passed' diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 2732bb3e..189e3d55 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -14,7 +14,7 @@ import distutils.core from setuptools.compat import StringIO, BytesIO, next, urlparse from setuptools.sandbox import run_setup, SandboxViolation -from setuptools.command.easy_install import easy_install, fix_jython_executable, get_script_args +from setuptools.command.easy_install import easy_install, fix_jython_executable, get_script_args, nt_quote_arg from setuptools.command.easy_install import PthDistributions from setuptools.command import easy_install as easy_install_pkg from setuptools.dist import Distribution @@ -52,7 +52,7 @@ if __name__ == '__main__': sys.exit( load_entry_point('spec', 'console_scripts', 'name')() ) -""" % fix_jython_executable(sys.executable, "") +""" % nt_quote_arg(fix_jython_executable(sys.executable, "")) SETUP_PY = """\ from setuptools import setup diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py index 3791914a..08969b7e 100644 --- a/setuptools/tests/test_packageindex.py +++ b/setuptools/tests/test_packageindex.py @@ -142,6 +142,15 @@ class TestPackageIndex(unittest.TestCase): self.assertEqual(setuptools.package_index.parse_bdist_wininst( 'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64')) + def test__vcs_split_rev_from_url(self): + """ + Test the basic usage of _vcs_split_rev_from_url + """ + vsrfu = setuptools.package_index.PackageIndex._vcs_split_rev_from_url + url, rev = vsrfu('https://example.com/bar@2995') + self.assertEqual(url, 'https://example.com/bar') + self.assertEqual(rev, '2995') + class TestContentCheckers(unittest.TestCase): def test_md5(self): @@ -169,11 +178,7 @@ class TestContentCheckers(unittest.TestCase): def test_get_hash_name_md5(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') - if sys.version_info >= (2,5): - self.assertEqual(checker.hash.name, 'md5') - else: - # Python 2.4 compatability - self.assertEqual(checker._get_hash_name(), 'md5') + self.assertEqual(checker.hash_name, 'md5') def test_report(self): checker = setuptools.package_index.HashChecker.from_url( diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py index df5261d1..c9fcf76c 100644 --- a/setuptools/tests/test_resources.py +++ b/setuptools/tests/test_resources.py @@ -1,11 +1,24 @@ #!/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 +# NOTE: the shebang and encoding lines are for ScriptHeaderTests do not remove + +import os +import sys +import tempfile +import shutil +from unittest import TestCase + +import pkg_resources +from pkg_resources import (parse_requirements, VersionConflict, parse_version, + Distribution, EntryPoint, Requirement, safe_version, safe_name, + WorkingSet) + +from setuptools.command.easy_install import (get_script_header, is_sh, + nt_quote_arg) from setuptools.compat import StringIO, iteritems -import os, pkg_resources, sys, tempfile, shutil -try: frozenset + +try: + frozenset except NameError: from sets import ImmutableSet as frozenset @@ -15,11 +28,11 @@ def safe_repr(obj, short=False): result = repr(obj) except Exception: result = object.__repr__(obj) - if not short or len(result) < _MAX_LENGTH: + if not short or len(result) < pkg_resources._MAX_LENGTH: return result - return result[:_MAX_LENGTH] + ' [truncated]...' + return result[:pkg_resources._MAX_LENGTH] + ' [truncated]...' -class Metadata(EmptyProvider): +class Metadata(pkg_resources.EmptyProvider): """Mock object to return metadata as if from an on-disk distribution""" def __init__(self,*pairs): @@ -32,18 +45,20 @@ class Metadata(EmptyProvider): return self.metadata[name] def get_metadata_lines(self,name): - return yield_lines(self.get_metadata(name)) + return pkg_resources.yield_lines(self.get_metadata(name)) + +dist_from_fn = pkg_resources.Distribution.from_filename class DistroTests(TestCase): def testCollection(self): # empty path should produce no distributions - ad = Environment([], platform=None, python=None) + ad = pkg_resources.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")) + ad.add(dist_from_fn("FooPkg-1.3_1.egg")) + ad.add(dist_from_fn("FooPkg-1.4-py2.4-win32.egg")) + ad.add(dist_from_fn("FooPkg-1.2-py2.4.egg")) # Name is in there now self.assertTrue(ad['FooPkg']) @@ -60,27 +75,33 @@ class DistroTests(TestCase): [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")) + ad.add(dist_from_fn("FooPkg-1.9.egg")) self.assertEqual( [dist.version for dist in ad['FooPkg']], ['1.9','1.4','1.2'] ) ws = WorkingSet([]) - foo12 = Distribution.from_filename("FooPkg-1.2-py2.4.egg") - foo14 = Distribution.from_filename("FooPkg-1.4-py2.4-win32.egg") + foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg") + foo14 = dist_from_fn("FooPkg-1.4-py2.4-win32.egg") req, = parse_requirements("FooPkg>=1.3") # Nominal case: no distros on path, should yield all applicable self.assertEqual(ad.best_match(req,ws).version, '1.9') # If a matching distro is already installed, should return only that - ws.add(foo14); self.assertEqual(ad.best_match(req,ws).version, '1.4') + 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) + 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); + 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): @@ -103,9 +124,9 @@ class DistroTests(TestCase): self.assertEqual(d.platform, None) def testDistroParse(self): - d = Distribution.from_filename("FooPkg-1.3_1-py2.4-win32.egg") + d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg") self.checkFooPkg(d) - d = Distribution.from_filename("FooPkg-1.3_1-py2.4-win32.egg-info") + d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg-info") self.checkFooPkg(d) def testDistroMetadata(self): @@ -117,7 +138,6 @@ class DistroTests(TestCase): ) self.checkFooPkg(d) - def distRequires(self, txt): return Distribution("/foo", metadata=Metadata(('depends.txt', txt))) @@ -131,20 +151,21 @@ class DistroTests(TestCase): 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([]) + ad = pkg_resources.Environment([]) + ws = WorkingSet([]) # Resolving no requirements -> nothing to install - self.assertEqual( list(ws.resolve([],ad)), [] ) + self.assertEqual(list(ws.resolve([],ad)), []) # Request something not in the collection -> DistributionNotFound self.assertRaises( - DistributionNotFound, ws.resolve, parse_requirements("Foo"), ad + pkg_resources.DistributionNotFound, ws.resolve, parse_requirements("Foo"), ad ) Foo = Distribution.from_filename( "/foo_dir/Foo-1.2.egg", metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")) ) - ad.add(Foo); ad.add(Distribution.from_filename("Foo-0.9.egg")) + 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): @@ -157,7 +178,7 @@ class DistroTests(TestCase): # Request an extra that causes an unresolved dependency for "Baz" self.assertRaises( - DistributionNotFound, ws.resolve,parse_requirements("Foo[bar]"), ad + pkg_resources.DistributionNotFound, ws.resolve,parse_requirements("Foo[bar]"), ad ) Baz = Distribution.from_filename( "/foo_dir/Baz-2.1.egg", metadata=Metadata(('depends.txt', "Foo")) @@ -169,9 +190,8 @@ class DistroTests(TestCase): 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 - ) + self.assertRaises(VersionConflict, + ws.resolve, parse_requirements("Foo==1.2\nFoo!=1.2"), ad) def testDistroDependsOptions(self): d = self.distRequires(""" @@ -196,7 +216,7 @@ class DistroTests(TestCase): d,"Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), ["fastcgi", "docgen"] ) - self.assertRaises(UnknownExtra, d.requires, ["foo"]) + self.assertRaises(pkg_resources.UnknownExtra, d.requires, ["foo"]) class EntryPointTests(TestCase): @@ -304,8 +324,8 @@ class RequirementsTests(TestCase): 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") + 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) @@ -321,7 +341,6 @@ class RequirementsTests(TestCase): 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") @@ -366,15 +385,6 @@ class RequirementsTests(TestCase): Requirement.parse('setuptools >= 0.7').project_name, 'setuptools') - - - - - - - - - class ParseTests(TestCase): def testEmptyParse(self): @@ -388,9 +398,7 @@ class ParseTests(TestCase): self.assertEqual(list(pkg_resources.yield_lines(inp)),out) def testSplitting(self): - self.assertEqual( - list( - pkg_resources.split_sections(""" + sample = """ x [Y] z @@ -403,8 +411,7 @@ class ParseTests(TestCase): [q] v """ - ) - ), + self.assertEqual(list(pkg_resources.split_sections(sample)), [(None,["x"]), ("Y",["z","a"]), ("b",["c"]), ("d",[]), ("q",["v"])] ) self.assertRaises(ValueError,list,pkg_resources.split_sections("[foo")) @@ -455,7 +462,8 @@ class ParseTests(TestCase): c('0pre1', '0.0c1') c('0.0.0preview1', '0c1') c('0.0c1', '0-rc1') - c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a') + c('1.2a1', '1.2.a.1') + c('1.2...a', '1.2a') def testVersionOrdering(self): def c(s1,s2): @@ -492,30 +500,30 @@ class ParseTests(TestCase): c(v2,v1) - - - - - - class ScriptHeaderTests(TestCase): non_ascii_exe = '/Users/José/bin/python' + exe_with_spaces = r'C:\Program Files\Python33\python.exe' def test_get_script_header(self): if not sys.platform.startswith('java') or not is_sh(sys.executable): # This test is for non-Jython platforms + expected = '#!%s\n' % nt_quote_arg(os.path.normpath(sys.executable)) self.assertEqual(get_script_header('#!/usr/local/bin/python'), - '#!%s\n' % os.path.normpath(sys.executable)) + expected) + expected = '#!%s -x\n' % nt_quote_arg(os.path.normpath(sys.executable)) self.assertEqual(get_script_header('#!/usr/bin/python -x'), - '#!%s -x\n' % os.path.normpath(sys.executable)) + expected) self.assertEqual(get_script_header('#!/usr/bin/python', executable=self.non_ascii_exe), '#!%s -x\n' % self.non_ascii_exe) + candidate = get_script_header('#!/usr/bin/python', + executable=self.exe_with_spaces) + self.assertEqual(candidate, '#!"%s"\n' % self.exe_with_spaces) def test_get_script_header_jython_workaround(self): # This test doesn't work with Python 3 in some locales if (sys.version_info >= (3,) and os.environ.get("LC_CTYPE") - in (None, "C", "POSIX")): + in (None, "C", "POSIX")): return class java: @@ -554,8 +562,6 @@ class ScriptHeaderTests(TestCase): sys.stdout, sys.stderr = stdout, stderr - - class NamespaceTests(TestCase): def setUp(self): @@ -610,6 +616,5 @@ class NamespaceTests(TestCase): 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") ]) - + os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"), + os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2")]) diff --git a/setuptools/tests/test_sandbox.py b/setuptools/tests/test_sandbox.py index 1609ee86..3dad1376 100644 --- a/setuptools/tests/test_sandbox.py +++ b/setuptools/tests/test_sandbox.py @@ -5,7 +5,10 @@ import os import shutil import unittest import tempfile +import types +import pkg_resources +import setuptools.sandbox from setuptools.sandbox import DirectorySandbox, SandboxViolation def has_win32com(): @@ -62,5 +65,15 @@ class TestSandbox(unittest.TestCase): finally: if os.path.exists(target): os.remove(target) + def test_setup_py_with_BOM(self): + """ + It should be possible to execute a setup.py with a Byte Order Mark + """ + target = pkg_resources.resource_filename(__name__, + 'script-with-bom.py') + namespace = types.ModuleType('namespace') + setuptools.sandbox.execfile(target, vars(namespace)) + assert namespace.result == 'passed' + if __name__ == '__main__': unittest.main() diff --git a/setuptools/version.py b/setuptools/version.py new file mode 100644 index 00000000..9910ac22 --- /dev/null +++ b/setuptools/version.py @@ -0,0 +1 @@ +__version__ = '1.1.7' diff --git a/tests/api_tests.txt b/tests/api_tests.txt index 86ca245d..d34f2314 100644 --- a/tests/api_tests.txt +++ b/tests/api_tests.txt @@ -341,8 +341,8 @@ Environment Markers >>> print(im("sys_platform")) Comparison or logical expression expected - >>> print(im("sys_platform==")) # doctest: +ELLIPSIS - unexpected EOF while parsing (...line 1) + >>> print(im("sys_platform==")) + invalid syntax >>> print(im("sys_platform=='win32'")) False @@ -353,8 +353,8 @@ Environment Markers >>> print(im("(extra)")) Comparison or logical expression expected - >>> print(im("(extra")) # doctest: +ELLIPSIS - unexpected EOF while parsing (...line 1) + >>> print(im("(extra")) + invalid syntax >>> print(im("os.open('foo')=='y'")) Language feature not supported in environment markers diff --git a/tests/manual_test.py b/tests/manual_test.py index 3eab99e1..e6489b1c 100644 --- a/tests/manual_test.py +++ b/tests/manual_test.py @@ -1,31 +1,16 @@ #!/usr/bin/env python -import sys - -if sys.version_info[0] >= 3: - raise NotImplementedError('Py3 not supported in this test yet') +import sys import os import shutil import tempfile +import subprocess from distutils.command.install import INSTALL_SCHEMES from string import Template from setuptools.compat 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 _system_call(*args): + assert subprocess.call(args) == 0 def tempdir(func): def _tempdir(*args, **kwargs): |