From 4a52a71956a8d46fcb7294ac71734504bb09bcc2 Mon Sep 17 00:00:00 2001 From: S. Solomon Darnell Date: Fri, 28 Mar 2025 21:52:21 -0500 Subject: two version of R2R are here --- .../setuptools/tests/test_easy_install.py | 1476 ++++++++++++++++++++ 1 file changed, 1476 insertions(+) create mode 100644 .venv/lib/python3.12/site-packages/setuptools/tests/test_easy_install.py (limited to '.venv/lib/python3.12/site-packages/setuptools/tests/test_easy_install.py') diff --git a/.venv/lib/python3.12/site-packages/setuptools/tests/test_easy_install.py b/.venv/lib/python3.12/site-packages/setuptools/tests/test_easy_install.py new file mode 100644 index 00000000..b58b0b66 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/setuptools/tests/test_easy_install.py @@ -0,0 +1,1476 @@ +"""Easy install Tests""" + +import contextlib +import io +import itertools +import logging +import os +import pathlib +import re +import site +import subprocess +import sys +import tarfile +import tempfile +import time +import warnings +import zipfile +from pathlib import Path +from typing import NamedTuple +from unittest import mock + +import pytest +from jaraco import path + +import pkg_resources +import setuptools.command.easy_install as ei +from pkg_resources import Distribution as PRDistribution, normalize_path, working_set +from setuptools import sandbox +from setuptools._normalization import safer_name +from setuptools.command.easy_install import PthDistributions +from setuptools.dist import Distribution +from setuptools.sandbox import run_setup +from setuptools.tests import fail_on_ascii +from setuptools.tests.server import MockServer, path_to_url + +from . import contexts +from .textwrap import DALS + +import distutils.errors + + +@pytest.fixture(autouse=True) +def pip_disable_index(monkeypatch): + """ + Important: Disable the default index for pip to avoid + querying packages in the index and potentially resolving + and installing packages there. + """ + monkeypatch.setenv('PIP_NO_INDEX', 'true') + + +class FakeDist: + def get_entry_map(self, group): + if group != 'console_scripts': + return {} + return {'name': 'ep'} + + def as_requirement(self): + return 'spec' + + +SETUP_PY = DALS( + """ + from setuptools import setup + + setup() + """ +) + + +class TestEasyInstallTest: + def test_get_script_args(self): + header = ei.CommandSpec.best().from_environment().as_header() + dist = FakeDist() + args = next(ei.ScriptWriter.get_args(dist)) + _name, script = itertools.islice(args, 2) + 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 + # the project level + dist = Distribution() + cmd = ei.easy_install(dist) + cmd.check_pth_processing = lambda: True + cmd.no_find_links = True + cmd.find_links = ['link1', 'link2'] + cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok') + cmd.args = ['ok'] + cmd.ensure_finalized() + assert cmd.package_index.scanned_urls == {} + + # let's try without it (default behavior) + cmd = ei.easy_install(dist) + cmd.check_pth_processing = lambda: True + cmd.find_links = ['link1', 'link2'] + cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok') + cmd.args = ['ok'] + cmd.ensure_finalized() + keys = sorted(cmd.package_index.scanned_urls.keys()) + assert keys == ['link1', 'link2'] + + def test_write_exception(self): + """ + Test that `cant_write_to_target` is rendered as a DistutilsError. + """ + dist = Distribution() + cmd = ei.easy_install(dist) + cmd.install_dir = os.getcwd() + with pytest.raises(distutils.errors.DistutilsError): + cmd.cant_write_to_target() + + def test_all_site_dirs(self, monkeypatch): + """ + get_site_dirs should always return site dirs reported by + site.getsitepackages. + """ + path = normalize_path('/setuptools/test/site-packages') + + def mock_gsp(): + return [path] + + monkeypatch.setattr(site, 'getsitepackages', mock_gsp, raising=False) + assert path in ei.get_site_dirs() + + def test_all_site_dirs_works_without_getsitepackages(self, monkeypatch): + monkeypatch.delattr(site, 'getsitepackages', raising=False) + assert ei.get_site_dirs() + + @pytest.fixture + def sdist_unicode(self, tmpdir): + files = [ + ( + 'setup.py', + DALS( + """ + import setuptools + setuptools.setup( + name="setuptools-test-unicode", + version="1.0", + packages=["mypkg"], + include_package_data=True, + ) + """ + ), + ), + ( + 'mypkg/__init__.py', + "", + ), + ( + 'mypkg/☃.txt', + "", + ), + ] + sdist_name = 'setuptools-test-unicode-1.0.zip' + sdist = tmpdir / sdist_name + # can't use make_sdist, because the issue only occurs + # with zip sdists. + sdist_zip = zipfile.ZipFile(str(sdist), 'w') + for filename, content in files: + sdist_zip.writestr(filename, content) + 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 + the package has unicode filenames. + """ + dist = Distribution({'script_args': ['easy_install']}) + target = (tmpdir / 'target').ensure_dir() + cmd = ei.easy_install( + dist, + install_dir=str(target), + args=['x'], + ) + monkeypatch.setitem(os.environ, 'PYTHONPATH', str(target)) + cmd.ensure_finalized() + cmd.easy_install(sdist_unicode) + + @pytest.fixture + def sdist_unicode_in_script(self, tmpdir): + files = [ + ( + "setup.py", + DALS( + """ + import setuptools + setuptools.setup( + name="setuptools-test-unicode", + version="1.0", + packages=["mypkg"], + include_package_data=True, + scripts=['mypkg/unicode_in_script'], + ) + """ + ), + ), + ("mypkg/__init__.py", ""), + ( + "mypkg/unicode_in_script", + DALS( + """ + #!/bin/sh + # á + + non_python_fn() { + } + """ + ), + ), + ] + sdist_name = "setuptools-test-unicode-script-1.0.zip" + sdist = tmpdir / sdist_name + # can't use make_sdist, because the issue only occurs + # with zip sdists. + sdist_zip = zipfile.ZipFile(str(sdist), "w") + for filename, content in files: + sdist_zip.writestr(filename, content.encode('utf-8')) + sdist_zip.close() + return str(sdist) + + @fail_on_ascii + def test_unicode_content_in_sdist( + self, sdist_unicode_in_script, tmpdir, monkeypatch + ): + """ + The install command should execute correctly even if + the package has unicode in scripts. + """ + dist = Distribution({"script_args": ["easy_install"]}) + target = (tmpdir / "target").ensure_dir() + cmd = ei.easy_install(dist, install_dir=str(target), args=["x"]) + monkeypatch.setitem(os.environ, "PYTHONPATH", str(target)) + cmd.ensure_finalized() + cmd.easy_install(sdist_unicode_in_script) + + @pytest.fixture + def sdist_script(self, tmpdir): + files = [ + ( + 'setup.py', + DALS( + """ + import setuptools + setuptools.setup( + name="setuptools-test-script", + version="1.0", + scripts=["mypkg_script"], + ) + """ + ), + ), + ( + 'mypkg_script', + DALS( + """ + #/usr/bin/python + print('mypkg_script') + """ + ), + ), + ] + sdist_name = 'setuptools-test-script-1.0.zip' + sdist = str(tmpdir / sdist_name) + make_sdist(sdist, files) + return sdist + + @pytest.mark.skipif( + not sys.platform.startswith('linux'), reason="Test can only be run on Linux" + ) + def test_script_install(self, sdist_script, tmpdir, monkeypatch): + """ + Check scripts are installed. + """ + dist = Distribution({'script_args': ['easy_install']}) + target = (tmpdir / 'target').ensure_dir() + cmd = ei.easy_install( + dist, + install_dir=str(target), + args=['x'], + ) + monkeypatch.setitem(os.environ, 'PYTHONPATH', str(target)) + cmd.ensure_finalized() + cmd.easy_install(sdist_script) + assert (target / 'mypkg_script').exists() + + +@pytest.mark.filterwarnings('ignore:Unbuilt egg') +class TestPTHFileWriter: + def test_add_from_cwd_site_sets_dirty(self): + """a pth file manager should set dirty + if a distribution is in site but also the cwd + """ + pth = PthDistributions('does-not_exist', [os.getcwd()]) + assert not pth.dirty + pth.add(PRDistribution(os.getcwd())) + assert pth.dirty + + def test_add_from_site_is_ignored(self): + location = '/test/location/does-not-have-to-exist' + # PthDistributions expects all locations to be normalized + location = pkg_resources.normalize_path(location) + pth = PthDistributions( + 'does-not_exist', + [ + location, + ], + ) + assert not pth.dirty + pth.add(PRDistribution(location)) + assert not pth.dirty + + def test_many_pth_distributions_merge_together(self, tmpdir): + """ + If the pth file is modified under the hood, then PthDistribution + will refresh its content before saving, merging contents when + necessary. + """ + # putting the pth file in a dedicated sub-folder, + pth_subdir = tmpdir.join("pth_subdir") + pth_subdir.mkdir() + pth_path = str(pth_subdir.join("file1.pth")) + pth1 = PthDistributions(pth_path) + pth2 = PthDistributions(pth_path) + assert pth1.paths == pth2.paths == [], ( + "unless there would be some default added at some point" + ) + # and so putting the src_subdir in folder distinct than the pth one, + # so to keep it absolute by PthDistributions + new_src_path = tmpdir.join("src_subdir") + new_src_path.mkdir() # must exist to be accounted + new_src_path_str = str(new_src_path) + pth1.paths.append(new_src_path_str) + pth1.save() + assert pth1.paths, ( + "the new_src_path added must still be present/valid in pth1 after save" + ) + # now, + assert new_src_path_str not in pth2.paths, ( + "right before we save the entry should still not be present" + ) + pth2.save() + assert new_src_path_str in pth2.paths, ( + "the new_src_path entry should have been added by pth2 with its save() call" + ) + assert pth2.paths[-1] == new_src_path, ( + "and it should match exactly on the last entry actually " + "given we append to it in save()" + ) + # finally, + assert PthDistributions(pth_path).paths == pth2.paths, ( + "and we should have the exact same list at the end " + "with a fresh PthDistributions instance" + ) + + +@pytest.fixture +def setup_context(tmpdir): + with (tmpdir / 'setup.py').open('w', encoding="utf-8") as f: + f.write(SETUP_PY) + with tmpdir.as_cwd(): + yield tmpdir + + +@pytest.mark.usefixtures("user_override") +@pytest.mark.usefixtures("setup_context") +class TestUserInstallTest: + # prevent check that site-packages is writable. easy_install + # shouldn't be writing to system site-packages during finalize + # options, but while it does, bypass the behavior. + prev_sp_write = mock.patch( + 'setuptools.command.easy_install.easy_install.check_site_dir', + mock.Mock(), + ) + + # simulate setuptools installed in user site packages + @mock.patch('setuptools.command.easy_install.__file__', site.USER_SITE) + @mock.patch('site.ENABLE_USER_SITE', True) + @prev_sp_write + def test_user_install_not_implied_user_site_enabled(self): + self.assert_not_user_site() + + @mock.patch('site.ENABLE_USER_SITE', False) + @prev_sp_write + def test_user_install_not_implied_user_site_disabled(self): + self.assert_not_user_site() + + @staticmethod + def assert_not_user_site(): + # create a finalized easy_install command + dist = Distribution() + dist.script_name = 'setup.py' + cmd = ei.easy_install(dist) + cmd.args = ['py'] + cmd.ensure_finalized() + assert not cmd.user, 'user should not be implied' + + def test_multiproc_atexit(self): + pytest.importorskip('multiprocessing') + + log = logging.getLogger('test_easy_install') + logging.basicConfig(level=logging.INFO, stream=sys.stderr) + log.info('this should not break') + + @pytest.fixture + def foo_package(self, tmpdir): + egg_file = tmpdir / 'foo-1.0.egg-info' + with egg_file.open('w') as f: + f.write('Name: foo\n') + return str(tmpdir) + + @pytest.fixture + def install_target(self, tmpdir): + target = str(tmpdir) + with mock.patch('sys.path', sys.path + [target]): + python_path = os.path.pathsep.join(sys.path) + with mock.patch.dict(os.environ, PYTHONPATH=python_path): + yield target + + def test_local_index(self, foo_package, install_target): + """ + The local index must be used when easy_install locates installed + packages. + """ + dist = Distribution() + dist.script_name = 'setup.py' + cmd = ei.easy_install(dist) + cmd.install_dir = install_target + cmd.args = ['foo'] + cmd.ensure_finalized() + cmd.local_index.scan([foo_package]) + res = cmd.easy_install('foo') + actual = os.path.normcase(os.path.realpath(res.location)) + expected = os.path.normcase(os.path.realpath(foo_package)) + assert actual == expected + + @contextlib.contextmanager + def user_install_setup_context(self, *args, **kwargs): + """ + Wrap sandbox.setup_context to patch easy_install in that context to + appear as user-installed. + """ + with self.orig_context(*args, **kwargs): + import setuptools.command.easy_install as ei + + ei.__file__ = site.USER_SITE + yield + + def patched_setup_context(self): + self.orig_context = sandbox.setup_context + + return mock.patch( + 'setuptools.sandbox.setup_context', + self.user_install_setup_context, + ) + + +@pytest.fixture +def distutils_package(): + distutils_setup_py = SETUP_PY.replace( + 'from setuptools import setup', + 'from distutils.core import setup', + ) + with contexts.tempdir(cd=os.chdir): + with open('setup.py', 'w', encoding="utf-8") as f: + f.write(distutils_setup_py) + yield + + +@pytest.mark.usefixtures("distutils_package") +class TestDistutilsPackage: + def test_bdist_egg_available_on_distutils_pkg(self): + run_setup('setup.py', ['bdist_egg']) + + +@pytest.fixture +def mock_index(): + # set up a server which will simulate an alternate package index. + p_index = MockServer() + if p_index.server_port == 0: + # Some platforms (Jython) don't find a port to which to bind, + # so skip test for them. + pytest.skip("could not find a valid port") + p_index.start() + return p_index + + +class TestInstallRequires: + def test_setup_install_includes_dependencies(self, tmp_path, mock_index): + """ + When ``python setup.py install`` is called directly, it will use easy_install + to fetch dependencies. + """ + # TODO: Remove these tests once `setup.py install` is completely removed + project_root = tmp_path / "project" + project_root.mkdir(exist_ok=True) + install_root = tmp_path / "install" + install_root.mkdir(exist_ok=True) + + self.create_project(project_root) + cmd = [ + sys.executable, + '-c', + '__import__("setuptools").setup()', + 'install', + '--install-base', + str(install_root), + '--install-lib', + str(install_root), + '--install-headers', + str(install_root), + '--install-scripts', + str(install_root), + '--install-data', + str(install_root), + '--install-purelib', + str(install_root), + '--install-platlib', + str(install_root), + ] + env = {**os.environ, "__EASYINSTALL_INDEX": mock_index.url} + cp = subprocess.run( + cmd, + cwd=str(project_root), + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + encoding="utf-8", + ) + assert cp.returncode != 0 + try: + assert '/does-not-exist/' in {r.path for r in mock_index.requests} + assert next( + line + for line in cp.stdout.splitlines() + if "not find suitable distribution for" in line + and "does-not-exist" in line + ) + except Exception: + if "failed to get random numbers" in cp.stdout: + pytest.xfail(f"{sys.platform} failure - {cp.stdout}") + raise + + def create_project(self, root): + config = """ + [metadata] + name = project + version = 42 + + [options] + install_requires = does-not-exist + py_modules = mod + """ + (root / 'setup.cfg').write_text(DALS(config), encoding="utf-8") + (root / 'mod.py').touch() + + +class TestSetupRequires: + def test_setup_requires_honors_fetch_params(self, mock_index, monkeypatch): + """ + When easy_install installs a source distribution which specifies + setup_requires, it should honor the fetch parameters (such as + index-url, and find-links). + """ + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + monkeypatch.setenv('PIP_NO_INDEX', 'false') + with contexts.quiet(): + # create an sdist that has a build-time dependency. + with TestSetupRequires.create_sdist() as dist_file: + with contexts.tempdir() as temp_install_dir: + with contexts.environment(PYTHONPATH=temp_install_dir): + cmd = [ + sys.executable, + '-c', + '__import__("setuptools").setup()', + 'easy_install', + '--index-url', + mock_index.url, + '--exclude-scripts', + '--install-dir', + temp_install_dir, + dist_file, + ] + subprocess.Popen(cmd).wait() + # there should have been one requests to the server + assert [r.path for r in mock_index.requests] == ['/does-not-exist/'] + + @staticmethod + @contextlib.contextmanager + def create_sdist(): + """ + Return an sdist with a setup_requires dependency (of something that + doesn't exist) + """ + with contexts.tempdir() as dir: + dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz') + make_sdist( + dist_path, + [ + ( + 'setup.py', + DALS( + """ + import setuptools + setuptools.setup( + name="setuptools-test-fetcher", + version="1.0", + setup_requires = ['does-not-exist'], + ) + """ + ), + ), + ('setup.cfg', ''), + ], + ) + yield dist_path + + use_setup_cfg = ( + (), + ('dependency_links',), + ('setup_requires',), + ('dependency_links', 'setup_requires'), + ) + + @pytest.mark.parametrize('use_setup_cfg', use_setup_cfg) + def test_setup_requires_overrides_version_conflict(self, use_setup_cfg): + """ + Regression test for distribution issue 323: + https://bitbucket.org/tarek/distribute/issues/323 + + Ensures that a distribution's setup_requires requirements can still be + installed and used locally even if a conflicting version of that + requirement is already on the path. + """ + + fake_dist = PRDistribution( + 'does-not-matter', project_name='foobar', version='0.0' + ) + working_set.add(fake_dist) + + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + test_pkg = create_setup_requires_package( + temp_dir, use_setup_cfg=use_setup_cfg + ) + test_setup_py = os.path.join(test_pkg, 'setup.py') + with contexts.quiet() as (stdout, _stderr): + # Don't even need to install the package, just + # running the setup.py at all is sufficient + run_setup(test_setup_py, ['--name']) + + lines = stdout.readlines() + assert len(lines) > 0 + assert lines[-1].strip() == 'test_pkg' + + @pytest.mark.parametrize('use_setup_cfg', use_setup_cfg) + def test_setup_requires_override_nspkg(self, use_setup_cfg): + """ + Like ``test_setup_requires_overrides_version_conflict`` but where the + ``setup_requires`` package is part of a namespace package that has + *already* been imported. + """ + + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + foobar_1_archive = os.path.join(temp_dir, 'foo_bar-0.1.tar.gz') + make_nspkg_sdist(foobar_1_archive, 'foo.bar', '0.1') + # Now actually go ahead an extract to the temp dir and add the + # extracted path to sys.path so foo.bar v0.1 is importable + foobar_1_dir = os.path.join(temp_dir, 'foo_bar-0.1') + os.mkdir(foobar_1_dir) + with tarfile.open(foobar_1_archive) as tf: + tf.extraction_filter = lambda member, path: member + tf.extractall(foobar_1_dir) + sys.path.insert(1, foobar_1_dir) + + dist = PRDistribution( + foobar_1_dir, project_name='foo.bar', version='0.1' + ) + working_set.add(dist) + + template = DALS( + """\ + import foo # Even with foo imported first the + # setup_requires package should override + import setuptools + setuptools.setup(**%r) + + if not (hasattr(foo, '__path__') and + len(foo.__path__) == 2): + print('FAIL') + + if 'foo_bar-0.2' not in foo.__path__[0]: + print('FAIL') + """ + ) + + test_pkg = create_setup_requires_package( + temp_dir, + 'foo.bar', + '0.2', + make_nspkg_sdist, + template, + use_setup_cfg=use_setup_cfg, + ) + + test_setup_py = os.path.join(test_pkg, 'setup.py') + + with contexts.quiet() as (stdout, _stderr): + try: + # Don't even need to install the package, just + # running the setup.py at all is sufficient + run_setup(test_setup_py, ['--name']) + except pkg_resources.VersionConflict: # pragma: nocover + pytest.fail( + 'Installing setup.py requirements caused a VersionConflict' + ) + + assert 'FAIL' not in stdout.getvalue() + lines = stdout.readlines() + assert len(lines) > 0 + assert lines[-1].strip() == 'test_pkg' + + @pytest.mark.parametrize('use_setup_cfg', use_setup_cfg) + def test_setup_requires_with_attr_version(self, use_setup_cfg): + def make_dependency_sdist(dist_path, distname, version): + files = [ + ( + 'setup.py', + DALS( + f""" + import setuptools + setuptools.setup( + name={distname!r}, + version={version!r}, + py_modules=[{distname!r}], + ) + """ + ), + ), + ( + distname + '.py', + DALS( + """ + version = 42 + """ + ), + ), + ] + make_sdist(dist_path, files) + + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + test_pkg = create_setup_requires_package( + temp_dir, + setup_attrs=dict(version='attr: foobar.version'), + make_package=make_dependency_sdist, + use_setup_cfg=use_setup_cfg + ('version',), + ) + test_setup_py = os.path.join(test_pkg, 'setup.py') + with contexts.quiet() as (stdout, _stderr): + run_setup(test_setup_py, ['--version']) + lines = stdout.readlines() + assert len(lines) > 0 + assert lines[-1].strip() == '42' + + def test_setup_requires_honors_pip_env(self, mock_index, monkeypatch): + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + monkeypatch.setenv('PIP_NO_INDEX', 'false') + monkeypatch.setenv('PIP_INDEX_URL', mock_index.url) + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + test_pkg = create_setup_requires_package( + temp_dir, + 'python-xlib', + '0.19', + setup_attrs=dict(dependency_links=[]), + ) + test_setup_cfg = os.path.join(test_pkg, 'setup.cfg') + with open(test_setup_cfg, 'w', encoding="utf-8") as fp: + fp.write( + DALS( + """ + [easy_install] + index_url = https://pypi.org/legacy/ + """ + ) + ) + test_setup_py = os.path.join(test_pkg, 'setup.py') + with pytest.raises(distutils.errors.DistutilsError): + run_setup(test_setup_py, ['--version']) + assert len(mock_index.requests) == 1 + assert mock_index.requests[0].path == '/python-xlib/' + + def test_setup_requires_with_pep508_url(self, mock_index, monkeypatch): + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + monkeypatch.setenv('PIP_INDEX_URL', mock_index.url) + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + dep_sdist = os.path.join(temp_dir, 'dep.tar.gz') + make_trivial_sdist(dep_sdist, 'dependency', '42') + dep_url = path_to_url(dep_sdist, authority='localhost') + test_pkg = create_setup_requires_package( + temp_dir, + # Ignored (overridden by setup_attrs) + 'python-xlib', + '0.19', + setup_attrs=dict(setup_requires=f'dependency @ {dep_url}'), + ) + test_setup_py = os.path.join(test_pkg, 'setup.py') + run_setup(test_setup_py, ['--version']) + assert len(mock_index.requests) == 0 + + def test_setup_requires_with_allow_hosts(self, mock_index): + """The `allow-hosts` option in not supported anymore.""" + files = { + 'test_pkg': { + 'setup.py': DALS( + """ + from setuptools import setup + setup(setup_requires='python-xlib') + """ + ), + 'setup.cfg': DALS( + """ + [easy_install] + allow_hosts = * + """ + ), + } + } + with contexts.save_pkg_resources_state(): + with contexts.tempdir() as temp_dir: + path.build(files, prefix=temp_dir) + setup_py = str(pathlib.Path(temp_dir, 'test_pkg', 'setup.py')) + with pytest.raises(distutils.errors.DistutilsError): + run_setup(setup_py, ['--version']) + assert len(mock_index.requests) == 0 + + def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir): + """Check `python_requires` is honored.""" + monkeypatch.setenv('PIP_RETRIES', '0') + monkeypatch.setenv('PIP_TIMEOUT', '0') + monkeypatch.setenv('PIP_NO_INDEX', '1') + monkeypatch.setenv('PIP_VERBOSE', '1') + dep_1_0_sdist = 'dep-1.0.tar.gz' + dep_1_0_url = path_to_url(str(tmpdir / dep_1_0_sdist)) + dep_1_0_python_requires = '>=2.7' + make_python_requires_sdist( + str(tmpdir / dep_1_0_sdist), 'dep', '1.0', dep_1_0_python_requires + ) + dep_2_0_sdist = 'dep-2.0.tar.gz' + dep_2_0_url = path_to_url(str(tmpdir / dep_2_0_sdist)) + dep_2_0_python_requires = ( + f'!={sys.version_info.major}.{sys.version_info.minor}.*' + ) + make_python_requires_sdist( + str(tmpdir / dep_2_0_sdist), 'dep', '2.0', dep_2_0_python_requires + ) + index = tmpdir / 'index.html' + index.write_text( + DALS( + """ + +