codekingpro/portable-devtools
114k
1"""Tests for the 'setuptools' package"""2 3import os4import re5import sys6from zipfile import ZipFile7 8import pytest9from packaging.version import Version10 11import setuptools12import setuptools.depends as dep13import setuptools.dist14from setuptools.depends import Require15 16import distutils.cmd17import distutils.core18from distutils.core import Extension19from distutils.errors import DistutilsSetupError20 21 22@pytest.fixture(autouse=True)23def isolated_dir(tmpdir_cwd):24 return25 26 27def makeSetup(**args):28 """Return distribution from 'setup(**args)', without executing commands"""29 30 distutils.core._setup_stop_after = "commandline"31 32 # Don't let system command line leak into tests!33 args.setdefault('script_args', ['install'])34 35 try:36 return setuptools.setup(**args)37 finally:38 distutils.core._setup_stop_after = None39 40 41needs_bytecode = pytest.mark.skipif(42 not hasattr(dep, 'get_module_constant'),43 reason="bytecode support not available",44)45 46 47class TestDepends:48 def testExtractConst(self):49 if not hasattr(dep, 'extract_constant'):50 # skip on non-bytecode platforms51 return52 53 def f1():54 global x, y, z55 x = "test"56 y = z # pyright: ignore[reportUnboundVariable] # Explicitly testing for this runtime issue57 58 fc = f1.__code__59 60 # unrecognized name61 assert dep.extract_constant(fc, 'q', -1) is None62 63 # constant assigned64 assert dep.extract_constant(fc, 'x', -1) == "test"65 66 # expression assigned67 assert dep.extract_constant(fc, 'y', -1) == -168 69 # recognized name, not assigned70 assert dep.extract_constant(fc, 'z', -1) is None71 72 def testFindModule(self):73 with pytest.raises(ImportError):74 dep.find_module('no-such.-thing')75 with pytest.raises(ImportError):76 dep.find_module('setuptools.non-existent')77 f, _p, _i = dep.find_module('setuptools.tests')78 f.close()79 80 @pytest.fixture81 def sample_module(self, monkeypatch, tmp_path):82 monkeypatch.syspath_prepend(str(tmp_path))83 module = "mod_with_version"84 version = "2.0.9"85 file = tmp_path / f"{module}.py"86 file.write_text(f"__version__ = {version!r}", encoding="utf-8")87 return (module, version)88 89 @needs_bytecode90 def testModuleExtract(self, sample_module):91 (module, version) = sample_module92 assert dep.get_module_constant(module, '__version__') == version93 assert dep.get_module_constant('sys', 'version') == sys.version94 assert dep.get_module_constant(__name__, '__doc__') == __doc__95 96 @needs_bytecode97 def testRequire(self, sample_module):98 (module, version) = sample_module99 req = Require('GivenName', '1.0.3', module)100 101 assert req.name == 'GivenName'102 assert req.module == module103 assert req.requested_version == Version('1.0.3')104 assert req.attribute == '__version__'105 assert req.full_name() == 'GivenName-1.0.3'106 107 assert str(req.get_version()) == version108 assert req.version_ok('1.0.9')109 assert not req.version_ok('0.9.1')110 assert not req.version_ok('unknown')111 112 assert req.is_present()113 assert req.is_current()114 115 req = Require('Do-what-I-mean', '1.0', 'd-w-i-m')116 assert not req.is_present()117 assert not req.is_current()118 119 @needs_bytecode120 def test_require_present(self):121 # In #1896, this test was failing for months with the only122 # complaint coming from test runners (not end users).123 # TODO: Evaluate if this code is needed at all.124 req = Require('Tests', None, 'tests', homepage="http://example.com")125 assert req.format is None126 assert req.attribute is None127 assert req.requested_version is None128 assert req.full_name() == 'Tests'129 assert req.homepage == 'http://example.com'130 131 from setuptools.tests import __path__132 133 paths = [os.path.dirname(p) for p in __path__]134 assert req.is_present(paths)135 assert req.is_current(paths)136 137 138class TestDistro:139 def setup_method(self, method):140 self.e1 = Extension('bar.ext', ['bar.c'])141 self.e2 = Extension('c.y', ['y.c'])142 143 self.dist = makeSetup(144 packages=['a', 'a.b', 'a.b.c', 'b', 'c'],145 py_modules=['b.d', 'x'],146 ext_modules=(self.e1, self.e2),147 package_dir={},148 )149 150 def testDistroType(self):151 assert isinstance(self.dist, setuptools.dist.Distribution)152 153 def testExcludePackage(self):154 self.dist.exclude_package('a')155 assert self.dist.packages == ['b', 'c']156 157 self.dist.exclude_package('b')158 assert self.dist.packages == ['c']159 assert self.dist.py_modules == ['x']160 assert self.dist.ext_modules == [self.e1, self.e2]161 162 self.dist.exclude_package('c')163 assert self.dist.packages == []164 assert self.dist.py_modules == ['x']165 assert self.dist.ext_modules == [self.e1]166 167 # test removals from unspecified options168 makeSetup().exclude_package('x')169 170 def testIncludeExclude(self):171 # remove an extension172 self.dist.exclude(ext_modules=[self.e1])173 assert self.dist.ext_modules == [self.e2]174 175 # add it back in176 self.dist.include(ext_modules=[self.e1])177 assert self.dist.ext_modules == [self.e2, self.e1]178 179 # should not add duplicate180 self.dist.include(ext_modules=[self.e1])181 assert self.dist.ext_modules == [self.e2, self.e1]182 183 def testExcludePackages(self):184 self.dist.exclude(packages=['c', 'b', 'a'])185 assert self.dist.packages == []186 assert self.dist.py_modules == ['x']187 assert self.dist.ext_modules == [self.e1]188 189 def testEmpty(self):190 dist = makeSetup()191 dist.include(packages=['a'], py_modules=['b'], ext_modules=[self.e2])192 dist = makeSetup()193 dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2])194 195 def testContents(self):196 assert self.dist.has_contents_for('a')197 self.dist.exclude_package('a')198 assert not self.dist.has_contents_for('a')199 200 assert self.dist.has_contents_for('b')201 self.dist.exclude_package('b')202 assert not self.dist.has_contents_for('b')203 204 assert self.dist.has_contents_for('c')205 self.dist.exclude_package('c')206 assert not self.dist.has_contents_for('c')207 208 def testInvalidIncludeExclude(self):209 with pytest.raises(DistutilsSetupError):210 self.dist.include(nonexistent_option='x')211 with pytest.raises(DistutilsSetupError):212 self.dist.exclude(nonexistent_option='x')213 with pytest.raises(DistutilsSetupError):214 self.dist.include(packages={'x': 'y'})215 with pytest.raises(DistutilsSetupError):216 self.dist.exclude(packages={'x': 'y'})217 with pytest.raises(DistutilsSetupError):218 self.dist.include(ext_modules={'x': 'y'})219 with pytest.raises(DistutilsSetupError):220 self.dist.exclude(ext_modules={'x': 'y'})221 222 with pytest.raises(DistutilsSetupError):223 self.dist.include(package_dir=['q'])224 with pytest.raises(DistutilsSetupError):225 self.dist.exclude(package_dir=['q'])226 227 228@pytest.fixture229def example_source(tmpdir):230 tmpdir.mkdir('foo')231 (tmpdir / 'foo/bar.py').write('')232 (tmpdir / 'readme.txt').write('')233 return tmpdir234 235 236def test_findall(example_source):237 found = list(setuptools.findall(str(example_source)))238 expected = ['readme.txt', 'foo/bar.py']239 expected = [example_source.join(fn) for fn in expected]240 assert found == expected241 242 243def test_findall_curdir(example_source):244 with example_source.as_cwd():245 found = list(setuptools.findall())246 expected = ['readme.txt', os.path.join('foo', 'bar.py')]247 assert found == expected248 249 250@pytest.fixture251def can_symlink(tmpdir):252 """253 Skip if cannot create a symbolic link254 """255 link_fn = 'link'256 target_fn = 'target'257 try:258 os.symlink(target_fn, link_fn)259 except (OSError, NotImplementedError, AttributeError):260 pytest.skip("Cannot create symbolic links")261 os.remove(link_fn)262 263 264@pytest.mark.usefixtures("can_symlink")265def test_findall_missing_symlink(tmpdir):266 with tmpdir.as_cwd():267 os.symlink('foo', 'bar')268 found = list(setuptools.findall())269 assert found == []270 271 272@pytest.mark.xfail(reason="unable to exclude tests; #4475 #3260")273def test_its_own_wheel_does_not_contain_tests(setuptools_wheel):274 with ZipFile(setuptools_wheel) as zipfile:275 contents = [f.replace(os.sep, '/') for f in zipfile.namelist()]276 277 for member in contents:278 assert '/tests/' not in member279 280 281def test_wheel_includes_cli_scripts(setuptools_wheel):282 with ZipFile(setuptools_wheel) as zipfile:283 contents = [f.replace(os.sep, '/') for f in zipfile.namelist()]284 285 assert any('cli-64.exe' in member for member in contents)286 287 288def test_wheel_includes_vendored_metadata(setuptools_wheel):289 with ZipFile(setuptools_wheel) as zipfile:290 contents = [f.replace(os.sep, '/') for f in zipfile.namelist()]291 292 assert any(293 re.search(r'_vendor/.*\.dist-info/METADATA', member) for member in contents294 )295 