Imported Upstream version 47.2.0 upstream/47.2.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 28 Dec 2020 02:29:44 +0000 (11:29 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 28 Dec 2020 02:29:44 +0000 (11:29 +0900)
26 files changed:
.bumpversion.cfg
.github/ISSUE_TEMPLATE/setuptools-warns-about-python-2-incompatibility.md
.travis.yml
CHANGES.rst
README.rst
azure-pipelines.yml
docs/build_meta.txt
docs/developer-guide.txt
docs/keywords.txt [new file with mode: 0644]
docs/pkg_resources.txt
docs/python 2 sunset.txt [new file with mode: 0644]
docs/requirements.txt
docs/setuptools.txt
pkg_resources/__init__.py
pkg_resources/py2_warn.py
setup.cfg
setuptools/__init__.py
setuptools/command/easy_install.py
setuptools/config.py
setuptools/tests/test_config.py
setuptools/tests/test_easy_install.py
setuptools/tests/test_packageindex.py
setuptools/tests/test_virtualenv.py
setuptools/wheel.py
tools/finalize.py
tox.ini

index 09a3be9..ffb0f2e 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 46.3.0
+current_version = 47.2.0
 commit = True
 tag = True
 
index 2f5fe53..1a4f58f 100644 (file)
@@ -13,7 +13,7 @@ Please DO NOT SUBMIT this template without first investigating the issue and ans
 
 If you did not intend to use this template, but only meant to file a blank issue, just hit the back button and click "Open a blank issue".
 
-It's by design that Setuptools 45 and later will stop working on Python 2. To ease the transition, Setuptools 45 was released to continue to have Python 2 compatibility, but emit a strenuous warning that it will stop working.
+Setuptools 45 dropped support for Python 2 with a strenuous warning and Setuptools 47 fails to run on Python 2.
 
 In most cases, using pip 9 or later to install Setuptools from PyPI or any index supporting the Requires-Python metadata will do the right thing and install Setuptools 44.x on Python 2.
 
@@ -28,6 +28,7 @@ Your first course of action should be to reason about how you managed to get an
 <!-- These are the recommended workarounds for the issue. Please
 try them first. -->
 
+- [ ] Read [Python 2 Sunset docs](https://setuptools.readthedocs.io/en/latest/python%202%20sunset.html).
 - [ ] Python 2 is required for this application.
 - [ ] I maintain the software that installs Setuptools (if not, please contact that project).
 - [ ] Setuptools installed with pip 9 or later.
@@ -40,6 +41,11 @@ try them first. -->
 - Python installed how:
 - Virtualenv version (if using virtualenv): n/a
 
+Command(s) that triggered the warning/error (and output):
+
+```
+```
+
 Command(s) used to install setuptools (and output):
 
 ```
index 3e97f35..f97abc5 100644 (file)
@@ -4,11 +4,6 @@ language: python
 jobs:
   fast_finish: true
   include:
-  - &latest_py2
-    python: 2.7
-    env: TOXENV=py27
-  - <<: *latest_py2
-    env: LANG=C TOXENV=py27
   - python: pypy3
     env: DISABLE_COVERAGE=1  # Don't run coverage on pypy (too slow).
   - python: 3.5
@@ -24,6 +19,8 @@ jobs:
   allow_failures:
   # suppress failures due to pypa/setuptools#2000
   - python: pypy3
+  - <<: *latest_py3
+    env: TOXENV=docs DISABLE_COVERAGE=1
 
 cache: pip
 
index 9793453..44abab7 100644 (file)
@@ -1,3 +1,53 @@
+v47.2.0
+-------
+
+* #2194: Editable-installed entry points now load significantly faster on Python versions 3.8+.
+
+
+v47.1.1
+-------
+
+* #2156: Update mailing list pointer in developer docs
+
+Incorporate changes from v44.1.1:
+
+* #2158: Avoid loading working set during ``Distribution.finalize_options`` prior to invoking ``_install_setup_requires``, broken since v42.0.0.
+
+
+v44.1.1
+-------
+
+* #2158: Avoid loading working set during ``Distribution.finalize_options`` prior to invoking ``_install_setup_requires``, broken since v42.0.0.
+
+
+v47.1.0
+-------
+
+* #2070: In wheel-to-egg conversion, use simple pkg_resources-style namespace declaration for packages that declare namespace_packages.
+
+
+v47.0.0
+-------
+
+* #2094: Setuptools now actively crashes under Python 2. Python 3.5 or later is required. Users of Python 2 should use ``setuptools<45``.
+* #1700: Document all supported keywords by migrating the ones from distutils.
+
+
+v46.4.0
+-------
+
+* #1753: ``attr:`` now extracts variables through rudimentary examination of the AST,
+  thereby supporting modules with third-party imports. If examining the AST
+  fails to find the variable, ``attr:`` falls back to the old behavior of
+  importing the module. Works on Python 3 only.
+
+
+v46.3.1
+-------
+
+No significant changes.
+
+
 v46.3.0
 -------
 
index 6caaa75..9cbf7b8 100644 (file)
@@ -6,7 +6,7 @@
 
 .. _PyPI link: https://pypi.org/project/setuptools
 
-.. image:: https://dev.azure.com/jaraco/setuptools/_apis/build/status/jaraco.setuptools?branchName=master
+.. image:: https://dev.azure.com/jaraco/setuptools/_apis/build/status/pypa.setuptools?branchName=master
    :target: https://dev.azure.com/jaraco/setuptools/_build/latest?definitionId=1&branchName=master
 
 .. image:: https://img.shields.io/travis/pypa/setuptools/master.svg?label=Linux%20CI&logo=travis&logoColor=white
index 0253a77..ee77268 100644 (file)
@@ -11,10 +11,12 @@ trigger:
     - '*'
 
 pool:
-  vmimage: 'Ubuntu-18.04'
+  vmImage: $(pool_vm_image)
 
 variables:
 - group: Azure secrets
+- name: pool_vm_image
+  value: Ubuntu-18.04
 
 stages:
 - stage: Test
@@ -23,10 +25,17 @@ stages:
   - job: 'Test'
     strategy:
       matrix:
-        Python36:
+        Bionic Python 3.6:
           python.version: '3.6'
-        Python38:
+        Bionic Python 3.8:
           python.version: '3.8'
+        Windows:
+          python.version: '3.8'
+          pool_vm_image: vs2017-win2016
+        MacOS:
+          python.version: '3.8'
+          pool_vm_image: macos-10.15
+
       maxParallel: 4
 
     steps:
index ef9fb2a..fcc2b7f 100644 (file)
@@ -68,7 +68,7 @@ Use ``setuptools``' `declarative config`_ to specify the package information::
 
 Now generate the distribution. Although the PyPA is still working to
 `provide a recommended tool <https://github.com/pypa/packaging-problems/issues/219>`_
-to build packages, the `pep517 package <https://pypi.org/project/pep517`_
+to build packages, the `pep517 package <https://pypi.org/project/pep517>`_
 provides this functionality. To build the package::
 
     $ pip install -q pep517
index 0b4ae4d..4a78e22 100644 (file)
@@ -23,16 +23,16 @@ contribution.
 Project Management
 ------------------
 
-Setuptools is maintained primarily in Github at `this home
+Setuptools is maintained primarily in GitHub at `this home
 <https://github.com/pypa/setuptools>`_. Setuptools is maintained under the
 Python Packaging Authority (PyPA) with several core contributors. All bugs
-for Setuptools are filed and the canonical source is maintained in Github.
+for Setuptools are filed and the canonical source is maintained in GitHub.
 
 User support and discussions are done through the issue tracker (for specific)
-issues, through the distutils-sig mailing list, or on IRC (Freenode) at
+issues, through the `distutils-sig mailing list <https://mail.python.org/mailman3/lists/distutils-sig.python.org/>`_, or on IRC (Freenode) at
 #pypa.
 
-Discussions about development happen on the pypa-dev mailing list or on
+Discussions about development happen on the distutils-sig mailing list or on
 `Gitter <https://gitter.im/pypa/setuptools>`_.
 
 -----------------
@@ -44,7 +44,7 @@ describing the motivation behind making changes. First search to see if a
 ticket already exists for your issue. If not, create one. Try to think from
 the perspective of the reader. Explain what behavior you expected, what you
 got instead, and what factors might have contributed to the unexpected
-behavior. In Github, surround a block of code or traceback with the triple
+behavior. In GitHub, surround a block of code or traceback with the triple
 backtick "\`\`\`" so that it is formatted nicely.
 
 Filing a ticket provides a forum for justification, discussion, and
@@ -139,7 +139,7 @@ Vendored Dependencies
 ---------------------
 
 Setuptools has some dependencies, but due to `bootstrapping issues
-<https://github.com/pypa/setuptools/issues/980>`, those dependencies
+<https://github.com/pypa/setuptools/issues/980>`_, those dependencies
 cannot be declared as they won't be resolved soon enough to build
 setuptools from source. Eventually, this limitation may be lifted as
 PEP 517/518 reach ubiquitous adoption, but for now, Setuptools
diff --git a/docs/keywords.txt b/docs/keywords.txt
new file mode 100644 (file)
index 0000000..5635619
--- /dev/null
@@ -0,0 +1,336 @@
+``name``
+    A string specifying the name of the package.
+
+``version``
+    A string specifying the version number of the package.
+
+``description``
+    A string describing the package in a single line.
+
+``long_description``
+    A string providing a longer description of the package.
+
+``long_description_content_type``
+    A string specifying the content type is used for the ``long_description``
+    (e.g. ``text/markdown``)
+
+``author``
+    A string specifying the author of the package.
+
+``author_email``
+    A string specifying the email address of the package author.
+
+``maintainer``
+    A string specifying the name of the current maintainer, if different from
+    the author. Note that if the maintainer is provided, setuptools will use it
+    as the author in ``PKG-INFO``.
+
+``maintainer_email``
+    A string specifying the email address of the current maintainer, if
+    different from the author.
+
+``url``
+    A string specifying the URL for the package homepage.
+
+``download_url``
+    A string specifying the URL to download the package.
+
+``packages``
+    A list of strings specifying the packages that setuptools will manipulate.
+
+``py_modules``
+    A list of strings specifying the modules that setuptools will manipulate.
+
+``scripts``
+    A list of strings specifying the standalone script files to be built and
+    installed.
+
+``ext_package``
+    A string specifying the base package name for the extensions provided by
+    this package.
+
+``ext_modules``
+    A list of instances of ``setuptools.Extension`` providing the list of
+    Python extensions to be built.
+
+``classifiers``
+    A list of strings describing the categories for the package.
+
+``distclass``
+    A subclass of ``Distribution`` to use.
+
+``script_name``
+    A string specifying the name of the setup.py script -- defaults to
+    ``sys.argv[0]``
+
+``script_args``
+    A list of strings defining the arguments to supply to the setup script.
+
+``options``
+    A dictionary providing the default options for the setup script.
+
+``license``
+    A string specifying the license of the package.
+
+``keywords``
+    A list of strings or a comma-separated string providing descriptive
+    meta-data. See: `PEP 0314`_.
+
+.. _PEP 0314: https://www.python.org/dev/peps/pep-0314/
+
+``platforms``
+    A list of strings or comma-separated string.
+
+``cmdclass``
+    A dictionary providing a mapping of command names to ``Command``
+    subclasses.
+
+``data_files``
+
+    .. warning::
+        ``data_files`` is deprecated. It does not work with wheels, so it
+        should be avoided.
+
+    A list of strings specifying the data files to install.
+
+``package_dir``
+    A dictionary providing a mapping of package to directory names.
+
+``requires``
+
+   .. warning::
+      ``requires`` is superseded by ``install_requires`` and should not be used
+      anymore.
+
+``obsoletes``
+
+   .. warning::
+      ``obsoletes`` is currently ignored by ``pip``.
+
+   List of strings describing packages which this package renders obsolete,
+   meaning that the two projects should not be installed at the same time.
+
+   Version declarations can be supplied. Version numbers must be in the format
+   specified in Version specifiers (e.g. ``foo (<3.0)``).
+
+   This field may be followed by an environment marker after a semicolon (e.g.
+   ``foo; os_name == "posix"``)
+
+   The most common use of this field will be in case a project name changes,
+   e.g. Gorgon 2.3 gets subsumed into Torqued Python 1.0. When you install
+   Torqued Python, the Gorgon distribution should be removed.
+
+``provides``
+
+   .. warning::
+      ``provides`` is currently ignored by ``pip``.
+
+   List of strings describing package- and virtual package names contained
+   within this package.
+
+   A package may provide additional names, e.g. to indicate that multiple
+   projects have been bundled together. For instance, source distributions of
+   the ZODB project have historically included the transaction project, which
+   is now available as a separate distribution. Installing such a source
+   distribution satisfies requirements for both ZODB and transaction.
+
+   A package may also provide a “virtual” project name, which does not
+   correspond to any separately-distributed project: such a name might be used
+   to indicate an abstract capability which could be supplied by one of
+   multiple projects. E.g., multiple projects might supply RDBMS bindings for
+   use by a given ORM: each project might declare that it provides
+   ORM-bindings, allowing other projects to depend only on having at most one
+   of them installed.
+
+   A version declaration may be supplied and must follow the rules described in
+   Version specifiers. The distribution’s version number will be implied if
+   none is specified (e.g. ``foo (<3.0)``).
+
+   Each package may be followed by an environment marker after a semicolon
+   (e.g. ``foo; os_name == "posix"``).
+
+.. Below are setuptools keywords, above are distutils
+
+``include_package_data``
+    If set to ``True``, this tells ``setuptools`` to automatically include any
+    data files it finds inside your package directories that are specified by
+    your ``MANIFEST.in`` file.  For more information, see the section on
+    :ref:`Including Data Files`.
+
+``exclude_package_data``
+    A dictionary mapping package names to lists of glob patterns that should
+    be *excluded* from your package directories.  You can use this to trim back
+    any excess files included by ``include_package_data``.  For a complete
+    description and examples, see the section on :ref:`Including Data Files`.
+
+``package_data``
+    A dictionary mapping package names to lists of glob patterns.  For a
+    complete description and examples, see the section on :ref:`Including Data
+    Files`.  You do not need to use this option if you are using
+    ``include_package_data``, unless you need to add e.g. files that are
+    generated by your setup script and build process.  (And are therefore not
+    in source control or are files that you don't want to include in your
+    source distribution.)
+
+``zip_safe``
+    A boolean (True or False) flag specifying whether the project can be
+    safely installed and run from a zip file.  If this argument is not
+    supplied, the ``bdist_egg`` command will have to analyze all of your
+    project's contents for possible problems each time it builds an egg.
+
+``install_requires``
+    A string or list of strings specifying what other distributions need to
+    be installed when this one is.  See the section on :ref:`Declaring
+    Dependencies` for details and examples of the format of this argument.
+
+``entry_points``
+    A dictionary mapping entry point group names to strings or lists of strings
+    defining the entry points.  Entry points are used to support dynamic
+    discovery of services or plugins provided by a project.  See :ref:`Dynamic
+    Discovery of Services and Plugins` for details and examples of the format
+    of this argument.  In addition, this keyword is used to support
+    :ref:`Automatic Script Creation`.
+
+``extras_require``
+    A dictionary mapping names of "extras" (optional features of your project)
+    to strings or lists of strings specifying what other distributions must be
+    installed to support those features.  See the section on :ref:`Declaring
+    Dependencies` for details and examples of the format of this argument.
+
+``python_requires``
+    A string corresponding to a version specifier (as defined in PEP 440) for
+    the Python version, used to specify the Requires-Python defined in PEP 345.
+
+``setup_requires``
+
+    .. warning::
+        Using ``setup_requires`` is discouraged in favor of `PEP-518`_
+
+    A string or list of strings specifying what other distributions need to
+    be present in order for the *setup script* to run.  ``setuptools`` will
+    attempt to obtain these (even going so far as to download them using
+    ``EasyInstall``) before processing the rest of the setup script or commands.
+    This argument is needed if you are using distutils extensions as part of
+    your build process; for example, extensions that process setup() arguments
+    and turn them into EGG-INFO metadata files.
+
+    (Note: projects listed in ``setup_requires`` will NOT be automatically
+    installed on the system where the setup script is being run.  They are
+    simply downloaded to the ./.eggs directory if they're not locally available
+    already.  If you want them to be installed, as well as being available
+    when the setup script is run, you should add them to ``install_requires``
+    **and** ``setup_requires``.)
+
+.. _PEP-518: http://www.python.org/dev/peps/pep-0518/
+
+``dependency_links``
+
+    .. warning::
+        ``dependency_links`` is deprecated. It is not supported anymore by pip.
+
+    A list of strings naming URLs to be searched when satisfying dependencies.
+    These links will be used if needed to install packages specified by
+    ``setup_requires`` or ``tests_require``.  They will also be written into
+    the egg's metadata for use by tools like EasyInstall to use when installing
+    an ``.egg`` file.
+
+``namespace_packages``
+    A list of strings naming the project's "namespace packages".  A namespace
+    package is a package that may be split across multiple project
+    distributions.  For example, Zope 3's ``zope`` package is a namespace
+    package, because subpackages like ``zope.interface`` and ``zope.publisher``
+    may be distributed separately.  The egg runtime system can automatically
+    merge such subpackages into a single parent package at runtime, as long
+    as you declare them in each project that contains any subpackages of the
+    namespace package, and as long as the namespace package's ``__init__.py``
+    does not contain any code other than a namespace declaration.  See the
+    section on :ref:`Namespace Packages` for more information.
+
+``test_suite``
+    A string naming a ``unittest.TestCase`` subclass (or a package or module
+    containing one or more of them, or a method of such a subclass), or naming
+    a function that can be called with no arguments and returns a
+    ``unittest.TestSuite``.  If the named suite is a module, and the module
+    has an ``additional_tests()`` function, it is called and the results are
+    added to the tests to be run.  If the named suite is a package, any
+    submodules and subpackages are recursively added to the overall test suite.
+
+    Specifying this argument enables use of the :ref:`test` command to run the
+    specified test suite, e.g. via ``setup.py test``.  See the section on the
+    :ref:`test` command below for more details.
+
+    New in 41.5.0: Deprecated the test command.
+
+``tests_require``
+    If your project's tests need one or more additional packages besides those
+    needed to install it, you can use this option to specify them.  It should
+    be a string or list of strings specifying what other distributions need to
+    be present for the package's tests to run.  When you run the ``test``
+    command, ``setuptools`` will  attempt to obtain these (even going
+    so far as to download them using ``EasyInstall``).  Note that these
+    required projects will *not* be installed on the system where the tests
+    are run, but only downloaded to the project's setup directory if they're
+    not already installed locally.
+
+    New in 41.5.0: Deprecated the test command.
+
+.. _test_loader:
+
+``test_loader``
+    If you would like to use a different way of finding tests to run than what
+    setuptools normally uses, you can specify a module name and class name in
+    this argument.  The named class must be instantiable with no arguments, and
+    its instances must support the ``loadTestsFromNames()`` method as defined
+    in the Python ``unittest`` module's ``TestLoader`` class.  Setuptools will
+    pass only one test "name" in the `names` argument: the value supplied for
+    the ``test_suite`` argument.  The loader you specify may interpret this
+    string in any way it likes, as there are no restrictions on what may be
+    contained in a ``test_suite`` string.
+
+    The module name and class name must be separated by a ``:``.  The default
+    value of this argument is ``"setuptools.command.test:ScanningLoader"``.  If
+    you want to use the default ``unittest`` behavior, you can specify
+    ``"unittest:TestLoader"`` as your ``test_loader`` argument instead.  This
+    will prevent automatic scanning of submodules and subpackages.
+
+    The module and class you specify here may be contained in another package,
+    as long as you use the ``tests_require`` option to ensure that the package
+    containing the loader class is available when the ``test`` command is run.
+
+    New in 41.5.0: Deprecated the test command.
+
+``eager_resources``
+    A list of strings naming resources that should be extracted together, if
+    any of them is needed, or if any C extensions included in the project are
+    imported.  This argument is only useful if the project will be installed as
+    a zipfile, and there is a need to have all of the listed resources be
+    extracted to the filesystem *as a unit*.  Resources listed here
+    should be '/'-separated paths, relative to the source root, so to list a
+    resource ``foo.png`` in package ``bar.baz``, you would include the string
+    ``bar/baz/foo.png`` in this argument.
+
+    If you only need to obtain resources one at a time, or you don't have any C
+    extensions that access other files in the project (such as data files or
+    shared libraries), you probably do NOT need this argument and shouldn't
+    mess with it.  For more details on how this argument works, see the section
+    below on :ref:`Automatic Resource Extraction`.
+
+``use_2to3``
+    Convert the source code from Python 2 to Python 3 with 2to3 during the
+    build process. See :doc:`python3` for more details.
+
+``convert_2to3_doctests``
+    List of doctest source files that need to be converted with 2to3.
+    See :doc:`python3` for more details.
+
+``use_2to3_fixers``
+    A list of modules to search for additional fixers to be used during
+    the 2to3 conversion. See :doc:`python3` for more details.
+
+``use_2to3_exclude_fixers``
+    List of fixer names to be skipped.
+
+``project_urls``
+    An arbitrary map of URL names to hyperlinks, allowing more extensible
+    documentation of where various resources can be found than the simple
+    ``url`` and ``download_url`` options provide.
index 71568c1..f2e554f 100644 (file)
@@ -594,7 +594,7 @@ Requirements Parsing
 
         FooProject >= 1.2
         Fizzy [foo, bar]
-        PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1
+        PickyThing>1.6,<=1.9,!=1.8.6
         SomethingWhoseVersionIDontCareAbout
         SomethingWithMarker[foo]>1.0;python_version<"2.7"
 
diff --git a/docs/python 2 sunset.txt b/docs/python 2 sunset.txt
new file mode 100644 (file)
index 0000000..f7b7ee2
--- /dev/null
@@ -0,0 +1,69 @@
+:orphan:
+
+Python 2 Sunset
+===============
+
+Since January 2020 and the release of Setuptools 45, Python 2 is no longer
+supported by the most current release (`discussion
+<https://github.com/pypa/setuptools/issues/1458>`_). Setuptools as a project
+continues to support Python 2 with bugfixes and important features on
+Setuptools 44.x.
+
+By design, most users will be unaffected by this change. That's because
+Setuptools 45 declares its supported Python versions to exclude Python 2.7,
+and installers such as pip 9 or later will honor this declaration and prevent
+installation of Setuptools 45 or later in Python 2 environments.
+
+Users that do import any portion of Setuptools 45 or later on Python 2 are
+directed to this documentation to provide guidance on how to work around the
+issues.
+
+Workarounds
+-----------
+
+The best recommendation is to avoid Python 2 and move to Python 3 where
+possible. This project acknowledges that not all environments can drop Python
+2 support, so provides other options.
+
+In less common scenarios, later versions of Setuptools can be installed on
+unsupported Python versions. In these environments, the installer is advised
+to first install ``setuptools<45`` to "pin Setuptools" to a compatible
+version.
+
+- When using older versions of pip (before 9.0), the ``Requires-Python``
+  directive is not honored and invalid versions can be installed. Users are
+  advised first to upgrade pip and retry or to pin Setuptools. Use ``pip
+  --version`` to determine the version of pip.
+- When using ``easy_install``, ``Requires-Python`` is not honored and later
+  versions can be installed. In this case, users are advised to pin
+  Setuptools. This applies to ``setup.py install`` invocations as well, as
+  they use Setuptools under the hood.
+
+It's still not working
+----------------------
+
+If after trying the above steps, the Python environment still has incompatible
+versions of Setuptools installed, here are some things to try.
+
+1. Uninstall and reinstall Setuptools. Run ``pip uninstall -y setuptools`` for
+   the relevant environment. Repeat until there is no Setuptools installed.
+   Then ``pip install setuptools``.
+2. If possible, attempt to replicate the problem in a second environment
+   (virtual machine, friend's computer, etc). If the issue is isolated to just
+   one unique enviornment, first determine what is different about those
+   environments (or reinstall/reset the failing one to defaults).
+3. End users who are not themselves the maintainers for the package they are
+   trying to install should contact the support channels for the relevant
+   application. Please be considerate of those projects by searching for
+   existing issues and following the latest guidance before reaching out for
+   support. When filing an issue, be sure to give as much detail as possible
+   to help the maintainers understand what factors led to the issue after
+   following their recommended guidance.
+4. Reach out to your local support groups. There's a good chance someone
+   nearby has the expertise and willingness to help.
+5. If all else fails, `file this template
+   <https://github.com/pypa/setuptools/issues/new?assignees=&labels=Python+2&template=setuptools-warns-about-python-2-incompatibility.md&title=Incompatible+install+in+(summarize+your+environment)>`_
+   with Setuptools. Please complete the whole template, providing as much
+   detail about what factors led to the issue. Setuptools maintainers will
+   summarily close tickets filed without any meaningful detail or engagement
+   with the issue.
index 6c35bf6..104d68f 100644 (file)
@@ -2,3 +2,6 @@
 sphinx
 jaraco.packaging>=6.1
 rst.linker>=1.9
+pygments-github-lexers==0.0.5
+
+setuptools>=34
index 30a30c2..7e0914b 100644 (file)
@@ -229,174 +229,7 @@ The following keyword arguments to ``setup()`` are added or changed by
 ``setuptools``.  All of them are optional; you do not have to supply them
 unless you need the associated ``setuptools`` feature.
 
-``include_package_data``
-    If set to ``True``, this tells ``setuptools`` to automatically include any
-    data files it finds inside your package directories that are specified by
-    your ``MANIFEST.in`` file.  For more information, see the section below on
-    `Including Data Files`_.
-
-``exclude_package_data``
-    A dictionary mapping package names to lists of glob patterns that should
-    be *excluded* from your package directories.  You can use this to trim back
-    any excess files included by ``include_package_data``.  For a complete
-    description and examples, see the section below on `Including Data Files`_.
-
-``package_data``
-    A dictionary mapping package names to lists of glob patterns.  For a
-    complete description and examples, see the section below on `Including
-    Data Files`_.  You do not need to use this option if you are using
-    ``include_package_data``, unless you need to add e.g. files that are
-    generated by your setup script and build process.  (And are therefore not
-    in source control or are files that you don't want to include in your
-    source distribution.)
-
-``zip_safe``
-    A boolean (True or False) flag specifying whether the project can be
-    safely installed and run from a zip file.  If this argument is not
-    supplied, the ``bdist_egg`` command will have to analyze all of your
-    project's contents for possible problems each time it builds an egg.
-
-``install_requires``
-    A string or list of strings specifying what other distributions need to
-    be installed when this one is.  See the section below on `Declaring
-    Dependencies`_ for details and examples of the format of this argument.
-
-``entry_points``
-    A dictionary mapping entry point group names to strings or lists of strings
-    defining the entry points.  Entry points are used to support dynamic
-    discovery of services or plugins provided by a project.  See `Dynamic
-    Discovery of Services and Plugins`_ for details and examples of the format
-    of this argument.  In addition, this keyword is used to support `Automatic
-    Script Creation`_.
-
-``extras_require``
-    A dictionary mapping names of "extras" (optional features of your project)
-    to strings or lists of strings specifying what other distributions must be
-    installed to support those features.  See the section below on `Declaring
-    Dependencies`_ for details and examples of the format of this argument.
-
-``python_requires``
-    A string corresponding to a version specifier (as defined in PEP 440) for
-    the Python version, used to specify the Requires-Python defined in PEP 345.
-
-``setup_requires``
-    A string or list of strings specifying what other distributions need to
-    be present in order for the *setup script* to run.  ``setuptools`` will
-    attempt to obtain these (using pip if available) before processing the
-    rest of the setup script or commands.  This argument is needed if you
-    are using distutils extensions as part of your build process; for
-    example, extensions that process setup() arguments and turn them into
-    EGG-INFO metadata files.
-
-    (Note: projects listed in ``setup_requires`` will NOT be automatically
-    installed on the system where the setup script is being run.  They are
-    simply downloaded to the ./.eggs directory if they're not locally available
-    already.  If you want them to be installed, as well as being available
-    when the setup script is run, you should add them to ``install_requires``
-    **and** ``setup_requires``.)
-
-``dependency_links``
-    A list of strings naming URLs to be searched when satisfying dependencies.
-    These links will be used if needed to install packages specified by
-    ``setup_requires`` or ``tests_require``.  They will also be written into
-    the egg's metadata for use during install by tools that support them.
-
-``namespace_packages``
-    A list of strings naming the project's "namespace packages".  A namespace
-    package is a package that may be split across multiple project
-    distributions.  For example, Zope 3's ``zope`` package is a namespace
-    package, because subpackages like ``zope.interface`` and ``zope.publisher``
-    may be distributed separately.  The egg runtime system can automatically
-    merge such subpackages into a single parent package at runtime, as long
-    as you declare them in each project that contains any subpackages of the
-    namespace package, and as long as the namespace package's ``__init__.py``
-    does not contain any code other than a namespace declaration.  See the
-    section below on `Namespace Packages`_ for more information.
-
-``test_suite``
-    A string naming a ``unittest.TestCase`` subclass (or a package or module
-    containing one or more of them, or a method of such a subclass), or naming
-    a function that can be called with no arguments and returns a
-    ``unittest.TestSuite``.  If the named suite is a module, and the module
-    has an ``additional_tests()`` function, it is called and the results are
-    added to the tests to be run.  If the named suite is a package, any
-    submodules and subpackages are recursively added to the overall test suite.
-
-    Specifying this argument enables use of the `test`_ command to run the
-    specified test suite, e.g. via ``setup.py test``.  See the section on the
-    `test`_ command below for more details.
-
-    New in 41.5.0: Deprecated the test command.
-
-``tests_require``
-    If your project's tests need one or more additional packages besides those
-    needed to install it, you can use this option to specify them.  It should
-    be a string or list of strings specifying what other distributions need to
-    be present for the package's tests to run.  When you run the ``test``
-    command, ``setuptools`` will  attempt to obtain these (using pip if
-    available).  Note that these required projects will *not* be installed on
-    the system where the tests are run, but only downloaded to the project's setup
-    directory if they're not already installed locally.
-
-    New in 41.5.0: Deprecated the test command.
-
-.. _test_loader:
-
-``test_loader``
-    If you would like to use a different way of finding tests to run than what
-    setuptools normally uses, you can specify a module name and class name in
-    this argument.  The named class must be instantiable with no arguments, and
-    its instances must support the ``loadTestsFromNames()`` method as defined
-    in the Python ``unittest`` module's ``TestLoader`` class.  Setuptools will
-    pass only one test "name" in the `names` argument: the value supplied for
-    the ``test_suite`` argument.  The loader you specify may interpret this
-    string in any way it likes, as there are no restrictions on what may be
-    contained in a ``test_suite`` string.
-
-    The module name and class name must be separated by a ``:``.  The default
-    value of this argument is ``"setuptools.command.test:ScanningLoader"``.  If
-    you want to use the default ``unittest`` behavior, you can specify
-    ``"unittest:TestLoader"`` as your ``test_loader`` argument instead.  This
-    will prevent automatic scanning of submodules and subpackages.
-
-    The module and class you specify here may be contained in another package,
-    as long as you use the ``tests_require`` option to ensure that the package
-    containing the loader class is available when the ``test`` command is run.
-
-    New in 41.5.0: Deprecated the test command.
-
-``eager_resources``
-    A list of strings naming resources that should be extracted together, if
-    any of them is needed, or if any C extensions included in the project are
-    imported.  This argument is only useful if the project will be installed as
-    a zipfile, and there is a need to have all of the listed resources be
-    extracted to the filesystem *as a unit*.  Resources listed here
-    should be "/"-separated paths, relative to the source root, so to list a
-    resource ``foo.png`` in package ``bar.baz``, you would include the string
-    ``bar/baz/foo.png`` in this argument.
-
-    If you only need to obtain resources one at a time, or you don't have any C
-    extensions that access other files in the project (such as data files or
-    shared libraries), you probably do NOT need this argument and shouldn't
-    mess with it.  For more details on how this argument works, see the section
-    below on `Automatic Resource Extraction`_.
-
-``use_2to3``
-    Convert the source code from Python 2 to Python 3 with 2to3 during the
-    build process. See :doc:`python3` for more details.
-
-``convert_2to3_doctests``
-    List of doctest source files that need to be converted with 2to3.
-    See :doc:`python3` for more details.
-
-``use_2to3_fixers``
-    A list of modules to search for additional fixers to be used during
-    the 2to3 conversion. See :doc:`python3` for more details.
-
-``project_urls``
-    An arbitrary map of URL names to hyperlinks, allowing more extensible
-    documentation of where various resources can be found than the simple
-    ``url`` and ``download_url`` options provide.
+.. include:: keywords.txt
 
 
 Using ``find_packages()``
@@ -505,6 +338,8 @@ With this layout, the package directory is specified as ``src``, as such::
 
 .. _PEP 420: https://www.python.org/dev/peps/pep-0420/
 
+.. _Automatic Script Creation:
+
 Automatic Script Creation
 =========================
 
@@ -591,6 +426,7 @@ and version is in use.  The header script will check this and exit with an
 error if the ``.egg`` file has been renamed or is invoked via a symlink that
 changes its base name.
 
+.. _Declaring Dependencies:
 
 Declaring Dependencies
 ======================
@@ -846,6 +682,8 @@ detailed in `PEP 508`_.
 
 .. _PEP 508: https://www.python.org/dev/peps/pep-0508/
 
+.. _Including Data Files:
+
 Including Data Files
 ====================
 
@@ -1021,6 +859,7 @@ no supported facility to reliably retrieve these resources.
 Instead, the PyPA recommends that any data files you wish to be accessible at
 run time be included in the package.
 
+.. _Automatic Resource Extraction:
 
 Automatic Resource Extraction
 -----------------------------
@@ -1066,6 +905,8 @@ Extensible Applications and Frameworks
 
 .. _Entry Points:
 
+.. _Dynamic Discovery of Services and Plugins:
+
 Dynamic Discovery of Services and Plugins
 -----------------------------------------
 
@@ -2054,7 +1895,7 @@ result (which must be a ``unittest.TestSuite``) is added to the tests to be
 run.  If the named suite is a package, any submodules and subpackages are
 recursively added to the overall test suite.  (Note: if your project specifies
 a ``test_loader``, the rules for processing the chosen ``test_suite`` may
-differ; see the `test_loader`_ documentation for more details.)
+differ; see the :ref:`test_loader <test_loader>` documentation for more details.)
 
 Note that many test systems including ``doctest`` support wrapping their
 non-``unittest`` tests in ``TestSuite`` objects.  So, if you are using a test
@@ -2193,11 +2034,54 @@ 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:`` and ``find_namespace:`` directives in
+* Some keys allow ``file:``, ``attr:``, ``find:``, and ``find_namespace:`` directives in
   order to cover common usecases.
 
 * Unknown keys are ignored.
 
+setup.cfg-only projects
+=======================
+
+.. versionadded:: 40.9.0
+
+If ``setup.py`` is missing from the project directory when a :pep:`517`
+build is invoked, ``setuptools`` emulates a dummy ``setup.py`` file containing
+only a ``setuptools.setup()`` call.
+
+.. note::
+
+    :pep:`517` doesn't support editable installs so this is currently
+    incompatible with ``pip install -e .``, as :pep:`517` does not support editable installs.
+
+This means that you can have a Python project with all build configuration
+specified in ``setup.cfg``, without a ``setup.py`` file, if you **can rely
+on** your project always being built by a :pep:`517`/:pep:`518` compatible
+frontend.
+
+To use this feature:
+
+* Specify build requirements and :pep:`517` build backend in
+  ``pyproject.toml``.
+  For example:
+
+  .. code-block:: toml
+
+      [build-system]
+      requires = [
+        "setuptools >= 40.9.0",
+        "wheel",
+      ]
+      build-backend = "setuptools.build_meta"
+
+* Use a :pep:`517` compatible build frontend, such as ``pip >= 19`` or ``pep517``.
+
+  .. warning::
+
+      As :pep:`517` is new, support is not universal, and frontends that
+      do support it may still have bugs. For compatibility, you may want to
+      put a ``setup.py`` file containing only a ``setuptools.setup()``
+      invocation.
+
 
 Using a ``src/`` layout
 =======================
@@ -2247,6 +2131,12 @@ Special directives:
 
 * ``attr:`` - Value is read from a module attribute.  ``attr:`` supports
   callables and iterables; unsupported types are cast using ``str()``.
+
+  In order to support the common case of a literal value assigned to a variable
+  in a module containing (directly or indirectly) third-party imports,
+  ``attr:`` first tries to read the value from the module by examining the
+  module's AST.  If that fails, ``attr:`` falls back to importing the module.
+
 * ``file:`` - Value is read from a list of files and then concatenated
 
 
index edd3d2e..2e7d505 100644 (file)
@@ -1577,6 +1577,17 @@ is not allowed.
 register_loader_type(object, NullProvider)
 
 
+def _parents(path):
+    """
+    yield all parents of path including path
+    """
+    last = None
+    while path != last:
+        yield path
+        last = path
+        path, _ = os.path.split(path)
+
+
 class EggProvider(NullProvider):
     """Provider based on a virtual filesystem"""
 
@@ -1585,18 +1596,16 @@ class EggProvider(NullProvider):
         self._setup_prefix()
 
     def _setup_prefix(self):
-        # we assume here that our metadata may be nested inside a "basket"
-        # of multiple eggs; that's why we use module_path instead of .archive
-        path = self.module_path
-        old = None
-        while path != old:
-            if _is_egg_path(path):
-                self.egg_name = os.path.basename(path)
-                self.egg_info = os.path.join(path, 'EGG-INFO')
-                self.egg_root = path
-                break
-            old = path
-            path, base = os.path.split(path)
+        # Assume that metadata may be nested inside a "basket"
+        # of multiple eggs and use module_path instead of .archive.
+        eggs = filter(_is_egg_path, _parents(self.module_path))
+        egg = next(eggs, None)
+        egg and self._set_egg(egg)
+
+    def _set_egg(self, path):
+        self.egg_name = os.path.basename(path)
+        self.egg_info = os.path.join(path, 'EGG-INFO')
+        self.egg_root = path
 
 
 class DefaultProvider(EggProvider):
index bfc3523..6855aa2 100644 (file)
@@ -4,18 +4,13 @@ import textwrap
 
 
 msg = textwrap.dedent("""
-    You are running Setuptools on Python 2, which is no longer
-    supported and
-    >>> SETUPTOOLS WILL STOP WORKING <<<
-    in a subsequent release (no sooner than 2020-04-20).
-    Please ensure you are installing
-    Setuptools using pip 9.x or later or pin to `setuptools<45`
-    in your environment.
-    If you have done those things and are still encountering
-    this message, please follow up at
-    https://bit.ly/setuptools-py2-warning.
+    Encountered a version of Setuptools that no longer supports
+    this version of Python. Please head to
+    https://bit.ly/setuptools-py2-sunset for support.
     """)
 
-pre = "Setuptools will stop working on Python 2\n"
+pre = "Setuptools no longer works on Python 2\n"
 
-sys.version_info < (3,) and warnings.warn(pre + "*" * 60 + msg + "*" * 60)
+if sys.version_info < (3,):
+    warnings.warn(pre + "*" * 60 + msg + "*" * 60)
+    raise SystemExit(32)
index 5495343..4beae65 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,7 +16,7 @@ formats = zip
 
 [metadata]
 name = setuptools
-version = 46.3.0
+version = 47.2.0
 description = Easily download, build, install, upgrade, and uninstall Python packages
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
@@ -78,3 +78,4 @@ docs =
     sphinx
     jaraco.packaging>=6.1
     rst.linker>=1.9
+    pygments-github-lexers==0.0.5
index 811f3fd..833e20e 100644 (file)
@@ -128,10 +128,27 @@ if PY3:
 def _install_setup_requires(attrs):
     # Note: do not use `setuptools.Distribution` directly, as
     # our PEP 517 backend patch `distutils.core.Distribution`.
-    dist = distutils.core.Distribution(dict(
-        (k, v) for k, v in attrs.items()
-        if k in ('dependency_links', 'setup_requires')
-    ))
+    class MinimalDistribution(distutils.core.Distribution):
+        """
+        A minimal version of a distribution for supporting the
+        fetch_build_eggs interface.
+        """
+        def __init__(self, attrs):
+            _incl = 'dependency_links', 'setup_requires'
+            filtered = {
+                k: attrs[k]
+                for k in set(_incl) & set(attrs)
+            }
+            distutils.core.Distribution.__init__(self, filtered)
+
+        def finalize_options(self):
+            """
+            Disable finalize_options to avoid building the working set.
+            Ref #2158.
+            """
+
+    dist = MinimalDistribution(attrs)
+
     # Honor setup.cfg's options.
     dist.parse_config_files(ignore_option_errors=True)
     if dist.setup_requires:
index 5a9576f..ab8258c 100644 (file)
@@ -2070,19 +2070,33 @@ class ScriptWriter:
     gui apps.
     """
 
-    template = textwrap.dedent(r"""
-        # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r
-        __requires__ = %(spec)r
-        import re
-        import sys
-        from pkg_resources import load_entry_point
-
-        if __name__ == '__main__':
-            sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
-            sys.exit(
-                load_entry_point(%(spec)r, %(group)r, %(name)r)()
-            )
-    """).lstrip()
+    if sys.version_info >= (3, 8):
+        template = textwrap.dedent(r"""
+            # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r
+            import re
+            import sys
+            from importlib.metadata import distribution
+
+            if __name__ == '__main__':
+                sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+                for entry_point in distribution(%(spec)r).entry_points:
+                    if entry_point.group == %(group)r and entry_point.name == %(name)r:
+                        sys.exit(entry_point.load()())
+        """).lstrip()  # noqa: E501
+    else:
+        template = textwrap.dedent(r"""
+            # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r
+            __requires__ = %(spec)r
+            import re
+            import sys
+            from pkg_resources import load_entry_point
+
+            if __name__ == '__main__':
+                sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+                sys.exit(
+                    load_entry_point(%(spec)r, %(group)r, %(name)r)()
+                )
+        """).lstrip()  # noqa: E501
 
     command_spec_class = CommandSpec
 
index 9b9a0c4..45df2e3 100644 (file)
@@ -1,14 +1,16 @@
 from __future__ import absolute_import, unicode_literals
+import ast
 import io
 import os
 import sys
 
 import warnings
 import functools
+import importlib
 from collections import defaultdict
 from functools import partial
 from functools import wraps
-from importlib import import_module
+import contextlib
 
 from distutils.errors import DistutilsOptionError, DistutilsFileError
 from setuptools.extern.packaging.version import LegacyVersion, parse
@@ -19,6 +21,44 @@ from setuptools.extern.six import string_types, PY3
 __metaclass__ = type
 
 
+class StaticModule:
+    """
+    Attempt to load the module by the name
+    """
+    def __init__(self, name):
+        spec = importlib.util.find_spec(name)
+        with open(spec.origin) as strm:
+            src = strm.read()
+        module = ast.parse(src)
+        vars(self).update(locals())
+        del self.self
+
+    def __getattr__(self, attr):
+        try:
+            return next(
+                ast.literal_eval(statement.value)
+                for statement in self.module.body
+                if isinstance(statement, ast.Assign)
+                for target in statement.targets
+                if isinstance(target, ast.Name) and target.id == attr
+            )
+        except Exception:
+            raise AttributeError(
+                "{self.name} has no attribute {attr}".format(**locals()))
+
+
+@contextlib.contextmanager
+def patch_path(path):
+    """
+    Add path to front of sys.path for the duration of the context.
+    """
+    try:
+        sys.path.insert(0, path)
+        yield
+    finally:
+        sys.path.remove(path)
+
+
 def read_configuration(
         filepath, find_others=False, ignore_option_errors=False):
     """Read given configuration file and returns options from it as a dict.
@@ -344,15 +384,16 @@ class ConfigHandler:
             elif '' in package_dir:
                 # A custom parent directory was specified for all root modules
                 parent_path = os.path.join(os.getcwd(), package_dir[''])
-        sys.path.insert(0, parent_path)
-        try:
-            module = import_module(module_name)
-            value = getattr(module, attr_name)
 
-        finally:
-            sys.path = sys.path[1:]
+        with patch_path(parent_path):
+            try:
+                # attempt to load value statically
+                return getattr(StaticModule(module_name), attr_name)
+            except Exception:
+                # fallback to simple import
+                module = importlib.import_module(module_name)
 
-        return value
+        return getattr(module, attr_name)
 
     @classmethod
     def _get_parser_compound(cls, *parse_methods):
index 2fa0b37..67992c0 100644 (file)
@@ -2,6 +2,7 @@
 from __future__ import unicode_literals
 
 import contextlib
+
 import pytest
 
 from distutils.errors import DistutilsOptionError, DistutilsFileError
@@ -9,6 +10,7 @@ from mock import patch
 from setuptools.dist import Distribution, _Distribution
 from setuptools.config import ConfigHandler, read_configuration
 from setuptools.extern.six.moves import configparser
+from setuptools.extern import six
 from . import py2_only, py3_only
 from .textwrap import DALS
 
@@ -53,6 +55,7 @@ def fake_env(
         '    return [3, 4, 5, "dev"]\n'
         '\n'
     )
+
     return package_dir, config
 
 
@@ -267,11 +270,23 @@ class TestMetadata:
 
     def test_version(self, tmpdir):
 
-        _, config = fake_env(
+        package_dir, config = fake_env(
             tmpdir,
             '[metadata]\n'
             'version = attr: fake_package.VERSION\n'
         )
+
+        sub_a = package_dir.mkdir('subpkg_a')
+        sub_a.join('__init__.py').write('')
+        sub_a.join('mod.py').write('VERSION = (2016, 11, 26)')
+
+        sub_b = package_dir.mkdir('subpkg_b')
+        sub_b.join('__init__.py').write('')
+        sub_b.join('mod.py').write(
+            'import third_party_module\n'
+            'VERSION = (2016, 11, 26)'
+        )
+
         with get_dist(tmpdir) as dist:
             assert dist.metadata.version == '1.2.3'
 
@@ -289,13 +304,20 @@ class TestMetadata:
         with get_dist(tmpdir) as dist:
             assert dist.metadata.version == '1'
 
-        subpack = tmpdir.join('fake_package').mkdir('subpackage')
-        subpack.join('__init__.py').write('')
-        subpack.join('submodule.py').write('VERSION = (2016, 11, 26)')
+        config.write(
+            '[metadata]\n'
+            'version = attr: fake_package.subpkg_a.mod.VERSION\n'
+        )
+        with get_dist(tmpdir) as dist:
+            assert dist.metadata.version == '2016.11.26'
+
+        if six.PY2:
+            # static version loading is unsupported on Python 2
+            return
 
         config.write(
             '[metadata]\n'
-            'version = attr: fake_package.subpackage.submodule.VERSION\n'
+            'version = attr: fake_package.subpkg_b.mod.VERSION\n'
         )
         with get_dist(tmpdir) as dist:
             assert dist.metadata.version == '2016.11.26'
index 3044cbd..8611dc1 100644 (file)
@@ -16,6 +16,7 @@ import io
 import zipfile
 import mock
 import time
+import re
 
 from setuptools.extern import six
 
@@ -71,25 +72,15 @@ class TestEasyInstallTest:
 
     def test_get_script_args(self):
         header = ei.CommandSpec.best().from_environment().as_header()
-        expected = header + DALS(r"""
-            # EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
-            __requires__ = 'spec'
-            import re
-            import sys
-            from pkg_resources import load_entry_point
-
-            if __name__ == '__main__':
-                sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
-                sys.exit(
-                    load_entry_point('spec', 'console_scripts', 'name')()
-                )
-            """)  # noqa: E501
         dist = FakeDist()
-
         args = next(ei.ScriptWriter.get_args(dist))
         name, script = itertools.islice(args, 2)
-
-        assert script == expected
+        assert script.startswith(header)
+        assert "'spec'" in script
+        assert "'console_scripts'" in script
+        assert "'name'" in script
+        assert re.search(
+            '^# EASY-INSTALL-ENTRY-SCRIPT', script, flags=re.MULTILINE)
 
     def test_no_find_links(self):
         # new option '--no-find-links', that blocks find-links added at
index 4529689..29aace1 100644 (file)
@@ -3,6 +3,7 @@ from __future__ import absolute_import
 import sys
 import os
 import distutils.errors
+import platform
 
 from setuptools.extern import six
 from setuptools.extern.six.moves import urllib, http_client
@@ -283,17 +284,27 @@ class TestContentCheckers:
         assert rep == 'My message about md5'
 
 
+@pytest.fixture
+def temp_home(tmpdir, monkeypatch):
+    key = (
+        'USERPROFILE'
+        if platform.system() == 'Windows' and sys.version_info > (3, 8) else
+        'HOME'
+    )
+
+    monkeypatch.setitem(os.environ, key, str(tmpdir))
+    return tmpdir
+
+
 class TestPyPIConfig:
-    def test_percent_in_password(self, tmpdir, monkeypatch):
-        monkeypatch.setitem(os.environ, 'HOME', str(tmpdir))
-        pypirc = tmpdir / '.pypirc'
-        with pypirc.open('w') as strm:
-            strm.write(DALS("""
-                [pypi]
-                repository=https://pypi.org
-                username=jaraco
-                password=pity%
-            """))
+    def test_percent_in_password(self, temp_home):
+        pypirc = temp_home / '.pypirc'
+        pypirc.write(DALS("""
+            [pypi]
+            repository=https://pypi.org
+            username=jaraco
+            password=pity%
+        """))
         cfg = setuptools.package_index.PyPIConfig()
         cred = cfg.creds_by_repository['https://pypi.org']
         assert cred.username == 'jaraco'
index 6549a6c..555273a 100644 (file)
@@ -57,10 +57,7 @@ def test_clean_env_install(bare_virtualenv):
     """
     Check setuptools can be installed in a clean environment.
     """
-    bare_virtualenv.run(' && '.join((
-        'cd {source}',
-        'python setup.py install',
-    )).format(source=SOURCE_DIR))
+    bare_virtualenv.run(['python', 'setup.py', 'install'], cd=SOURCE_DIR)
 
 
 def _get_pip_versions():
@@ -115,10 +112,9 @@ def test_pip_upgrade_from_source(pip_version, virtualenv):
     dist_dir = virtualenv.workspace
     # Generate source distribution / wheel.
     virtualenv.run(' && '.join((
-        'cd {source}',
         'python setup.py -q sdist -d {dist}',
         'python setup.py -q bdist_wheel -d {dist}',
-    )).format(source=SOURCE_DIR, dist=dist_dir))
+    )).format(dist=dist_dir), cd=SOURCE_DIR)
     sdist = glob.glob(os.path.join(dist_dir, '*.zip'))[0]
     wheel = glob.glob(os.path.join(dist_dir, '*.whl'))[0]
     # Then update from wheel.
