Aluode/PerceptionLabPortable
0
1"""Tests for distutils.command.install."""2 3import logging4import os5import pathlib6import site7import sys8from distutils import sysconfig9from distutils.command import install as install_module10from distutils.command.build_ext import build_ext11from distutils.command.install import INSTALL_SCHEMES, install12from distutils.core import Distribution13from distutils.errors import DistutilsOptionError14from distutils.extension import Extension15from distutils.tests import missing_compiler_executable, support16from distutils.util import is_mingw17 18import pytest19 20 21def _make_ext_name(modname):22 return modname + sysconfig.get_config_var('EXT_SUFFIX')23 24 25@support.combine_markers26@pytest.mark.usefixtures('save_env')27class TestInstall(28 support.TempdirManager,29):30 @pytest.mark.xfail(31 'platform.system() == "Windows" and sys.version_info > (3, 11)',32 reason="pypa/distutils#148",33 )34 def test_home_installation_scheme(self):35 # This ensure two things:36 # - that --home generates the desired set of directory names37 # - test --home is supported on all platforms38 builddir = self.mkdtemp()39 destination = os.path.join(builddir, "installation")40 41 dist = Distribution({"name": "foopkg"})42 # script_name need not exist, it just need to be initialized43 dist.script_name = os.path.join(builddir, "setup.py")44 dist.command_obj["build"] = support.DummyCommand(45 build_base=builddir,46 build_lib=os.path.join(builddir, "lib"),47 )48 49 cmd = install(dist)50 cmd.home = destination51 cmd.ensure_finalized()52 53 assert cmd.install_base == destination54 assert cmd.install_platbase == destination55 56 def check_path(got, expected):57 got = os.path.normpath(got)58 expected = os.path.normpath(expected)59 assert got == expected60 61 impl_name = sys.implementation.name.replace("cpython", "python")62 libdir = os.path.join(destination, "lib", impl_name)63 check_path(cmd.install_lib, libdir)64 _platlibdir = getattr(sys, "platlibdir", "lib")65 platlibdir = os.path.join(destination, _platlibdir, impl_name)66 check_path(cmd.install_platlib, platlibdir)67 check_path(cmd.install_purelib, libdir)68 check_path(69 cmd.install_headers,70 os.path.join(destination, "include", impl_name, "foopkg"),71 )72 check_path(cmd.install_scripts, os.path.join(destination, "bin"))73 check_path(cmd.install_data, destination)74 75 def test_user_site(self, monkeypatch):76 # test install with --user77 # preparing the environment for the test78 self.tmpdir = self.mkdtemp()79 orig_site = site.USER_SITE80 orig_base = site.USER_BASE81 monkeypatch.setattr(site, 'USER_BASE', os.path.join(self.tmpdir, 'B'))82 monkeypatch.setattr(site, 'USER_SITE', os.path.join(self.tmpdir, 'S'))83 monkeypatch.setattr(install_module, 'USER_BASE', site.USER_BASE)84 monkeypatch.setattr(install_module, 'USER_SITE', site.USER_SITE)85 86 def _expanduser(path):87 if path.startswith('~'):88 return os.path.normpath(self.tmpdir + path[1:])89 return path90 91 monkeypatch.setattr(os.path, 'expanduser', _expanduser)92 93 for key in ('nt_user', 'posix_user'):94 assert key in INSTALL_SCHEMES95 96 dist = Distribution({'name': 'xx'})97 cmd = install(dist)98 99 # making sure the user option is there100 options = [name for name, short, label in cmd.user_options]101 assert 'user' in options102 103 # setting a value104 cmd.user = True105 106 # user base and site shouldn't be created yet107 assert not os.path.exists(site.USER_BASE)108 assert not os.path.exists(site.USER_SITE)109 110 # let's run finalize111 cmd.ensure_finalized()112 113 # now they should114 assert os.path.exists(site.USER_BASE)115 assert os.path.exists(site.USER_SITE)116 117 assert 'userbase' in cmd.config_vars118 assert 'usersite' in cmd.config_vars119 120 actual_headers = os.path.relpath(cmd.install_headers, site.USER_BASE)121 if os.name == 'nt' and not is_mingw():122 site_path = os.path.relpath(os.path.dirname(orig_site), orig_base)123 include = os.path.join(site_path, 'Include')124 else:125 include = sysconfig.get_python_inc(0, '')126 expect_headers = os.path.join(include, 'xx')127 128 assert os.path.normcase(actual_headers) == os.path.normcase(expect_headers)129 130 def test_handle_extra_path(self):131 dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'})132 cmd = install(dist)133 134 # two elements135 cmd.handle_extra_path()136 assert cmd.extra_path == ['path', 'dirs']137 assert cmd.extra_dirs == 'dirs'138 assert cmd.path_file == 'path'139 140 # one element141 cmd.extra_path = ['path']142 cmd.handle_extra_path()143 assert cmd.extra_path == ['path']144 assert cmd.extra_dirs == 'path'145 assert cmd.path_file == 'path'146 147 # none148 dist.extra_path = cmd.extra_path = None149 cmd.handle_extra_path()150 assert cmd.extra_path is None151 assert cmd.extra_dirs == ''152 assert cmd.path_file is None153 154 # three elements (no way !)155 cmd.extra_path = 'path,dirs,again'156 with pytest.raises(DistutilsOptionError):157 cmd.handle_extra_path()158 159 def test_finalize_options(self):160 dist = Distribution({'name': 'xx'})161 cmd = install(dist)162 163 # must supply either prefix/exec-prefix/home or164 # install-base/install-platbase -- not both165 cmd.prefix = 'prefix'166 cmd.install_base = 'base'167 with pytest.raises(DistutilsOptionError):168 cmd.finalize_options()169 170 # must supply either home or prefix/exec-prefix -- not both171 cmd.install_base = None172 cmd.home = 'home'173 with pytest.raises(DistutilsOptionError):174 cmd.finalize_options()175 176 # can't combine user with prefix/exec_prefix/home or177 # install_(plat)base178 cmd.prefix = None179 cmd.user = 'user'180 with pytest.raises(DistutilsOptionError):181 cmd.finalize_options()182 183 def test_record(self):184 install_dir = self.mkdtemp()185 project_dir, dist = self.create_dist(py_modules=['hello'], scripts=['sayhi'])186 os.chdir(project_dir)187 self.write_file('hello.py', "def main(): print('o hai')")188 self.write_file('sayhi', 'from hello import main; main()')189 190 cmd = install(dist)191 dist.command_obj['install'] = cmd192 cmd.root = install_dir193 cmd.record = os.path.join(project_dir, 'filelist')194 cmd.ensure_finalized()195 cmd.run()196 197 content = pathlib.Path(cmd.record).read_text(encoding='utf-8')198 199 found = [pathlib.Path(line).name for line in content.splitlines()]200 expected = [201 'hello.py',202 f'hello.{sys.implementation.cache_tag}.pyc',203 'sayhi',204 'UNKNOWN-0.0.0-py{}.{}.egg-info'.format(*sys.version_info[:2]),205 ]206 assert found == expected207 208 def test_record_extensions(self):209 cmd = missing_compiler_executable()210 if cmd is not None:211 pytest.skip(f'The {cmd!r} command is not found')212 install_dir = self.mkdtemp()213 project_dir, dist = self.create_dist(214 ext_modules=[Extension('xx', ['xxmodule.c'])]215 )216 os.chdir(project_dir)217 support.copy_xxmodule_c(project_dir)218 219 buildextcmd = build_ext(dist)220 support.fixup_build_ext(buildextcmd)221 buildextcmd.ensure_finalized()222 223 cmd = install(dist)224 dist.command_obj['install'] = cmd225 dist.command_obj['build_ext'] = buildextcmd226 cmd.root = install_dir227 cmd.record = os.path.join(project_dir, 'filelist')228 cmd.ensure_finalized()229 cmd.run()230 231 content = pathlib.Path(cmd.record).read_text(encoding='utf-8')232 233 found = [pathlib.Path(line).name for line in content.splitlines()]234 expected = [235 _make_ext_name('xx'),236 'UNKNOWN-0.0.0-py{}.{}.egg-info'.format(*sys.version_info[:2]),237 ]238 assert found == expected239 240 def test_debug_mode(self, caplog, monkeypatch):241 # this covers the code called when DEBUG is set242 monkeypatch.setattr(install_module, 'DEBUG', True)243 caplog.set_level(logging.DEBUG)244 self.test_record()245 assert any(rec for rec in caplog.records if rec.levelno == logging.DEBUG)246 