Imported Upstream version 36.2.0 upstream/36.2.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 14 Jan 2019 01:33:19 +0000 (10:33 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 14 Jan 2019 01:33:19 +0000 (10:33 +0900)
.travis.yml
CHANGES.rst
pytest.ini
setup.cfg
setup.py
setuptools/dist.py
setuptools/tests/__init__.py
setuptools/tests/test_easy_install.py
setuptools/tests/test_egg_info.py
tests/clean_install.sh [new file with mode: 0755]
tox.ini

index 6d6333f..cbf49da 100644 (file)
@@ -1,43 +1,49 @@
+sudo: false
 language: python
-python:
-  - 2.6
-  - 2.7
-  - 3.3
-  - 3.4
-  - 3.5
-  - 3.6
-  - nightly
-  - pypy
-matrix:
+jobs:
+  fast_finish: true
   include:
-  - python: 3.6
-    env: LC_ALL=C LC_CTYPE=C
-  - python: 2.7
-    env: LC_ALL=C LC_CTYPE=C
-script:
- # need tox to get started
- - pip install tox
+  - python: 2.6
+  - python: &latest_py2 2.7
+  - python: 3.3
+  - python: 3.4
+  - python: 3.5
+  - python: &latest_py3 3.6
+  - python: nightly
+  - python: pypy
+  - python: *latest_py3
+    env: LANG=C
+  - python: *latest_py2
+    env: LANG=C
+  - stage: deploy (does actual deploy to PYPI only for tagged commits)
+    python: *latest_py3
+    install: skip
+    script: skip
+    before_deploy: python bootstrap.py
+    deploy:
+      provider: pypi
+      on:
+        tags: true
+        all_branches: true
+      user: jaraco
+      password:
+        secure: tfWrsQMH2bHrWjqnP+08IX1WlkbW94Q30f4d7lCyhWS1FIf/jBDx4jrEILNfMxQ1NCwuBRje5sihj1Ow0BFf0vVrkaeff2IdvnNDEGFduMejaEQJL3s3QrLfpiAvUbtqwyWaHfAdGfk48PovDKTx0ZTvXZKYGXZhxGCYSlG2CE6Y6RDvnEl6Tk8e+LqUohkcSOwxrRwUoyxSnUaavdGohXxDT8MJlfWOXgr2u+KsRrriZqp3l6Fdsnk4IGvy6pXpy42L1HYQyyVu9XyJilR2JTbC6eCp5f8p26093m1Qas49+t6vYb0VLqQe12dO+Jm3v4uztSS5pPQzS7PFyjEYd2Rdb6ijsdbsy1074S4q7G9Sz+T3RsPUwYEJ07lzez8cxP64dtj5j94RL8m35A1Fb1OE8hHN+4c1yLG1gudfXbem+fUhi2eqhJrzQo5vsvDv1xS5x5GIS5ZHgKHCsWcW1Tv+dsFkrhaup3uU6VkOuc9UN+7VPsGEY7NvquGpTm8O1CnGJRzuJg6nbYRGj8ORwDpI0KmrExx6akV92P72fMC/I5TCgbSQSZn370H3Jj40gz1SM30WAli9M+wFHFd4ddMVY65yxj0NLmrP+m1tvnWdKtNh/RHuoW92d9/UFtiA5IhMf1/3djfsjBq6S9NT1uaLkVkTttqrPYJ7hOql8+g=
+      distributions: release
+      skip_upload_docs: true
 
- # Output the env, to verify behavior
- - env
+cache: pip
 
- # update egg_info based on setup.py in checkout
- - python bootstrap.py
+install:
+# need tox to get started
+- pip install tox
 
- #- python -m tox
- - tox
+# Output the env, to verify behavior
+- env
 
-deploy:
-  provider: pypi
-  # Also update server in setup.cfg
-  server: https://upload.pypi.org/legacy/
-  on:
-    tags: true
-    all_branches: true
-    python: 3.6
-    condition: $LC_ALL != "C"
-  user: jaraco
-  password:
-    secure: tfWrsQMH2bHrWjqnP+08IX1WlkbW94Q30f4d7lCyhWS1FIf/jBDx4jrEILNfMxQ1NCwuBRje5sihj1Ow0BFf0vVrkaeff2IdvnNDEGFduMejaEQJL3s3QrLfpiAvUbtqwyWaHfAdGfk48PovDKTx0ZTvXZKYGXZhxGCYSlG2CE6Y6RDvnEl6Tk8e+LqUohkcSOwxrRwUoyxSnUaavdGohXxDT8MJlfWOXgr2u+KsRrriZqp3l6Fdsnk4IGvy6pXpy42L1HYQyyVu9XyJilR2JTbC6eCp5f8p26093m1Qas49+t6vYb0VLqQe12dO+Jm3v4uztSS5pPQzS7PFyjEYd2Rdb6ijsdbsy1074S4q7G9Sz+T3RsPUwYEJ07lzez8cxP64dtj5j94RL8m35A1Fb1OE8hHN+4c1yLG1gudfXbem+fUhi2eqhJrzQo5vsvDv1xS5x5GIS5ZHgKHCsWcW1Tv+dsFkrhaup3uU6VkOuc9UN+7VPsGEY7NvquGpTm8O1CnGJRzuJg6nbYRGj8ORwDpI0KmrExx6akV92P72fMC/I5TCgbSQSZn370H3Jj40gz1SM30WAli9M+wFHFd4ddMVY65yxj0NLmrP+m1tvnWdKtNh/RHuoW92d9/UFtiA5IhMf1/3djfsjBq6S9NT1uaLkVkTttqrPYJ7hOql8+g=
-  distributions: release
-  skip_upload_docs: true
+# update egg_info based on setup.py in checkout
+- python bootstrap.py
+
+# Check that setuptools can be installed in a clean environment
+- tests/clean_install.sh
+
+script: tox
index 487accd..02ec2f7 100644 (file)
@@ -1,3 +1,16 @@
+v36.2.0
+-------
+
+* #1081: Environment markers indicated in ``install_requires``
+  are now processed and treated as nameless ``extras_require``
+  with markers, allowing their metadata in requires.txt to be
+  correctly generated.
+
+* #1053: Tagged commits are now released using Travis-CI
+  build stages, meaning releases depend on passing tests on
+  all supported Python versions (Linux) and not just the latest
+  Python version.
+
 v36.1.1
 -------
 
@@ -77,7 +90,7 @@ v34.4.1
 
 * #992: In msvc.msvc9_query_vcvarsall, ensure the
   returned dicts have str values and not Unicode for
-  compatibilty with os.environ.
+  compatibility with os.environ.
 
 v34.4.0
 -------
index 11a213d..16fdc5a 100755 (executable)
@@ -1,5 +1,5 @@
 [pytest]
-addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/test_pypi.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt --ignore scripts/upload-old-releases-as-zip.py --ignore pavement.py --ignore setuptools/tests/mod_with_constant.py
+addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/test_pypi.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt --ignore scripts/upload-old-releases-as-zip.py --ignore pavement.py --ignore setuptools/tests/mod_with_constant.py -rsxX
 norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern .*
 flake8-ignore =
     setuptools/site-patch.py F821
index 9046b41..416f654 100755 (executable)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 36.1.1
+current_version = 36.2.0
 commit = True
 tag = True
 
index 42a4c06..b3f5a7d 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -89,7 +89,7 @@ def pypi_link(pkg_filename):
 
 setup_params = dict(
     name="setuptools",
-    version="36.1.1",
+    version="36.2.0",
     description="Easily download, build, install, upgrade, and uninstall "
         "Python packages",
     author="Python Packaging Authority",
index 6b97ed3..68c8747 100644 (file)
@@ -8,17 +8,18 @@ import distutils.log
 import distutils.core
 import distutils.cmd
 import distutils.dist
-from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
-    DistutilsSetupError)
+import itertools
+import operator
+from collections import defaultdict
+from distutils.errors import (
+    DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
+)
 from distutils.util import rfc822_escape
 
 from setuptools.extern import six
-from setuptools.extern.six.moves import map
+from setuptools.extern.six.moves import map, filter
 from pkg_resources.extern import packaging
 
-__import__('pkg_resources.extern.packaging.specifiers')
-__import__('pkg_resources.extern.packaging.version')
-
 from setuptools.depends import Require
 from setuptools import windows_support
 from setuptools.monkey import get_unpatched
@@ -26,6 +27,9 @@ from setuptools.config import parse_configuration
 import pkg_resources
 from .py36compat import Distribution_parse_config_files
 
+__import__('pkg_resources.extern.packaging.specifiers')
+__import__('pkg_resources.extern.packaging.version')
+
 
 def _get_unpatched(cls):
     warnings.warn("Do not call this function", DeprecationWarning)
@@ -129,12 +133,7 @@ def check_nsp(dist, attr, value):
 def check_extras(dist, attr, value):
     """Verify that extras_require mapping is valid"""
     try:
-        for k, v in value.items():
-            if ':' in k:
-                k, m = k.split(':', 1)
-                if pkg_resources.invalid_marker(m):
-                    raise DistutilsSetupError("Invalid environment marker: " + m)
-            list(pkg_resources.parse_requirements(v))
+        list(itertools.starmap(_check_extra, value.items()))
     except (TypeError, ValueError, AttributeError):
         raise DistutilsSetupError(
             "'extras_require' must be a dictionary whose values are "
@@ -143,6 +142,23 @@ def check_extras(dist, attr, value):
         )
 
 
+def _check_extra(extra, reqs):
+    name, sep, marker = extra.partition(':')
+    if marker and pkg_resources.invalid_marker(marker):
+        raise DistutilsSetupError("Invalid environment marker: " + marker)
+
+    # extras requirements cannot themselves have markers
+    parsed = pkg_resources.parse_requirements(reqs)
+    marked_reqs = filter(operator.attrgetter('marker'), parsed)
+    bad_req = next(marked_reqs, None)
+    if bad_req:
+        tmpl = (
+            "'extras_require' requirements cannot include "
+            "environment markers, in {name!r}: '{bad_req!s}'"
+        )
+        raise DistutilsSetupError(tmpl.format(**locals()))
+
+
 def assert_bool(dist, attr, value):
     """Verify that value is True, False, 0, or 1"""
     if bool(value) != value:
@@ -346,6 +362,32 @@ class Distribution(Distribution_parse_config_files, _Distribution):
                 )
         if getattr(self, 'python_requires', None):
             self.metadata.python_requires = self.python_requires
