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 site.ENABLE_USER_SITE and 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 | @unittest.skipUnless(site.ENABLE_USER_SITE, "requires access to PEP 370 "
|
---|
165 | "user-site (site.ENABLE_USER_SITE)")
|
---|
166 | def test_s_option(self):
|
---|
167 | usersite = site.USER_SITE
|
---|
168 | self.assertIn(usersite, sys.path)
|
---|
169 |
|
---|
170 | env = os.environ.copy()
|
---|
171 | rc = subprocess.call([sys.executable, '-c',
|
---|
172 | 'import sys; sys.exit(%r in sys.path)' % usersite],
|
---|
173 | env=env)
|
---|
174 | self.assertEqual(rc, 1, "%r is not in sys.path (sys.exit returned %r)"
|
---|
175 | % (usersite, rc))
|
---|
176 |
|
---|
177 | env = os.environ.copy()
|
---|
178 | rc = subprocess.call([sys.executable, '-s', '-c',
|
---|
179 | 'import sys; sys.exit(%r in sys.path)' % usersite],
|
---|
180 | env=env)
|
---|
181 | self.assertEqual(rc, 0)
|
---|
182 |
|
---|
183 | env = os.environ.copy()
|
---|
184 | env["PYTHONNOUSERSITE"] = "1"
|
---|
185 | rc = subprocess.call([sys.executable, '-c',
|
---|
186 | 'import sys; sys.exit(%r in sys.path)' % usersite],
|
---|
187 | env=env)
|
---|
188 | self.assertEqual(rc, 0)
|
---|
189 |
|
---|
190 | env = os.environ.copy()
|
---|
191 | env["PYTHONUSERBASE"] = "/tmp"
|
---|
192 | rc = subprocess.call([sys.executable, '-c',
|
---|
193 | 'import sys, site; sys.exit(site.USER_BASE.startswith("/tmp"))'],
|
---|
194 | env=env)
|
---|
195 | self.assertEqual(rc, 1)
|
---|
196 |
|
---|
197 | def test_getuserbase(self):
|
---|
198 | site.USER_BASE = None
|
---|
199 | user_base = site.getuserbase()
|
---|
200 |
|
---|
201 | # the call sets site.USER_BASE
|
---|
202 | self.assertEqual(site.USER_BASE, user_base)
|
---|
203 |
|
---|
204 | # let's set PYTHONUSERBASE and see if it uses it
|
---|
205 | site.USER_BASE = None
|
---|
206 | import sysconfig
|
---|
207 | sysconfig._CONFIG_VARS = None
|
---|
208 |
|
---|
209 | with EnvironmentVarGuard() as environ:
|
---|
210 | environ['PYTHONUSERBASE'] = 'xoxo'
|
---|
211 | self.assertTrue(site.getuserbase().startswith('xoxo'),
|
---|
212 | site.getuserbase())
|
---|
213 |
|
---|
214 | def test_getusersitepackages(self):
|
---|
215 | site.USER_SITE = None
|
---|
216 | site.USER_BASE = None
|
---|
217 | user_site = site.getusersitepackages()
|
---|
218 |
|
---|
219 | # the call sets USER_BASE *and* USER_SITE
|
---|
220 | self.assertEqual(site.USER_SITE, user_site)
|
---|
221 | self.assertTrue(user_site.startswith(site.USER_BASE), user_site)
|
---|
222 |
|
---|
223 | def test_getsitepackages(self):
|
---|
224 | site.PREFIXES = ['xoxo']
|
---|
225 | dirs = site.getsitepackages()
|
---|
226 |
|
---|
227 | if sys.platform in ('os2emx', 'riscos'):
|
---|
228 | self.assertEqual(len(dirs), 1)
|
---|
229 | wanted = os.path.join('xoxo', 'Lib', 'site-packages')
|
---|
230 | self.assertEqual(dirs[0], wanted)
|
---|
231 | elif (sys.platform == "darwin" and
|
---|
232 | sysconfig.get_config_var("PYTHONFRAMEWORK")):
|
---|
233 | # OS X framework builds
|
---|
234 | site.PREFIXES = ['Python.framework']
|
---|
235 | dirs = site.getsitepackages()
|
---|
236 | self.assertEqual(len(dirs), 3)
|
---|
237 | wanted = os.path.join('/Library',
|
---|
238 | sysconfig.get_config_var("PYTHONFRAMEWORK"),
|
---|
239 | sys.version[:3],
|
---|
240 | 'site-packages')
|
---|
241 | self.assertEqual(dirs[2], wanted)
|
---|
242 | elif os.sep == '/':
|
---|
243 | # OS X non-framwework builds, Linux, FreeBSD, etc
|
---|
244 | self.assertEqual(len(dirs), 2)
|
---|
245 | wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3],
|
---|
246 | 'site-packages')
|
---|
247 | self.assertEqual(dirs[0], wanted)
|
---|
248 | wanted = os.path.join('xoxo', 'lib', 'site-python')
|
---|
249 | self.assertEqual(dirs[1], wanted)
|
---|
250 | else:
|
---|
251 | # other platforms
|
---|
252 | self.assertEqual(len(dirs), 2)
|
---|
253 | self.assertEqual(dirs[0], 'xoxo')
|
---|
254 | wanted = os.path.join('xoxo', 'lib', 'site-packages')
|
---|
255 | self.assertEqual(dirs[1], wanted)
|
---|
256 |
|
---|
257 | class PthFile(object):
|
---|
258 | """Helper class for handling testing of .pth files"""
|
---|
259 |
|
---|
260 | def __init__(self, filename_base=TESTFN, imported="time",
|
---|
261 | good_dirname="__testdir__", bad_dirname="__bad"):
|
---|
262 | """Initialize instance variables"""
|
---|
263 | self.filename = filename_base + ".pth"
|
---|
264 | self.base_dir = os.path.abspath('')
|
---|
265 | self.file_path = os.path.join(self.base_dir, self.filename)
|
---|
266 | self.imported = imported
|
---|
267 | self.good_dirname = good_dirname
|
---|
268 | self.bad_dirname = bad_dirname
|
---|
269 | self.good_dir_path = os.path.join(self.base_dir, self.good_dirname)
|
---|
270 | self.bad_dir_path = os.path.join(self.base_dir, self.bad_dirname)
|
---|
271 |
|
---|
272 | def create(self):
|
---|
273 | """Create a .pth file with a comment, blank lines, an ``import
|
---|
274 | <self.imported>``, a line with self.good_dirname, and a line with
|
---|
275 | self.bad_dirname.
|
---|
276 |
|
---|
277 | Creation of the directory for self.good_dir_path (based off of
|
---|
278 | self.good_dirname) is also performed.
|
---|
279 |
|
---|
280 | Make sure to call self.cleanup() to undo anything done by this method.
|
---|
281 |
|
---|
282 | """
|
---|
283 | FILE = open(self.file_path, 'w')
|
---|
284 | try:
|
---|
285 | print>>FILE, "#import @bad module name"
|
---|
286 | print>>FILE, "\n"
|
---|
287 | print>>FILE, "import %s" % self.imported
|
---|
288 | print>>FILE, self.good_dirname
|
---|
289 | print>>FILE, self.bad_dirname
|
---|
290 | finally:
|
---|
291 | FILE.close()
|
---|
292 | os.mkdir(self.good_dir_path)
|
---|
293 |
|
---|
294 | def cleanup(self, prep=False):
|
---|
295 | """Make sure that the .pth file is deleted, self.imported is not in
|
---|
296 | sys.modules, and that both self.good_dirname and self.bad_dirname are
|
---|
297 | not existing directories."""
|
---|
298 | if os.path.exists(self.file_path):
|
---|
299 | os.remove(self.file_path)
|
---|
300 | if prep:
|
---|
301 | self.imported_module = sys.modules.get(self.imported)
|
---|
302 | if self.imported_module:
|
---|
303 | del sys.modules[self.imported]
|
---|
304 | else:
|
---|
305 | if self.imported_module:
|
---|
306 | sys.modules[self.imported] = self.imported_module
|
---|
307 | if os.path.exists(self.good_dir_path):
|
---|
308 | os.rmdir(self.good_dir_path)
|
---|
309 | if os.path.exists(self.bad_dir_path):
|
---|
310 | os.rmdir(self.bad_dir_path)
|
---|
311 |
|
---|
312 | class ImportSideEffectTests(unittest.TestCase):
|
---|
313 | """Test side-effects from importing 'site'."""
|
---|
314 |
|
---|
315 | def setUp(self):
|
---|
316 | """Make a copy of sys.path"""
|
---|
317 | self.sys_path = sys.path[:]
|
---|
318 |
|
---|
319 | def tearDown(self):
|
---|
320 | """Restore sys.path"""
|
---|
321 | sys.path[:] = self.sys_path
|
---|
322 |
|
---|
323 | def test_abs__file__(self):
|
---|
324 | # Make sure all imported modules have their __file__ attribute
|
---|
325 | # as an absolute path.
|
---|
326 | # Handled by abs__file__()
|
---|
327 | site.abs__file__()
|
---|
328 | for module in (sys, os, __builtin__):
|
---|
329 | try:
|
---|
330 | self.assertTrue(os.path.isabs(module.__file__), repr(module))
|
---|
331 | except AttributeError:
|
---|
332 | continue
|
---|
333 | # We could try everything in sys.modules; however, when regrtest.py
|
---|
334 | # runs something like test_frozen before test_site, then we will
|
---|
335 | # be testing things loaded *after* test_site did path normalization
|
---|
336 |
|
---|
337 | def test_no_duplicate_paths(self):
|
---|
338 | # No duplicate paths should exist in sys.path
|
---|
339 | # Handled by removeduppaths()
|
---|
340 | site.removeduppaths()
|
---|
341 | seen_paths = set()
|
---|
342 | for path in sys.path:
|
---|
343 | self.assertNotIn(path, seen_paths)
|
---|
344 | seen_paths.add(path)
|
---|
345 |
|
---|
346 | def test_add_build_dir(self):
|
---|
347 | # Test that the build directory's Modules directory is used when it
|
---|
348 | # should be.
|
---|
349 | # XXX: implement
|
---|
350 | pass
|
---|
351 |
|
---|
352 | def test_setting_quit(self):
|
---|
353 | # 'quit' and 'exit' should be injected into __builtin__
|
---|
354 | self.assertTrue(hasattr(__builtin__, "quit"))
|
---|
355 | self.assertTrue(hasattr(__builtin__, "exit"))
|
---|
356 |
|
---|
357 | def test_setting_copyright(self):
|
---|
358 | # 'copyright' and 'credits' should be in __builtin__
|
---|
359 | self.assertTrue(hasattr(__builtin__, "copyright"))
|
---|
360 | self.assertTrue(hasattr(__builtin__, "credits"))
|
---|
361 |
|
---|
362 | def test_setting_help(self):
|
---|
363 | # 'help' should be set in __builtin__
|
---|
364 | self.assertTrue(hasattr(__builtin__, "help"))
|
---|
365 |
|
---|
366 | def test_aliasing_mbcs(self):
|
---|
367 | if sys.platform == "win32":
|
---|
368 | import locale
|
---|
369 | if locale.getdefaultlocale()[1].startswith('cp'):
|
---|
370 | for value in encodings.aliases.aliases.itervalues():
|
---|
371 | if value == "mbcs":
|
---|
372 | break
|
---|
373 | else:
|
---|
374 | self.fail("did not alias mbcs")
|
---|
375 |
|
---|
376 | def test_setdefaultencoding_removed(self):
|
---|
377 | # Make sure sys.setdefaultencoding is gone
|
---|
378 | self.assertTrue(not hasattr(sys, "setdefaultencoding"))
|
---|
379 |
|
---|
380 | def test_sitecustomize_executed(self):
|
---|
381 | # If sitecustomize is available, it should have been imported.
|
---|
382 | if "sitecustomize" not in sys.modules:
|
---|
383 | try:
|
---|
384 | import sitecustomize
|
---|
385 | except ImportError:
|
---|
386 | pass
|
---|
387 | else:
|
---|
388 | self.fail("sitecustomize not imported automatically")
|
---|
389 |
|
---|
390 | def test_main():
|
---|
391 | run_unittest(HelperFunctionsTests, ImportSideEffectTests)
|
---|
392 |
|
---|
393 | if __name__ == "__main__":
|
---|
394 | test_main()
|
---|