1"""Tests for distutils.command.install.""" 2 3import os 4import sys 5import unittest 6import site 7 8from test.support import captured_stdout, run_unittest 9 10from distutils import sysconfig 11from distutils.command.install import install, HAS_USER_SITE 12from distutils.command import install as install_module 13from distutils.command.build_ext import build_ext 14from distutils.command.install import INSTALL_SCHEMES 15from distutils.core import Distribution 16from distutils.errors import DistutilsOptionError 17from distutils.extension import Extension 18 19from distutils.tests import support 20from test import support as test_support 21 22 23def _make_ext_name(modname): 24 return modname + sysconfig.get_config_var('EXT_SUFFIX') 25 26 27class InstallTestCase(support.TempdirManager, 28 support.EnvironGuard, 29 support.LoggingSilencer, 30 unittest.TestCase): 31 32 def setUp(self): 33 super().setUp() 34 self._backup_config_vars = dict(sysconfig._config_vars) 35 36 def tearDown(self): 37 super().tearDown() 38 sysconfig._config_vars.clear() 39 sysconfig._config_vars.update(self._backup_config_vars) 40 41 def test_home_installation_scheme(self): 42 # This ensure two things: 43 # - that --home generates the desired set of directory names 44 # - test --home is supported on all platforms 45 builddir = self.mkdtemp() 46 destination = os.path.join(builddir, "installation") 47 48 dist = Distribution({"name": "foopkg"}) 49 # script_name need not exist, it just need to be initialized 50 dist.script_name = os.path.join(builddir, "setup.py") 51 dist.command_obj["build"] = support.DummyCommand( 52 build_base=builddir, 53 build_lib=os.path.join(builddir, "lib"), 54 ) 55 56 cmd = install(dist) 57 cmd.home = destination 58 cmd.ensure_finalized() 59 60 self.assertEqual(cmd.install_base, destination) 61 self.assertEqual(cmd.install_platbase, destination) 62 63 def check_path(got, expected): 64 got = os.path.normpath(got) 65 expected = os.path.normpath(expected) 66 self.assertEqual(got, expected) 67 68 libdir = os.path.join(destination, "lib", "python") 69 check_path(cmd.install_lib, libdir) 70 platlibdir = os.path.join(destination, sys.platlibdir, "python") 71 check_path(cmd.install_platlib, platlibdir) 72 check_path(cmd.install_purelib, libdir) 73 check_path(cmd.install_headers, 74 os.path.join(destination, "include", "python", "foopkg")) 75 check_path(cmd.install_scripts, os.path.join(destination, "bin")) 76 check_path(cmd.install_data, destination) 77 78 @unittest.skipUnless(HAS_USER_SITE, 'need user site') 79 def test_user_site(self): 80 # test install with --user 81 # preparing the environment for the test 82 self.old_user_base = site.USER_BASE 83 self.old_user_site = site.USER_SITE 84 self.tmpdir = self.mkdtemp() 85 self.user_base = os.path.join(self.tmpdir, 'B') 86 self.user_site = os.path.join(self.tmpdir, 'S') 87 site.USER_BASE = self.user_base 88 site.USER_SITE = self.user_site 89 install_module.USER_BASE = self.user_base 90 install_module.USER_SITE = self.user_site 91 92 def _expanduser(path): 93 return self.tmpdir 94 self.old_expand = os.path.expanduser 95 os.path.expanduser = _expanduser 96 97 def cleanup(): 98 site.USER_BASE = self.old_user_base 99 site.USER_SITE = self.old_user_site 100 install_module.USER_BASE = self.old_user_base 101 install_module.USER_SITE = self.old_user_site 102 os.path.expanduser = self.old_expand 103 104 self.addCleanup(cleanup) 105 106 if HAS_USER_SITE: 107 for key in ('nt_user', 'unix_user'): 108 self.assertIn(key, INSTALL_SCHEMES) 109 110 dist = Distribution({'name': 'xx'}) 111 cmd = install(dist) 112 113 # making sure the user option is there 114 options = [name for name, short, lable in 115 cmd.user_options] 116 self.assertIn('user', options) 117 118 # setting a value 119 cmd.user = 1 120 121 # user base and site shouldn't be created yet 122 self.assertFalse(os.path.exists(self.user_base)) 123 self.assertFalse(os.path.exists(self.user_site)) 124 125 # let's run finalize 126 cmd.ensure_finalized() 127 128 # now they should 129 self.assertTrue(os.path.exists(self.user_base)) 130 self.assertTrue(os.path.exists(self.user_site)) 131 132 self.assertIn('userbase', cmd.config_vars) 133 self.assertIn('usersite', cmd.config_vars) 134 135 def test_handle_extra_path(self): 136 dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'}) 137 cmd = install(dist) 138 139 # two elements 140 cmd.handle_extra_path() 141 self.assertEqual(cmd.extra_path, ['path', 'dirs']) 142 self.assertEqual(cmd.extra_dirs, 'dirs') 143 self.assertEqual(cmd.path_file, 'path') 144 145 # one element 146 cmd.extra_path = ['path'] 147 cmd.handle_extra_path() 148 self.assertEqual(cmd.extra_path, ['path']) 149 self.assertEqual(cmd.extra_dirs, 'path') 150 self.assertEqual(cmd.path_file, 'path') 151 152 # none 153 dist.extra_path = cmd.extra_path = None 154 cmd.handle_extra_path() 155 self.assertEqual(cmd.extra_path, None) 156 self.assertEqual(cmd.extra_dirs, '') 157 self.assertEqual(cmd.path_file, None) 158 159 # three elements (no way !) 160 cmd.extra_path = 'path,dirs,again' 161 self.assertRaises(DistutilsOptionError, cmd.handle_extra_path) 162 163 def test_finalize_options(self): 164 dist = Distribution({'name': 'xx'}) 165 cmd = install(dist) 166 167 # must supply either prefix/exec-prefix/home or 168 # install-base/install-platbase -- not both 169 cmd.prefix = 'prefix' 170 cmd.install_base = 'base' 171 self.assertRaises(DistutilsOptionError, cmd.finalize_options) 172 173 # must supply either home or prefix/exec-prefix -- not both 174 cmd.install_base = None 175 cmd.home = 'home' 176 self.assertRaises(DistutilsOptionError, cmd.finalize_options) 177 178 # can't combine user with prefix/exec_prefix/home or 179 # install_(plat)base 180 cmd.prefix = None 181 cmd.user = 'user' 182 self.assertRaises(DistutilsOptionError, cmd.finalize_options) 183 184 def test_record(self): 185 install_dir = self.mkdtemp() 186 project_dir, dist = self.create_dist(py_modules=['hello'], 187 scripts=['sayhi']) 188 os.chdir(project_dir) 189 self.write_file('hello.py', "def main(): print('o hai')") 190 self.write_file('sayhi', 'from hello import main; main()') 191 192 cmd = install(dist) 193 dist.command_obj['install'] = cmd 194 cmd.root = install_dir 195 cmd.record = os.path.join(project_dir, 'filelist') 196 cmd.ensure_finalized() 197 cmd.run() 198 199 f = open(cmd.record) 200 try: 201 content = f.read() 202 finally: 203 f.close() 204 205 found = [os.path.basename(line) for line in content.splitlines()] 206 expected = ['hello.py', 'hello.%s.pyc' % sys.implementation.cache_tag, 207 'sayhi', 208 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] 209 self.assertEqual(found, expected) 210 211 def test_record_extensions(self): 212 cmd = test_support.missing_compiler_executable() 213 if cmd is not None: 214 self.skipTest('The %r command is not found' % cmd) 215 install_dir = self.mkdtemp() 216 project_dir, dist = self.create_dist(ext_modules=[ 217 Extension('xx', ['xxmodule.c'])]) 218 os.chdir(project_dir) 219 support.copy_xxmodule_c(project_dir) 220 221 buildextcmd = build_ext(dist) 222 support.fixup_build_ext(buildextcmd) 223 buildextcmd.ensure_finalized() 224 225 cmd = install(dist) 226 dist.command_obj['install'] = cmd 227 dist.command_obj['build_ext'] = buildextcmd 228 cmd.root = install_dir 229 cmd.record = os.path.join(project_dir, 'filelist') 230 cmd.ensure_finalized() 231 cmd.run() 232 233 f = open(cmd.record) 234 try: 235 content = f.read() 236 finally: 237 f.close() 238 239 found = [os.path.basename(line) for line in content.splitlines()] 240 expected = [_make_ext_name('xx'), 241 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] 242 self.assertEqual(found, expected) 243 244 def test_debug_mode(self): 245 # this covers the code called when DEBUG is set 246 old_logs_len = len(self.logs) 247 install_module.DEBUG = True 248 try: 249 with captured_stdout(): 250 self.test_record() 251 finally: 252 install_module.DEBUG = False 253 self.assertGreater(len(self.logs), old_logs_len) 254 255 256def test_suite(): 257 return unittest.makeSuite(InstallTestCase) 258 259if __name__ == "__main__": 260 run_unittest(test_suite()) 261