Imported Upstream version 36.2.1 upstream/36.2.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 14 Jan 2019 01:33:26 +0000 (10:33 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 14 Jan 2019 01:33:26 +0000 (10:33 +0900)
13 files changed:
.travis.yml
CHANGES.rst
pkg_resources/tests/test_markers.py
setup.cfg
setup.py
setuptools/dist.py
setuptools/tests/test_build_clib.py
setuptools/tests/test_easy_install.py
setuptools/tests/test_egg_info.py
setuptools/tests/test_msvc.py
setuptools/tests/test_virtualenv.py [new file with mode: 0644]
tests/clean_install.sh [deleted file]
tests/requirements.txt

index cbf49da658620b7397daa72eae5f87a8e02c0d48..b207a8d2f3bf911d761af378a251b66e93927143 100644 (file)
@@ -43,7 +43,4 @@ install:
 # 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 02ec2f74b261eb0cc681e5026cb0d79088a5c674..36b2fca542c6cc1a586f0edf4b130360bd26ff33 100644 (file)
@@ -1,3 +1,10 @@
+v36.2.1
+-------
+
+* fix #1086
+* fix #1087
+* support extras specifiers in install_requires requirements
+
 v36.2.0
 -------
 
index 9306d5b3483e8913b4a04d702091fb5efbc3f444..15a3b499a6038cef16024ee8519a342acd22ba9b 100644 (file)
@@ -1,4 +1,4 @@
-from unittest import mock
+import mock
 
 from pkg_resources import evaluate_marker
 
index 416f654366da694ca6f94b9edaae9fe9be548041..203b9312e35ba747501a4d4565fc9a1e5e79a473 100755 (executable)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 36.2.0
+current_version = 36.2.1
 commit = True
 tag = True
 
index b3f5a7d9b33ae12fd0532cae80535ad54fba60d0..854aee387897f95993296d5b96165b437c940a9f 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -89,7 +89,7 @@ def pypi_link(pkg_filename):
 
 setup_params = dict(
     name="setuptools",
-    version="36.2.0",
+    version="36.2.1",
     description="Easily download, build, install, upgrade, and uninstall "
         "Python packages",
     author="Python Packaging Authority",
index 68c8747a7649842e09bc6e3edd21804bfd7420c7..9a034db553b8bf1d9bc3d1efe73b7e3e73e398c7 100644 (file)
@@ -9,7 +9,6 @@ import distutils.core
 import distutils.cmd
 import distutils.dist
 import itertools
-import operator
 from collections import defaultdict
 from distutils.errors import (
     DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
@@ -17,7 +16,7 @@ from distutils.errors import (
 from distutils.util import rfc822_escape
 
 from setuptools.extern import six
-from setuptools.extern.six.moves import map, filter
+from setuptools.extern.six.moves import map
 from pkg_resources.extern import packaging
 
 from setuptools.depends import Require
@@ -146,17 +145,7 @@ 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()))
+    list(pkg_resources.parse_requirements(reqs))
 
 
 def assert_bool(dist, attr, value):
@@ -366,23 +355,41 @@ class Distribution(Distribution_parse_config_files, _Distribution):
 
     def _finalize_requires(self):
         """
-        Move requirements in `install_requires` that
-        are using environment markers to `extras_require`.
+        Fix environment markers in `install_requires` and `extras_require`.
+
+        - move requirements in `install_requires` that are using environment
+          markers or extras to `extras_require`.
+        - convert requirements in `extras_require` of the form
+          `"extra": ["barbazquux; {marker}"]` to
+          `"extra:{marker}": ["barbazquux"]`.
         """
-        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()
-        ))
+        extras_require = defaultdict(list)
+        for k, v in (
+            getattr(self, 'extras_require', None) or {}
+        ).items():
+            for r in pkg_resources.parse_requirements(v):
+                marker = r.marker
+                if marker:
+                    r.marker = None
+                    extras_require[k + ':' + str(marker)].append(r)
+                else:
+                    extras_require[k].append(r)
         install_requires = []