+        self._finalize_requires()
+
+    def _finalize_requires(self):
+        """
+        Move requirements in `install_requires` that
+        are using environment markers to `extras_require`.
+        """
+        if not self.install_requires:
+            return
+        extras_require = defaultdict(list, (
+            (k, list(pkg_resources.parse_requirements(v)))
+            for k, v in (self.extras_require or {}).items()
+        ))
+        install_requires = []
+        for r in pkg_resources.parse_requirements(self.install_requires):
+            marker = r.marker
+            if not marker:
+                install_requires.append(r)
+                continue
+            r.marker = None
+            extras_require[':' + str(marker)].append(r)
+        self.extras_require = dict(
+            (k, [str(r) for r in v])
+            for k, v in extras_require.items()
+        )
+        self.install_requires = [str(r) for r in install_requires]
 
     def parse_config_files(self, filenames=None):
         """Parses configuration files from various levels
@@ -392,7 +434,10 @@ class Distribution(Distribution_parse_config_files, _Distribution):
                 ep.load()(self, ep.name, value)
         if getattr(self, 'convert_2to3_doctests', None):
             # XXX may convert to set here when we can rely on set being builtin
-            self.convert_2to3_doctests = [os.path.abspath(p) for p in self.convert_2to3_doctests]
+            self.convert_2to3_doctests = [
+                os.path.abspath(p)
+                for p in self.convert_2to3_doctests
+            ]
         else:
             self.convert_2to3_doctests = []
 
@@ -436,7 +481,8 @@ class Distribution(Distribution_parse_config_files, _Distribution):
                 opts['find_links'] = ('setup', links)
             install_dir = self.get_egg_cache_dir()
             cmd = easy_install(
-                dist, args=["x"], install_dir=install_dir, exclude_scripts=True,
+                dist, args=["x"], install_dir=install_dir,
+                exclude_scripts=True,
                 always_copy=False, build_directory=None, editable=False,
                 upgrade=False, multi_version=True, no_report=True, user=False
             )
@@ -461,8 +507,11 @@ class Distribution(Distribution_parse_config_files, _Distribution):
                 if not feature.include_by_default():
                     excdef, incdef = incdef, excdef
 
-                go.append(('with-' + name, None, 'include ' + descr + incdef))
-                go.append(('without-' + name, None, 'exclude ' + descr + excdef))
+                new = (
+                    ('with-' + name, None, 'include ' + descr + incdef),
+                    ('without-' + name, None, 'exclude ' + descr + excdef),
+                )
+                go.extend(new)
                 no['without-' + name] = 'with-' + name
 
         self.global_options = self.feature_options = go + self.global_options
@@ -490,7 +539,8 @@ class Distribution(Distribution_parse_config_files, _Distribution):
         if command in self.cmdclass:
             return self.cmdclass[command]
 
-        for ep in pkg_resources.iter_entry_points('distutils.commands', command):
+        eps = pkg_resources.iter_entry_points('distutils.commands', command)
+        for ep in eps:
             ep.require(installer=self.fetch_build_egg)
             self.cmdclass[command] = cmdclass = ep.load()
             return cmdclass
@@ -624,7 +674,8 @@ class Distribution(Distribution_parse_config_files, _Distribution):
                 name + ": this setting cannot be changed via include/exclude"
             )
         else:
-            setattr(self, name, old + [item for item in value if item not in old])
+            new = [item for item in value if item not in old]
+            setattr(self, name, old + new)
 
     def exclude(self, **attrs):
         """Remove items from distribution that are named in keyword arguments
