diff options
72 files changed, 1388 insertions, 864 deletions
@@ -10,6 +10,7 @@ setuptools.egg-info .coverage .eggs .tox +.venv *.egg *.py[cod] *.swp diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..3aef6b6b --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,4 @@ +python: + version: 3 + requirements_file: docs/requirements.txt + pip_install: false diff --git a/CHANGES.rst b/CHANGES.rst index 156ba47d..5c673a74 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,42 @@ +v40.2.0 +------- + +* #1466: Fix handling of Unicode arguments in PEP 517 backend + + +v40.1.1 +-------- + +* #1465: Fix regression with `egg_info` command when tagging is used. + + +v40.1.0 +------- + +* #1410: Deprecated ``upload`` and ``register`` commands. +* #1312: Introduced find_namespace_packages() to find PEP 420 namespace packages. +* #1420: Added find_namespace: directive to config parser. +* #1418: Solved race in when creating egg cache directories. +* #1450: Upgraded vendored PyParsing from 2.1.10 to 2.2.0. +* #1451: Upgraded vendored appdirs from 1.4.0 to 1.4.3. +* #1388: Fixed "Microsoft Visual C++ Build Tools" link in exception when Visual C++ not found. +* #1389: Added support for scripts which have unicode content. +* #1416: Moved several Python version checks over to using ``six.PY2`` and ``six.PY3``. +* #1441: Removed spurious executable permissions from files that don't need them. + + +v40.0.0 +------- + +* #1342: Drop support for Python 3.3. +* #1366: In package_index, fixed handling of encoded entities in URLs. +* #1383: In pkg_resources VendorImporter, avoid removing packages imported from the root. +* #1379: Minor doc fixes after actually using the new release process. +* #1385: Removed section on non-package data files. +* #1403: Fix developer's guide. +* #1404: Fix PEP 518 configuration: set build requirements in ``pyproject.toml`` to ``["wheel"]``. + + v39.2.0 ------- @@ -19,7 +58,7 @@ v39.2.0 after any ``distutils`` ``setup_keywords`` calls, allowing them to override values. * #1352: Added ``tox`` environment for documentation builds. -* #1354: Added ``towncrier`` for changelog managment. +* #1354: Added ``towncrier`` for changelog management. * #1355: Add PR template. * #1368: Fixed tests which failed without network connectivity. * #1369: Added unit tests for PEP 425 compatibility tags support. @@ -3171,6 +3210,37 @@ easy_install gracefully under Google App Engine (with an ``ImportError`` loading the C-based module, instead of getting a ``NameError``). + * Fixed ``win32.exe`` support for .pth files, so unnecessary directory nesting + is flattened out in the resulting egg. (There was a case-sensitivity + problem that affected some distributions, notably ``pywin32``.) + + * Prevent ``--help-commands`` and other junk from showing under Python 2.5 + when running ``easy_install --help``. + + * Fixed GUI scripts sometimes not executing on Windows + + * Fixed not picking up dependency links from recursive dependencies. + + * Only make ``.py``, ``.dll`` and ``.so`` files executable when unpacking eggs + + * Changes for Jython compatibility + + * Improved error message when a requirement is also a directory name, but the + specified directory is not a source package. + + * Fixed ``--allow-hosts`` option blocking ``file:`` URLs + + * Fixed HTTP SVN detection failing when the page title included a project + name (e.g. on SourceForge-hosted SVN) + + * Fix Jython script installation to handle ``#!`` lines better when + ``sys.executable`` is a script. + + * Removed use of deprecated ``md5`` module if ``hashlib`` is available + + * Keep site directories (e.g. ``site-packages``) from being included in + ``.pth`` files. + 0.6c7 ----- @@ -3181,6 +3251,11 @@ easy_install ``--root`` or ``--single-version-externally-managed``, due to the parent package not having the child package as an attribute. + * ``ftp:`` download URLs now work correctly. + + * The default ``--index-url`` is now ``https://pypi.python.org/simple``, to use + the Python Package Index's new simpler (and faster!) REST API. + 0.6c6 ----- @@ -3204,6 +3279,18 @@ easy_install * Fix ``find_packages()`` treating ``ez_setup`` and directories with ``.`` in their names as packages. + * EasyInstall no longer aborts the installation process if a URL it wants to + retrieve can't be downloaded, unless the URL is an actual package download. + Instead, it issues a warning and tries to keep going. + + * Fixed distutils-style scripts originally built on Windows having their line + endings doubled when installed on any platform. + + * Added ``--local-snapshots-ok`` flag, to allow building eggs from projects + installed using ``setup.py develop``. + + * Fixed not HTML-decoding URLs scraped from web pages + 0.6c5 ----- @@ -3213,6 +3300,9 @@ easy_install * Fix uploaded ``bdist_wininst`` packages being described as suitable for "any" version by Python 2.5, even if a ``--target-version`` was specified. + * Fixed ``.dll`` files on Cygwin not having executable permissions when an egg + is installed unzipped. + 0.6c4 ----- @@ -3242,11 +3332,34 @@ easy_install listed a namespace package ``foo.bar`` without explicitly listing ``foo`` as a namespace package. + * Added support for HTTP "Basic" authentication using ``http://user:pass@host`` + URLs. If a password-protected page contains links to the same host (and + protocol), those links will inherit the credentials used to access the + original page. + + * Removed all special support for Sourceforge mirrors, as Sourceforge's + mirror system now works well for non-browser downloads. + + * Fixed not recognizing ``win32.exe`` installers that included a custom + bitmap. + + * Fixed not allowing ``os.open()`` of paths outside the sandbox, even if they + are opened read-only (e.g. reading ``/dev/urandom`` for random numbers, as + is done by ``os.urandom()`` on some platforms). + + * Fixed a problem with ``.pth`` testing on Windows when ``sys.executable`` + has a space in it (e.g., the user installed Python to a ``Program Files`` + directory). + 0.6c3 ----- * Fixed breakages caused by Subversion 1.4's new "working copy" format + * You can once again use "python -m easy_install" with Python 2.4 and above. + + * Python 2.5 compatibility fixes added. + 0.6c2 ----- @@ -3257,6 +3370,19 @@ easy_install * Running ``setup.py develop`` on a setuptools-using project will now install setuptools if needed, instead of only downloading the egg. + * Windows script wrappers now support quoted arguments and arguments + containing spaces. (Patch contributed by Jim Fulton.) + + * The ``ez_setup.py`` script now actually works when you put a setuptools + ``.egg`` alongside it for bootstrapping an offline machine. + + * A writable installation directory on ``sys.path`` is no longer required to + download and extract a source distribution using ``--editable``. + + * Generated scripts now use ``-x`` on the ``#!`` line when ``sys.executable`` + contains non-ASCII characters, to prevent deprecation warnings about an + unspecified encoding when the script is run. + 0.6c1 ----- @@ -3280,6 +3406,9 @@ easy_install the version was overridden on the command line that built the source distribution.) + * EasyInstall now includes setuptools version information in the + ``User-Agent`` string sent to websites it visits. + 0.6b4 ----- @@ -3292,6 +3421,27 @@ easy_install * Fixed redundant warnings about missing ``README`` file(s); it should now appear only if you are actually a source distribution. + * Fix creating Python wrappers for non-Python scripts + + * Fix ``ftp://`` directory listing URLs from causing a crash when used in the + "Home page" or "Download URL" slots on PyPI. + + * Fix ``sys.path_importer_cache`` not being updated when an existing zipfile + or directory is deleted/overwritten. + + * Fix not recognizing HTML 404 pages from package indexes. + + * Allow ``file://`` URLs to be used as a package index. URLs that refer to + directories will use an internally-generated directory listing if there is + no ``index.html`` file in the directory. + + * Allow external links in a package index to be specified using + ``rel="homepage"`` or ``rel="download"``, without needing the old + PyPI-specific visible markup. + + * Suppressed warning message about possibly-misspelled project name, if an egg + or link for that project name has already been seen. + 0.6b3 ----- @@ -3302,6 +3452,28 @@ easy_install ``include_package_data`` and ``package_data`` are used to refer to the same files. + * Fix local ``--find-links`` eggs not being copied except with + ``--always-copy``. + + * Fix sometimes not detecting local packages installed outside of "site" + directories. + + * Fix mysterious errors during initial ``setuptools`` install, caused by + ``ez_setup`` trying to run ``easy_install`` twice, due to a code fallthru + after deleting the egg from which it's running. + +0.6b2 +----- + + * Don't install or update a ``site.py`` patch when installing to a + ``PYTHONPATH`` directory with ``--multi-version``, unless an + ``easy-install.pth`` file is already in use there. + + * Construct ``.pth`` file paths in such a way that installing an egg whose + name begins with ``import`` doesn't cause a syntax error. + + * Fixed a bogus warning message that wasn't updated since the 0.5 versions. + 0.6b1 ----- @@ -3309,6 +3481,21 @@ easy_install the name of a ``.py`` loader/wrapper. (Python's import machinery ignores this suffix when searching for an extension module.) + * Better ambiguity management: accept ``#egg`` name/version even if processing + what appears to be a correctly-named distutils file, and ignore ``.egg`` + files with no ``-``, since valid Python ``.egg`` files always have a version + number (but Scheme eggs often don't). + + * Support ``file://`` links to directories in ``--find-links``, so that + easy_install can build packages from local source checkouts. + + * Added automatic retry for Sourceforge mirrors. The new download process is + to first just try dl.sourceforge.net, then randomly select mirror IPs and + remove ones that fail, until something works. The removed IPs stay removed + for the remainder of the run. + + * Ignore bdist_dumb distributions when looking at download URLs. + 0.6a11 ------ @@ -3342,11 +3529,75 @@ easy_install 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. + * Process ``dependency_links.txt`` if found in a distribution, by adding the + URLs to the list for scanning. + + * Use relative paths in ``.pth`` files when eggs are being installed to the + same directory as the ``.pth`` file. This maximizes portability of the + target directory when building applications that contain eggs. + + * Added ``easy_install-N.N`` script(s) for convenience when using multiple + Python versions. + + * Added automatic handling of installation conflicts. Eggs are now shifted to + the front of sys.path, in an order consistent with where they came from, + making EasyInstall seamlessly co-operate with system package managers. + + The ``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk`` options + are now no longer necessary, and will generate warnings at the end of a + run if you use them. + + * Don't recursively traverse subdirectories given to ``--find-links``. + 0.6a10 ------ * Fixed the ``develop`` command ignoring ``--find-links``. + * Added exhaustive testing of the install directory, including a spawn test + for ``.pth`` file support, and directory writability/existence checks. This + should virtually eliminate the need to set or configure ``--site-dirs``. + + * Added ``--prefix`` option for more do-what-I-mean-ishness in the absence of + RTFM-ing. :) + + * Enhanced ``PYTHONPATH`` support so that you don't have to put any eggs on it + manually to make it work. ``--multi-version`` is no longer a silent + default; you must explicitly use it if installing to a non-PYTHONPATH, + non-"site" directory. + + * Expand ``$variables`` used in the ``--site-dirs``, ``--build-directory``, + ``--install-dir``, and ``--script-dir`` options, whether on the command line + or in configuration files. + + * Improved SourceForge mirror processing to work faster and be less affected + by transient HTML changes made by SourceForge. + + * PyPI searches now use the exact spelling of requirements specified on the + command line or in a project's ``install_requires``. Previously, a + normalized form of the name was used, which could lead to unnecessary + full-index searches when a project's name had an underscore (``_``) in it. + + * EasyInstall can now download bare ``.py`` files and wrap them in an egg, + as long as you include an ``#egg=name-version`` suffix on the URL, or if + the ``.py`` file is listed as the "Download URL" on the project's PyPI page. + This allows third parties to "package" trivial Python modules just by + linking to them (e.g. from within their own PyPI page or download links + page). + + * The ``--always-copy`` option now skips "system" and "development" eggs since + they can't be reliably copied. Note that this may cause EasyInstall to + choose an older version of a package than what you expected, or it may cause + downloading and installation of a fresh version of what's already installed. + + * The ``--find-links`` option previously scanned all supplied URLs and + directories as early as possible, but now only directories and direct + archive links are scanned immediately. URLs are not retrieved unless a + package search was already going to go online due to a package not being + available locally, or due to the use of the ``--update`` or ``-U`` option. + + * Fixed the annoying ``--help-commands`` wart. + 0.6a9 ----- @@ -3397,6 +3648,22 @@ easy_install and entry-point wrapper scripts), and ``easy_install`` can turn the .exe back into an ``.egg`` file or directory and install it as such. + * Fixed ``.pth`` file processing picking up nested eggs (i.e. ones inside + "baskets") when they weren't explicitly listed in the ``.pth`` file. + + * If more than one URL appears to describe the exact same distribution, prefer + the shortest one. This helps to avoid "table of contents" CGI URLs like the + ones on effbot.org. + + * Quote arguments to python.exe (including python's path) to avoid problems + when Python (or a script) is installed in a directory whose name contains + spaces on Windows. + + * Support full roundtrip translation of eggs to and from ``bdist_wininst`` + format. Running ``bdist_wininst`` on a setuptools-based package wraps the + egg in an .exe that will safely install it as an egg (i.e., with metadata + and entry-point wrapper scripts), and ``easy_install`` can turn the .exe + back into an ``.egg`` file or directory and install it as such. 0.6a8 ----- @@ -3425,6 +3692,45 @@ easy_install 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). + * Update for changed SourceForge mirror format + + * Fixed not installing dependencies for some packages fetched via Subversion + + * Fixed dependency installation with ``--always-copy`` not using the same + dependency resolution procedure as other operations. + + * Fixed not fully removing temporary directories on Windows, if a Subversion + checkout left read-only files behind + + * Fixed some problems building extensions when Pyrex was installed, especially + with Python 2.4 and/or packages using SWIG. + +0.6a7 +----- + + * Fixed not being able to install Windows script wrappers using Python 2.3 + +0.6a6 +----- + + * Added support for "traditional" PYTHONPATH-based non-root installation, and + also the convenient ``virtual-python.py`` script, based on a contribution + by Ian Bicking. The setuptools egg now contains a hacked ``site`` module + that makes the PYTHONPATH-based approach work with .pth files, so that you + can get the full EasyInstall feature set on such installations. + + * Added ``--no-deps`` and ``--allow-hosts`` options. + + * Improved Windows ``.exe`` script wrappers so that the script can have the + same name as a module without confusing Python. + + * Changed dependency processing so that it's breadth-first, allowing a + depender's preferences to override those of a dependee, to prevent conflicts + when a lower version is acceptable to the dependee, but not the depender. + Also, ensure that currently installed/selected packages aren't given + precedence over ones desired by a package being installed, which could + cause conflict errors. + 0.6a5 ----- @@ -3437,6 +3743,17 @@ easy_install on Windows and other platforms. (The special handling is only for Windows; other platforms are treated the same as for ``console_scripts``.) + * Improved error message when trying to use old ways of running + ``easy_install``. Removed the ability to run via ``python -m`` or by + running ``easy_install.py``; ``easy_install`` is the command to run on all + supported platforms. + + * Improved wrapper script generation and runtime initialization so that a + VersionConflict doesn't occur if you later install a competing version of a + needed package as the default version of that package. + + * Fixed a problem parsing version numbers in ``#egg=`` links. + 0.6a2 ----- @@ -3445,6 +3762,15 @@ easy_install scripts get an ``.exe`` wrapper so you can just type their name. On other platforms, the scripts are written without a file extension. + * EasyInstall can now install "console_scripts" defined by packages that use + ``setuptools`` and define appropriate entry points. On Windows, console + scripts get an ``.exe`` wrapper so you can just type their name. On other + platforms, the scripts are installed without a file extension. + + * Using ``python -m easy_install`` or running ``easy_install.py`` is now + DEPRECATED, since an ``easy_install`` wrapper is now available on all + platforms. + 0.6a1 ----- @@ -3490,6 +3816,55 @@ easy_install or documented, and never would have worked without EasyInstall - which it pre-dated and was never compatible with. + * EasyInstall now does MD5 validation of downloads from PyPI, or from any link + that has an "#md5=..." trailer with a 32-digit lowercase hex md5 digest. + + * EasyInstall now handles symlinks in target directories by removing the link, + rather than attempting to overwrite the link's destination. This makes it + easier to set up an alternate Python "home" directory (as described in + the Non-Root Installation section of the docs). + + * Added support for handling MacOS platform information in ``.egg`` filenames, + based on a contribution by Kevin Dangoor. You may wish to delete and + reinstall any eggs whose filename includes "darwin" and "Power_Macintosh", + because the format for this platform information has changed so that minor + OS X upgrades (such as 10.4.1 to 10.4.2) do not cause eggs built with a + previous OS version to become obsolete. + + * easy_install's dependency processing algorithms have changed. When using + ``--always-copy``, it now ensures that dependencies are copied too. When + not using ``--always-copy``, it tries to use a single resolution loop, + rather than recursing. + + * Fixed installing extra ``.pyc`` or ``.pyo`` files for scripts with ``.py`` + extensions. + + * Added ``--site-dirs`` option to allow adding custom "site" directories. + Made ``easy-install.pth`` work in platform-specific alternate site + directories (e.g. ``~/Library/Python/2.x/site-packages`` on Mac OS X). + + * If you manually delete the current version of a package, the next run of + EasyInstall against the target directory will now remove the stray entry + from the ``easy-install.pth`` file. + + * EasyInstall now recognizes URLs with a ``#egg=project_name`` fragment ID + as pointing to the named project's source checkout. Such URLs have a lower + match precedence than any other kind of distribution, so they'll only be + used if they have a higher version number than any other available + distribution, or if you use the ``--editable`` option. The ``#egg`` + fragment can contain a version if it's formatted as ``#egg=proj-ver``, + where ``proj`` is the project name, and ``ver`` is the version number. You + *must* use the format for these values that the ``bdist_egg`` command uses; + i.e., all non-alphanumeric runs must be condensed to single underscore + characters. + + * Added the ``--editable`` option; see Editing and Viewing Source Packages + in the docs. Also, slightly changed the behavior of the + ``--build-directory`` option. + + * Fixed the setup script sandbox facility not recognizing certain paths as + valid on case-insensitive platforms. + 0.5a12 ------ @@ -3497,12 +3872,28 @@ easy_install ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't handle ``-m`` on zipped modules. + * Fix ``python -m easy_install`` not working due to setuptools being installed + as a zipfile. Update safety scanner to check for modules that might be used + as ``python -m`` scripts. + + * Misc. fixes for win32.exe support, including changes to support Python 2.4's + changed ``bdist_wininst`` format. + 0.5a11 ------ * Fix breakage of the "develop" command that was caused by the addition of ``--always-unzip`` to the ``easy_install`` command. +0.5a10 +------ + + * Put the ``easy_install`` module back in as a module, as it's needed for + ``python -m`` to run it! + + * Allow ``--find-links/-f`` to accept local directories or filenames as well + as URLs. + 0.5a9 ----- @@ -3537,6 +3928,31 @@ easy_install * Fixed the swapped ``-d`` and ``-b`` options of ``bdist_egg``. + * EasyInstall now automatically detects when an "unmanaged" package or + module is going to be on ``sys.path`` ahead of a package you're installing, + thereby preventing the newer version from being imported. By default, it + will abort installation to alert you of the problem, but there are also + new options (``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk``) + available to change the default behavior. (Note: this new feature doesn't + take effect for egg files that were built with older ``setuptools`` + versions, because they lack the new metadata file required to implement it.) + + * The ``easy_install`` distutils command now uses ``DistutilsError`` as its + base error type for errors that should just issue a message to stderr and + exit the program without a traceback. + + * EasyInstall can now be given a path to a directory containing a setup + script, and it will attempt to build and install the package there. + + * EasyInstall now performs a safety analysis on module contents to determine + whether a package is likely to run in zipped form, and displays + information about what modules may be doing introspection that would break + when running as a zipfile. + + * Added the ``--always-unzip/-Z`` option, to force unzipping of packages that + would ordinarily be considered safe to unzip, and changed the meaning of + ``--zip-ok/-z`` to "always leave everything zipped". + 0.5a8 ----- @@ -3564,6 +3980,9 @@ easy_install * Added a "setopt" command that sets a single option in a specified distutils configuration file. + * There is now a separate documentation page for setuptools; revision + history that's not specific to EasyInstall has been moved to that page. + 0.5a7 ----- @@ -3631,6 +4050,39 @@ easy_install * Setup scripts using setuptools now always install using ``easy_install`` internally, for ease of uninstallation and upgrading. + * Added ``--always-copy/-a`` option to always copy needed packages to the + installation directory, even if they're already present elsewhere on + sys.path. (In previous versions, this was the default behavior, but now + you must request it.) + + * Added ``--upgrade/-U`` option to force checking PyPI for latest available + version(s) of all packages requested by name and version, even if a matching + version is available locally. + + * Added automatic installation of dependencies declared by a distribution + being installed. These dependencies must be listed in the distribution's + ``EGG-INFO`` directory, so the distribution has to have declared its + dependencies by using setuptools. If a package has requirements it didn't + declare, you'll still have to deal with them yourself. (E.g., by asking + EasyInstall to find and install them.) + + * Added the ``--record`` option to ``easy_install`` for the benefit of tools + that run ``setup.py install --record=filename`` on behalf of another + packaging system.) + +0.5a3 +----- + + * Fixed not setting script permissions to allow execution. + + * Improved sandboxing so that setup scripts that want a temporary directory + (e.g. pychecker) can still run in the sandbox. + +0.5a2 +----- + + * Fix stupid stupid refactoring-at-the-last-minute typos. :( + 0.5a1 ----- @@ -3645,6 +4097,29 @@ easy_install from setuptools import setup # etc... + * Added support for converting ``.win32.exe`` installers to eggs on the fly. + EasyInstall will now recognize such files by name and install them. + + * Fixed a problem with picking the "best" version to install (versions were + being sorted as strings, rather than as parsed values) + +0.4a4 +----- + + * Added support for the distutils "verbose/quiet" and "dry-run" options, as + well as the "optimize" flag. + + * Support downloading packages that were uploaded to PyPI (by scanning all + links on package pages, not just the homepage/download links). + +0.4a3 +----- + + * Add progress messages to the search/download process so that you can tell + what URLs it's reading to find download links. (Hopefully, this will help + people report out-of-date and broken links to package authors, and to tell + when they've asked for a package that doesn't exist.) + 0.4a2 ----- @@ -3672,6 +4147,44 @@ easy_install their ``command_consumes_arguments`` attribute to ``True`` in order to receive an ``args`` option containing the rest of the command line. + * Added support for installing scripts + + * Added support for setting options via distutils configuration files, and + using distutils' default options as a basis for EasyInstall's defaults. + + * Renamed ``--scan-url/-s`` to ``--find-links/-f`` to free up ``-s`` for the + script installation directory option. + + * Use ``urllib2`` instead of ``urllib``, to allow use of ``https:`` URLs if + Python includes SSL support. + +0.4a1 +----- + + * Added ``--scan-url`` and ``--index-url`` options, to scan download pages + and search PyPI for needed packages. + +0.3a4 +----- + + * Restrict ``--build-directory=DIR/-b DIR`` option to only be used with single + URL installs, to avoid running the wrong setup.py. + +0.3a3 +----- + + * Added ``--build-directory=DIR/-b DIR`` option. + + * Added "installation report" that explains how to use 'require()' when doing + a multiversion install or alternate installation directory. + + * Added SourceForge mirror auto-select (Contributed by Ian Bicking) + + * Added "sandboxing" that stops a setup script from running if it attempts to + write to the filesystem outside of the build area + + * Added more workarounds for packages with quirky ``install_data`` hacks + 0.3a2 ----- @@ -3679,6 +4192,9 @@ easy_install with a subversion revision number, the current date, or an explicit tag value. Run ``setup.py bdist_egg --help`` to get more information. + * Added subversion download support for ``svn:`` and ``svn+`` URLs, as well as + automatic recognition of HTTP subversion URLs (Contributed by Ian Bicking) + * Misc. bug fixes 0.3a1 diff --git a/README.rst b/README.rst index 8505c551..a9bed521 100755..100644 --- a/README.rst +++ b/README.rst @@ -15,6 +15,9 @@ .. image:: https://img.shields.io/pypi/pyversions/setuptools.svg +.. image:: https://tidelift.com/badges/github/pypa/setuptools + :target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme + See the `Installation Instructions <https://packaging.python.org/installing/>`_ in the Python Packaging User's Guide for instructions on installing, upgrading, and uninstalling diff --git a/changelog.d/.gitignore b/changelog.d/.gitignore new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/changelog.d/.gitignore diff --git a/changelog.d/1324.change.rst b/changelog.d/1324.change.rst new file mode 100644 index 00000000..5c97dd2a --- /dev/null +++ b/changelog.d/1324.change.rst @@ -0,0 +1 @@ +Make safe_name compliant with PEP 503. diff --git a/changelog.d/1342.breaking.rst b/changelog.d/1342.breaking.rst deleted file mode 100644 index 9756e313..00000000 --- a/changelog.d/1342.breaking.rst +++ /dev/null @@ -1 +0,0 @@ -Drop support for Python 3.3. diff --git a/changelog.d/1366.change.rst b/changelog.d/1366.change.rst deleted file mode 100644 index f70e2a2e..00000000 --- a/changelog.d/1366.change.rst +++ /dev/null @@ -1 +0,0 @@ -In package_index, fixed handling of encoded entities in URLs. diff --git a/changelog.d/1379.doc.rst b/changelog.d/1379.doc.rst deleted file mode 100644 index ca017719..00000000 --- a/changelog.d/1379.doc.rst +++ /dev/null @@ -1 +0,0 @@ -Minor doc fixes after actually using the new release process. diff --git a/changelog.d/1385.doc.rst b/changelog.d/1385.doc.rst deleted file mode 100644 index 7bd88e8f..00000000 --- a/changelog.d/1385.doc.rst +++ /dev/null @@ -1 +0,0 @@ -Removed section on non-package data files. diff --git a/changelog.d/1427.change.rst b/changelog.d/1427.change.rst new file mode 100644 index 00000000..86260235 --- /dev/null +++ b/changelog.d/1427.change.rst @@ -0,0 +1 @@ +Set timestamp of ``.egg-info`` directory whenever ``egg_info`` command is run. diff --git a/changelog.d/1474.change.rst b/changelog.d/1474.change.rst new file mode 100644 index 00000000..9d40e785 --- /dev/null +++ b/changelog.d/1474.change.rst @@ -0,0 +1 @@ +``build_meta.get_requires_for_build_sdist`` now does not include the ``wheel`` package anymore diff --git a/changelog.d/1479.misc.rst b/changelog.d/1479.misc.rst new file mode 100644 index 00000000..b04b0ce1 --- /dev/null +++ b/changelog.d/1479.misc.rst @@ -0,0 +1 @@ +Remove internal use of six.binary_type diff --git a/changelog.d/1486.change.rst b/changelog.d/1486.change.rst new file mode 100644 index 00000000..561784fb --- /dev/null +++ b/changelog.d/1486.change.rst @@ -0,0 +1 @@ +Suppress warnings in pkg_resources.handle_ns. diff --git a/docs/developer-guide.txt b/docs/developer-guide.txt index 8a967f6c..c011491a 100644 --- a/docs/developer-guide.txt +++ b/docs/developer-guide.txt @@ -89,31 +89,6 @@ code changes. See the following for an example news fragment: $ cat changelog.d/1288.change.rst Add support for maintainer in PKG-INFO ------------ -Source Code ------------ - -Grab the code at Github:: - - $ git clone https://github.com/pypa/setuptools - -If you want to contribute changes, we recommend you fork the repository on -Github, commit the changes to your repository, and then make a pull request -on Github. If you make some changes, don't forget to: - -- add a note in CHANGES.rst - -Please commit all changes in the 'master' branch against the latest available -commit or for bug-fixes, against an earlier commit or release in which the -bug occurred. - -If you find yourself working on more than one issue at a time, Setuptools -generally prefers Git-style branches, so use Mercurial bookmarks or Git -branches or multiple forks to maintain separate efforts. - -The Continuous Integration tests that validate every release are run -from this repository. - ------- Testing ------- diff --git a/docs/easy_install.txt b/docs/easy_install.txt index f426b6ff..41d182e0 100644 --- a/docs/easy_install.txt +++ b/docs/easy_install.txt @@ -2,6 +2,12 @@ Easy Install ============ +..warning:: + Easy Install is deprecated. Do not use it. Instead use pip. If + you think you need Easy Install, please reach out to the PyPA + team (a ticket to pip or setuptools is fine), describing your + use-case. + Easy Install is a python module (``easy_install``) bundled with ``setuptools`` that lets you automatically download, build, install, and manage Python packages. @@ -17,7 +23,7 @@ bug -- and then do so via list discussion first.) (Also, if you'd like to learn about how you can use ``setuptools`` to make your own packages work better with EasyInstall, or provide EasyInstall-like features without requiring your users to use EasyInstall directly, you'll probably want -to check out the full `setuptools`_ documentation as well.) +to check out the full documentation as well.) .. contents:: **Table of Contents** @@ -1077,546 +1083,3 @@ EasyInstall to be able to look up and download packages: 8. If a package index is accessed via a ``file://`` URL, then EasyInstall will automatically use ``index.html`` files, if present, when trying to read a directory with a trailing ``/`` on the URL. - - -Backward Compatibility -~~~~~~~~~~~~~~~~~~~~~~ - -Package indexes that wish to support setuptools versions prior to 0.6b4 should -also follow these rules: - -* Homepage and download links must be preceded with ``"<th>Home Page"`` or - ``"<th>Download URL"``, in addition to (or instead of) the ``rel=""`` - attributes on the actual links. These marker strings do not need to be - visible, or uncommented, however! For example, the following is a valid - homepage link that will work with any version of setuptools:: - - <li> - <strong>Home Page:</strong> - <!-- <th>Home Page --> - <a rel="homepage" href="http://sqlobject.org">http://sqlobject.org</a> - </li> - - Even though the marker string is in an HTML comment, older versions of - EasyInstall will still "see" it and know that the link that follows is the - project's home page URL. - -* The pages described by paragraph 3(b) of the preceding section *must* - contain the string ``"Index of Packages</title>"`` somewhere in their text. - This can be inside of an HTML comment, if desired, and it can be anywhere - in the page. (Note: this string MUST NOT appear on normal project pages, as - described in paragraphs 2 and 3(a)!) - -In addition, for compatibility with PyPI versions that do not use ``#md5=`` -fragment IDs, EasyInstall uses the following regular expression to match PyPI's -displayed MD5 info (broken onto two lines for readability):: - - <a href="([^"#]+)">([^<]+)</a>\n\s+\(<a href="[^?]+\?:action=show_md5 - &digest=([0-9a-f]{32})">md5</a>\) - -History -======= - -0.6c9 - * Fixed ``win32.exe`` support for .pth files, so unnecessary directory nesting - is flattened out in the resulting egg. (There was a case-sensitivity - problem that affected some distributions, notably ``pywin32``.) - - * Prevent ``--help-commands`` and other junk from showing under Python 2.5 - when running ``easy_install --help``. - - * Fixed GUI scripts sometimes not executing on Windows - - * Fixed not picking up dependency links from recursive dependencies. - - * Only make ``.py``, ``.dll`` and ``.so`` files executable when unpacking eggs - - * Changes for Jython compatibility - - * Improved error message when a requirement is also a directory name, but the - specified directory is not a source package. - - * Fixed ``--allow-hosts`` option blocking ``file:`` URLs - - * Fixed HTTP SVN detection failing when the page title included a project - name (e.g. on SourceForge-hosted SVN) - - * Fix Jython script installation to handle ``#!`` lines better when - ``sys.executable`` is a script. - - * Removed use of deprecated ``md5`` module if ``hashlib`` is available - - * Keep site directories (e.g. ``site-packages``) from being included in - ``.pth`` files. - -0.6c7 - * ``ftp:`` download URLs now work correctly. - - * The default ``--index-url`` is now ``https://pypi.python.org/simple``, to use - the Python Package Index's new simpler (and faster!) REST API. - -0.6c6 - * EasyInstall no longer aborts the installation process if a URL it wants to - retrieve can't be downloaded, unless the URL is an actual package download. - Instead, it issues a warning and tries to keep going. - - * Fixed distutils-style scripts originally built on Windows having their line - endings doubled when installed on any platform. - - * Added ``--local-snapshots-ok`` flag, to allow building eggs from projects - installed using ``setup.py develop``. - - * Fixed not HTML-decoding URLs scraped from web pages - -0.6c5 - * Fixed ``.dll`` files on Cygwin not having executable permissions when an egg - is installed unzipped. - -0.6c4 - * Added support for HTTP "Basic" authentication using ``http://user:pass@host`` - URLs. If a password-protected page contains links to the same host (and - protocol), those links will inherit the credentials used to access the - original page. - - * Removed all special support for Sourceforge mirrors, as Sourceforge's - mirror system now works well for non-browser downloads. - - * Fixed not recognizing ``win32.exe`` installers that included a custom - bitmap. - - * Fixed not allowing ``os.open()`` of paths outside the sandbox, even if they - are opened read-only (e.g. reading ``/dev/urandom`` for random numbers, as - is done by ``os.urandom()`` on some platforms). - - * Fixed a problem with ``.pth`` testing on Windows when ``sys.executable`` - has a space in it (e.g., the user installed Python to a ``Program Files`` - directory). - -0.6c3 - * You can once again use "python -m easy_install" with Python 2.4 and above. - - * Python 2.5 compatibility fixes added. - -0.6c2 - * Windows script wrappers now support quoted arguments and arguments - containing spaces. (Patch contributed by Jim Fulton.) - - * The ``ez_setup.py`` script now actually works when you put a setuptools - ``.egg`` alongside it for bootstrapping an offline machine. - - * A writable installation directory on ``sys.path`` is no longer required to - download and extract a source distribution using ``--editable``. - - * Generated scripts now use ``-x`` on the ``#!`` line when ``sys.executable`` - contains non-ASCII characters, to prevent deprecation warnings about an - unspecified encoding when the script is run. - -0.6c1 - * EasyInstall now includes setuptools version information in the - ``User-Agent`` string sent to websites it visits. - -0.6b4 - * Fix creating Python wrappers for non-Python scripts - - * Fix ``ftp://`` directory listing URLs from causing a crash when used in the - "Home page" or "Download URL" slots on PyPI. - - * Fix ``sys.path_importer_cache`` not being updated when an existing zipfile - or directory is deleted/overwritten. - - * Fix not recognizing HTML 404 pages from package indexes. - - * Allow ``file://`` URLs to be used as a package index. URLs that refer to - directories will use an internally-generated directory listing if there is - no ``index.html`` file in the directory. - - * Allow external links in a package index to be specified using - ``rel="homepage"`` or ``rel="download"``, without needing the old - PyPI-specific visible markup. - - * Suppressed warning message about possibly-misspelled project name, if an egg - or link for that project name has already been seen. - -0.6b3 - * Fix local ``--find-links`` eggs not being copied except with - ``--always-copy``. - - * Fix sometimes not detecting local packages installed outside of "site" - directories. - - * Fix mysterious errors during initial ``setuptools`` install, caused by - ``ez_setup`` trying to run ``easy_install`` twice, due to a code fallthru - after deleting the egg from which it's running. - -0.6b2 - * Don't install or update a ``site.py`` patch when installing to a - ``PYTHONPATH`` directory with ``--multi-version``, unless an - ``easy-install.pth`` file is already in use there. - - * Construct ``.pth`` file paths in such a way that installing an egg whose - name begins with ``import`` doesn't cause a syntax error. - - * Fixed a bogus warning message that wasn't updated since the 0.5 versions. - -0.6b1 - * Better ambiguity management: accept ``#egg`` name/version even if processing - what appears to be a correctly-named distutils file, and ignore ``.egg`` - files with no ``-``, since valid Python ``.egg`` files always have a version - number (but Scheme eggs often don't). - - * Support ``file://`` links to directories in ``--find-links``, so that - easy_install can build packages from local source checkouts. - - * Added automatic retry for Sourceforge mirrors. The new download process is - to first just try dl.sourceforge.net, then randomly select mirror IPs and - remove ones that fail, until something works. The removed IPs stay removed - for the remainder of the run. - - * Ignore bdist_dumb distributions when looking at download URLs. - -0.6a11 - * Process ``dependency_links.txt`` if found in a distribution, by adding the - URLs to the list for scanning. - - * Use relative paths in ``.pth`` files when eggs are being installed to the - same directory as the ``.pth`` file. This maximizes portability of the - target directory when building applications that contain eggs. - - * Added ``easy_install-N.N`` script(s) for convenience when using multiple - Python versions. - - * Added automatic handling of installation conflicts. Eggs are now shifted to - the front of sys.path, in an order consistent with where they came from, - making EasyInstall seamlessly co-operate with system package managers. - - The ``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk`` options - are now no longer necessary, and will generate warnings at the end of a - run if you use them. - - * Don't recursively traverse subdirectories given to ``--find-links``. - -0.6a10 - * Added exhaustive testing of the install directory, including a spawn test - for ``.pth`` file support, and directory writability/existence checks. This - should virtually eliminate the need to set or configure ``--site-dirs``. - - * Added ``--prefix`` option for more do-what-I-mean-ishness in the absence of - RTFM-ing. :) - - * Enhanced ``PYTHONPATH`` support so that you don't have to put any eggs on it - manually to make it work. ``--multi-version`` is no longer a silent - default; you must explicitly use it if installing to a non-PYTHONPATH, - non-"site" directory. - - * Expand ``$variables`` used in the ``--site-dirs``, ``--build-directory``, - ``--install-dir``, and ``--script-dir`` options, whether on the command line - or in configuration files. - - * Improved SourceForge mirror processing to work faster and be less affected - by transient HTML changes made by SourceForge. - - * PyPI searches now use the exact spelling of requirements specified on the - command line or in a project's ``install_requires``. Previously, a - normalized form of the name was used, which could lead to unnecessary - full-index searches when a project's name had an underscore (``_``) in it. - - * EasyInstall can now download bare ``.py`` files and wrap them in an egg, - as long as you include an ``#egg=name-version`` suffix on the URL, or if - the ``.py`` file is listed as the "Download URL" on the project's PyPI page. - This allows third parties to "package" trivial Python modules just by - linking to them (e.g. from within their own PyPI page or download links - page). - - * The ``--always-copy`` option now skips "system" and "development" eggs since - they can't be reliably copied. Note that this may cause EasyInstall to - choose an older version of a package than what you expected, or it may cause - downloading and installation of a fresh version of what's already installed. - - * The ``--find-links`` option previously scanned all supplied URLs and - directories as early as possible, but now only directories and direct - archive links are scanned immediately. URLs are not retrieved unless a - package search was already going to go online due to a package not being - available locally, or due to the use of the ``--update`` or ``-U`` option. - - * Fixed the annoying ``--help-commands`` wart. - -0.6a9 - * Fixed ``.pth`` file processing picking up nested eggs (i.e. ones inside - "baskets") when they weren't explicitly listed in the ``.pth`` file. - - * If more than one URL appears to describe the exact same distribution, prefer - the shortest one. This helps to avoid "table of contents" CGI URLs like the - ones on effbot.org. - - * Quote arguments to python.exe (including python's path) to avoid problems - when Python (or a script) is installed in a directory whose name contains - spaces on Windows. - - * Support full roundtrip translation of eggs to and from ``bdist_wininst`` - format. Running ``bdist_wininst`` on a setuptools-based package wraps the - egg in an .exe that will safely install it as an egg (i.e., with metadata - and entry-point wrapper scripts), and ``easy_install`` can turn the .exe - back into an ``.egg`` file or directory and install it as such. - -0.6a8 - * Update for changed SourceForge mirror format - - * Fixed not installing dependencies for some packages fetched via Subversion - - * Fixed dependency installation with ``--always-copy`` not using the same - dependency resolution procedure as other operations. - - * Fixed not fully removing temporary directories on Windows, if a Subversion - checkout left read-only files behind - - * Fixed some problems building extensions when Pyrex was installed, especially - with Python 2.4 and/or packages using SWIG. - -0.6a7 - * Fixed not being able to install Windows script wrappers using Python 2.3 - -0.6a6 - * Added support for "traditional" PYTHONPATH-based non-root installation, and - also the convenient ``virtual-python.py`` script, based on a contribution - by Ian Bicking. The setuptools egg now contains a hacked ``site`` module - that makes the PYTHONPATH-based approach work with .pth files, so that you - can get the full EasyInstall feature set on such installations. - - * Added ``--no-deps`` and ``--allow-hosts`` options. - - * Improved Windows ``.exe`` script wrappers so that the script can have the - same name as a module without confusing Python. - - * Changed dependency processing so that it's breadth-first, allowing a - depender's preferences to override those of a dependee, to prevent conflicts - when a lower version is acceptable to the dependee, but not the depender. - Also, ensure that currently installed/selected packages aren't given - precedence over ones desired by a package being installed, which could - cause conflict errors. - -0.6a3 - * Improved error message when trying to use old ways of running - ``easy_install``. Removed the ability to run via ``python -m`` or by - running ``easy_install.py``; ``easy_install`` is the command to run on all - supported platforms. - - * Improved wrapper script generation and runtime initialization so that a - VersionConflict doesn't occur if you later install a competing version of a - needed package as the default version of that package. - - * Fixed a problem parsing version numbers in ``#egg=`` links. - -0.6a2 - * EasyInstall can now install "console_scripts" defined by packages that use - ``setuptools`` and define appropriate entry points. On Windows, console - scripts get an ``.exe`` wrapper so you can just type their name. On other - platforms, the scripts are installed without a file extension. - - * Using ``python -m easy_install`` or running ``easy_install.py`` is now - DEPRECATED, since an ``easy_install`` wrapper is now available on all - platforms. - -0.6a1 - * EasyInstall now does MD5 validation of downloads from PyPI, or from any link - that has an "#md5=..." trailer with a 32-digit lowercase hex md5 digest. - - * EasyInstall now handles symlinks in target directories by removing the link, - rather than attempting to overwrite the link's destination. This makes it - easier to set up an alternate Python "home" directory (as described above in - the `Non-Root Installation`_ section). - - * Added support for handling MacOS platform information in ``.egg`` filenames, - based on a contribution by Kevin Dangoor. You may wish to delete and - reinstall any eggs whose filename includes "darwin" and "Power_Macintosh", - because the format for this platform information has changed so that minor - OS X upgrades (such as 10.4.1 to 10.4.2) do not cause eggs built with a - previous OS version to become obsolete. - - * easy_install's dependency processing algorithms have changed. When using - ``--always-copy``, it now ensures that dependencies are copied too. When - not using ``--always-copy``, it tries to use a single resolution loop, - rather than recursing. - - * Fixed installing extra ``.pyc`` or ``.pyo`` files for scripts with ``.py`` - extensions. - - * Added ``--site-dirs`` option to allow adding custom "site" directories. - Made ``easy-install.pth`` work in platform-specific alternate site - directories (e.g. ``~/Library/Python/2.x/site-packages`` on Mac OS X). - - * If you manually delete the current version of a package, the next run of - EasyInstall against the target directory will now remove the stray entry - from the ``easy-install.pth`` file. - - * EasyInstall now recognizes URLs with a ``#egg=project_name`` fragment ID - as pointing to the named project's source checkout. Such URLs have a lower - match precedence than any other kind of distribution, so they'll only be - used if they have a higher version number than any other available - distribution, or if you use the ``--editable`` option. The ``#egg`` - fragment can contain a version if it's formatted as ``#egg=proj-ver``, - where ``proj`` is the project name, and ``ver`` is the version number. You - *must* use the format for these values that the ``bdist_egg`` command uses; - i.e., all non-alphanumeric runs must be condensed to single underscore - characters. - - * Added the ``--editable`` option; see `Editing and Viewing Source Packages`_ - above for more info. Also, slightly changed the behavior of the - ``--build-directory`` option. - - * Fixed the setup script sandbox facility not recognizing certain paths as - valid on case-insensitive platforms. - -0.5a12 - * Fix ``python -m easy_install`` not working due to setuptools being installed - as a zipfile. Update safety scanner to check for modules that might be used - as ``python -m`` scripts. - - * Misc. fixes for win32.exe support, including changes to support Python 2.4's - changed ``bdist_wininst`` format. - -0.5a10 - * Put the ``easy_install`` module back in as a module, as it's needed for - ``python -m`` to run it! - - * Allow ``--find-links/-f`` to accept local directories or filenames as well - as URLs. - -0.5a9 - * EasyInstall now automatically detects when an "unmanaged" package or - module is going to be on ``sys.path`` ahead of a package you're installing, - thereby preventing the newer version from being imported. By default, it - will abort installation to alert you of the problem, but there are also - new options (``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk``) - available to change the default behavior. (Note: this new feature doesn't - take effect for egg files that were built with older ``setuptools`` - versions, because they lack the new metadata file required to implement it.) - - * The ``easy_install`` distutils command now uses ``DistutilsError`` as its - base error type for errors that should just issue a message to stderr and - exit the program without a traceback. - - * EasyInstall can now be given a path to a directory containing a setup - script, and it will attempt to build and install the package there. - - * EasyInstall now performs a safety analysis on module contents to determine - whether a package is likely to run in zipped form, and displays - information about what modules may be doing introspection that would break - when running as a zipfile. - - * Added the ``--always-unzip/-Z`` option, to force unzipping of packages that - would ordinarily be considered safe to unzip, and changed the meaning of - ``--zip-ok/-z`` to "always leave everything zipped". - -0.5a8 - * There is now a separate documentation page for `setuptools`_; revision - history that's not specific to EasyInstall has been moved to that page. - - .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools - -0.5a5 - * Made ``easy_install`` a standard ``setuptools`` command, moving it from - the ``easy_install`` module to ``setuptools.command.easy_install``. Note - that if you were importing or extending it, you must now change your imports - accordingly. ``easy_install.py`` is still installed as a script, but not as - a module. - -0.5a4 - * Added ``--always-copy/-a`` option to always copy needed packages to the - installation directory, even if they're already present elsewhere on - sys.path. (In previous versions, this was the default behavior, but now - you must request it.) - - * Added ``--upgrade/-U`` option to force checking PyPI for latest available - version(s) of all packages requested by name and version, even if a matching - version is available locally. - - * Added automatic installation of dependencies declared by a distribution - being installed. These dependencies must be listed in the distribution's - ``EGG-INFO`` directory, so the distribution has to have declared its - dependencies by using setuptools. If a package has requirements it didn't - declare, you'll still have to deal with them yourself. (E.g., by asking - EasyInstall to find and install them.) - - * Added the ``--record`` option to ``easy_install`` for the benefit of tools - that run ``setup.py install --record=filename`` on behalf of another - packaging system.) - -0.5a3 - * Fixed not setting script permissions to allow execution. - - * Improved sandboxing so that setup scripts that want a temporary directory - (e.g. pychecker) can still run in the sandbox. - -0.5a2 - * Fix stupid stupid refactoring-at-the-last-minute typos. :( - -0.5a1 - * Added support for converting ``.win32.exe`` installers to eggs on the fly. - EasyInstall will now recognize such files by name and install them. - - * Fixed a problem with picking the "best" version to install (versions were - being sorted as strings, rather than as parsed values) - -0.4a4 - * Added support for the distutils "verbose/quiet" and "dry-run" options, as - well as the "optimize" flag. - - * Support downloading packages that were uploaded to PyPI (by scanning all - links on package pages, not just the homepage/download links). - -0.4a3 - * Add progress messages to the search/download process so that you can tell - what URLs it's reading to find download links. (Hopefully, this will help - people report out-of-date and broken links to package authors, and to tell - when they've asked for a package that doesn't exist.) - -0.4a2 - * Added support for installing scripts - - * Added support for setting options via distutils configuration files, and - using distutils' default options as a basis for EasyInstall's defaults. - - * Renamed ``--scan-url/-s`` to ``--find-links/-f`` to free up ``-s`` for the - script installation directory option. - - * Use ``urllib2`` instead of ``urllib``, to allow use of ``https:`` URLs if - Python includes SSL support. - -0.4a1 - * Added ``--scan-url`` and ``--index-url`` options, to scan download pages - and search PyPI for needed packages. - -0.3a4 - * Restrict ``--build-directory=DIR/-b DIR`` option to only be used with single - URL installs, to avoid running the wrong setup.py. - -0.3a3 - * Added ``--build-directory=DIR/-b DIR`` option. - - * Added "installation report" that explains how to use 'require()' when doing - a multiversion install or alternate installation directory. - - * Added SourceForge mirror auto-select (Contributed by Ian Bicking) - - * Added "sandboxing" that stops a setup script from running if it attempts to - write to the filesystem outside of the build area - - * Added more workarounds for packages with quirky ``install_data`` hacks - -0.3a2 - * Added subversion download support for ``svn:`` and ``svn+`` URLs, as well as - automatic recognition of HTTP subversion URLs (Contributed by Ian Bicking) - - * Misc. bug fixes - -0.3a1 - * Initial release. - - -Future Plans -============ - -* Additional utilities to list/remove/verify packages -* Signature checking? SSL? Ability to suppress PyPI search? -* Display byte progress meter when downloading distributions and long pages? -* Redirect stdout/stderr to log during run_setup? diff --git a/docs/pkg_resources.txt b/docs/pkg_resources.txt index 18545f4b..0c9fb5f2 100644 --- a/docs/pkg_resources.txt +++ b/docs/pkg_resources.txt @@ -703,7 +703,7 @@ entry point group and look for entry points named "pre_process" and To advertise an entry point, a project needs to use ``setuptools`` and provide an ``entry_points`` argument to ``setup()`` in its setup script, so that the entry points will be included in the distribution's metadata. For more -details, see the ``setuptools`` documentation. (XXX link here to setuptools) +details, see the [``setuptools`` documentation](https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins). Each project distribution can advertise at most one entry point of a given name within the same entry point group. For example, a distutils extension diff --git a/docs/requirements.txt b/docs/requirements.txt index 2138c884..c6d594e8 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -sphinx +sphinx!=1.8.0 rst.linker>=1.9 jaraco.packaging>=3.2 diff --git a/docs/setuptools.txt b/docs/setuptools.txt index c82dc511..89f45bd8 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -48,8 +48,6 @@ Feature Highlights: * Command aliases - create project-specific, per-user, or site-wide shortcut names for commonly used commands and options -* PyPI upload support - upload your source distributions and eggs to PyPI - * Deploy your project in "development mode", such that it's available on ``sys.path``, yet can still be edited directly from its source checkout. @@ -59,6 +57,9 @@ Feature Highlights: * Create extensible applications and frameworks that automatically discover extensions, using simple "entry points" declared in a project's setup script. +* Full support for PEP 420 via ``find_namespace_packages()``, which is also backwards + compatible to the existing ``find_packages()`` for Python >= 3.3. + .. contents:: **Table of Contents** .. _ez_setup.py: `bootstrap module`_ @@ -107,11 +108,10 @@ As you can see, it doesn't take much to use setuptools in a project. Run that script in your project folder, alongside the Python packages you have developed. -Invoke that script to produce eggs, upload to -PyPI, and automatically include all packages in the directory where the -setup.py lives. See the `Command Reference`_ section below to see what -commands you can give to this setup script. For example, -to produce a source distribution, simply invoke:: +Invoke that script to produce distributions and automatically include all +packages in the directory where the setup.py lives. See the `Command +Reference`_ section below to see what commands you can give to this setup +script. For example, to produce a source distribution, simply invoke:: python setup.py sdist @@ -138,7 +138,7 @@ dependencies, and perhaps some data files and scripts:: 'hello': ['*.msg'], }, - # metadata for upload to PyPI + # metadata to display on PyPI author="Me", author_email="me@example.com", description="This is an Example Package", @@ -462,6 +462,67 @@ argument in your setup script. Especially since it frees you from having to remember to modify your setup script whenever your project grows additional top-level packages or subpackages. +``find_namespace_packages()`` +----------------------------- +In Python 3.3+, ``setuptools`` also provides the ``find_namespace_packages`` variant +of ``find_packages``, which has the same function signature as +``find_packages``, but works with `PEP 420`_ compliant implicit namespace +packages. Here is a minimal setup script using ``find_namespace_packages``:: + + from setuptools import setup, find_namespace_packages + setup( + name="HelloWorld", + version="0.1", + packages=find_namespace_packages(), + ) + + +Keep in mind that according to PEP 420, you may have to either re-organize your +codebase a bit or define a few exclusions, as the definition of an implicit +namespace package is quite lenient, so for a project organized like so:: + + + ├── namespace + │ └── mypackage + │ ├── __init__.py + │ └── mod1.py + ├── setup.py + └── tests + └── test_mod1.py + +A naive ``find_namespace_packages()`` would install both ``namespace.mypackage`` and a +top-level package called ``tests``! One way to avoid this problem is to use the +``include`` keyword to whitelist the packages to include, like so:: + + from setuptools import setup, find_namespace_packages + + setup( + name="namespace.mypackage", + version="0.1", + packages=find_namespace_packages(include=['namespace.*']) + ) + +Another option is to use the "src" layout, where all package code is placed in +the ``src`` directory, like so:: + + + ├── setup.py + ├── src + │ └── namespace + │ └── mypackage + │ ├── __init__.py + │ └── mod1.py + └── tests + └── test_mod1.py + +With this layout, the package directory is specified as ``src``, as such:: + + setup(name="namespace.mypackage", + version="0.1", + package_dir={'': 'src'}, + packages=find_namespace_packages(where='src')) + +.. _PEP 420: https://www.python.org/dev/peps/pep-0420/ Automatic Script Creation ========================= @@ -618,9 +679,8 @@ using ``setup.py develop``.) Dependencies that aren't in PyPI -------------------------------- -If your project depends on packages that aren't registered in PyPI, you may -still be able to depend on them, as long as they are available for download -as: +If your project depends on packages that don't exist on PyPI, you may still be +able to depend on them, as long as they are available for download as: - an egg, in the standard distutils ``sdist`` format, - a single ``.py`` file, or @@ -1192,15 +1252,6 @@ Whenever you install an updated version of setuptools, you should also update 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 -``setup.py sdist upload`` or ``setup.py bdist_egg upload`` to upload your -source or egg distributions respectively. Your project's current version must -be registered with PyPI first, of course; you can use ``setup.py register`` to -do that. Or you can do it all in one step, e.g. ``setup.py register sdist -bdist_egg upload`` will register the package, build source and egg -distributions, and then upload them both to PyPI, where they'll be easily -found by other projects that depend on them. - (By the way, if you need to distribute a specific version of ``setuptools``, you can specify the exact version and base download URL as parameters to the ``use_setuptools()`` function. See the function's docstring for details.) @@ -1517,22 +1568,11 @@ you use any option at all. Making your package available for EasyInstall --------------------------------------------- -If you use the ``register`` command (``setup.py register``) to register your -package with PyPI, that's most of the battle right there. (See the -`docs for the register command`_ for more details.) - -.. _docs for the register command: http://docs.python.org/dist/package-index.html - -If you also use the `upload`_ command to upload actual distributions of your -package, that's even better, because EasyInstall will be able to find and -download them directly from your project's PyPI page. - -However, there may be reasons why you don't want to upload distributions to +There may be reasons why you don't want to upload distributions to PyPI, and just want your existing distributions (or perhaps a Subversion checkout) to be used instead. -So here's what you need to do before running the ``register`` command. There -are three ``setup()`` arguments that affect EasyInstall: +There are three ``setup()`` arguments that affect EasyInstall: ``url`` and ``download_url`` These become links on your project's PyPI page. EasyInstall will examine @@ -1590,13 +1630,12 @@ tagging the release, so the trunk will still produce development snapshots. Alternately, if you are not branching for releases, you can override the default version options on the command line, using something like:: - python setup.py egg_info -Db "" sdist bdist_egg register upload + python setup.py egg_info -Db "" sdist bdist_egg The first part of this command (``egg_info -Db ""``) will override the -configured tag information, before creating source and binary eggs, registering -the project with PyPI, and uploading the files. Thus, these commands will use -the plain version from your ``setup.py``, without adding the build designation -string. +configured tag information, before creating source and binary eggs. Thus, these +commands will use the plain version from your ``setup.py``, without adding the +build designation string. Of course, if you will be doing this a lot, you may wish to create a personal alias for this operation, e.g.:: @@ -1605,7 +1644,7 @@ alias for this operation, e.g.:: You can then use it like this:: - python setup.py release sdist bdist_egg register upload + python setup.py release sdist bdist_egg Or of course you can create more elaborate aliases that do all of the above. See the sections below on the `egg_info`_ and `alias`_ commands for more ideas. @@ -1921,11 +1960,11 @@ This command performs two operations: it updates a project's ``.egg-info`` metadata directory (used by the ``bdist_egg``, ``develop``, and ``test`` commands), and it allows you to temporarily change a project's version string, to support "daily builds" or "snapshot" releases. It is run automatically by -the ``sdist``, ``bdist_egg``, ``develop``, ``register``, and ``test`` commands -in order to update the project's metadata, but you can also specify it -explicitly in order to temporarily change the project's version string while -executing other commands. (It also generates the``.egg-info/SOURCES.txt`` -manifest file, which is used when you are building source distributions.) +the ``sdist``, ``bdist_egg``, ``develop``, and ``test`` commands in order to +update the project's metadata, but you can also specify it explicitly in order +to temporarily change the project's version string while executing other +commands. (It also generates the``.egg-info/SOURCES.txt`` manifest file, which +is used when you are building source distributions.) In addition to writing the core egg metadata defined by ``setuptools`` and required by ``pkg_resources``, this command can be extended to write other @@ -1999,10 +2038,10 @@ Creating a dated "nightly build" snapshot egg:: python setup.py egg_info --tag-date --tag-build=DEV bdist_egg -Creating and uploading a release with no version tags, even if some default -tags are specified in ``setup.cfg``:: +Creating a release with no version tags, even if some default tags are +specified in ``setup.cfg``:: - python setup.py egg_info -RDb "" sdist bdist_egg register upload + python setup.py egg_info -RDb "" sdist bdist_egg (Notice that ``egg_info`` must always appear on the command line *before* any commands that you want the version changes to apply to.) @@ -2251,25 +2290,16 @@ available: ``upload`` - Upload source and/or egg distributions to PyPI =========================================================== +.. warning:: + **upload** is deprecated in favor of using `twine + <https://pypi.org/p/twine>`_ + The ``upload`` command is implemented and `documented <https://docs.python.org/3.1/distutils/uploading.html>`_ in distutils. -Setuptools augments the ``upload`` command with support -for `keyring <https://pypi.org/project/keyring/>`_, -allowing the password to be stored in a secure -location and not in plaintext in the .pypirc file. To use -keyring, first install keyring and set the password for -the relevant repository, e.g.:: - - python -m keyring set <repository> <username> - Password for '<username>' in '<repository>': ******** - -Then, in .pypirc, set the repository configuration as normal, -but omit the password. Thereafter, uploads will use the -password from the keyring. - New in 20.1: Added keyring support. +New in 40.0: Deprecated the upload command. ----------------------------------------- @@ -2359,8 +2389,8 @@ Metadata and options are set in the config sections of the same name. * In some cases, complex values can be provided in dedicated subsections for clarity. -* Some keys allow ``file:``, ``attr:``, and ``find:`` directives in order to - cover common usecases. +* Some keys allow ``file:``, ``attr:``, and ``find:`` and ``find_namespace:`` directives in + order to cover common usecases. * Unknown keys are ignored. @@ -2449,7 +2479,7 @@ eager_resources list-comma dependency_links list-comma tests_require list-semi include_package_data bool -packages find:, list-comma +packages find:, find_namespace:, list-comma package_dir dict package_data section exclude_package_data section @@ -2459,10 +2489,13 @@ py_modules list-comma .. note:: - **packages** - The ``find:`` directive can be further configured + **packages** - The ``find:`` and ``find_namespace:`` directive can be further configured in a dedicated subsection ``options.packages.find``. This subsection - accepts the same keys as the `setuptools.find` function: + accepts the same keys as the `setuptools.find_packages` and the + `setuptools.find_namespace_packages` function: ``where``, ``include``, and ``exclude``. + + **find_namespace directive** - The ``find_namespace:`` directive is supported since Python >=3.3. Configuration API diff --git a/easy_install.py b/easy_install.py index d87e9840..d87e9840 100755..100644 --- a/easy_install.py +++ b/easy_install.py diff --git a/launcher.c b/launcher.c index be69f0c6..be69f0c6 100755..100644 --- a/launcher.c +++ b/launcher.c diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index d642a405..84a4b34b 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -47,6 +47,11 @@ except ImportError: # Python 3.2 compatibility import imp as _imp +try: + FileExistsError +except NameError: + FileExistsError = OSError + from pkg_resources.extern import six from pkg_resources.extern.six.moves import urllib, map, filter @@ -640,13 +645,12 @@ class WorkingSet: distributions in the working set, otherwise only ones matching both `group` and `name` are yielded (in distribution order). """ - for dist in self: - entries = dist.get_entry_map(group) - if name is None: - for ep in entries.values(): - yield ep - elif name in entries: - yield entries[name] + return ( + entry + for dist in self + for entry in dist.get_entry_map(group).values() + if name is None or name == entry.name + ) def run_script(self, requires, script_name): """Locate distribution for `requires` and run `script_name` script""" @@ -1308,9 +1312,9 @@ def get_default_cache(): def safe_name(name): """Convert an arbitrary string to a standard distribution name - Any runs of non-alphanumeric/. characters are replaced with a single '-'. + Any runs of non-alphanumeric characters are replaced with a single '-'. """ - return re.sub('[^A-Za-z0-9.]+', '-', name) + return re.sub('[^A-Za-z0-9]+', '-', name) def safe_version(version): @@ -2090,7 +2094,12 @@ def _handle_ns(packageName, path_item): importer = get_importer(path_item) if importer is None: return None - loader = importer.find_module(packageName) + + # capture warnings due to #1111 + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + loader = importer.find_module(packageName) + if loader is None: return None module = sys.modules.get(packageName) @@ -2152,9 +2161,10 @@ def declare_namespace(packageName): if packageName in _namespace_packages: return - path, parent = sys.path, None - if '.' in packageName: - parent = '.'.join(packageName.split('.')[:-1]) + path = sys.path + parent, _, _ = packageName.rpartition('.') + + if parent: declare_namespace(parent) if parent not in _namespace_packages: __import__(parent) @@ -2165,7 +2175,7 @@ def declare_namespace(packageName): # Track what packages are namespaces, so when new path items are added, # they can be updated - _namespace_packages.setdefault(parent, []).append(packageName) + _namespace_packages.setdefault(parent or None, []).append(packageName) _namespace_packages.setdefault(packageName, []) for path_item in path: @@ -3031,7 +3041,10 @@ def _bypass_ensure_directory(path): dirname, filename = split(path) if dirname and filename and not isdir(dirname): _bypass_ensure_directory(dirname) - mkdir(dirname, 0o755) + try: + mkdir(dirname, 0o755) + except FileExistsError: + pass def split_sections(s): diff --git a/pkg_resources/_vendor/appdirs.py b/pkg_resources/_vendor/appdirs.py index f4dba095..ae67001a 100644 --- a/pkg_resources/_vendor/appdirs.py +++ b/pkg_resources/_vendor/appdirs.py @@ -13,7 +13,7 @@ See <http://github.com/ActiveState/appdirs> for details and usage. # - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html # - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -__version_info__ = (1, 4, 0) +__version_info__ = (1, 4, 3) __version__ = '.'.join(map(str, __version_info__)) @@ -98,7 +98,7 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): - """Return full path to the user-shared data dir for this application. + r"""Return full path to the user-shared data dir for this application. "appname" is the name of application. If None, just the system directory is returned. @@ -117,7 +117,7 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): returned, or '/usr/local/share/<AppName>', if XDG_DATA_DIRS is not set - Typical user data directories are: + Typical site data directories are: Mac OS X: /Library/Application Support/<AppName> Unix: /usr/local/share/<AppName> or /usr/share/<AppName> Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName> @@ -184,13 +184,13 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> for a discussion of issues. - Typical user data directories are: + Typical user config directories are: Mac OS X: same as user_data_dir Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined Win *: same as user_data_dir For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. - That means, by deafult "~/.config/<AppName>". + That means, by default "~/.config/<AppName>". """ if system in ["win32", "darwin"]: path = user_data_dir(appname, appauthor, None, roaming) @@ -204,7 +204,7 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): - """Return full path to the user-shared data dir for this application. + r"""Return full path to the user-shared data dir for this application. "appname" is the name of application. If None, just the system directory is returned. @@ -222,7 +222,7 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False) returned. By default, the first item from XDG_CONFIG_DIRS is returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set - Typical user data directories are: + Typical site config directories are: Mac OS X: same as site_data_dir Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in $XDG_CONFIG_DIRS @@ -311,6 +311,48 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): return path +def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific state dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user state directories are: + Mac OS X: same as user_data_dir + Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state> + to extend the XDG spec and support $XDG_STATE_HOME. + + That means, by default "~/.local/state/<AppName>". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): r"""Return full path to the user-specific log dir for this application. @@ -329,7 +371,7 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): "Logs" to the base app data dir for Windows, and "log" to the base cache dir for Unix. See discussion below. - Typical user cache directories are: + Typical user log directories are: Mac OS X: ~/Library/Logs/<AppName> Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs @@ -364,8 +406,8 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): class AppDirs(object): """Convenience wrapper for getting application dirs.""" - def __init__(self, appname, appauthor=None, version=None, roaming=False, - multipath=False): + def __init__(self, appname=None, appauthor=None, version=None, + roaming=False, multipath=False): self.appname = appname self.appauthor = appauthor self.version = version @@ -398,6 +440,11 @@ class AppDirs(object): version=self.version) @property + def user_state_dir(self): + return user_state_dir(self.appname, self.appauthor, + version=self.version) + + @property def user_log_dir(self): return user_log_dir(self.appname, self.appauthor, version=self.version) @@ -410,7 +457,10 @@ def _get_win_folder_from_registry(csidl_name): registry for this guarantees us the correct answer for all CSIDL_* names. """ - import _winreg + if PY3: + import winreg as _winreg + else: + import _winreg shell_folder_name = { "CSIDL_APPDATA": "AppData", @@ -500,7 +550,7 @@ def _get_win_folder_with_jna(csidl_name): if has_high_char: buf = array.zeros('c', buf_size) kernel = win32.Kernel32.INSTANCE - if kernal.GetShortPathName(dir, buf, buf_size): + if kernel.GetShortPathName(dir, buf, buf_size): dir = jna.Native.toString(buf.tostring()).rstrip("\0") return dir @@ -527,9 +577,15 @@ if __name__ == "__main__": appname = "MyApp" appauthor = "MyCompany" - props = ("user_data_dir", "site_data_dir", - "user_config_dir", "site_config_dir", - "user_cache_dir", "user_log_dir") + props = ("user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "site_data_dir", + "site_config_dir") + + print("-- app dirs %s --" % __version__) print("-- app dirs (with optional 'version')") dirs = AppDirs(appname, appauthor, version="1.0") diff --git a/pkg_resources/_vendor/pyparsing.py b/pkg_resources/_vendor/pyparsing.py index a2122435..e8aefc8c 100644 --- a/pkg_resources/_vendor/pyparsing.py +++ b/pkg_resources/_vendor/pyparsing.py @@ -60,8 +60,8 @@ The pyparsing module handles some of the problems that are typically vexing when - embedded comments
"""
-__version__ = "2.1.10"
-__versionTime__ = "07 Oct 2016 01:31 UTC"
+__version__ = "2.2.0"
+__versionTime__ = "06 Mar 2017 02:06 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -144,7 +144,7 @@ else: except UnicodeEncodeError:
# Else encode it
ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace')
- xmlcharref = Regex('&#\d+;')
+ xmlcharref = Regex(r'&#\d+;')
xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:])
return xmlcharref.transformString(ret)
@@ -809,7 +809,7 @@ class ParseResults(object): return None
def getName(self):
- """
+ r"""
Returns the results name for this token expression. Useful when several
different expressions might match at a particular location.
@@ -1226,7 +1226,7 @@ class ParserElement(object): def setParseAction( self, *fns, **kwargs ):
"""
- Define action to perform when successfully matching parse element definition.
+ Define one or more actions to perform when successfully matching parse element definition.
Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
- s = the original string being parsed (see note below)
@@ -1264,7 +1264,7 @@ class ParserElement(object): def addParseAction( self, *fns, **kwargs ):
"""
- Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}.
+ Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}.
See examples in L{I{copy}<copy>}.
"""
@@ -1443,10 +1443,14 @@ class ParserElement(object): def clear(self):
cache.clear()
+
+ def cache_len(self):
+ return len(cache)
self.get = types.MethodType(get, self)
self.set = types.MethodType(set, self)
self.clear = types.MethodType(clear, self)
+ self.__len__ = types.MethodType(cache_len, self)
if _OrderedDict is not None:
class _FifoCache(object):
@@ -1460,15 +1464,22 @@ class ParserElement(object): def set(self, key, value):
cache[key] = value
- if len(cache) > size:
- cache.popitem(False)
+ while len(cache) > size:
+ try:
+ cache.popitem(False)
+ except KeyError:
+ pass
def clear(self):
cache.clear()
+ def cache_len(self):
+ return len(cache)
+
self.get = types.MethodType(get, self)
self.set = types.MethodType(set, self)
self.clear = types.MethodType(clear, self)
+ self.__len__ = types.MethodType(cache_len, self)
else:
class _FifoCache(object):
@@ -1483,7 +1494,7 @@ class ParserElement(object): def set(self, key, value):
cache[key] = value
- if len(cache) > size:
+ while len(key_fifo) > size:
cache.pop(key_fifo.popleft(), None)
key_fifo.append(key)
@@ -1491,9 +1502,13 @@ class ParserElement(object): cache.clear()
key_fifo.clear()
+ def cache_len(self):
+ return len(cache)
+
self.get = types.MethodType(get, self)
self.set = types.MethodType(set, self)
self.clear = types.MethodType(clear, self)
+ self.__len__ = types.MethodType(cache_len, self)
# argument cache for optimizing repeated calls when backtracking through recursive expressions
packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail
@@ -1743,8 +1758,12 @@ class ParserElement(object): cap_word = Word(alphas.upper(), alphas.lower())
print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))
+
+ # the sum() builtin can be used to merge results into a single ParseResults object
+ print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")))
prints::
- ['More', 'Iron', 'Lead', 'Gold', 'I']
+ [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']]
+ ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
"""
try:
return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
@@ -1819,7 +1838,7 @@ class ParserElement(object): warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
SyntaxWarning, stacklevel=2)
return None
- return And( [ self, And._ErrorStop(), other ] )
+ return self + And._ErrorStop() + other
def __rsub__(self, other ):
"""
@@ -2722,7 +2741,7 @@ class Word(Token): class Regex(Token):
- """
+ r"""
Token for matching strings that match a given regular expression.
Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as
@@ -2911,7 +2930,7 @@ class QuotedString(Token): # replace escaped characters
if self.escChar:
- ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
+ ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret)
# replace escaped quotes
if self.escQuote:
@@ -5020,7 +5039,9 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}.
- parseAction is the parse action to be associated with
expressions matching this operator expression (the
- parse action tuple member may be omitted)
+ parse action tuple member may be omitted); if the parse action
+ is passed a tuple or list of functions, this is equivalent to
+ calling C{setParseAction(*fn)} (L{ParserElement.setParseAction})
- lpar - expression for matching left-parentheses (default=C{Suppress('(')})
- rpar - expression for matching right-parentheses (default=C{Suppress(')')})
@@ -5093,7 +5114,10 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): else:
raise ValueError("operator must indicate right or left associativity")
if pa:
- matchExpr.setParseAction( pa )
+ if isinstance(pa, (tuple, list)):
+ matchExpr.setParseAction(*pa)
+ else:
+ matchExpr.setParseAction(pa)
thisExpr <<= ( matchExpr.setName(termName) | lastExpr )
lastExpr = thisExpr
ret <<= lastExpr
diff --git a/pkg_resources/_vendor/vendored.txt b/pkg_resources/_vendor/vendored.txt index 9a94c5bc..e3d564f1 100644 --- a/pkg_resources/_vendor/vendored.txt +++ b/pkg_resources/_vendor/vendored.txt @@ -1,4 +1,4 @@ packaging==16.8 -pyparsing==2.1.10 +pyparsing==2.2.0 six==1.10.0 -appdirs==1.4.0 +appdirs==1.4.3 diff --git a/pkg_resources/extern/__init__.py b/pkg_resources/extern/__init__.py index dfde433d..c1eb9e99 100644 --- a/pkg_resources/extern/__init__.py +++ b/pkg_resources/extern/__init__.py @@ -48,7 +48,7 @@ class VendorImporter: # on later Python versions to cause relative imports # in the vendor package to resolve the same modules # as those going through this importer. - if sys.version_info.major >= 3: + if prefix and sys.version_info > (3, 3): del sys.modules[extant] return mod except ImportError: diff --git a/pkg_resources/py31compat.py b/pkg_resources/py31compat.py index fd4b6fd0..a381c424 100644 --- a/pkg_resources/py31compat.py +++ b/pkg_resources/py31compat.py @@ -2,6 +2,8 @@ import os import errno import sys +from .extern import six + def _makedirs_31(path, exist_ok=False): try: @@ -15,7 +17,7 @@ def _makedirs_31(path, exist_ok=False): # and exists_ok considerations are disentangled. # See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663 needs_makedirs = ( - sys.version_info.major == 2 or + six.PY2 or (3, 4) <= sys.version_info < (3, 4, 1) ) makedirs = _makedirs_31 if needs_makedirs else os.makedirs diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 4e2cac94..62a39b8f 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -12,6 +12,11 @@ import stat import distutils.dist import distutils.command.install_egg_info +try: + from unittest import mock +except ImportError: + import mock + from pkg_resources.extern.six.moves import map from pkg_resources.extern.six import text_type, string_types @@ -138,8 +143,34 @@ class TestResourceManager: message = "Unexpected type from get_cache_path: " + type_ assert isinstance(path, string_types), message + def test_get_cache_path_race(self, tmpdir): + # Patch to os.path.isdir to create a race condition + def patched_isdir(dirname, unpatched_isdir=pkg_resources.isdir): + patched_isdir.dirnames.append(dirname) + + was_dir = unpatched_isdir(dirname) + if not was_dir: + os.makedirs(dirname) + return was_dir + + patched_isdir.dirnames = [] + + # Get a cache path with a "race condition" + mgr = pkg_resources.ResourceManager() + mgr.set_extraction_path(str(tmpdir)) + + archive_name = os.sep.join(('foo', 'bar', 'baz')) + with mock.patch.object(pkg_resources, 'isdir', new=patched_isdir): + mgr.get_cache_path(archive_name) + + # Because this test relies on the implementation details of this + # function, these assertions are a sentinel to ensure that the + # test suite will not fail silently if the implementation changes. + called_dirnames = patched_isdir.dirnames + assert len(called_dirnames) == 2 + assert called_dirnames[0].split(os.sep)[-2:] == ['foo', 'bar'] + assert called_dirnames[1].split(os.sep)[-1:] == ['foo'] -class TestIndependence: """ Tests to ensure that pkg_resources runs independently from setuptools. """ diff --git a/pyproject.toml b/pyproject.toml index cffd0e9a..07c23bb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[build-system] +requires = ["wheel"] + [tool.towncrier] package = "setuptools" package_dir = "setuptools" diff --git a/pytest.ini b/pytest.ini index 1c5b6b09..1c5b6b09 100755..100644 --- a/pytest.ini +++ b/pytest.ini diff --git a/setup.cfg b/setup.cfg index e23ee6f0..df021971 100755..100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 39.2.0 +current_version = 40.2.0 commit = True tag = True @@ -89,7 +89,7 @@ def pypi_link(pkg_filename): setup_params = dict( name="setuptools", - version="39.2.0", + version="40.2.0", description=( "Easily download, build, install, upgrade, and uninstall " "Python packages" diff --git a/setuptools/__init__.py b/setuptools/__init__.py index ce55ec35..54309b57 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -1,12 +1,14 @@ """Extensions to the 'distutils' for large or complex distributions""" import os +import sys import functools import distutils.core import distutils.filelist from distutils.util import convert_path from fnmatch import fnmatchcase +from setuptools.extern.six import PY3 from setuptools.extern.six.moves import filter, map import setuptools.version @@ -17,11 +19,15 @@ from . import monkey __metaclass__ = type + __all__ = [ 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', - 'find_packages', + 'find_packages' ] +if PY3: + __all__.append('find_namespace_packages') + __version__ = setuptools.version.__version__ bootstrap_install_from = None @@ -111,6 +117,9 @@ class PEP420PackageFinder(PackageFinder): find_packages = PackageFinder.find +if PY3: + find_namespace_packages = PEP420PackageFinder.find + def _install_setup_requires(attrs): # Note: do not use `setuptools.Distribution` directly, as diff --git a/setuptools/_vendor/pyparsing.py b/setuptools/_vendor/pyparsing.py index a2122435..e8aefc8c 100644 --- a/setuptools/_vendor/pyparsing.py +++ b/setuptools/_vendor/pyparsing.py @@ -60,8 +60,8 @@ The pyparsing module handles some of the problems that are typically vexing when - embedded comments
"""
-__version__ = "2.1.10"
-__versionTime__ = "07 Oct 2016 01:31 UTC"
+__version__ = "2.2.0"
+__versionTime__ = "06 Mar 2017 02:06 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -144,7 +144,7 @@ else: except UnicodeEncodeError:
# Else encode it
ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace')
- xmlcharref = Regex('&#\d+;')
+ xmlcharref = Regex(r'&#\d+;')
xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:])
return xmlcharref.transformString(ret)
@@ -809,7 +809,7 @@ class ParseResults(object): return None
def getName(self):
- """
+ r"""
Returns the results name for this token expression. Useful when several
different expressions might match at a particular location.
@@ -1226,7 +1226,7 @@ class ParserElement(object): def setParseAction( self, *fns, **kwargs ):
"""
- Define action to perform when successfully matching parse element definition.
+ Define one or more actions to perform when successfully matching parse element definition.
Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
- s = the original string being parsed (see note below)
@@ -1264,7 +1264,7 @@ class ParserElement(object): def addParseAction( self, *fns, **kwargs ):
"""
- Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}.
+ Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}.
See examples in L{I{copy}<copy>}.
"""
@@ -1443,10 +1443,14 @@ class ParserElement(object): def clear(self):
cache.clear()
+
+ def cache_len(self):
+ return len(cache)
self.get = types.MethodType(get, self)
self.set = types.MethodType(set, self)
self.clear = types.MethodType(clear, self)
+ self.__len__ = types.MethodType(cache_len, self)
if _OrderedDict is not None:
class _FifoCache(object):
@@ -1460,15 +1464,22 @@ class ParserElement(object): def set(self, key, value):
cache[key] = value
- if len(cache) > size:
- cache.popitem(False)
+ while len(cache) > size:
+ try:
+ cache.popitem(False)
+ except KeyError:
+ pass
def clear(self):
cache.clear()
+ def cache_len(self):
+ return len(cache)
+
self.get = types.MethodType(get, self)
self.set = types.MethodType(set, self)
self.clear = types.MethodType(clear, self)
+ self.__len__ = types.MethodType(cache_len, self)
else:
class _FifoCache(object):
@@ -1483,7 +1494,7 @@ class ParserElement(object): def set(self, key, value):
cache[key] = value
- if len(cache) > size:
+ while len(key_fifo) > size:
cache.pop(key_fifo.popleft(), None)
key_fifo.append(key)
@@ -1491,9 +1502,13 @@ class ParserElement(object): cache.clear()
key_fifo.clear()
+ def cache_len(self):
+ return len(cache)
+
self.get = types.MethodType(get, self)
self.set = types.MethodType(set, self)
self.clear = types.MethodType(clear, self)
+ self.__len__ = types.MethodType(cache_len, self)
# argument cache for optimizing repeated calls when backtracking through recursive expressions
packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail
@@ -1743,8 +1758,12 @@ class ParserElement(object): cap_word = Word(alphas.upper(), alphas.lower())
print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))
+
+ # the sum() builtin can be used to merge results into a single ParseResults object
+ print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")))
prints::
- ['More', 'Iron', 'Lead', 'Gold', 'I']
+ [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']]
+ ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
"""
try:
return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
@@ -1819,7 +1838,7 @@ class ParserElement(object): warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
SyntaxWarning, stacklevel=2)
return None
- return And( [ self, And._ErrorStop(), other ] )
+ return self + And._ErrorStop() + other
def __rsub__(self, other ):
"""
@@ -2722,7 +2741,7 @@ class Word(Token): class Regex(Token):
- """
+ r"""
Token for matching strings that match a given regular expression.
Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as
@@ -2911,7 +2930,7 @@ class QuotedString(Token): # replace escaped characters
if self.escChar:
- ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
+ ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret)
# replace escaped quotes
if self.escQuote:
@@ -5020,7 +5039,9 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}.
- parseAction is the parse action to be associated with
expressions matching this operator expression (the
- parse action tuple member may be omitted)
+ parse action tuple member may be omitted); if the parse action
+ is passed a tuple or list of functions, this is equivalent to
+ calling C{setParseAction(*fn)} (L{ParserElement.setParseAction})
- lpar - expression for matching left-parentheses (default=C{Suppress('(')})
- rpar - expression for matching right-parentheses (default=C{Suppress(')')})
@@ -5093,7 +5114,10 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): else:
raise ValueError("operator must indicate right or left associativity")
if pa:
- matchExpr.setParseAction( pa )
+ if isinstance(pa, (tuple, list)):
+ matchExpr.setParseAction(*pa)
+ else:
+ matchExpr.setParseAction(pa)
thisExpr <<= ( matchExpr.setName(termName) | lastExpr )
lastExpr = thisExpr
ret <<= lastExpr
diff --git a/setuptools/_vendor/vendored.txt b/setuptools/_vendor/vendored.txt index be3e72eb..ca0d5ce3 100644 --- a/setuptools/_vendor/vendored.txt +++ b/setuptools/_vendor/vendored.txt @@ -1,3 +1,3 @@ packaging==16.8 -pyparsing==2.1.10 +pyparsing==2.2.0 six==1.10.0 diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index 81436044..81436044 100755..100644 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 609ea1e5..f7f9bda2 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -61,6 +61,19 @@ class Distribution(setuptools.dist.Distribution): distutils.core.Distribution = orig +def _to_str(s): + """ + Convert a filename to a string (on Python 2, explicitly + a byte string, not Unicode) as distutils checks for the + exact type str. + """ + if sys.version_info[0] == 2 and not isinstance(s, str): + # Assume it's Unicode, as that's what the PEP says + # should be provided. + return s.encode(sys.getfilesystemencoding()) + return s + + def _run_setup(setup_script='setup.py'): # Note that we can reuse our build directory between calls # Correctness comes first, then optimization later @@ -78,9 +91,8 @@ def _fix_config(config_settings): return config_settings -def _get_build_requires(config_settings): +def _get_build_requires(config_settings, requirements): config_settings = _fix_config(config_settings) - requirements = ['setuptools', 'wheel'] sys.argv = sys.argv[:1] + ['egg_info'] + \ config_settings["--global-option"] @@ -100,20 +112,20 @@ def _get_immediate_subdirectories(a_dir): def get_requires_for_build_wheel(config_settings=None): config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings) + return _get_build_requires(config_settings, requirements=['setuptools', 'wheel']) def get_requires_for_build_sdist(config_settings=None): config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings) + return _get_build_requires(config_settings, requirements=['setuptools']) def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): - sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory] + sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', _to_str(metadata_directory)] _run_setup() - + dist_info_directory = metadata_directory - while True: + while True: dist_infos = [f for f in os.listdir(dist_info_directory) if f.endswith('.dist-info')] diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py index 4532b1cc..4532b1cc 100755..100644 --- a/setuptools/command/alias.py +++ b/setuptools/command/alias.py diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 14530729..9f8df917 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -411,7 +411,7 @@ def scan_module(egg_dir, base, name, stubs): return True # Extension module pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] - if sys.version_info.major == 2: + if six.PY2: skip = 8 # skip magic & date elif sys.version_info < (3, 7): skip = 12 # skip magic & date & file size diff --git a/setuptools/command/bdist_rpm.py b/setuptools/command/bdist_rpm.py index 70730927..70730927 100755..100644 --- a/setuptools/command/bdist_rpm.py +++ b/setuptools/command/bdist_rpm.py diff --git a/setuptools/command/bdist_wininst.py b/setuptools/command/bdist_wininst.py index 073de97b..073de97b 100755..100644 --- a/setuptools/command/bdist_wininst.py +++ b/setuptools/command/bdist_wininst.py diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py index fdc9fc43..fdc9fc43 100755..100644 --- a/setuptools/command/develop.py +++ b/setuptools/command/develop.py diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 05508ceb..dd17cc13 100755..100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -96,7 +96,7 @@ def samefile(p1, p2): if six.PY2: - def _to_ascii(s): + def _to_bytes(s): return s def isascii(s): @@ -107,8 +107,8 @@ if six.PY2: return False else: - def _to_ascii(s): - return s.encode('ascii') + def _to_bytes(s): + return s.encode('utf8') def isascii(s): try: @@ -805,7 +805,7 @@ class easy_install(Command): if is_script: body = self._load_template(dev_path) % locals() script_text = ScriptWriter.get_header(script_text) + body - self.write_script(script_name, _to_ascii(script_text), 'b') + self.write_script(script_name, _to_bytes(script_text), 'b') @staticmethod def _load_template(dev_path): diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index f3e604d3..bd116e1f 100755..100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -116,7 +116,33 @@ def translate_pattern(glob): return re.compile(pat, flags=re.MULTILINE|re.DOTALL) -class egg_info(Command): +class InfoCommon: + tag_build = None + tag_date = None + + @property + def name(self): + return safe_name(self.distribution.get_name()) + + def tagged_version(self): + version = self.distribution.get_version() + # egg_info may be called more than once for a distribution, + # in which case the version string already contains all tags. + if self.vtags and version.endswith(self.vtags): + return safe_version(version) + return safe_version(version + self.vtags) + + def tags(self): + version = '' + if self.tag_build: + version += self.tag_build + if self.tag_date: + version += time.strftime("-%Y%m%d") + return version + vtags = property(tags) + + +class egg_info(InfoCommon, Command): description = "create a distribution's .egg-info directory" user_options = [ @@ -133,14 +159,11 @@ class egg_info(Command): } def initialize_options(self): - self.egg_name = None - self.egg_version = None self.egg_base = None + self.egg_name = None self.egg_info = None - self.tag_build = None - self.tag_date = 0 + self.egg_version = None self.broken_egg_info = False - self.vtags = None #################################### # allow the 'tag_svn_revision' to be detected and @@ -168,10 +191,12 @@ class egg_info(Command): edit_config(filename, dict(egg_info=egg_info)) def finalize_options(self): - self.egg_name = safe_name(self.distribution.get_name()) - self.vtags = self.tags() + # Note: we need to capture the current value returned + # by `self.tagged_version()`, so we can later update + # `self.distribution.metadata.version` without + # repercussions. + self.egg_name = self.name self.egg_version = self.tagged_version() - parsed_version = parse_version(self.egg_version) try: @@ -254,16 +279,9 @@ class egg_info(Command): if not self.dry_run: os.unlink(filename) - def tagged_version(self): - version = self.distribution.get_version() - # egg_info may be called more than once for a distribution, - # in which case the version string already contains all tags. - if self.vtags and version.endswith(self.vtags): - return safe_version(version) - return safe_version(version + self.vtags) - def run(self): self.mkpath(self.egg_info) + os.utime(self.egg_info, None) installer = self.distribution.fetch_build_egg for ep in iter_entry_points('egg_info.writers'): ep.require(installer=installer) @@ -277,14 +295,6 @@ class egg_info(Command): self.find_sources() - def tags(self): - version = '' - if self.tag_build: - version += self.tag_build - if self.tag_date: - version += time.strftime("-%Y%m%d") - return version - def find_sources(self): """Generate SOURCES.txt manifest file""" manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py index edc4718b..edc4718b 100755..100644 --- a/setuptools/command/install_egg_info.py +++ b/setuptools/command/install_egg_info.py diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py index 16234273..16234273 100755..100644 --- a/setuptools/command/install_scripts.py +++ b/setuptools/command/install_scripts.py diff --git a/setuptools/command/register.py b/setuptools/command/register.py index 8d6336a1..98bc0156 100755..100644 --- a/setuptools/command/register.py +++ b/setuptools/command/register.py @@ -1,3 +1,4 @@ +from distutils import log import distutils.command.register as orig @@ -5,6 +6,13 @@ class register(orig.register): __doc__ = orig.register.__doc__ def run(self): - # Make sure that we are using valid current name/version info - self.run_command('egg_info') - orig.register.run(self) + try: + # Make sure that we are using valid current name/version info + self.run_command('egg_info') + orig.register.run(self) + finally: + self.announce( + "WARNING: Registering is deprecated, use twine to " + "upload instead (https://pypi.org/p/twine/)", + log.WARN + ) diff --git a/setuptools/command/rotate.py b/setuptools/command/rotate.py index b89353f5..b89353f5 100755..100644 --- a/setuptools/command/rotate.py +++ b/setuptools/command/rotate.py diff --git a/setuptools/command/saveopts.py b/setuptools/command/saveopts.py index 611cec55..611cec55 100755..100644 --- a/setuptools/command/saveopts.py +++ b/setuptools/command/saveopts.py diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index bcfae4d8..bcfae4d8 100755..100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py diff --git a/setuptools/command/setopt.py b/setuptools/command/setopt.py index 7e57cc02..7e57cc02 100755..100644 --- a/setuptools/command/setopt.py +++ b/setuptools/command/setopt.py diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py index a44173a9..72f24d8f 100644 --- a/setuptools/command/upload.py +++ b/setuptools/command/upload.py @@ -1,4 +1,5 @@ import getpass +from distutils import log from distutils.command import upload as orig @@ -8,6 +9,16 @@ class upload(orig.upload): in a variety of different ways. """ + def run(self): + try: + orig.upload.run(self) + finally: + self.announce( + "WARNING: Uploading via this command is deprecated, use twine " + "to upload instead (https://pypi.org/p/twine/)", + log.WARN + ) + def finalize_options(self): orig.upload.finalize_options(self) self.username = ( diff --git a/setuptools/config.py b/setuptools/config.py index 5f908cf1..0da3dbc9 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -8,7 +8,7 @@ from importlib import import_module from distutils.errors import DistutilsOptionError, DistutilsFileError from setuptools.extern.packaging.version import LegacyVersion, parse -from setuptools.extern.six import string_types +from setuptools.extern.six import string_types, PY3 __metaclass__ = type @@ -515,16 +515,24 @@ class ConfigOptionsHandler(ConfigHandler): :param value: :rtype: list """ - find_directive = 'find:' + find_directives = ['find:', 'find_namespace:'] + trimmed_value = value.strip() - if not value.startswith(find_directive): + if not trimmed_value in find_directives: return self._parse_list(value) + findns = trimmed_value == find_directives[1] + if findns and not PY3: + raise DistutilsOptionError('find_namespace: directive is unsupported on Python < 3.3') + # Read function arguments from a dedicated section. find_kwargs = self.parse_section_packages__find( self.sections.get('packages.find', {})) - from setuptools import find_packages + if findns: + from setuptools import find_namespace_packages as find_packages + else: + from setuptools import find_packages return find_packages(**find_kwargs) diff --git a/setuptools/extern/__init__.py b/setuptools/extern/__init__.py index 52785a03..cb2fa329 100644 --- a/setuptools/extern/__init__.py +++ b/setuptools/extern/__init__.py @@ -48,7 +48,7 @@ class VendorImporter: # on later Python versions to cause relative imports # in the vendor package to resolve the same modules # as those going through this importer. - if sys.version_info.major >= 3: + if sys.version_info >= (3, ): del sys.modules[extant] return mod except ImportError: diff --git a/setuptools/glob.py b/setuptools/glob.py index 6c781de3..9d7cbc5d 100644 --- a/setuptools/glob.py +++ b/setuptools/glob.py @@ -3,14 +3,12 @@ Filename globbing utility. Mostly a copy of `glob` from Python 3.5. Changes include: * `yield from` and PEP3102 `*` removed. - * `bytes` changed to `six.binary_type`. * Hidden files are not ignored. """ import os import re import fnmatch -from setuptools.extern.six import binary_type __all__ = ["glob", "iglob", "escape"] @@ -92,7 +90,7 @@ def _iglob(pathname, recursive): def glob1(dirname, pattern): if not dirname: - if isinstance(pattern, binary_type): + if isinstance(pattern, bytes): dirname = os.curdir.encode('ASCII') else: dirname = os.curdir @@ -129,8 +127,8 @@ def glob2(dirname, pattern): # Recursively yields relative pathnames inside a literal directory. def _rlistdir(dirname): if not dirname: - if isinstance(dirname, binary_type): - dirname = binary_type(os.curdir, 'ASCII') + if isinstance(dirname, bytes): + dirname = os.curdir.encode('ASCII') else: dirname = os.curdir try: @@ -149,7 +147,7 @@ magic_check_bytes = re.compile(b'([*?[])') def has_magic(s): - if isinstance(s, binary_type): + if isinstance(s, bytes): match = magic_check_bytes.search(s) else: match = magic_check.search(s) @@ -157,7 +155,7 @@ def has_magic(s): def _isrecursive(pattern): - if isinstance(pattern, binary_type): + if isinstance(pattern, bytes): return pattern == b'**' else: return pattern == '**' @@ -169,7 +167,7 @@ def escape(pathname): # Escaping is done by wrapping any of "*?[" between square brackets. # Metacharacters do not work in the drive part and shouldn't be escaped. drive, pathname = os.path.splitdrive(pathname) - if isinstance(pathname, binary_type): + if isinstance(pathname, bytes): pathname = magic_check_bytes.sub(br'[\1]', pathname) else: pathname = magic_check.sub(r'[\1]', pathname) diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 5e20b3f1..b9c472f1 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -232,8 +232,7 @@ def _augment_exception(exc, version, arch=''): elif version >= 14.0: # For VC++ 14.0 Redirect user to Visual C++ Build Tools message += (' Get it with "Microsoft Visual C++ Build Tools": ' - r'http://landinghub.visualstudio.com/' - 'visual-cpp-build-tools') + r'https://visualstudio.microsoft.com/downloads/') exc.args = (message, ) diff --git a/setuptools/namespaces.py b/setuptools/namespaces.py index dc16106d..dc16106d 100755..100644 --- a/setuptools/namespaces.py +++ b/setuptools/namespaces.py diff --git a/setuptools/package_index.py b/setuptools/package_index.py index cda54b71..cda54b71 100755..100644 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py diff --git a/setuptools/pep425tags.py b/setuptools/pep425tags.py index a86a0d18..8bf4277d 100644 --- a/setuptools/pep425tags.py +++ b/setuptools/pep425tags.py @@ -12,6 +12,8 @@ import sysconfig import warnings from collections import OrderedDict +from .extern import six + from . import glibc _osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') @@ -97,8 +99,8 @@ def get_abi_tag(): lambda: sys.maxunicode == 0x10ffff, expected=4, warn=(impl == 'cp' and - sys.version_info.major == 2)) \ - and sys.version_info.major == 2: + six.PY2)) \ + and six.PY2: u = 'u' abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u) elif soabi and soabi.startswith('cpython-'): diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 685f3f72..685f3f72 100755..100644 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py index 54dd7d2b..5f4a1c29 100644 --- a/setuptools/tests/__init__.py +++ b/setuptools/tests/__init__.py @@ -2,5 +2,17 @@ import locale import pytest +from setuptools.extern.six import PY2, PY3 + + +__all__ = [ + 'fail_on_ascii', 'py2_only', 'py3_only' +] + + is_ascii = locale.getpreferredencoding() == 'ANSI_X3.4-1968' fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale") + + +py2_only = pytest.mark.skipif(not PY2, reason="Test runs on Python 2 only") +py3_only = pytest.mark.skipif(not PY3, reason="Test runs on Python 3 only") diff --git a/setuptools/tests/files.py b/setuptools/tests/files.py index f5f0e6bb..465a6b41 100644 --- a/setuptools/tests/files.py +++ b/setuptools/tests/files.py @@ -1,7 +1,6 @@ import os -from setuptools.extern.six import binary_type import pkg_resources.py31compat @@ -31,7 +30,7 @@ def build_files(file_defs, prefix=""): pkg_resources.py31compat.makedirs(full_name, exist_ok=True) build_files(contents, prefix=full_name) else: - if isinstance(contents, binary_type): + if isinstance(contents, bytes): with open(full_name, 'wb') as f: f.write(contents) else: diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index b39b7b8f..f1d517bb 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import os import pytest @@ -44,50 +46,52 @@ class BuildBackendCaller(BuildBackendBase): return getattr(mod, name)(*args, **kw) -defns = [{ - 'setup.py': DALS(""" - __import__('setuptools').setup( - name='foo', - py_modules=['hello'], - setup_requires=['six'], - ) - """), - 'hello.py': DALS(""" - def run(): - print('hello') - """), - }, - { - 'setup.py': DALS(""" - assert __name__ == '__main__' - __import__('setuptools').setup( - name='foo', - py_modules=['hello'], - setup_requires=['six'], - ) - """), - 'hello.py': DALS(""" - def run(): - print('hello') - """), - }, - { - 'setup.py': DALS(""" - variable = True - def function(): - return variable - assert variable - __import__('setuptools').setup( - name='foo', - py_modules=['hello'], - setup_requires=['six'], - ) - """), - 'hello.py': DALS(""" - def run(): - print('hello') - """), - }] +defns = [ + { + 'setup.py': DALS(""" + __import__('setuptools').setup( + name='foo', + py_modules=['hello'], + setup_requires=['six'], + ) + """), + 'hello.py': DALS(""" + def run(): + print('hello') + """), + }, + { + 'setup.py': DALS(""" + assert __name__ == '__main__' + __import__('setuptools').setup( + name='foo', + py_modules=['hello'], + setup_requires=['six'], + ) + """), + 'hello.py': DALS(""" + def run(): + print('hello') + """), + }, + { + 'setup.py': DALS(""" + variable = True + def function(): + return variable + assert variable + __import__('setuptools').setup( + name='foo', + py_modules=['hello'], + setup_requires=['six'], + ) + """), + 'hello.py': DALS(""" + def run(): + print('hello') + """), + }, +] @pytest.fixture(params=defns) @@ -103,6 +107,12 @@ def test_get_requires_for_build_wheel(build_backend): assert sorted(actual) == sorted(expected) +def test_get_requires_for_build_sdist(build_backend): + actual = build_backend.get_requires_for_build_sdist() + expected = ['six', 'setuptools'] + assert sorted(actual) == sorted(expected) + + def test_build_wheel(build_backend): dist_dir = os.path.abspath('pip-wheel') os.makedirs(dist_dir) @@ -126,3 +136,13 @@ def test_prepare_metadata_for_build_wheel(build_backend): dist_info = build_backend.prepare_metadata_for_build_wheel(dist_dir) assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA')) + + +@pytest.mark.skipif('sys.version_info > (3,)') +def test_prepare_metadata_for_build_wheel_with_str(build_backend): + dist_dir = os.path.abspath(str('pip-dist-info')) + os.makedirs(dist_dir) + + dist_info = build_backend.prepare_metadata_for_build_wheel(dist_dir) + + assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA')) diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index 19b37633..acf22154 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -4,18 +4,20 @@ from distutils.errors import DistutilsOptionError, DistutilsFileError from mock import patch from setuptools.dist import Distribution, _Distribution from setuptools.config import ConfigHandler, read_configuration - +from . import py2_only, py3_only class ErrConfigHandler(ConfigHandler): """Erroneous handler. Fails to implement required methods.""" -def make_package_dir(name, base_dir): +def make_package_dir(name, base_dir, ns=False): dir_package = base_dir for dir_name in name.split('/'): dir_package = dir_package.mkdir(dir_name) - init_file = dir_package.join('__init__.py') - init_file.write('') + init_file = None + if not ns: + init_file = dir_package.join('__init__.py') + init_file.write('') return dir_package, init_file @@ -596,6 +598,60 @@ class TestOptions: assert set(dist.packages) == set( ['fake_package', 'fake_package.sub_two']) + @py2_only + def test_find_namespace_directive_fails_on_py2(self, tmpdir): + dir_package, config = fake_env( + tmpdir, + '[options]\n' + 'packages = find_namespace:\n' + ) + + with pytest.raises(DistutilsOptionError): + with get_dist(tmpdir) as dist: + dist.parse_config_files() + + @py3_only + def test_find_namespace_directive(self, tmpdir): + dir_package, config = fake_env( + tmpdir, + '[options]\n' + 'packages = find_namespace:\n' + ) + + dir_sub_one, _ = make_package_dir('sub_one', dir_package) + dir_sub_two, _ = make_package_dir('sub_two', dir_package, ns=True) + + with get_dist(tmpdir) as dist: + assert set(dist.packages) == { + 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one' + } + + config.write( + '[options]\n' + 'packages = find_namespace:\n' + '\n' + '[options.packages.find]\n' + 'where = .\n' + 'include =\n' + ' fake_package.sub_one\n' + ' two\n' + ) + with get_dist(tmpdir) as dist: + assert dist.packages == ['fake_package.sub_one'] + + config.write( + '[options]\n' + 'packages = find_namespace:\n' + '\n' + '[options.packages.find]\n' + 'exclude =\n' + ' fake_package.sub_one\n' + ) + with get_dist(tmpdir) as dist: + assert set(dist.packages) == { + 'fake_package', 'fake_package.sub_two' + } + def test_extras_require(self, tmpdir): fake_env( tmpdir, diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 345d283c..955c2ae9 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Easy install Tests """ -from __future__ import absolute_import +from __future__ import absolute_import, unicode_literals import sys import os @@ -17,6 +17,7 @@ import zipfile import mock import time +from setuptools.extern import six from setuptools.extern.six.moves import urllib import pytest @@ -43,7 +44,7 @@ class FakeDist: def get_entry_map(self, group): if group != 'console_scripts': return {} - return {'name': 'ep'} + return {str('name'): 'ep'} def as_requirement(self): return 'spec' @@ -79,7 +80,7 @@ class TestEasyInstallTest: sys.exit( load_entry_point('spec', 'console_scripts', 'name')() ) - """) + """) # noqa: E501 dist = FakeDist() args = next(ei.ScriptWriter.get_args(dist)) @@ -126,7 +127,9 @@ class TestEasyInstallTest: site.getsitepackages. """ path = normalize_path('/setuptools/test/site-packages') - mock_gsp = lambda: [path] + + def mock_gsp(): + return [path] monkeypatch.setattr(site, 'getsitepackages', mock_gsp, raising=False) assert path in ei.get_site_dirs() @@ -154,7 +157,7 @@ class TestEasyInstallTest: "", ), ( - u'mypkg/\u2603.txt', + 'mypkg/☃.txt', "", ), ] @@ -169,7 +172,8 @@ class TestEasyInstallTest: return str(sdist) @fail_on_ascii - def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): + def test_unicode_filename_in_sdist( + self, sdist_unicode, tmpdir, monkeypatch): """ The install command should execute correctly even if the package has unicode filenames. @@ -186,6 +190,59 @@ class TestEasyInstallTest: cmd.easy_install(sdist_unicode) @pytest.fixture + def sdist_unicode_in_script(self, tmpdir): + files = [ + ( + "setup.py", + DALS(""" + import setuptools + setuptools.setup( + name="setuptools-test-unicode", + version="1.0", + packages=["mypkg"], + include_package_data=True, + scripts=['mypkg/unicode_in_script'], + ) + """), + ), + ("mypkg/__init__.py", ""), + ( + "mypkg/unicode_in_script", + DALS( + """ + #!/bin/sh + # á + + non_python_fn() { + } + """), + ), + ] + sdist_name = "setuptools-test-unicode-script-1.0.zip" + sdist = tmpdir / sdist_name + # can't use make_sdist, because the issue only occurs + # with zip sdists. + sdist_zip = zipfile.ZipFile(str(sdist), "w") + for filename, content in files: + sdist_zip.writestr(filename, content.encode('utf-8')) + sdist_zip.close() + return str(sdist) + + @fail_on_ascii + def test_unicode_content_in_sdist( + self, sdist_unicode_in_script, tmpdir, monkeypatch): + """ + The install command should execute correctly even if + the package has unicode in scripts. + """ + dist = Distribution({"script_args": ["easy_install"]}) + target = (tmpdir / "target").ensure_dir() + cmd = ei.easy_install(dist, install_dir=str(target), args=["x"]) + monkeypatch.setitem(os.environ, "PYTHONPATH", str(target)) + cmd.ensure_finalized() + cmd.easy_install(sdist_unicode_in_script) + + @pytest.fixture def sdist_script(self, tmpdir): files = [ ( @@ -200,7 +257,7 @@ class TestEasyInstallTest: """), ), ( - u'mypkg_script', + 'mypkg_script', DALS(""" #/usr/bin/python print('mypkg_script') @@ -398,8 +455,8 @@ class TestSetupRequires: dist_file, ] with sandbox.save_argv(['easy_install']): - # attempt to install the dist. It should fail because - # it doesn't exist. + # attempt to install the dist. It should + # fail because it doesn't exist. with pytest.raises(SystemExit): easy_install_pkg.main(ei_params) # there should have been two or three requests to the server @@ -451,12 +508,13 @@ class TestSetupRequires: with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: - test_pkg = create_setup_requires_package(temp_dir, use_setup_cfg=use_setup_cfg) + test_pkg = create_setup_requires_package( + temp_dir, use_setup_cfg=use_setup_cfg) test_setup_py = os.path.join(test_pkg, 'setup.py') with contexts.quiet() as (stdout, stderr): # Don't even need to install the package, just # running the setup.py at all is sufficient - run_setup(test_setup_py, ['--name']) + run_setup(test_setup_py, [str('--name')]) lines = stdout.readlines() assert len(lines) > 0 @@ -510,9 +568,10 @@ class TestSetupRequires: try: # Don't even need to install the package, just # running the setup.py at all is sufficient - run_setup(test_setup_py, ['--name']) + run_setup(test_setup_py, [str('--name')]) except pkg_resources.VersionConflict: - self.fail('Installing setup.py requirements ' + self.fail( + 'Installing setup.py requirements ' 'caused a VersionConflict') assert 'FAIL' not in stdout.getvalue() @@ -523,21 +582,23 @@ class TestSetupRequires: @pytest.mark.parametrize('use_setup_cfg', use_setup_cfg) def test_setup_requires_with_attr_version(self, use_setup_cfg): def make_dependency_sdist(dist_path, distname, version): - make_sdist(dist_path, [ - ('setup.py', - DALS(""" - import setuptools - setuptools.setup( - name={name!r}, - version={version!r}, - py_modules=[{name!r}], - ) - """.format(name=distname, version=version))), - (distname + '.py', - DALS(""" - version = 42 - """ - ))]) + files = [( + 'setup.py', + DALS(""" + import setuptools + setuptools.setup( + name={name!r}, + version={version!r}, + py_modules=[{name!r}], + ) + """.format(name=distname, version=version)), + ), ( + distname + '.py', + DALS(""" + version = 42 + """), + )] + make_sdist(dist_path, files) with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: test_pkg = create_setup_requires_package( @@ -547,7 +608,7 @@ class TestSetupRequires: ) test_setup_py = os.path.join(test_pkg, 'setup.py') with contexts.quiet() as (stdout, stderr): - run_setup(test_setup_py, ['--version']) + run_setup(test_setup_py, [str('--version')]) lines = stdout.readlines() assert len(lines) > 0 assert lines[-1].strip() == '42' @@ -674,7 +735,6 @@ def create_setup_requires_package(path, distname='foobar', version='0.1', import setuptools setuptools.setup(**%r) """) - with open(test_setup_py, 'w') as f: f.write(setup_py_template % test_setup_attrs) @@ -690,6 +750,8 @@ def create_setup_requires_package(path, distname='foobar', version='0.1', ) class TestScriptHeader: non_ascii_exe = '/Users/José/bin/python' + if six.PY2: + non_ascii_exe = non_ascii_exe.encode('utf-8') exe_with_spaces = r'C:\Program Files\Python36\python.exe' def test_get_script_header(self): @@ -698,19 +760,21 @@ class TestScriptHeader: assert actual == expected def test_get_script_header_args(self): - expected = '#!%s -x\n' % ei.nt_quote_arg(os.path.normpath - (sys.executable)) + expected = '#!%s -x\n' % ei.nt_quote_arg( + os.path.normpath(sys.executable)) actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python -x') assert actual == expected def test_get_script_header_non_ascii_exe(self): - actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python', + actual = ei.ScriptWriter.get_script_header( + '#!/usr/bin/python', executable=self.non_ascii_exe) - expected = '#!%s -x\n' % self.non_ascii_exe + expected = str('#!%s -x\n') % self.non_ascii_exe assert actual == expected def test_get_script_header_exe_with_spaces(self): - actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python', + actual = ei.ScriptWriter.get_script_header( + '#!/usr/bin/python', executable='"' + self.exe_with_spaces + '"') expected = '#!"%s"\n' % self.exe_with_spaces assert actual == expected diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index 1a100266..59ffb16d 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -1,9 +1,11 @@ +import datetime import sys import ast import os import glob import re import stat +import time from setuptools.command.egg_info import egg_info, manifest_maker from setuptools.dist import Distribution @@ -146,6 +148,21 @@ class TestEggInfo: ] assert sorted(actual) == expected + def test_rebuilt(self, tmpdir_cwd, env): + """Ensure timestamps are updated when the command is re-run.""" + self._create_project() + + self._run_egg_info_command(tmpdir_cwd, env) + timestamp_a = os.path.getmtime('foo.egg-info') + + # arbitrary sleep just to handle *really* fast systems + time.sleep(.001) + + self._run_egg_info_command(tmpdir_cwd, env) + timestamp_b = os.path.getmtime('foo.egg-info') + + assert timestamp_a != timestamp_b + def test_manifest_template_is_read(self, tmpdir_cwd, env): self._create_project() build_files({ @@ -570,3 +587,19 @@ class TestEggInfo: raise AssertionError(data) if output: assert output in data + + def test_egg_info_tag_only_once(self, tmpdir_cwd, env): + self._create_project() + build_files({ + 'setup.cfg': DALS(""" + [egg_info] + tag_build = dev + tag_date = 0 + tag_svn_revision = 0 + """), + }) + self._run_egg_info_command(tmpdir_cwd, env) + egg_info_dir = os.path.join('.', 'foo.egg-info') + with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file: + pkg_info_lines = pkginfo_file.read().split('\n') + assert 'Version: 0.0.0.dev0' in pkg_info_lines diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index a6023de9..b08f91c7 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -7,14 +7,15 @@ import platform import pytest -import setuptools -from setuptools import find_packages +from . import py3_only -find_420_packages = setuptools.PEP420PackageFinder.find +from setuptools.extern.six import PY3 +from setuptools import find_packages +if PY3: + from setuptools import find_namespace_packages # modeled after CPython's test.support.can_symlink - def can_symlink(): TESTFN = tempfile.mktemp() symlink_path = TESTFN + "can_symlink" @@ -153,30 +154,35 @@ class TestFindPackages: def _assert_packages(self, actual, expected): assert set(actual) == set(expected) + @py3_only def test_pep420_ns_package(self): - packages = find_420_packages( + packages = find_namespace_packages( self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets']) self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg']) + @py3_only def test_pep420_ns_package_no_includes(self): - packages = find_420_packages( + packages = find_namespace_packages( self.dist_dir, exclude=['pkg.subpkg.assets']) self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg']) + @py3_only def test_pep420_ns_package_no_includes_or_excludes(self): - packages = find_420_packages(self.dist_dir) - expected = [ - 'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets'] + packages = find_namespace_packages(self.dist_dir) + expected = ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets'] self._assert_packages(packages, expected) + @py3_only def test_regular_package_with_nested_pep420_ns_packages(self): self._touch('__init__.py', self.pkg_dir) - packages = find_420_packages( + packages = find_namespace_packages( self.dist_dir, exclude=['docs', 'pkg.subpkg.assets']) self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg']) + @py3_only def test_pep420_ns_package_no_non_package_dirs(self): shutil.rmtree(self.docs_dir) shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets')) - packages = find_420_packages(self.dist_dir) + packages = find_namespace_packages(self.dist_dir) self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg']) + diff --git a/setuptools/tests/test_glob.py b/setuptools/tests/test_glob.py new file mode 100644 index 00000000..a0728c5d --- /dev/null +++ b/setuptools/tests/test_glob.py @@ -0,0 +1,35 @@ +import pytest + +from setuptools.glob import glob + +from .files import build_files + + +@pytest.mark.parametrize('tree, pattern, matches', ( + ('', b'', []), + ('', '', []), + (''' + appveyor.yml + CHANGES.rst + LICENSE + MANIFEST.in + pyproject.toml + README.rst + setup.cfg + setup.py + ''', '*.rst', ('CHANGES.rst', 'README.rst')), + (''' + appveyor.yml + CHANGES.rst + LICENSE + MANIFEST.in + pyproject.toml + README.rst + setup.cfg + setup.py + ''', b'*.rst', (b'CHANGES.rst', b'README.rst')), +)) +def test_glob(monkeypatch, tmpdir, tree, pattern, matches): + monkeypatch.chdir(tmpdir) + build_files({name: '' for name in tree.split()}) + assert list(sorted(glob(pattern))) == list(sorted(matches)) diff --git a/setuptools/tests/test_register.py b/setuptools/tests/test_register.py new file mode 100644 index 00000000..96114595 --- /dev/null +++ b/setuptools/tests/test_register.py @@ -0,0 +1,43 @@ +import mock +from distutils import log + +import pytest + +from setuptools.command.register import register +from setuptools.dist import Distribution + + +class TestRegisterTest: + def test_warns_deprecation(self): + dist = Distribution() + + cmd = register(dist) + cmd.run_command = mock.Mock() + cmd.send_metadata = mock.Mock() + cmd.announce = mock.Mock() + + cmd.run() + + cmd.announce.assert_called_with( + "WARNING: Registering is deprecated, use twine to upload instead " + "(https://pypi.org/p/twine/)", + log.WARN + ) + + def test_warns_deprecation_when_raising(self): + dist = Distribution() + + cmd = register(dist) + cmd.run_command = mock.Mock() + cmd.send_metadata = mock.Mock() + cmd.send_metadata.side_effect = Exception + cmd.announce = mock.Mock() + + with pytest.raises(Exception): + cmd.run() + + cmd.announce.assert_called_with( + "WARNING: Registering is deprecated, use twine to upload instead " + "(https://pypi.org/p/twine/)", + log.WARN + ) diff --git a/setuptools/tests/test_upload.py b/setuptools/tests/test_upload.py new file mode 100644 index 00000000..95a8d16b --- /dev/null +++ b/setuptools/tests/test_upload.py @@ -0,0 +1,43 @@ +import mock +from distutils import log + +import pytest + +from setuptools.command.upload import upload +from setuptools.dist import Distribution + + +class TestUploadTest: + def test_warns_deprecation(self): + dist = Distribution() + dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())] + + cmd = upload(dist) + cmd.upload_file = mock.Mock() + cmd.announce = mock.Mock() + + cmd.run() + + cmd.announce.assert_called_once_with( + "WARNING: Uploading via this command is deprecated, use twine to " + "upload instead (https://pypi.org/p/twine/)", + log.WARN + ) + + def test_warns_deprecation_when_raising(self): + dist = Distribution() + dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())] + + cmd = upload(dist) + cmd.upload_file = mock.Mock() + cmd.upload_file.side_effect = Exception + cmd.announce = mock.Mock() + + with pytest.raises(Exception): + cmd.run() + + cmd.announce.assert_called_once_with( + "WARNING: Uploading via this command is deprecated, use twine to " + "upload instead (https://pypi.org/p/twine/)", + log.WARN + ) diff --git a/towncrier_template.rst b/towncrier_template.rst index 9c23b977..fbc5ef03 100644 --- a/towncrier_template.rst +++ b/towncrier_template.rst @@ -2,6 +2,7 @@ {% set underline = underlines[0] %}{% if section %}{{section}} {{ underline * section|length }} {% endif %} + {% if sections[section] %} {% for category, val in definitions.items() if category in sections[section]%} {% if definitions[category]['showcontent'] %} @@ -9,6 +9,12 @@ envlist=python [testenv] deps=-rtests/requirements.txt +# Changed from default (`python -m pip ...`) +# to prevent the current working directory +# from being added to `sys.path`. +install_command={envbindir}/pip install {opts} {packages} +# Same as above. +list_dependencies_command={envbindir}/pip freeze setenv=COVERAGE_FILE={toxworkdir}/.coverage.{envname} # TODO: The passed environment variables came from copying other tox.ini files # These should probably be individually annotated to explain what needs them. |
