blob: 845e380bee89a69c6d0b254df44ca7403d7cb130 [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 Cannon2c5c79c2009-01-18 06:55:05 +00009def case_insensitive_tests(class_):
Brett Cannon1262e7c2009-05-11 01:47:11 +000010 """Class decorator that nullifies tests requiring a case-insensitive
Brett Cannon2c5c79c2009-01-18 06:55:05 +000011 file system."""
Brett Cannon1262e7c2009-05-11 01:47:11 +000012 # Windows is the only OS that is *always* case-insensitive
13 # (OS X *can* be case-sensitive).
14 if sys.platform not in ('win32', 'cygwin'):
15 changed_name = __file__.upper()
16 if changed_name == __file__:
17 changed_name = __file__.lower()
Brett Cannona3d056e2009-04-02 05:17:54 +000018 if os.path.exists(changed_name):
19 return class_
Brett Cannon1262e7c2009-05-11 01:47:11 +000020 else:
21 return unittest.TestCase
Brett Cannon2c5c79c2009-01-18 06:55:05 +000022 else:
23 return class_
24
25
Brett Cannon23cbd8a2009-01-18 00:24:28 +000026@contextmanager
27def uncache(*names):
28 """Uncache a module from sys.modules.
29
30 A basic sanity check is performed to prevent uncaching modules that either
31 cannot/shouldn't be uncached.
32
33 """
34 for name in names:
35 if name in ('sys', 'marshal', 'imp'):
36 raise ValueError(
37 "cannot uncache {0} as it will break _importlib".format(name))
38 try:
39 del sys.modules[name]
40 except KeyError:
41 pass
42 try:
43 yield
44 finally:
45 for name in names:
46 try:
47 del sys.modules[name]
48 except KeyError:
49 pass
50
51@contextmanager
52def import_state(**kwargs):
53 """Context manager to manage the various importers and stored state in the
54 sys module.
55
56 The 'modules' attribute is not supported as the interpreter state stores a
57 pointer to the dict that the interpreter uses internally;
58 reassigning to sys.modules does not have the desired effect.
59
60 """
61 originals = {}
62 try:
63 for attr, default in (('meta_path', []), ('path', []),
64 ('path_hooks', []),
65 ('path_importer_cache', {})):
66 originals[attr] = getattr(sys, attr)
67 if attr in kwargs:
68 new_value = kwargs[attr]
69 del kwargs[attr]
70 else:
71 new_value = default
72 setattr(sys, attr, new_value)
73 if len(kwargs):
74 raise ValueError(
75 'unrecognized arguments: {0}'.format(kwargs.keys()))
76 yield
77 finally:
78 for attr, value in originals.items():
79 setattr(sys, attr, value)
80
81
Brett Cannon23cbd8a2009-01-18 00:24:28 +000082class mock_modules:
83
84 """A mock importer/loader."""
85
86 def __init__(self, *names):
87 self.modules = {}
88 for name in names:
89 if not name.endswith('.__init__'):
90 import_name = name
91 else:
92 import_name = name[:-len('.__init__')]
93 if '.' not in name:
94 package = None
95 elif import_name == name:
96 package = name.rsplit('.', 1)[0]
97 else:
98 package = import_name
99 module = imp.new_module(import_name)
100 module.__loader__ = self
101 module.__file__ = '<mock __file__>'
102 module.__package__ = package
103 module.attr = name
104 if import_name != name:
105 module.__path__ = ['<mock __path__>']
106 self.modules[import_name] = module
107
108 def __getitem__(self, name):
109 return self.modules[name]
110
111 def find_module(self, fullname, path=None):
112 if fullname not in self.modules:
113 return None
114 else:
115 return self
116
117 def load_module(self, fullname):
118 if fullname not in self.modules:
119 raise ImportError
120 else:
121 sys.modules[fullname] = self.modules[fullname]
122 return self.modules[fullname]
123
124 def __enter__(self):
125 self._uncache = uncache(*self.modules.keys())
126 self._uncache.__enter__()
127 return self
128
129 def __exit__(self, *exc_info):
130 self._uncache.__exit__(None, None, None)