@@ -183,10 +179,8 @@ def _check_test_command_install_requirements(virtualenv, tmpdir):
             open('success', 'w').close()
             '''))
     # Run test command for test package.
-    virtualenv.run(' && '.join((
-        'cd {tmpdir}',
-        'python setup.py test -s test',
-    )).format(tmpdir=tmpdir))
+    virtualenv.run(
+        ['python', 'setup.py', 'test', '-s', 'test'], cd=str(tmpdir))
     assert tmpdir.join('success').check()
 
 
@@ -207,7 +201,5 @@ def test_no_missing_dependencies(bare_virtualenv):
     Quick and dirty test to ensure all external dependencies are vendored.
     """
     for command in ('upload',):  # sorted(distutils.command.__all__):
-        bare_virtualenv.run(' && '.join((
-            'cd {source}',
-            'python setup.py {command} -h',
-        )).format(command=command, source=SOURCE_DIR))
+        bare_virtualenv.run(
+            ['python', 'setup.py', command, '-h'], cd=SOURCE_DIR)
index ec1106a..ca09bd1 100644 (file)
@@ -27,12 +27,8 @@ WHEEL_NAME = re.compile(
     )\.whl$""",
     re.VERBOSE).match
 
-NAMESPACE_PACKAGE_INIT = '''\
-try:
-    __import__('pkg_resources').declare_namespace(__name__)
-except ImportError:
-    __path__ = __import__('pkgutil').extend_path(__path__, __name__)
-'''
+NAMESPACE_PACKAGE_INIT = \
+    "__import__('pkg_resources').declare_namespace(__name__)\n"
 
 
 def unpack(src_dir, dst_dir):
index 5f28456..98b06c0 100644 (file)
@@ -60,8 +60,22 @@ def ensure_config():
     subprocess.check_output(['git', 'config', 'user.email'])
 
 
+def check_changes():
+    """
+    Verify that all of the files in changelog.d have the appropriate
+    names.
+    """
+    allowed = 'deprecation', 'breaking', 'change', 'doc', 'misc'
+    assert all(
+        any(key in file.name for key in allowed)
+        for file in pathlib.Path('changelog.d').iterdir()
+        if file.name != '.gitignore'
+    )
+
+
 if __name__ == '__main__':
     print("Cutting release at", get_version())
     ensure_config()
+    check_changes()
     update_changelog()
     bump_version()
diff --git a/tox.ini b/tox.ini
index aa99e28..d3df21b 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -8,7 +8,7 @@ minversion = 3.2
 requires =
        tox-pip-version >= 0.0.6
        # workaround for #1998
-       virtualenv < 20
+       virtualenv < 20; python_version=="2.7"
 
 [helpers]
 # Custom pip behavior