From: DongHun Kwak Date: Mon, 14 Jan 2019 01:33:19 +0000 (+0900) Subject: Imported Upstream version 36.2.0 X-Git-Tag: upstream/36.2.0^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f5a5038be03b3dcc0cb9c71a4afb0a9e5bcf0723;p=platform%2Fupstream%2Fpython-setuptools.git Imported Upstream version 36.2.0 --- diff --git a/.travis.yml b/.travis.yml index 6d6333f..cbf49da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/CHANGES.rst b/CHANGES.rst index 487accd..02ec2f7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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 ------- diff --git a/pytest.ini b/pytest.ini index 11a213d..16fdc5a 100755 --- a/pytest.ini +++ b/pytest.ini @@ -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 diff --git a/setup.cfg b/setup.cfg index 9046b41..416f654 100755 --- 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 diff --git a/setup.py b/setup.py index 42a4c06..b3f5a7d 100755 --- 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", diff --git a/setuptools/dist.py b/setuptools/dist.py index 6b97ed3..68c8747 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -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): diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py index dbf1620..8ae4402 100644 --- a/setuptools/tests/__init__.py +++ b/setuptools/tests/__init__.py @@ -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") diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 2d9682a..1b7178a 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -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 diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index a32b981..07bd881 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -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 index 0000000..f8f80dc --- /dev/null +++ b/tests/clean_install.sh @@ -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 --- 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