test_install.py 8.8 KB

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