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