-        for r in pkg_resources.parse_requirements(self.install_requires):
+        for r in pkg_resources.parse_requirements(
+            getattr(self, 'install_requires', None) or ()
+        ):
             marker = r.marker
-            if not marker:
+            extras = r.extras
+            if not marker and not extras:
                 install_requires.append(r)
                 continue
+            r.extras = ()
             r.marker = None
-            extras_require[':' + str(marker)].append(r)
+            for e in extras or ('',):
+                section = e
+                if marker:
+                    section += ':' + str(marker)
+                extras_require[section].append(r)
         self.extras_require = dict(
             (k, [str(r) for r in v])
             for k, v in extras_require.items()
index 7e3d1de9d486266160f20b1d45a915796136be73..aebcc350ecb1c9e6435d22e5af817cc2fed41c7d 100644 (file)
@@ -2,7 +2,7 @@ import pytest
 import os
 import shutil
 
-from unittest import mock
+import mock
 from distutils.errors import DistutilsSetupError
 from setuptools.command.build_clib import build_clib
 from setuptools.dist import Distribution
index 1b7178a11a22afcdae4b8f8842875da7171ca38d..26cdd90d5d0253dd1d8b9caac868b16a64a3aea9 100644 (file)
@@ -14,7 +14,7 @@ import itertools
 import distutils.errors
 import io
 import zipfile
-from unittest import mock
+import mock
 
 import time
 from setuptools.extern.six.moves import urllib
index 07bd88181e3d5a54237e093a34b3d856c456ec36..5ea55d6188f8f4f381d14449984a81d2f5831e2e 100644 (file)
@@ -182,8 +182,13 @@ class TestEggInfo(object):
     mismatch_marker = "python_version<'{this_ver}'".format(
         this_ver=sys.version_info[0],
     )
+    # Alternate equivalent syntax.
+    mismatch_marker_alternate = 'python_version < "{this_ver}"'.format(
+        this_ver=sys.version_info[0],
+    )
+    invalid_marker = "<=>++"
 
-    def test_install_requires_with_markers(self, tmpdir_cwd, env):
+    def test_install_requires_with_marker(self, tmpdir_cwd, env):
         tmpl = 'install_requires=["barbazquux;{marker}"],'
         req = tmpl.format(marker=self.mismatch_marker)
         self._setup_script_with_requires(req)
@@ -193,9 +198,40 @@ class TestEggInfo(object):
         with open(requires_txt) as fp:
             install_requires = fp.read()
         expected_requires = DALS('''
-             [:python_version < "{sys.version_info[0]}"]
+             [:{marker}]
+             barbazquux
+             ''').format(marker=self.mismatch_marker_alternate)
+        assert install_requires.lstrip() == expected_requires
+        assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
+
+    def test_install_requires_with_extra(self, tmpdir_cwd, env):
+        req = 'install_requires=["barbazquux [test]"],'
+        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')
+        with open(requires_txt) as fp:
+            install_requires = fp.read()
+        expected_requires = DALS('''
+             [test]
+             barbazquux
+             ''')
+        assert install_requires.lstrip() == expected_requires
+        assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
+
+    def test_install_requires_with_extra_and_marker(self, tmpdir_cwd, env):
+        tmpl = 'install_requires=["barbazquux [test]; {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')
+        with open(requires_txt) as fp:
+            install_requires = fp.read()
+        expected_requires = DALS('''
+             [test:{marker}]
              barbazquux
-             ''').format(sys=sys)
+             ''').format(marker=self.mismatch_marker_alternate)
         assert install_requires.lstrip() == expected_requires
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
@@ -214,19 +250,53 @@ class TestEggInfo(object):
             tmpdir_cwd, env, cmd=['test'], output="Ran 0 tests in")
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
-    def test_extras_require_with_markers(self, tmpdir_cwd, env):
+    def test_extras_require_with_marker(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)
+        egg_info_dir = self._find_egg_info_files(env.paths['lib']).base
+        requires_txt = os.path.join(egg_info_dir, 'requires.txt')
+        with open(requires_txt) as fp:
+            install_requires = fp.read()
+        expected_requires = DALS('''
+             [:{marker}]
+             barbazquux
+             ''').format(marker=self.mismatch_marker)
+        assert install_requires.lstrip() == expected_requires
         assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
-    def test_extras_require_with_markers_in_req(self, tmpdir_cwd, env):
+    def test_extras_require_with_marker_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)
+        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')
+        with open(requires_txt) as fp:
+            install_requires = fp.read()
+        expected_requires = DALS('''
+             [extra:{marker}]
+             barbazquux
+             ''').format(marker=self.mismatch_marker_alternate)
+        assert install_requires.lstrip() == expected_requires
+        assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
+
+    def test_extras_require_with_invalid_marker(self, tmpdir_cwd, env):
+        tmpl = 'extras_require={{":{marker}": ["barbazquux"]}},'
+        req = tmpl.format(marker=self.invalid_marker)
+        self._setup_script_with_requires(req)
+        with pytest.raises(AssertionError):
+            self._run_install_command(tmpdir_cwd, env)
+        assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
+
+    def test_extras_require_with_invalid_marker_in_req(self, tmpdir_cwd, env):
+        tmpl = 'extras_require={{"extra": ["barbazquux; {marker}"]}},'
+        req = tmpl.format(marker=self.invalid_marker)
+        self._setup_script_with_requires(req)
         with pytest.raises(AssertionError):
             self._run_install_command(tmpdir_cwd, env)
+        assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
 
     def test_python_requires_egg_info(self, tmpdir_cwd, env):
         self._setup_script_with_requires(
index fbeed1d5c53acb758855d8978e4fd0d0321167c7..32d7a907cfff809eaee3786f2e56fda53231803b 100644 (file)
@@ -5,7 +5,7 @@ Tests for msvc support module.
 import os
 import contextlib
 import distutils.errors
-from unittest import mock
+import mock
 
 import pytest
 
diff --git a/setuptools/tests/test_virtualenv.py b/setuptools/tests/test_virtualenv.py
new file mode 100644 (file)
index 0000000..a7f485a
--- /dev/null
@@ -0,0 +1,50 @@
+import glob
+import os
+
+from pytest import yield_fixture
+from pytest_fixture_config import yield_requires_config
+
+import pytest_virtualenv
+
+
+@yield_requires_config(pytest_virtualenv.CONFIG, ['virtualenv_executable'])
+@yield_fixture(scope='function')
+def bare_virtualenv():
+    """ Bare virtualenv (no pip/setuptools/wheel).
+    """
+    with pytest_virtualenv.VirtualEnv(args=(
+        '--no-wheel',
+        '--no-pip',
+        '--no-setuptools',
+    )) as venv:
+        yield venv
+
+
+SOURCE_DIR = os.path.join(os.path.dirname(__file__), '../..')
+
+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))
+
+def test_pip_upgrade_from_source(virtualenv):
+    """
+    Check pip can upgrade setuptools from source.
+    """
+    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))
+    sdist = glob.glob(os.path.join(dist_dir, '*.zip'))[0]
+    wheel = glob.glob(os.path.join(dist_dir, '*.whl'))[0]
+    # Then update from wheel.
+    virtualenv.run('pip install ' + wheel)
+    # And finally try to upgrade from source.
+    virtualenv.run('pip install --no-cache-dir --upgrade ' + sdist)
diff --git a/tests/clean_install.sh b/tests/clean_install.sh
deleted file mode 100755 (executable)
index f8f80dc..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/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
index 6e2e78e2a7ebc737f95a3572a518b8d7b287f335..0c4df8ef8f6c048abd1cb9d049bd1065f0594994 100644 (file)
@@ -1,4 +1,6 @@
+importlib; python_version<"2.7"
+mock
 pytest-flake8
+pytest-virtualenv>=1.2.7
 pytest>=3.0.2
-# pinned to 1.2 as temporary workaround for #1038
-backports.unittest_mock>=1.2,<1.3
+virtualenv