From 7502dc9ca767927db9599f93cd48851ca59f7a62 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Tue, 26 Nov 2019 20:56:57 +0100 Subject: fix possible issue with transitive build dependencies Handle the case where a missing transitive build dependency is required by an extra for an already installed build dependency. --- changelog.d/1922.change.rst | 1 + setuptools/installer.py | 7 ++++-- setuptools/tests/test_easy_install.py | 44 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 changelog.d/1922.change.rst diff --git a/changelog.d/1922.change.rst b/changelog.d/1922.change.rst new file mode 100644 index 00000000..7aeb251c --- /dev/null +++ b/changelog.d/1922.change.rst @@ -0,0 +1 @@ +Fix possible issue with transitive build dependencies. diff --git a/setuptools/installer.py b/setuptools/installer.py index 35bc3cc5..ba9cfce9 100644 --- a/setuptools/installer.py +++ b/setuptools/installer.py @@ -64,8 +64,11 @@ def fetch_build_egg(dist, req): pkg_resources.get_distribution('wheel') except pkg_resources.DistributionNotFound: dist.announce('WARNING: The wheel package is not available.', log.WARN) - if not isinstance(req, pkg_resources.Requirement): - req = pkg_resources.Requirement.parse(req) + # Ignore environment markers: if we're here, it's needed. This ensure + # we don't try to ask pip for something like `babel; extra == "i18n"`, + # which would always be ignored. + req = pkg_resources.Requirement.parse(str(req)) + req.marker = None # Take easy_install options into account, but do not override relevant # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll # take precedence. diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index aa75899a..f6da1b16 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -37,6 +37,7 @@ from setuptools.tests import fail_on_ascii import pkg_resources from . import contexts +from .files import build_files from .textwrap import DALS __metaclass__ = type @@ -744,6 +745,49 @@ class TestSetupRequires: eggs = list(map(str, pkg_resources.find_distributions(os.path.join(test_pkg, '.eggs')))) assert eggs == ['dep 1.0'] + def test_setup_requires_with_transitive_extra_dependency(self, monkeypatch): + # Use case: installing a package with a build dependency on + # an already installed `dep[extra]`, which in turn depends + # on `extra_dep` (whose is not already installed). + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + # Create source distribution for `extra_dep`. + make_trivial_sdist(os.path.join(temp_dir, 'extra_dep-1.0.tar.gz'), 'extra_dep', '1.0') + # Create source tree for `dep`. + dep_pkg = os.path.join(temp_dir, 'dep') + os.mkdir(dep_pkg) + build_files({ + 'setup.py': + DALS(""" + import setuptools + setuptools.setup( + name='dep', version='2.0', + extras_require={'extra': ['extra_dep']}, + ) + """), + 'setup.cfg': '', + }, prefix=dep_pkg) + # "Install" dep. + run_setup(os.path.join(dep_pkg, 'setup.py'), [str('dist_info')]) + working_set.add_entry(dep_pkg) + # Create source tree for test package. + test_pkg = os.path.join(temp_dir, 'test_pkg') + test_setup_py = os.path.join(test_pkg, 'setup.py') + test_setup_cfg = os.path.join(test_pkg, 'setup.cfg') + os.mkdir(test_pkg) + with open(test_setup_py, 'w') as fp: + fp.write(DALS( + ''' + from setuptools import installer, setup + setup(setup_requires='dep[extra]') + ''')) + # Check... + monkeypatch.setenv(str('PIP_FIND_LINKS'), str(temp_dir)) + monkeypatch.setenv(str('PIP_NO_INDEX'), str('1')) + monkeypatch.setenv(str('PIP_RETRIES'), str('0')) + monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) + run_setup(test_setup_py, [str('--version')]) + def make_trivial_sdist(dist_path, distname, version): """ -- cgit v1.2.3 From 2292718a151994efb7d364312c73d5b536988049 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 1 Dec 2019 09:23:31 -0500 Subject: Reword changelog to give more context --- changelog.d/1922.change.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/1922.change.rst b/changelog.d/1922.change.rst index 7aeb251c..837ef9c9 100644 --- a/changelog.d/1922.change.rst +++ b/changelog.d/1922.change.rst @@ -1 +1 @@ -Fix possible issue with transitive build dependencies. +Build dependencies (setup_requires and tests_require) now install transitive dependencies indicated by extras. -- cgit v1.2.3 From a2e883e1b838db529d992d4c6c8ab73c16f48591 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 1 Dec 2019 09:38:13 -0500 Subject: Extract function to strip the marker for concise code in the long function. --- setuptools/installer.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/setuptools/installer.py b/setuptools/installer.py index ba9cfce9..527b95de 100644 --- a/setuptools/installer.py +++ b/setuptools/installer.py @@ -64,11 +64,8 @@ def fetch_build_egg(dist, req): pkg_resources.get_distribution('wheel') except pkg_resources.DistributionNotFound: dist.announce('WARNING: The wheel package is not available.', log.WARN) - # Ignore environment markers: if we're here, it's needed. This ensure - # we don't try to ask pip for something like `babel; extra == "i18n"`, - # which would always be ignored. - req = pkg_resources.Requirement.parse(str(req)) - req.marker = None + # Ignore environment markers; if supplied, it is required. + req = strip_marker(req) # Take easy_install options into account, but do not override relevant # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll # take precedence. @@ -130,3 +127,15 @@ def fetch_build_egg(dist, req): dist = pkg_resources.Distribution.from_filename( dist_location, metadata=dist_metadata) return dist + + +def strip_marker(req): + """ + Return a new requirement without the environment marker to avoid + calling pip with something like `babel; extra == "i18n"`, which + would always be ignored. + """ + # create a copy to avoid mutating the input + req = pkg_resources.Requirement.parse(str(req)) + req.marker = None + return req -- cgit v1.2.3