@@ -835,14 +886,14 @@ class Feature:
 
     @staticmethod
     def warn_deprecated():
-        warnings.warn(
+        msg = (
             "Features are deprecated and will be removed in a future "
-                "version. See https://github.com/pypa/setuptools/issues/65.",
-            DeprecationWarning,
-            stacklevel=3,
+            "version. See https://github.com/pypa/setuptools/issues/65."
         )
+        warnings.warn(msg, DeprecationWarning, stacklevel=3)
 
-    def __init__(self, description, standard=False, available=True,
+    def __init__(
+            self, description, standard=False, available=True,
             optional=True, require_features=(), remove=(), **extras):
         self.warn_deprecated()
 
@@ -867,8 +918,8 @@ class Feature:
 
         if not remove and not require_features and not extras:
             raise DistutilsSetupError(
-                "Feature %s: must define 'require_features', 'remove', or at least one"
-                " of 'packages', 'py_modules', etc."
+                "Feature %s: must define 'require_features', 'remove', or "
+                "at least one of 'packages', 'py_modules', etc."
             )
 
     def include_by_default(self):
index dbf1620..8ae4402 100644 (file)
@@ -1,4 +1,5 @@
 """Tests for the 'setuptools' package"""
+import locale
 import sys
 import os
 import distutils.core
@@ -16,8 +17,7 @@ import setuptools.depends as dep
 from setuptools import Feature
 from setuptools.depends import Require
 
-c_type = os.environ.get("LC_CTYPE", os.environ.get("LC_ALL"))
-is_ascii = c_type in ("C", "POSIX")
+is_ascii = locale.getpreferredencoding() == 'ANSI_X3.4-1968'
 fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale")
 
 
index 2d9682a..1b7178a 100644 (file)
@@ -30,6 +30,7 @@ from setuptools.dist import Distribution
 from pkg_resources import normalize_path, working_set
 from pkg_resources import Distribution as PRDistribution
 import setuptools.tests.server
+from setuptools.tests import fail_on_ascii
 import pkg_resources
 
 from .py26compat import tarfile_open
@@ -166,6 +167,7 @@ class TestEasyInstallTest:
         sdist_zip.close()
         return str(sdist)
 
+    @fail_on_ascii
     def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch):
         """
         The install command should execute correctly even if
index a32b981..07bd881 100644 (file)
@@ -64,7 +64,7 @@ class TestEggInfo(object):
             yield env
 
     dict_order_fails = pytest.mark.skipif(
-        sys.version_info < (2,7),
+        sys.version_info < (2, 7),
         reason="Intermittent failures on Python 2.6",
     )
 
@@ -179,35 +179,55 @@ class TestEggInfo(object):
             'setup.py': setup_script,
         })
 
+    mismatch_marker = "python_version<'{this_ver}'".format(
+        this_ver=sys.version_info[0],
+    )
+
     def test_install_requires_with_markers(self, tmpdir_cwd, env):
-        self._setup_script_with_requires(
-            """install_requires=["barbazquux;python_version<'2'"],""")
+        tmpl = 'install_requires=["barbazquux;{marker}"],'
+        req = tmpl.format(marker=self.mismatch_marker)
+        self._setup_script_with_requires(req)
         self._run_install_command(tmpdir_cwd, env)
         egg_info_dir = self._find_egg_info_files(env.paths['lib']).base
         requires_txt = os.path.join(egg_info_dir, 'requires.txt')
-        assert "barbazquux;python_version<'2'" in open(
-            requires_txt).read().split('\n')
+        with open(requires_txt) as fp:
+            install_requires = fp.read()
+        expected_requires = DALS('''
+             [:python_version < "{sys.version_info[0]}"]
+             barbazquux
+             ''').format(sys=sys)
+        assert install_requires.lstrip() == expected_requires
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
     def test_setup_requires_with_markers(self, tmpdir_cwd, env):
-        self._setup_script_with_requires(
-            """setup_requires=["barbazquux;python_version<'2'"],""")
+        tmpl = 'setup_requires=["barbazquux;{marker}"],'
+        req = tmpl.format(marker=self.mismatch_marker)
+        self._setup_script_with_requires(req)
         self._run_install_command(tmpdir_cwd, env)
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
     def test_tests_require_with_markers(self, tmpdir_cwd, env):
-        self._setup_script_with_requires(
-            """tests_require=["barbazquux;python_version<'2'"],""")
+        tmpl = 'tests_require=["barbazquux;{marker}"],'
+        req = tmpl.format(marker=self.mismatch_marker)
+        self._setup_script_with_requires(req)
         self._run_install_command(
             tmpdir_cwd, env, cmd=['test'], output="Ran 0 tests in")
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
-    def test_extra_requires_with_markers(self, tmpdir_cwd, env):
-        self._setup_script_with_requires(
-            """extra_requires={":python_version<'2'": ["barbazquux"]},""")
+    def test_extras_require_with_markers(self, tmpdir_cwd, env):
+        tmpl = 'extras_require={{":{marker}": ["barbazquux"]}},'
+        req = tmpl.format(marker=self.mismatch_marker)
+        self._setup_script_with_requires(req)
         self._run_install_command(tmpdir_cwd, env)
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
+    def test_extras_require_with_markers_in_req(self, tmpdir_cwd, env):
+        tmpl = 'extras_require={{"extra": ["barbazquux; {marker}"]}},'
+        req = tmpl.format(marker=self.mismatch_marker)
+        self._setup_script_with_requires(req)
+        with pytest.raises(AssertionError):
+            self._run_install_command(tmpdir_cwd, env)
+
     def test_python_requires_egg_info(self, tmpdir_cwd, env):
         self._setup_script_with_requires(
             """python_requires='>=2.7.12',""")
diff --git a/tests/clean_install.sh b/tests/clean_install.sh
new file mode 100755 (executable)
index 0000000..f8f80dc
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# This test was created in
+# https://github.com/pypa/setuptools/pull/1050
+# but it really should be incorporated into the test suite
+# such that it runs on Windows and doesn't depend on
+# virtualenv. Moving to test_integration will likely address
+# those concerns.
+
+set -o errexit
+set -o xtrace
+
+# Create a temporary directory to install the virtualenv in
+VENV_DIR="$(mktemp -d)"
+function cleanup() {
+  rm -rf "$VENV_DIR"
+}
+trap cleanup EXIT
+
+# Create a virtualenv that doesn't have pip or setuptools installed
+wget https://raw.githubusercontent.com/pypa/virtualenv/master/virtualenv.py
+python virtualenv.py --no-wheel --no-pip --no-setuptools "$VENV_DIR"
+source "$VENV_DIR/bin/activate"
+
+# Now try to install setuptools
+python bootstrap.py
+python setup.py install
diff --git a/tox.ini b/tox.ini
index c3ea462..4b4b4fd 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -7,5 +7,5 @@
 [testenv]
 deps=-rtests/requirements.txt
 passenv=APPDATA USERPROFILE HOMEDRIVE HOMEPATH windir APPVEYOR
-commands=py.test {posargs:-rsx}
+commands=py.test {posargs}
 usedevelop=True