gpt2-small-repla / gpt2eval_env /lib /python3.11 /site-packages /setuptools /tests /test_easy_install.py
Download gpt2eval_env/lib/python3.11/site-packages/setuptools/tests/test_easy_install.py from michaelxing/gpt2-small-repla: direct link, hf CLI and curl.
- Browser
- Download file 53.5 kB
-
https://huggingface.co/michaelxing/gpt2-small-repla/resolve/main/gpt2eval_env/lib/python3.11/site-packages/setuptools/tests/test_easy_install.py
- Command line
-
hf download hf://michaelxing/gpt2-small-repla/gpt2eval_env/lib/python3.11/site-packages/setuptools/tests/test_easy_install.py
-
curl -L -o test_easy_install.py https://huggingface.co/michaelxing/gpt2-small-repla/resolve/main/gpt2eval_env/lib/python3.11/site-packages/setuptools/tests/test_easy_install.py
53.5 kB
| """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 | |
| 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() | |
| 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) | |
| 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) | |
| 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) | |
| 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) | |
| 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 | |
| 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() | |
| 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" | |
| ) | |
| 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 | |
| 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 | |
| def test_user_install_not_implied_user_site_enabled(self): | |
| self.assert_not_user_site() | |
| def test_user_install_not_implied_user_site_disabled(self): | |
| self.assert_not_user_site() | |
| 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') | |
| 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) | |
| 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 | |
| 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, | |
| ) | |
| 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 | |
| class TestDistutilsPackage: | |
| def test_bdist_egg_available_on_distutils_pkg(self): | |
| run_setup('setup.py', ['bdist_egg']) | |
| 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/'] | |
| 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'), | |
| ) | |
| 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' | |
| 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' | |
| 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( | |
| """ | |
| <!DOCTYPE html> | |
| <html><head><title>Links for dep</title></head> | |
| <body> | |
| <h1>Links for dep</h1> | |
| <a href="{dep_1_0_url}"\ | |
| data-requires-python="{dep_1_0_python_requires}">{dep_1_0_sdist}</a><br/> | |
| <a href="{dep_2_0_url}"\ | |
| data-requires-python="{dep_2_0_python_requires}">{dep_2_0_sdist}</a><br/> | |
| </body> | |
| </html> | |
| """ | |
| ).format( | |
| dep_1_0_url=dep_1_0_url, | |
| dep_1_0_sdist=dep_1_0_sdist, | |
| dep_1_0_python_requires=dep_1_0_python_requires, | |
| dep_2_0_url=dep_2_0_url, | |
| dep_2_0_sdist=dep_2_0_sdist, | |
| dep_2_0_python_requires=dep_2_0_python_requires, | |
| ), | |
| 'utf-8', | |
| ) | |
| index_url = path_to_url(str(index)) | |
| with contexts.save_pkg_resources_state(): | |
| test_pkg = create_setup_requires_package( | |
| str(tmpdir), | |
| 'python-xlib', | |
| '0.19', # Ignored (overridden by setup_attrs). | |
| setup_attrs=dict(setup_requires='dep', dependency_links=[index_url]), | |
| ) | |
| test_setup_py = os.path.join(test_pkg, 'setup.py') | |
| run_setup(test_setup_py, ['--version']) | |
| eggs = list( | |
| map(str, pkg_resources.find_distributions(os.path.join(test_pkg, '.eggs'))) | |
| ) | |
| assert eggs == ['dep 1.0'] | |
| def test_setup_requires_with_find_links_in_setup_cfg( | |
| self, monkeypatch, with_dependency_links_in_setup_py | |
| ): | |
| monkeypatch.setenv('PIP_RETRIES', '0') | |
| monkeypatch.setenv('PIP_TIMEOUT', '0') | |
| with contexts.save_pkg_resources_state(): | |
| with contexts.tempdir() as temp_dir: | |
| make_trivial_sdist( | |
| os.path.join(temp_dir, 'python-xlib-42.tar.gz'), 'python-xlib', '42' | |
| ) | |
| 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', encoding="utf-8") as fp: | |
| if with_dependency_links_in_setup_py: | |
| dependency_links = [os.path.join(temp_dir, 'links')] | |
| else: | |
| dependency_links = [] | |
| fp.write( | |
| DALS( | |
| """ | |
| from setuptools import installer, setup | |
| setup(setup_requires='python-xlib==42', | |
| dependency_links={dependency_links!r}) | |
| """ | |
| ).format(dependency_links=dependency_links) | |
| ) | |
| with open(test_setup_cfg, 'w', encoding="utf-8") as fp: | |
| fp.write( | |
| DALS( | |
| """ | |
| [easy_install] | |
| index_url = {index_url} | |
| find_links = {find_links} | |
| """ | |
| ).format( | |
| index_url=os.path.join(temp_dir, 'index'), | |
| find_links=temp_dir, | |
| ) | |
| ) | |
| run_setup(test_setup_py, ['--version']) | |
| 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) | |
| path.build( | |
| { | |
| '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'), ['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') | |
| os.mkdir(test_pkg) | |
| with open(test_setup_py, 'w', encoding="utf-8") as fp: | |
| fp.write( | |
| DALS( | |
| """ | |
| from setuptools import installer, setup | |
| setup(setup_requires='dep[extra]') | |
| """ | |
| ) | |
| ) | |
| # Check... | |
| monkeypatch.setenv('PIP_FIND_LINKS', str(temp_dir)) | |
| monkeypatch.setenv('PIP_NO_INDEX', '1') | |
| monkeypatch.setenv('PIP_RETRIES', '0') | |
| monkeypatch.setenv('PIP_TIMEOUT', '0') | |
| run_setup(test_setup_py, ['--version']) | |
| def test_setup_requires_with_distutils_command_dep(self, monkeypatch): | |
| """ | |
| Use case: ensure build requirements' extras | |
| are properly installed and activated. | |
| """ | |
| with contexts.save_pkg_resources_state(): | |
| with contexts.tempdir() as temp_dir: | |
| # Create source distribution for `extra_dep`. | |
| make_sdist( | |
| os.path.join(temp_dir, 'extra_dep-1.0.tar.gz'), | |
| [ | |
| ( | |
| 'setup.py', | |
| DALS( | |
| """ | |
| import setuptools | |
| setuptools.setup( | |
| name='extra_dep', | |
| version='1.0', | |
| py_modules=['extra_dep'], | |
| ) | |
| """ | |
| ), | |
| ), | |
| ('setup.cfg', ''), | |
| ('extra_dep.py', ''), | |
| ], | |
| ) | |
| # Create source tree for `epdep`. | |
| dep_pkg = os.path.join(temp_dir, 'epdep') | |
| os.mkdir(dep_pkg) | |
| path.build( | |
| { | |
| 'setup.py': DALS( | |
| """ | |
| import setuptools | |
| setuptools.setup( | |
| name='dep', version='2.0', | |
| py_modules=['epcmd'], | |
| extras_require={'extra': ['extra_dep']}, | |
| entry_points=''' | |
| [distutils.commands] | |
| epcmd = epcmd:epcmd [extra] | |
| ''', | |
| ) | |
| """ | |
| ), | |
| 'setup.cfg': '', | |
| 'epcmd.py': DALS( | |
| """ | |
| from distutils.command.build_py import build_py | |
| import extra_dep | |
| class epcmd(build_py): | |
| pass | |
| """ | |
| ), | |
| }, | |
| prefix=dep_pkg, | |
| ) | |
| # "Install" dep. | |
| run_setup(os.path.join(dep_pkg, 'setup.py'), ['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') | |
| os.mkdir(test_pkg) | |
| with open(test_setup_py, 'w', encoding="utf-8") as fp: | |
| fp.write( | |
| DALS( | |
| """ | |
| from setuptools import installer, setup | |
| setup(setup_requires='dep[extra]') | |
| """ | |
| ) | |
| ) | |
| # Check... | |
| monkeypatch.setenv('PIP_FIND_LINKS', str(temp_dir)) | |
| monkeypatch.setenv('PIP_NO_INDEX', '1') | |
| monkeypatch.setenv('PIP_RETRIES', '0') | |
| monkeypatch.setenv('PIP_TIMEOUT', '0') | |
| run_setup(test_setup_py, ['epcmd']) | |
| def make_trivial_sdist(dist_path, distname, version): | |
| """ | |
| Create a simple sdist tarball at dist_path, containing just a simple | |
| setup.py. | |
| """ | |
| make_sdist( | |
| dist_path, | |
| [ | |
| ( | |
| 'setup.py', | |
| DALS( | |
| f"""\ | |
| import setuptools | |
| setuptools.setup( | |
| name={distname!r}, | |
| version={version!r} | |
| ) | |
| """ | |
| ), | |
| ), | |
| ('setup.cfg', ''), | |
| ], | |
| ) | |
| def make_nspkg_sdist(dist_path, distname, version): | |
| """ | |
| Make an sdist tarball with distname and version which also contains one | |
| package with the same name as distname. The top-level package is | |
| designated a namespace package). | |
| """ | |
| # Assert that the distname contains at least one period | |
| assert '.' in distname | |
| parts = distname.split('.') | |
| nspackage = parts[0] | |
| packages = ['.'.join(parts[:idx]) for idx in range(1, len(parts) + 1)] | |
| setup_py = DALS( | |
| f"""\ | |
| import setuptools | |
| setuptools.setup( | |
| name={distname!r}, | |
| version={version!r}, | |
| packages={packages!r}, | |
| namespace_packages=[{nspackage!r}] | |
| ) | |
| """ | |
| ) | |
| init = "__import__('pkg_resources').declare_namespace(__name__)" | |
| files = [('setup.py', setup_py), (os.path.join(nspackage, '__init__.py'), init)] | |
| for package in packages[1:]: | |
| filename = os.path.join(*(package.split('.') + ['__init__.py'])) | |
| files.append((filename, '')) | |
| make_sdist(dist_path, files) | |
| def make_python_requires_sdist(dist_path, distname, version, python_requires): | |
| make_sdist( | |
| dist_path, | |
| [ | |
| ( | |
| 'setup.py', | |
| DALS( | |
| """\ | |
| import setuptools | |
| setuptools.setup( | |
| name={name!r}, | |
| version={version!r}, | |
| python_requires={python_requires!r}, | |
| ) | |
| """ | |
| ).format( | |
| name=distname, version=version, python_requires=python_requires | |
| ), | |
| ), | |
| ('setup.cfg', ''), | |
| ], | |
| ) | |
| def make_sdist(dist_path, files): | |
| """ | |
| Create a simple sdist tarball at dist_path, containing the files | |
| listed in ``files`` as ``(filename, content)`` tuples. | |
| """ | |
| # Distributions with only one file don't play well with pip. | |
| assert len(files) > 1 | |
| with tarfile.open(dist_path, 'w:gz') as dist: | |
| for filename, content in files: | |
| file_bytes = io.BytesIO(content.encode('utf-8')) | |
| file_info = tarfile.TarInfo(name=filename) | |
| file_info.size = len(file_bytes.getvalue()) | |
| file_info.mtime = int(time.time()) | |
| dist.addfile(file_info, fileobj=file_bytes) | |
| def create_setup_requires_package( | |
| path, | |
| distname='foobar', | |
| version='0.1', | |
| make_package=make_trivial_sdist, | |
| setup_py_template=None, | |
| setup_attrs=None, | |
| use_setup_cfg=(), | |
| ): | |
| """Creates a source tree under path for a trivial test package that has a | |
| single requirement in setup_requires--a tarball for that requirement is | |
| also created and added to the dependency_links argument. | |
| ``distname`` and ``version`` refer to the name/version of the package that | |
| the test package requires via ``setup_requires``. The name of the test | |
| package itself is just 'test_pkg'. | |
| """ | |
| normalized_distname = safer_name(distname) | |
| test_setup_attrs = { | |
| 'name': 'test_pkg', | |
| 'version': '0.0', | |
| 'setup_requires': [f'{normalized_distname}=={version}'], | |
| 'dependency_links': [os.path.abspath(path)], | |
| } | |
| if setup_attrs: | |
| test_setup_attrs.update(setup_attrs) | |
| test_pkg = os.path.join(path, 'test_pkg') | |
| os.mkdir(test_pkg) | |
| # setup.cfg | |
| if use_setup_cfg: | |
| options = [] | |
| metadata = [] | |
| for name in use_setup_cfg: | |
| value = test_setup_attrs.pop(name) | |
| if name in 'name version'.split(): | |
| section = metadata | |
| else: | |
| section = options | |
| if isinstance(value, (tuple, list)): | |
| value = ';'.join(value) | |
| section.append(f'{name}: {value}') | |
| test_setup_cfg_contents = DALS( | |
| """ | |
| [metadata] | |
| {metadata} | |
| [options] | |
| {options} | |
| """ | |
| ).format( | |
| options='\n'.join(options), | |
| metadata='\n'.join(metadata), | |
| ) | |
| else: | |
| test_setup_cfg_contents = '' | |
| with open(os.path.join(test_pkg, 'setup.cfg'), 'w', encoding="utf-8") as f: | |
| f.write(test_setup_cfg_contents) | |
| # setup.py | |
| if setup_py_template is None: | |
| setup_py_template = DALS( | |
| """\ | |
| import setuptools | |
| setuptools.setup(**%r) | |
| """ | |
| ) | |
| with open(os.path.join(test_pkg, 'setup.py'), 'w', encoding="utf-8") as f: | |
| f.write(setup_py_template % test_setup_attrs) | |
| foobar_path = os.path.join(path, f'{normalized_distname}-{version}.tar.gz') | |
| make_package(foobar_path, distname, version) | |
| return test_pkg | |
| class TestScriptHeader: | |
| non_ascii_exe = '/Users/José/bin/python' | |
| exe_with_spaces = r'C:\Program Files\Python36\python.exe' | |
| def test_get_script_header(self): | |
| expected = f'#!{ei.nt_quote_arg(os.path.normpath(sys.executable))}\n' | |
| actual = ei.ScriptWriter.get_header('#!/usr/local/bin/python') | |
| assert actual == expected | |
| def test_get_script_header_args(self): | |
| expected = f'#!{ei.nt_quote_arg(os.path.normpath(sys.executable))} -x\n' | |
| actual = ei.ScriptWriter.get_header('#!/usr/bin/python -x') | |
| assert actual == expected | |
| def test_get_script_header_non_ascii_exe(self): | |
| actual = ei.ScriptWriter.get_header( | |
| '#!/usr/bin/python', executable=self.non_ascii_exe | |
| ) | |
| expected = f'#!{self.non_ascii_exe} -x\n' | |
| assert actual == expected | |
| def test_get_script_header_exe_with_spaces(self): | |
| actual = ei.ScriptWriter.get_header( | |
| '#!/usr/bin/python', executable='"' + self.exe_with_spaces + '"' | |
| ) | |
| expected = f'#!"{self.exe_with_spaces}"\n' | |
| assert actual == expected | |
| class TestCommandSpec: | |
| def test_custom_launch_command(self): | |
| """ | |
| Show how a custom CommandSpec could be used to specify a #! executable | |
| which takes parameters. | |
| """ | |
| cmd = ei.CommandSpec(['/usr/bin/env', 'python3']) | |
| assert cmd.as_header() == '#!/usr/bin/env python3\n' | |
| def test_from_param_for_CommandSpec_is_passthrough(self): | |
| """ | |
| from_param should return an instance of a CommandSpec | |
| """ | |
| cmd = ei.CommandSpec(['python']) | |
| cmd_new = ei.CommandSpec.from_param(cmd) | |
| assert cmd is cmd_new | |
| def test_from_environment_with_spaces_in_executable(self): | |
| os.environ.pop('__PYVENV_LAUNCHER__', None) | |
| cmd = ei.CommandSpec.from_environment() | |
| assert len(cmd) == 1 | |
| assert cmd.as_header().startswith('#!"') | |
| def test_from_simple_string_uses_shlex(self): | |
| """ | |
| In order to support `executable = /usr/bin/env my-python`, make sure | |
| from_param invokes shlex on that input. | |
| """ | |
| cmd = ei.CommandSpec.from_param('/usr/bin/env my-python') | |
| assert len(cmd) == 2 | |
| assert '"' not in cmd.as_header() | |
| def test_from_param_raises_expected_error(self) -> None: | |
| """ | |
| from_param should raise its own TypeError when the argument's type is unsupported | |
| """ | |
| with pytest.raises(TypeError) as exc_info: | |
| ei.CommandSpec.from_param(object()) # type: ignore[arg-type] # We want a type error here | |
| assert ( | |
| str(exc_info.value) == "Argument has an unsupported type <class 'object'>" | |
| ), exc_info.value | |
| class TestWindowsScriptWriter: | |
| def test_header(self): | |
| hdr = ei.WindowsScriptWriter.get_header('') | |
| assert hdr.startswith('#!') | |
| assert hdr.endswith('\n') | |
| hdr = hdr.lstrip('#!') | |
| hdr = hdr.rstrip('\n') | |
| # header should not start with an escaped quote | |
| assert not hdr.startswith('\\"') | |
| class VersionStub(NamedTuple): | |
| major: int | |
| minor: int | |
| micro: int | |
| releaselevel: str | |
| serial: int | |
| def test_use_correct_python_version_string(tmpdir, tmpdir_cwd, monkeypatch): | |
| # In issue #3001, easy_install wrongly uses the `python3.1` directory | |
| # when the interpreter is `python3.10` and the `--user` option is given. | |
| # See pypa/setuptools#3001. | |
| dist = Distribution() | |
| cmd = dist.get_command_obj('easy_install') | |
| cmd.args = ['ok'] | |
| cmd.optimize = 0 | |
| cmd.user = True | |
| cmd.install_userbase = str(tmpdir) | |
| cmd.install_usersite = None | |
| install_cmd = dist.get_command_obj('install') | |
| install_cmd.install_userbase = str(tmpdir) | |
| install_cmd.install_usersite = None | |
| with monkeypatch.context() as patch, warnings.catch_warnings(): | |
| warnings.simplefilter("ignore") | |
| version = '3.10.1 (main, Dec 21 2021, 09:17:12) [GCC 10.2.1 20210110]' | |
| info = VersionStub(3, 10, 1, "final", 0) | |
| patch.setattr('site.ENABLE_USER_SITE', True) | |
| patch.setattr('sys.version', version) | |
| patch.setattr('sys.version_info', info) | |
| patch.setattr(cmd, 'create_home_path', mock.Mock()) | |
| cmd.finalize_options() | |
| name = "pypy" if hasattr(sys, 'pypy_version_info') else "python" | |
| install_dir = cmd.install_dir.lower() | |
| # In some platforms (e.g. Windows), install_dir is mostly determined | |
| # via `sysconfig`, which define constants eagerly at module creation. | |
| # This means that monkeypatching `sys.version` to emulate 3.10 for testing | |
| # may have no effect. | |
| # The safest test here is to rely on the fact that 3.1 is no longer | |
| # supported/tested, and make sure that if 'python3.1' ever appears in the string | |
| # it is followed by another digit (e.g. 'python3.10'). | |
| if re.search(name + r'3\.?1', install_dir): | |
| assert re.search(name + r'3\.?1\d', install_dir) | |
| # The following "variables" are used for interpolation in distutils | |
| # installation schemes, so it should be fair to treat them as "semi-public", | |
| # or at least public enough so we can have a test to make sure they are correct | |
| assert cmd.config_vars['py_version'] == '3.10.1' | |
| assert cmd.config_vars['py_version_short'] == '3.10' | |
| assert cmd.config_vars['py_version_nodot'] == '310' | |
| def test_editable_user_and_build_isolation(setup_context, monkeypatch, tmp_path): | |
| """`setup.py develop` should honor `--user` even under build isolation""" | |
| # == Arrange == | |
| # Pretend that build isolation was enabled | |
| # e.g pip sets the environment variable PYTHONNOUSERSITE=1 | |
| monkeypatch.setattr('site.ENABLE_USER_SITE', False) | |
| # Patching $HOME for 2 reasons: | |
| # 1. setuptools/command/easy_install.py:create_home_path | |
| # tries creating directories in $HOME. | |
| # Given:: | |
| # self.config_vars['DESTDIRS'] = ( | |
| # "/home/user/.pyenv/versions/3.9.10 " | |
| # "/home/user/.pyenv/versions/3.9.10/lib " | |
| # "/home/user/.pyenv/versions/3.9.10/lib/python3.9 " | |
| # "/home/user/.pyenv/versions/3.9.10/lib/python3.9/lib-dynload") | |
| # `create_home_path` will:: | |
| # makedirs( | |
| # "/home/user/.pyenv/versions/3.9.10 " | |
| # "/home/user/.pyenv/versions/3.9.10/lib " | |
| # "/home/user/.pyenv/versions/3.9.10/lib/python3.9 " | |
| # "/home/user/.pyenv/versions/3.9.10/lib/python3.9/lib-dynload") | |
| # | |
| # 2. We are going to force `site` to update site.USER_BASE and site.USER_SITE | |
| # To point inside our new home | |
| monkeypatch.setenv('HOME', str(tmp_path / '.home')) | |
| monkeypatch.setenv('USERPROFILE', str(tmp_path / '.home')) | |
| monkeypatch.setenv('APPDATA', str(tmp_path / '.home')) | |
| monkeypatch.setattr('site.USER_BASE', None) | |
| monkeypatch.setattr('site.USER_SITE', None) | |
| user_site = Path(site.getusersitepackages()) | |
| user_site.mkdir(parents=True, exist_ok=True) | |
| sys_prefix = tmp_path / '.sys_prefix' | |
| sys_prefix.mkdir(parents=True, exist_ok=True) | |
| monkeypatch.setattr('sys.prefix', str(sys_prefix)) | |
| setup_script = ( | |
| "__import__('setuptools').setup(name='aproj', version=42, packages=[])\n" | |
| ) | |
| (tmp_path / "setup.py").write_text(setup_script, encoding="utf-8") | |
| # == Sanity check == | |
| assert list(sys_prefix.glob("*")) == [] | |
| assert list(user_site.glob("*")) == [] | |
| # == Act == | |
| run_setup('setup.py', ['develop', '--user']) | |
| # == Assert == | |
| # Should not install to sys.prefix | |
| assert list(sys_prefix.glob("*")) == [] | |
| # Should install to user site | |
| installed = {f.name for f in user_site.glob("*")} | |
| # sometimes easy-install.pth is created and sometimes not | |
| installed = installed - {"easy-install.pth"} | |
| assert installed == {'aproj.egg-link'} | |