Home | History | Annotate | Download | only in test
      1 """Tests for 'site'.
      2 
      3 Tests assume the initial paths in sys.path once the interpreter has begun
      4 executing have not been removed.
      5 
      6 """
      7 import unittest
      8 from test.test_support import run_unittest, TESTFN, EnvironmentVarGuard
      9 from test.test_support import captured_output
     10 import __builtin__
     11 import os
     12 import sys
     13 import re
     14 import encodings
     15 import subprocess
     16 import sysconfig
     17 from copy import copy
     18 
     19 # Need to make sure to not import 'site' if someone specified ``-S`` at the

     20 # command-line.  Detect this by just making sure 'site' has not been imported

     21 # already.

     22 if "site" in sys.modules:
     23     import site
     24 else:
     25     raise unittest.SkipTest("importation of site.py suppressed")
     26 
     27 if not os.path.isdir(site.USER_SITE):
     28     # need to add user site directory for tests

     29     os.makedirs(site.USER_SITE)
     30     site.addsitedir(site.USER_SITE)
     31 
     32 class HelperFunctionsTests(unittest.TestCase):
     33     """Tests for helper functions.
     34 
     35     The setting of the encoding (set using sys.setdefaultencoding) used by
     36     the Unicode implementation is not tested.
     37 
     38     """
     39 
     40     def setUp(self):
     41         """Save a copy of sys.path"""
     42         self.sys_path = sys.path[:]
     43         self.old_base = site.USER_BASE
     44         self.old_site = site.USER_SITE
     45         self.old_prefixes = site.PREFIXES
     46         self.old_vars = copy(sysconfig._CONFIG_VARS)
     47 
     48     def tearDown(self):
     49         """Restore sys.path"""
     50         sys.path[:] = self.sys_path
     51         site.USER_BASE = self.old_base
     52         site.USER_SITE = self.old_site
     53         site.PREFIXES = self.old_prefixes
     54         sysconfig._CONFIG_VARS = self.old_vars
     55 
     56     def test_makepath(self):
     57         # Test makepath() have an absolute path for its first return value

     58         # and a case-normalized version of the absolute path for its

     59         # second value.

     60         path_parts = ("Beginning", "End")
     61         original_dir = os.path.join(*path_parts)
     62         abs_dir, norm_dir = site.makepath(*path_parts)
     63         self.assertEqual(os.path.abspath(original_dir), abs_dir)
     64         if original_dir == os.path.normcase(original_dir):
     65             self.assertEqual(abs_dir, norm_dir)
     66         else:
     67             self.assertEqual(os.path.normcase(abs_dir), norm_dir)
     68 
     69     def test_init_pathinfo(self):
     70         dir_set = site._init_pathinfo()
     71         for entry in [site.makepath(path)[1] for path in sys.path
     72                         if path and os.path.isdir(path)]:
     73             self.assertIn(entry, dir_set,
     74                           "%s from sys.path not found in set returned "
     75                           "by _init_pathinfo(): %s" % (entry, dir_set))
     76 
     77     def pth_file_tests(self, pth_file):
     78         """Contain common code for testing results of reading a .pth file"""
     79         self.assertIn(pth_file.imported, sys.modules,
     80                       "%s not in sys.modules" % pth_file.imported)
     81         self.assertIn(site.makepath(pth_file.good_dir_path)[0], sys.path)
     82         self.assertFalse(os.path.exists(pth_file.bad_dir_path))
     83 
     84     def test_addpackage(self):
     85         # Make sure addpackage() imports if the line starts with 'import',

     86         # adds directories to sys.path for any line in the file that is not a

     87         # comment or import that is a valid directory name for where the .pth

     88         # file resides; invalid directories are not added

     89         pth_file = PthFile()
     90         pth_file.cleanup(prep=True)  # to make sure that nothing is

     91                                       # pre-existing that shouldn't be

     92         try:
     93             pth_file.create()
     94             site.addpackage(pth_file.base_dir, pth_file.filename, set())
     95             self.pth_file_tests(pth_file)
     96         finally:
     97             pth_file.cleanup()
     98 
     99     def make_pth(self, contents, pth_dir='.', pth_name=TESTFN):
    100         # Create a .pth file and return its (abspath, basename).

    101         pth_dir = os.path.abspath(pth_dir)
    102         pth_basename = pth_name + '.pth'
    103         pth_fn = os.path.join(pth_dir, pth_basename)
    104         pth_file = open(pth_fn, 'w')
    105         self.addCleanup(lambda: os.remove(pth_fn))
    106         pth_file.write(contents)
    107         pth_file.close()
    108         return pth_dir, pth_basename
    109 
    110     def test_addpackage_import_bad_syntax(self):
    111         # Issue 10642

    112         pth_dir, pth_fn = self.make_pth("import bad)syntax\n")
    113         with captured_output("stderr") as err_out:
    114             site.addpackage(pth_dir, pth_fn, set())
    115         self.assertRegexpMatches(err_out.getvalue(), "line 1")
    116         self.assertRegexpMatches(err_out.getvalue(),
    117             re.escape(os.path.join(pth_dir, pth_fn)))
    118         # XXX: the previous two should be independent checks so that the

    119         # order doesn't matter.  The next three could be a single check

    120         # but my regex foo isn't good enough to write it.

    121         self.assertRegexpMatches(err_out.getvalue(), 'Traceback')
    122         self.assertRegexpMatches(err_out.getvalue(), r'import bad\)syntax')
    123         self.assertRegexpMatches(err_out.getvalue(), 'SyntaxError')
    124 
    125     def test_addpackage_import_bad_exec(self):
    126         # Issue 10642

    127         pth_dir, pth_fn = self.make_pth("randompath\nimport nosuchmodule\n")
    128         with captured_output("stderr") as err_out:
    129             site.addpackage(pth_dir, pth_fn, set())
    130         self.assertRegexpMatches(err_out.getvalue(), "line 2")
    131         self.assertRegexpMatches(err_out.getvalue(),
    132             re.escape(os.path.join(pth_dir, pth_fn)))
    133         # XXX: ditto previous XXX comment.

    134         self.assertRegexpMatches(err_out.getvalue(), 'Traceback')
    135         self.assertRegexpMatches(err_out.getvalue(), 'ImportError')
    136 
    137     @unittest.skipIf(sys.platform == "win32", "Windows does not raise an "
    138                       "error for file paths containing null characters")
    139     def test_addpackage_import_bad_pth_file(self):
    140         # Issue 5258

    141         pth_dir, pth_fn = self.make_pth("abc\x00def\n")
    142         with captured_output("stderr") as err_out:
    143             site.addpackage(pth_dir, pth_fn, set())
    144         self.assertRegexpMatches(err_out.getvalue(), "line 1")
    145         self.assertRegexpMatches(err_out.getvalue(),
    146             re.escape(os.path.join(pth_dir, pth_fn)))
    147         # XXX: ditto previous XXX comment.

    148         self.assertRegexpMatches(err_out.getvalue(), 'Traceback')
    149         self.assertRegexpMatches(err_out.getvalue(), 'TypeError')
    150 
    151     def test_addsitedir(self):
    152         # Same tests for test_addpackage since addsitedir() essentially just

    153         # calls addpackage() for every .pth file in the directory

    154         pth_file = PthFile()
    155         pth_file.cleanup(prep=True) # Make sure that nothing is pre-existing

    156                                     # that is tested for

    157         try:
    158             pth_file.create()
    159             site.addsitedir(pth_file.base_dir, set())
    160             self.pth_file_tests(pth_file)
    161         finally:
    162             pth_file.cleanup()
    163 
    164     def test_s_option(self):
    165         usersite = site.USER_SITE
    166         self.assertIn(usersite, sys.path)
    167 
    168         env = os.environ.copy()
    169         rc = subprocess.call([sys.executable, '-c',
    170             'import sys; sys.exit(%r in sys.path)' % usersite],
    171             env=env)
    172         self.assertEqual(rc, 1, "%r is not in sys.path (sys.exit returned %r)"
    173                 % (usersite, rc))
    174 
    175         env = os.environ.copy()
    176         rc = subprocess.call([sys.executable, '-s', '-c',
    177             'import sys; sys.exit(%r in sys.path)' % usersite],
    178             env=env)
    179         self.assertEqual(rc, 0)
    180 
    181         env = os.environ.copy()
    182         env["PYTHONNOUSERSITE"] = "1"
    183         rc = subprocess.call([sys.executable, '-c',
    184             'import sys; sys.exit(%r in sys.path)' % usersite],
    185             env=env)
    186         self.assertEqual(rc, 0)
    187 
    188         env = os.environ.copy()
    189         env["PYTHONUSERBASE"] = "/tmp"
    190         rc = subprocess.call([sys.executable, '-c',
    191             'import sys, site; sys.exit(site.USER_BASE.startswith("/tmp"))'],
    192             env=env)
    193         self.assertEqual(rc, 1)
    194 
    195     def test_getuserbase(self):
    196         site.USER_BASE = None
    197         user_base = site.getuserbase()
    198 
    199         # the call sets site.USER_BASE

    200         self.assertEqual(site.USER_BASE, user_base)
    201 
    202         # let's set PYTHONUSERBASE and see if it uses it

    203         site.USER_BASE = None
    204         import sysconfig
    205         sysconfig._CONFIG_VARS = None
    206 
    207         with EnvironmentVarGuard() as environ:
    208             environ['PYTHONUSERBASE'] = 'xoxo'
    209             self.assertTrue(site.getuserbase().startswith('xoxo'),
    210                             site.getuserbase())
    211 
    212     def test_getusersitepackages(self):
    213         site.USER_SITE = None
    214         site.USER_BASE = None
    215         user_site = site.getusersitepackages()
    216 
    217         # the call sets USER_BASE *and* USER_SITE

    218         self.assertEqual(site.USER_SITE, user_site)
    219         self.assertTrue(user_site.startswith(site.USER_BASE), user_site)
    220 
    221     def test_getsitepackages(self):
    222         site.PREFIXES = ['xoxo']
    223         dirs = site.getsitepackages()
    224 
    225         if sys.platform in ('os2emx', 'riscos'):
    226             self.assertEqual(len(dirs), 1)
    227             wanted = os.path.join('xoxo', 'Lib', 'site-packages')
    228             self.assertEqual(dirs[0], wanted)
    229         elif os.sep == '/':
    230             self.assertEqual(len(dirs), 2)
    231             wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3],
    232                                   'site-packages')
    233             self.assertEqual(dirs[0], wanted)
    234             wanted = os.path.join('xoxo', 'lib', 'site-python')
    235             self.assertEqual(dirs[1], wanted)
    236         else:
    237             self.assertEqual(len(dirs), 2)
    238             self.assertEqual(dirs[0], 'xoxo')
    239             wanted = os.path.join('xoxo', 'lib', 'site-packages')
    240             self.assertEqual(dirs[1], wanted)
    241 
    242         # let's try the specific Apple location

    243         if (sys.platform == "darwin" and
    244             sysconfig.get_config_var("PYTHONFRAMEWORK")):
    245             site.PREFIXES = ['Python.framework']
    246             dirs = site.getsitepackages()
    247             self.assertEqual(len(dirs), 4)
    248             wanted = os.path.join('~', 'Library', 'Python',
    249                                   sys.version[:3], 'site-packages')
    250             self.assertEqual(dirs[2], os.path.expanduser(wanted))
    251             wanted = os.path.join('/Library', 'Python', sys.version[:3],
    252                                   'site-packages')
    253             self.assertEqual(dirs[3], wanted)
    254 
    255 class PthFile(object):
    256     """Helper class for handling testing of .pth files"""
    257 
    258     def __init__(self, filename_base=TESTFN, imported="time",
    259                     good_dirname="__testdir__", bad_dirname="__bad"):
    260         """Initialize instance variables"""
    261         self.filename = filename_base + ".pth"
    262         self.base_dir = os.path.abspath('')
    263         self.file_path = os.path.join(self.base_dir, self.filename)
    264         self.imported = imported
    265         self.good_dirname = good_dirname
    266         self.bad_dirname = bad_dirname
    267         self.good_dir_path = os.path.join(self.base_dir, self.good_dirname)
    268         self.bad_dir_path = os.path.join(self.base_dir, self.bad_dirname)
    269 
    270     def create(self):
    271         """Create a .pth file with a comment, blank lines, an ``import
    272         <self.imported>``, a line with self.good_dirname, and a line with
    273         self.bad_dirname.
    274 
    275         Creation of the directory for self.good_dir_path (based off of
    276         self.good_dirname) is also performed.
    277 
    278         Make sure to call self.cleanup() to undo anything done by this method.
    279 
    280         """
    281         FILE = open(self.file_path, 'w')
    282         try:
    283             print>>FILE, "#import @bad module name"
    284             print>>FILE, "\n"
    285             print>>FILE, "import %s" % self.imported
    286             print>>FILE, self.good_dirname
    287             print>>FILE, self.bad_dirname
    288         finally:
    289             FILE.close()
    290         os.mkdir(self.good_dir_path)
    291 
    292     def cleanup(self, prep=False):
    293         """Make sure that the .pth file is deleted, self.imported is not in
    294         sys.modules, and that both self.good_dirname and self.bad_dirname are
    295         not existing directories."""
    296         if os.path.exists(self.file_path):
    297             os.remove(self.file_path)
    298         if prep:
    299             self.imported_module = sys.modules.get(self.imported)
    300             if self.imported_module:
    301                 del sys.modules[self.imported]
    302         else:
    303             if self.imported_module:
    304                 sys.modules[self.imported] = self.imported_module
    305         if os.path.exists(self.good_dir_path):
    306             os.rmdir(self.good_dir_path)
    307         if os.path.exists(self.bad_dir_path):
    308             os.rmdir(self.bad_dir_path)
    309 
    310 class ImportSideEffectTests(unittest.TestCase):
    311     """Test side-effects from importing 'site'."""
    312 
    313     def setUp(self):
    314         """Make a copy of sys.path"""
    315         self.sys_path = sys.path[:]
    316 
    317     def tearDown(self):
    318         """Restore sys.path"""
    319         sys.path[:] = self.sys_path
    320 
    321     def test_abs__file__(self):
    322         # Make sure all imported modules have their __file__ attribute

    323         # as an absolute path.

    324         # Handled by abs__file__()

    325         site.abs__file__()
    326         for module in (sys, os, __builtin__):
    327             try:
    328                 self.assertTrue(os.path.isabs(module.__file__), repr(module))
    329             except AttributeError:
    330                 continue
    331         # We could try everything in sys.modules; however, when regrtest.py

    332         # runs something like test_frozen before test_site, then we will

    333         # be testing things loaded *after* test_site did path normalization

    334 
    335     def test_no_duplicate_paths(self):
    336         # No duplicate paths should exist in sys.path

    337         # Handled by removeduppaths()

    338         site.removeduppaths()
    339         seen_paths = set()
    340         for path in sys.path:
    341             self.assertNotIn(path, seen_paths)
    342             seen_paths.add(path)
    343 
    344     def test_add_build_dir(self):
    345         # Test that the build directory's Modules directory is used when it

    346         # should be.

    347         # XXX: implement

    348         pass
    349 
    350     def test_setting_quit(self):
    351         # 'quit' and 'exit' should be injected into __builtin__

    352         self.assertTrue(hasattr(__builtin__, "quit"))
    353         self.assertTrue(hasattr(__builtin__, "exit"))
    354 
    355     def test_setting_copyright(self):
    356         # 'copyright' and 'credits' should be in __builtin__

    357         self.assertTrue(hasattr(__builtin__, "copyright"))
    358         self.assertTrue(hasattr(__builtin__, "credits"))
    359 
    360     def test_setting_help(self):
    361         # 'help' should be set in __builtin__

    362         self.assertTrue(hasattr(__builtin__, "help"))
    363 
    364     def test_aliasing_mbcs(self):
    365         if sys.platform == "win32":
    366             import locale
    367             if locale.getdefaultlocale()[1].startswith('cp'):
    368                 for value in encodings.aliases.aliases.itervalues():
    369                     if value == "mbcs":
    370                         break
    371                 else:
    372                     self.fail("did not alias mbcs")
    373 
    374     def test_setdefaultencoding_removed(self):
    375         # Make sure sys.setdefaultencoding is gone

    376         self.assertTrue(not hasattr(sys, "setdefaultencoding"))
    377 
    378     def test_sitecustomize_executed(self):
    379         # If sitecustomize is available, it should have been imported.

    380         if "sitecustomize" not in sys.modules:
    381             try:
    382                 import sitecustomize
    383             except ImportError:
    384                 pass
    385             else:
    386                 self.fail("sitecustomize not imported automatically")
    387 
    388 def test_main():
    389     run_unittest(HelperFunctionsTests, ImportSideEffectTests)
    390 
    391 if __name__ == "__main__":
    392     test_main()
    393