blob: ef32f7d690fe42ae8a4dd2c82dd5c305cc796cb6 [file] [log] [blame]
Brett Cannon23cbd8a2009-01-18 00:24:28 +00001from contextlib import contextmanager
Brett Cannon23cbd8a2009-01-18 00:24:28 +00002import imp
3import os.path
Brett Cannona3d056e2009-04-02 05:17:54 +00004from test import support
Brett Cannon534b2cd2009-02-07 02:06:43 +00005import unittest
Brett Cannon23cbd8a2009-01-18 00:24:28 +00006import sys
Brett Cannon23cbd8a2009-01-18 00:24:28 +00007
8
Brett Cannon4dc31932009-07-20 01:05:40 +00009CASE_INSENSITIVE_FS = True
10# Windows is the only OS that is *always* case-insensitive
11# (OS X *can* be case-sensitive).
12if sys.platform not in ('win32', 'cygwin'):
13 changed_name = __file__.upper()
14 if changed_name == __file__:
15 changed_name = __file__.lower()
16 if not os.path.exists(changed_name):
17 CASE_INSENSITIVE_FS = False
18
19
20def case_insensitive_tests(test):
Brett Cannon1262e7c2009-05-11 01:47:11 +000021 """Class decorator that nullifies tests requiring a case-insensitive
Brett Cannon2c5c79c2009-01-18 06:55:05 +000022 file system."""
Brett Cannon4dc31932009-07-20 01:05:40 +000023 return unittest.skipIf(not CASE_INSENSITIVE_FS,
24 "requires a case-insensitive filesystem")(test)
Brett Cannon2c5c79c2009-01-18 06:55:05 +000025
26
Brett Cannon23cbd8a2009-01-18 00:24:28 +000027@contextmanager
28def uncache(*names):
29 """Uncache a module from sys.modules.
30
31 A basic sanity check is performed to prevent uncaching modules that either
32 cannot/shouldn't be uncached.
33
34 """
35 for name in names:
36 if name in ('sys', 'marshal', 'imp'):
37 raise ValueError(
Brett Cannonfd074152012-04-14 14:10:13 -040038 "cannot uncache {0}".format(name))
Brett Cannon23cbd8a2009-01-18 00:24:28 +000039 try:
40 del sys.modules[name]
41 except KeyError:
42 pass
43 try:
44 yield
45 finally:
46 for name in names:
47 try:
48 del sys.modules[name]
49 except KeyError:
50 pass
51
52@contextmanager
53def import_state(**kwargs):
54 """Context manager to manage the various importers and stored state in the
55 sys module.
56
57 The 'modules' attribute is not supported as the interpreter state stores a
58 pointer to the dict that the interpreter uses internally;
59 reassigning to sys.modules does not have the desired effect.
60
61 """
62 originals = {}
63 try:
64 for attr, default in (('meta_path', []), ('path', []),
65 ('path_hooks', []),
66 ('path_importer_cache', {})):
67 originals[attr] = getattr(sys, attr)
68 if attr in kwargs:
69 new_value = kwargs[attr]
70 del kwargs[attr]
71 else:
72 new_value = default
73 setattr(sys, attr, new_value)
74 if len(kwargs):
75 raise ValueError(
76 'unrecognized arguments: {0}'.format(kwargs.keys()))
77 yield
78 finally:
79 for attr, value in originals.items():
80 setattr(sys, attr, value)
81
82
Brett Cannon23cbd8a2009-01-18 00:24:28 +000083class mock_modules:
84
85 """A mock importer/loader."""
86
Meador Inge416f12d2011-12-14 22:23:46 -060087 def __init__(self, *names, module_code={}):
Brett Cannon23cbd8a2009-01-18 00:24:28 +000088 self.modules = {}
Meador Inge416f12d2011-12-14 22:23:46 -060089 self.module_code = {}
Brett Cannon23cbd8a2009-01-18 00:24:28 +000090 for name in names:
91 if not name.endswith('.__init__'):
92 import_name = name
93 else:
94 import_name = name[:-len('.__init__')]
95 if '.' not in name:
96 package = None
97 elif import_name == name:
98 package = name.rsplit('.', 1)[0]
99 else:
100 package = import_name
101 module = imp.new_module(import_name)
102 module.__loader__ = self
103 module.__file__ = '<mock __file__>'
104 module.__package__ = package
105 module.attr = name
106 if import_name != name:
107 module.__path__ = ['<mock __path__>']
108 self.modules[import_name] = module
Meador Inge416f12d2011-12-14 22:23:46 -0600109 if import_name in module_code:
110 self.module_code[import_name] = module_code[import_name]
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000111
112 def __getitem__(self, name):
113 return self.modules[name]
114
115 def find_module(self, fullname, path=None):
116 if fullname not in self.modules:
117 return None
118 else:
119 return self
120
121 def load_module(self, fullname):
122 if fullname not in self.modules:
123 raise ImportError
124 else:
125 sys.modules[fullname] = self.modules[fullname]
Meador Inge416f12d2011-12-14 22:23:46 -0600126 if fullname in self.module_code:
Antoine Pitrou6efa50a2012-05-07 21:41:59 +0200127 try:
128 self.module_code[fullname]()
129 except Exception:
130 del sys.modules[fullname]
131 raise
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000132 return self.modules[fullname]
133
134 def __enter__(self):
135 self._uncache = uncache(*self.modules.keys())
136 self._uncache.__enter__()
137 return self
138
139 def __exit__(self, *exc_info):
140 self._uncache.__exit__(None, None, None)