Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 1 | import importlib |
| 2 | from importlib import abc |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 3 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 4 | from .. import abc as testing_abc |
| 5 | from .. import util |
| 6 | from . import util as source_util |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 7 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 8 | import imp |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 9 | import inspect |
Brett Cannon | 418182e | 2010-07-03 22:32:41 +0000 | [diff] [blame] | 10 | import io |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 11 | import marshal |
| 12 | import os |
| 13 | import sys |
| 14 | import types |
| 15 | import unittest |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 16 | import warnings |
| 17 | |
| 18 | |
| 19 | class SourceOnlyLoaderMock(abc.SourceLoader): |
| 20 | |
| 21 | # Globals that should be defined for all modules. |
| 22 | source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " |
| 23 | b"repr(__loader__)])") |
| 24 | |
| 25 | def __init__(self, path): |
| 26 | self.path = path |
| 27 | |
| 28 | def get_data(self, path): |
| 29 | assert self.path == path |
| 30 | return self.source |
| 31 | |
| 32 | def get_filename(self, fullname): |
| 33 | return self.path |
| 34 | |
Barry Warsaw | 0efcf99 | 2012-07-31 17:52:32 -0400 | [diff] [blame] | 35 | def module_repr(self, module): |
| 36 | return '<module>' |
| 37 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 38 | |
| 39 | class SourceLoaderMock(SourceOnlyLoaderMock): |
| 40 | |
| 41 | source_mtime = 1 |
| 42 | |
| 43 | def __init__(self, path, magic=imp.get_magic()): |
| 44 | super().__init__(path) |
| 45 | self.bytecode_path = imp.cache_from_source(self.path) |
Antoine Pitrou | 5136ac0 | 2012-01-13 18:52:16 +0100 | [diff] [blame] | 46 | self.source_size = len(self.source) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 47 | data = bytearray(magic) |
Brett Cannon | c264e3e | 2012-01-25 18:58:03 -0500 | [diff] [blame] | 48 | data.extend(importlib._w_long(self.source_mtime)) |
| 49 | data.extend(importlib._w_long(self.source_size)) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 50 | code_object = compile(self.source, self.path, 'exec', |
| 51 | dont_inherit=True) |
| 52 | data.extend(marshal.dumps(code_object)) |
| 53 | self.bytecode = bytes(data) |
| 54 | self.written = {} |
| 55 | |
| 56 | def get_data(self, path): |
| 57 | if path == self.path: |
| 58 | return super().get_data(path) |
| 59 | elif path == self.bytecode_path: |
| 60 | return self.bytecode |
| 61 | else: |
| 62 | raise IOError |
| 63 | |
Antoine Pitrou | 5136ac0 | 2012-01-13 18:52:16 +0100 | [diff] [blame] | 64 | def path_stats(self, path): |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 65 | assert path == self.path |
Antoine Pitrou | 5136ac0 | 2012-01-13 18:52:16 +0100 | [diff] [blame] | 66 | return {'mtime': self.source_mtime, 'size': self.source_size} |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 67 | |
| 68 | def set_data(self, path, data): |
| 69 | self.written[path] = bytes(data) |
| 70 | return path == self.bytecode_path |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 71 | |
| 72 | |
| 73 | class PyLoaderMock(abc.PyLoader): |
| 74 | |
| 75 | # Globals that should be defined for all modules. |
Brett Cannon | d43b30b | 2009-03-10 03:29:23 +0000 | [diff] [blame] | 76 | source = (b"_ = '::'.join([__name__, __file__, __package__, " |
| 77 | b"repr(__loader__)])") |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 78 | |
| 79 | def __init__(self, data): |
| 80 | """Take a dict of 'module_name: path' pairings. |
| 81 | |
| 82 | Paths should have no file extension, allowing packages to be denoted by |
| 83 | ending in '__init__'. |
| 84 | |
| 85 | """ |
| 86 | self.module_paths = data |
| 87 | self.path_to_module = {val:key for key,val in data.items()} |
| 88 | |
| 89 | def get_data(self, path): |
| 90 | if path not in self.path_to_module: |
| 91 | raise IOError |
Brett Cannon | d43b30b | 2009-03-10 03:29:23 +0000 | [diff] [blame] | 92 | return self.source |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 93 | |
| 94 | def is_package(self, name): |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 95 | filename = os.path.basename(self.get_filename(name)) |
| 96 | return os.path.splitext(filename)[0] == '__init__' |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 97 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 98 | def source_path(self, name): |
| 99 | try: |
| 100 | return self.module_paths[name] |
| 101 | except KeyError: |
| 102 | raise ImportError |
| 103 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 104 | def get_filename(self, name): |
| 105 | """Silence deprecation warning.""" |
| 106 | with warnings.catch_warnings(record=True) as w: |
| 107 | warnings.simplefilter("always") |
| 108 | path = super().get_filename(name) |
| 109 | assert len(w) == 1 |
Florent Xicluna | 6731775 | 2011-12-10 11:07:42 +0100 | [diff] [blame] | 110 | assert issubclass(w[0].category, DeprecationWarning) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 111 | return path |
| 112 | |
Barry Warsaw | 0efcf99 | 2012-07-31 17:52:32 -0400 | [diff] [blame] | 113 | def module_repr(self): |
| 114 | return '<module>' |
| 115 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 116 | |
| 117 | class PyLoaderCompatMock(PyLoaderMock): |
| 118 | |
| 119 | """Mock that matches what is suggested to have a loader that is compatible |
| 120 | from Python 3.1 onwards.""" |
| 121 | |
| 122 | def get_filename(self, fullname): |
| 123 | try: |
| 124 | return self.module_paths[fullname] |
| 125 | except KeyError: |
| 126 | raise ImportError |
| 127 | |
| 128 | def source_path(self, fullname): |
| 129 | try: |
| 130 | return self.get_filename(fullname) |
| 131 | except ImportError: |
| 132 | return None |
| 133 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 134 | |
| 135 | class PyPycLoaderMock(abc.PyPycLoader, PyLoaderMock): |
| 136 | |
| 137 | default_mtime = 1 |
| 138 | |
| 139 | def __init__(self, source, bc={}): |
| 140 | """Initialize mock. |
| 141 | |
| 142 | 'bc' is a dict keyed on a module's name. The value is dict with |
| 143 | possible keys of 'path', 'mtime', 'magic', and 'bc'. Except for 'path', |
| 144 | each of those keys control if any part of created bytecode is to |
| 145 | deviate from default values. |
| 146 | |
| 147 | """ |
| 148 | super().__init__(source) |
| 149 | self.module_bytecode = {} |
| 150 | self.path_to_bytecode = {} |
| 151 | self.bytecode_to_path = {} |
| 152 | for name, data in bc.items(): |
| 153 | self.path_to_bytecode[data['path']] = name |
| 154 | self.bytecode_to_path[name] = data['path'] |
| 155 | magic = data.get('magic', imp.get_magic()) |
| 156 | mtime = importlib._w_long(data.get('mtime', self.default_mtime)) |
Brett Cannon | 1e33156 | 2012-07-02 14:35:34 -0400 | [diff] [blame] | 157 | source_size = importlib._w_long(len(self.source) & 0xFFFFFFFF) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 158 | if 'bc' in data: |
| 159 | bc = data['bc'] |
| 160 | else: |
| 161 | bc = self.compile_bc(name) |
Brett Cannon | 1e33156 | 2012-07-02 14:35:34 -0400 | [diff] [blame] | 162 | self.module_bytecode[name] = magic + mtime + source_size + bc |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 163 | |
| 164 | def compile_bc(self, name): |
| 165 | source_path = self.module_paths.get(name, '<test>') or '<test>' |
| 166 | code = compile(self.source, source_path, 'exec') |
| 167 | return marshal.dumps(code) |
| 168 | |
| 169 | def source_mtime(self, name): |
| 170 | if name in self.module_paths: |
| 171 | return self.default_mtime |
| 172 | elif name in self.module_bytecode: |
| 173 | return None |
| 174 | else: |
| 175 | raise ImportError |
| 176 | |
| 177 | def bytecode_path(self, name): |
| 178 | try: |
| 179 | return self.bytecode_to_path[name] |
| 180 | except KeyError: |
| 181 | if name in self.module_paths: |
| 182 | return None |
| 183 | else: |
| 184 | raise ImportError |
| 185 | |
| 186 | def write_bytecode(self, name, bytecode): |
| 187 | self.module_bytecode[name] = bytecode |
| 188 | return True |
| 189 | |
| 190 | def get_data(self, path): |
| 191 | if path in self.path_to_module: |
| 192 | return super().get_data(path) |
| 193 | elif path in self.path_to_bytecode: |
| 194 | name = self.path_to_bytecode[path] |
| 195 | return self.module_bytecode[name] |
| 196 | else: |
| 197 | raise IOError |
| 198 | |
| 199 | def is_package(self, name): |
| 200 | try: |
| 201 | return super().is_package(name) |
| 202 | except TypeError: |
| 203 | return '__init__' in self.bytecode_to_path[name] |
| 204 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 205 | def get_code(self, name): |
| 206 | with warnings.catch_warnings(record=True) as w: |
| 207 | warnings.simplefilter("always") |
| 208 | code_object = super().get_code(name) |
| 209 | assert len(w) == 1 |
Florent Xicluna | 6731775 | 2011-12-10 11:07:42 +0100 | [diff] [blame] | 210 | assert issubclass(w[0].category, DeprecationWarning) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 211 | return code_object |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 212 | |
| 213 | class PyLoaderTests(testing_abc.LoaderTests): |
| 214 | |
| 215 | """Tests for importlib.abc.PyLoader.""" |
| 216 | |
| 217 | mocker = PyLoaderMock |
| 218 | |
| 219 | def eq_attrs(self, ob, **kwargs): |
| 220 | for attr, val in kwargs.items(): |
Brett Cannon | 978259e | 2009-04-02 15:32:07 +0000 | [diff] [blame] | 221 | found = getattr(ob, attr) |
| 222 | self.assertEqual(found, val, |
| 223 | "{} attribute: {} != {}".format(attr, found, val)) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 224 | |
| 225 | def test_module(self): |
| 226 | name = '<module>' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 227 | path = os.path.join('', 'path', 'to', 'module') |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 228 | mock = self.mocker({name: path}) |
| 229 | with util.uncache(name): |
| 230 | module = mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 231 | self.assertIn(name, sys.modules) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 232 | self.eq_attrs(module, __name__=name, __file__=path, __package__='', |
| 233 | __loader__=mock) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 234 | self.assertTrue(not hasattr(module, '__path__')) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 235 | return mock, name |
| 236 | |
| 237 | def test_package(self): |
| 238 | name = '<pkg>' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 239 | path = os.path.join('path', 'to', name, '__init__') |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 240 | mock = self.mocker({name: path}) |
| 241 | with util.uncache(name): |
| 242 | module = mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 243 | self.assertIn(name, sys.modules) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 244 | self.eq_attrs(module, __name__=name, __file__=path, |
| 245 | __path__=[os.path.dirname(path)], __package__=name, |
| 246 | __loader__=mock) |
| 247 | return mock, name |
| 248 | |
| 249 | def test_lacking_parent(self): |
| 250 | name = 'pkg.mod' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 251 | path = os.path.join('path', 'to', 'pkg', 'mod') |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 252 | mock = self.mocker({name: path}) |
| 253 | with util.uncache(name): |
| 254 | module = mock.load_module(name) |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 255 | self.assertIn(name, sys.modules) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 256 | self.eq_attrs(module, __name__=name, __file__=path, __package__='pkg', |
| 257 | __loader__=mock) |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 258 | self.assertFalse(hasattr(module, '__path__')) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 259 | return mock, name |
| 260 | |
| 261 | def test_module_reuse(self): |
| 262 | name = 'mod' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 263 | path = os.path.join('path', 'to', 'mod') |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 264 | module = imp.new_module(name) |
| 265 | mock = self.mocker({name: path}) |
| 266 | with util.uncache(name): |
| 267 | sys.modules[name] = module |
| 268 | loaded_module = mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 269 | self.assertIs(loaded_module, module) |
| 270 | self.assertIs(sys.modules[name], module) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 271 | return mock, name |
| 272 | |
| 273 | def test_state_after_failure(self): |
| 274 | name = "mod" |
| 275 | module = imp.new_module(name) |
| 276 | module.blah = None |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 277 | mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) |
Brett Cannon | d43b30b | 2009-03-10 03:29:23 +0000 | [diff] [blame] | 278 | mock.source = b"1/0" |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 279 | with util.uncache(name): |
| 280 | sys.modules[name] = module |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 281 | with self.assertRaises(ZeroDivisionError): |
| 282 | mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 283 | self.assertIs(sys.modules[name], module) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 284 | self.assertTrue(hasattr(module, 'blah')) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 285 | return mock |
| 286 | |
| 287 | def test_unloadable(self): |
| 288 | name = "mod" |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 289 | mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) |
Brett Cannon | d43b30b | 2009-03-10 03:29:23 +0000 | [diff] [blame] | 290 | mock.source = b"1/0" |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 291 | with util.uncache(name): |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 292 | with self.assertRaises(ZeroDivisionError): |
| 293 | mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 294 | self.assertNotIn(name, sys.modules) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 295 | return mock |
| 296 | |
| 297 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 298 | class PyLoaderCompatTests(PyLoaderTests): |
| 299 | |
| 300 | """Test that the suggested code to make a loader that is compatible from |
| 301 | Python 3.1 forward works.""" |
| 302 | |
| 303 | mocker = PyLoaderCompatMock |
| 304 | |
| 305 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 306 | class PyLoaderInterfaceTests(unittest.TestCase): |
| 307 | |
Brett Cannon | d43b30b | 2009-03-10 03:29:23 +0000 | [diff] [blame] | 308 | """Tests for importlib.abc.PyLoader to make sure that when source_path() |
| 309 | doesn't return a path everything works as expected.""" |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 310 | |
| 311 | def test_no_source_path(self): |
| 312 | # No source path should lead to ImportError. |
| 313 | name = 'mod' |
| 314 | mock = PyLoaderMock({}) |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 315 | with util.uncache(name), self.assertRaises(ImportError): |
| 316 | mock.load_module(name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 317 | |
| 318 | def test_source_path_is_None(self): |
| 319 | name = 'mod' |
| 320 | mock = PyLoaderMock({name: None}) |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 321 | with util.uncache(name), self.assertRaises(ImportError): |
| 322 | mock.load_module(name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 323 | |
Brett Cannon | 6919427 | 2009-07-20 04:23:48 +0000 | [diff] [blame] | 324 | def test_get_filename_with_source_path(self): |
| 325 | # get_filename() should return what source_path() returns. |
| 326 | name = 'mod' |
| 327 | path = os.path.join('path', 'to', 'source') |
| 328 | mock = PyLoaderMock({name: path}) |
| 329 | with util.uncache(name): |
| 330 | self.assertEqual(mock.get_filename(name), path) |
| 331 | |
| 332 | def test_get_filename_no_source_path(self): |
| 333 | # get_filename() should raise ImportError if source_path returns None. |
| 334 | name = 'mod' |
| 335 | mock = PyLoaderMock({name: None}) |
| 336 | with util.uncache(name), self.assertRaises(ImportError): |
| 337 | mock.get_filename(name) |
| 338 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 339 | |
| 340 | class PyPycLoaderTests(PyLoaderTests): |
| 341 | |
| 342 | """Tests for importlib.abc.PyPycLoader.""" |
| 343 | |
| 344 | mocker = PyPycLoaderMock |
| 345 | |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 346 | @source_util.writes_bytecode_files |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 347 | def verify_bytecode(self, mock, name): |
| 348 | assert name in mock.module_paths |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 349 | self.assertIn(name, mock.module_bytecode) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 350 | magic = mock.module_bytecode[name][:4] |
| 351 | self.assertEqual(magic, imp.get_magic()) |
| 352 | mtime = importlib._r_long(mock.module_bytecode[name][4:8]) |
| 353 | self.assertEqual(mtime, 1) |
Brett Cannon | 1e33156 | 2012-07-02 14:35:34 -0400 | [diff] [blame] | 354 | source_size = mock.module_bytecode[name][8:12] |
| 355 | self.assertEqual(len(mock.source) & 0xFFFFFFFF, |
| 356 | importlib._r_long(source_size)) |
| 357 | bc = mock.module_bytecode[name][12:] |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 358 | self.assertEqual(bc, mock.compile_bc(name)) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 359 | |
| 360 | def test_module(self): |
| 361 | mock, name = super().test_module() |
| 362 | self.verify_bytecode(mock, name) |
| 363 | |
| 364 | def test_package(self): |
| 365 | mock, name = super().test_package() |
| 366 | self.verify_bytecode(mock, name) |
| 367 | |
| 368 | def test_lacking_parent(self): |
| 369 | mock, name = super().test_lacking_parent() |
| 370 | self.verify_bytecode(mock, name) |
| 371 | |
| 372 | def test_module_reuse(self): |
| 373 | mock, name = super().test_module_reuse() |
| 374 | self.verify_bytecode(mock, name) |
| 375 | |
| 376 | def test_state_after_failure(self): |
| 377 | super().test_state_after_failure() |
| 378 | |
| 379 | def test_unloadable(self): |
| 380 | super().test_unloadable() |
| 381 | |
| 382 | |
Brett Cannon | 6919427 | 2009-07-20 04:23:48 +0000 | [diff] [blame] | 383 | class PyPycLoaderInterfaceTests(unittest.TestCase): |
| 384 | |
| 385 | """Test for the interface of importlib.abc.PyPycLoader.""" |
| 386 | |
| 387 | def get_filename_check(self, src_path, bc_path, expect): |
| 388 | name = 'mod' |
| 389 | mock = PyPycLoaderMock({name: src_path}, {name: {'path': bc_path}}) |
| 390 | with util.uncache(name): |
| 391 | assert mock.source_path(name) == src_path |
| 392 | assert mock.bytecode_path(name) == bc_path |
| 393 | self.assertEqual(mock.get_filename(name), expect) |
| 394 | |
| 395 | def test_filename_with_source_bc(self): |
| 396 | # When source and bytecode paths present, return the source path. |
| 397 | self.get_filename_check('source_path', 'bc_path', 'source_path') |
| 398 | |
| 399 | def test_filename_with_source_no_bc(self): |
| 400 | # With source but no bc, return source path. |
| 401 | self.get_filename_check('source_path', None, 'source_path') |
| 402 | |
| 403 | def test_filename_with_no_source_bc(self): |
| 404 | # With not source but bc, return the bc path. |
| 405 | self.get_filename_check(None, 'bc_path', 'bc_path') |
| 406 | |
| 407 | def test_filename_with_no_source_or_bc(self): |
| 408 | # With no source or bc, raise ImportError. |
| 409 | name = 'mod' |
| 410 | mock = PyPycLoaderMock({name: None}, {name: {'path': None}}) |
| 411 | with util.uncache(name), self.assertRaises(ImportError): |
| 412 | mock.get_filename(name) |
| 413 | |
| 414 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 415 | class SkipWritingBytecodeTests(unittest.TestCase): |
| 416 | |
| 417 | """Test that bytecode is properly handled based on |
| 418 | sys.dont_write_bytecode.""" |
| 419 | |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 420 | @source_util.writes_bytecode_files |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 421 | def run_test(self, dont_write_bytecode): |
| 422 | name = 'mod' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 423 | mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 424 | sys.dont_write_bytecode = dont_write_bytecode |
| 425 | with util.uncache(name): |
| 426 | mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 427 | self.assertIsNot(name in mock.module_bytecode, dont_write_bytecode) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 428 | |
| 429 | def test_no_bytecode_written(self): |
| 430 | self.run_test(True) |
| 431 | |
| 432 | def test_bytecode_written(self): |
| 433 | self.run_test(False) |
| 434 | |
| 435 | |
| 436 | class RegeneratedBytecodeTests(unittest.TestCase): |
| 437 | |
| 438 | """Test that bytecode is regenerated as expected.""" |
| 439 | |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 440 | @source_util.writes_bytecode_files |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 441 | def test_different_magic(self): |
| 442 | # A different magic number should lead to new bytecode. |
| 443 | name = 'mod' |
| 444 | bad_magic = b'\x00\x00\x00\x00' |
| 445 | assert bad_magic != imp.get_magic() |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 446 | mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, |
| 447 | {name: {'path': os.path.join('path', 'to', |
| 448 | 'mod.bytecode'), |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 449 | 'magic': bad_magic}}) |
| 450 | with util.uncache(name): |
| 451 | mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 452 | self.assertIn(name, mock.module_bytecode) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 453 | magic = mock.module_bytecode[name][:4] |
| 454 | self.assertEqual(magic, imp.get_magic()) |
| 455 | |
Brett Cannon | 1262e7c | 2009-05-11 01:47:11 +0000 | [diff] [blame] | 456 | @source_util.writes_bytecode_files |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 457 | def test_old_mtime(self): |
| 458 | # Bytecode with an older mtime should be regenerated. |
| 459 | name = 'mod' |
| 460 | old_mtime = PyPycLoaderMock.default_mtime - 1 |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 461 | mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 462 | {name: {'path': 'path/to/mod.bytecode', 'mtime': old_mtime}}) |
| 463 | with util.uncache(name): |
| 464 | mock.load_module(name) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 465 | self.assertIn(name, mock.module_bytecode) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 466 | mtime = importlib._r_long(mock.module_bytecode[name][4:8]) |
| 467 | self.assertEqual(mtime, PyPycLoaderMock.default_mtime) |
| 468 | |
| 469 | |
| 470 | class BadBytecodeFailureTests(unittest.TestCase): |
| 471 | |
| 472 | """Test import failures when there is no source and parts of the bytecode |
| 473 | is bad.""" |
| 474 | |
| 475 | def test_bad_magic(self): |
| 476 | # A bad magic number should lead to an ImportError. |
| 477 | name = 'mod' |
| 478 | bad_magic = b'\x00\x00\x00\x00' |
Brett Cannon | 3c27384 | 2009-07-20 00:14:29 +0000 | [diff] [blame] | 479 | bc = {name: |
| 480 | {'path': os.path.join('path', 'to', 'mod'), |
| 481 | 'magic': bad_magic}} |
| 482 | mock = PyPycLoaderMock({name: None}, bc) |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 483 | with util.uncache(name), self.assertRaises(ImportError) as cm: |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 484 | mock.load_module(name) |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 485 | self.assertEqual(cm.exception.name, name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 486 | |
Brett Cannon | 3c27384 | 2009-07-20 00:14:29 +0000 | [diff] [blame] | 487 | def test_no_bytecode(self): |
| 488 | # Missing code object bytecode should lead to an EOFError. |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 489 | name = 'mod' |
Brett Cannon | 3c27384 | 2009-07-20 00:14:29 +0000 | [diff] [blame] | 490 | bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b''}} |
| 491 | mock = PyPycLoaderMock({name: None}, bc) |
| 492 | with util.uncache(name), self.assertRaises(EOFError): |
| 493 | mock.load_module(name) |
| 494 | |
| 495 | def test_bad_bytecode(self): |
| 496 | # Malformed code object bytecode should lead to a ValueError. |
| 497 | name = 'mod' |
Benjamin Peterson | 2215c14 | 2010-06-28 00:24:13 +0000 | [diff] [blame] | 498 | bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b'1234'}} |
Brett Cannon | 3c27384 | 2009-07-20 00:14:29 +0000 | [diff] [blame] | 499 | mock = PyPycLoaderMock({name: None}, bc) |
| 500 | with util.uncache(name), self.assertRaises(ValueError): |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 501 | mock.load_module(name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 502 | |
| 503 | |
| 504 | def raise_ImportError(*args, **kwargs): |
| 505 | raise ImportError |
| 506 | |
| 507 | class MissingPathsTests(unittest.TestCase): |
| 508 | |
| 509 | """Test what happens when a source or bytecode path does not exist (either |
| 510 | from *_path returning None or raising ImportError).""" |
| 511 | |
| 512 | def test_source_path_None(self): |
| 513 | # Bytecode should be used when source_path returns None, along with |
| 514 | # __file__ being set to the bytecode path. |
| 515 | name = 'mod' |
| 516 | bytecode_path = 'path/to/mod' |
| 517 | mock = PyPycLoaderMock({name: None}, {name: {'path': bytecode_path}}) |
| 518 | with util.uncache(name): |
| 519 | module = mock.load_module(name) |
| 520 | self.assertEqual(module.__file__, bytecode_path) |
| 521 | |
| 522 | # Testing for bytecode_path returning None handled by all tests where no |
| 523 | # bytecode initially exists. |
| 524 | |
| 525 | def test_all_paths_None(self): |
| 526 | # If all *_path methods return None, raise ImportError. |
| 527 | name = 'mod' |
| 528 | mock = PyPycLoaderMock({name: None}) |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 529 | with util.uncache(name), self.assertRaises(ImportError) as cm: |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 530 | mock.load_module(name) |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 531 | self.assertEqual(cm.exception.name, name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 532 | |
| 533 | def test_source_path_ImportError(self): |
| 534 | # An ImportError from source_path should trigger an ImportError. |
| 535 | name = 'mod' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 536 | mock = PyPycLoaderMock({}, {name: {'path': os.path.join('path', 'to', |
| 537 | 'mod')}}) |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 538 | with util.uncache(name), self.assertRaises(ImportError): |
| 539 | mock.load_module(name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 540 | |
| 541 | def test_bytecode_path_ImportError(self): |
| 542 | # An ImportError from bytecode_path should trigger an ImportError. |
| 543 | name = 'mod' |
Brett Cannon | 5561982 | 2009-04-02 17:54:43 +0000 | [diff] [blame] | 544 | mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 545 | bad_meth = types.MethodType(raise_ImportError, mock) |
| 546 | mock.bytecode_path = bad_meth |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 547 | with util.uncache(name), self.assertRaises(ImportError) as cm: |
Brett Cannon | 0a49c58 | 2009-07-19 23:43:45 +0000 | [diff] [blame] | 548 | mock.load_module(name) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 549 | |
| 550 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 551 | class SourceLoaderTestHarness(unittest.TestCase): |
| 552 | |
| 553 | def setUp(self, *, is_package=True, **kwargs): |
| 554 | self.package = 'pkg' |
| 555 | if is_package: |
| 556 | self.path = os.path.join(self.package, '__init__.py') |
| 557 | self.name = self.package |
| 558 | else: |
| 559 | module_name = 'mod' |
| 560 | self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) |
| 561 | self.name = '.'.join([self.package, module_name]) |
| 562 | self.cached = imp.cache_from_source(self.path) |
| 563 | self.loader = self.loader_mock(self.path, **kwargs) |
| 564 | |
| 565 | def verify_module(self, module): |
| 566 | self.assertEqual(module.__name__, self.name) |
| 567 | self.assertEqual(module.__file__, self.path) |
| 568 | self.assertEqual(module.__cached__, self.cached) |
| 569 | self.assertEqual(module.__package__, self.package) |
| 570 | self.assertEqual(module.__loader__, self.loader) |
| 571 | values = module._.split('::') |
| 572 | self.assertEqual(values[0], self.name) |
| 573 | self.assertEqual(values[1], self.path) |
| 574 | self.assertEqual(values[2], self.cached) |
| 575 | self.assertEqual(values[3], self.package) |
| 576 | self.assertEqual(values[4], repr(self.loader)) |
| 577 | |
| 578 | def verify_code(self, code_object): |
| 579 | module = imp.new_module(self.name) |
| 580 | module.__file__ = self.path |
| 581 | module.__cached__ = self.cached |
| 582 | module.__package__ = self.package |
| 583 | module.__loader__ = self.loader |
| 584 | module.__path__ = [] |
| 585 | exec(code_object, module.__dict__) |
| 586 | self.verify_module(module) |
| 587 | |
| 588 | |
| 589 | class SourceOnlyLoaderTests(SourceLoaderTestHarness): |
| 590 | |
| 591 | """Test importlib.abc.SourceLoader for source-only loading. |
| 592 | |
| 593 | Reload testing is subsumed by the tests for |
| 594 | importlib.util.module_for_loader. |
| 595 | |
| 596 | """ |
| 597 | |
| 598 | loader_mock = SourceOnlyLoaderMock |
| 599 | |
| 600 | def test_get_source(self): |
| 601 | # Verify the source code is returned as a string. |
| 602 | # If an IOError is raised by get_data then raise ImportError. |
| 603 | expected_source = self.loader.source.decode('utf-8') |
| 604 | self.assertEqual(self.loader.get_source(self.name), expected_source) |
| 605 | def raise_IOError(path): |
| 606 | raise IOError |
| 607 | self.loader.get_data = raise_IOError |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 608 | with self.assertRaises(ImportError) as cm: |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 609 | self.loader.get_source(self.name) |
Brett Cannon | bbb6680 | 2012-04-12 21:09:01 -0400 | [diff] [blame] | 610 | self.assertEqual(cm.exception.name, self.name) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 611 | |
| 612 | def test_is_package(self): |
| 613 | # Properly detect when loading a package. |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 614 | self.setUp(is_package=False) |
| 615 | self.assertFalse(self.loader.is_package(self.name)) |
Brett Cannon | ea0b823 | 2012-06-15 20:00:53 -0400 | [diff] [blame] | 616 | self.setUp(is_package=True) |
| 617 | self.assertTrue(self.loader.is_package(self.name)) |
| 618 | self.assertFalse(self.loader.is_package(self.name + '.__init__')) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 619 | |
| 620 | def test_get_code(self): |
| 621 | # Verify the code object is created. |
| 622 | code_object = self.loader.get_code(self.name) |
| 623 | self.verify_code(code_object) |
| 624 | |
| 625 | def test_load_module(self): |
| 626 | # Loading a module should set __name__, __loader__, __package__, |
| 627 | # __path__ (for packages), __file__, and __cached__. |
| 628 | # The module should also be put into sys.modules. |
| 629 | with util.uncache(self.name): |
| 630 | module = self.loader.load_module(self.name) |
| 631 | self.verify_module(module) |
| 632 | self.assertEqual(module.__path__, [os.path.dirname(self.path)]) |
Eric V. Smith | faae3ad | 2012-06-27 15:26:26 -0400 | [diff] [blame] | 633 | self.assertIn(self.name, sys.modules) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 634 | |
| 635 | def test_package_settings(self): |
| 636 | # __package__ needs to be set, while __path__ is set on if the module |
| 637 | # is a package. |
| 638 | # Testing the values for a package are covered by test_load_module. |
| 639 | self.setUp(is_package=False) |
| 640 | with util.uncache(self.name): |
| 641 | module = self.loader.load_module(self.name) |
| 642 | self.verify_module(module) |
| 643 | self.assertTrue(not hasattr(module, '__path__')) |
| 644 | |
| 645 | def test_get_source_encoding(self): |
| 646 | # Source is considered encoded in UTF-8 by default unless otherwise |
| 647 | # specified by an encoding line. |
| 648 | source = "_ = 'ü'" |
| 649 | self.loader.source = source.encode('utf-8') |
| 650 | returned_source = self.loader.get_source(self.name) |
| 651 | self.assertEqual(returned_source, source) |
| 652 | source = "# coding: latin-1\n_ = ü" |
| 653 | self.loader.source = source.encode('latin-1') |
| 654 | returned_source = self.loader.get_source(self.name) |
| 655 | self.assertEqual(returned_source, source) |
| 656 | |
| 657 | |
| 658 | @unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") |
| 659 | class SourceLoaderBytecodeTests(SourceLoaderTestHarness): |
| 660 | |
| 661 | """Test importlib.abc.SourceLoader's use of bytecode. |
| 662 | |
| 663 | Source-only testing handled by SourceOnlyLoaderTests. |
| 664 | |
| 665 | """ |
| 666 | |
| 667 | loader_mock = SourceLoaderMock |
| 668 | |
| 669 | def verify_code(self, code_object, *, bytecode_written=False): |
| 670 | super().verify_code(code_object) |
| 671 | if bytecode_written: |
| 672 | self.assertIn(self.cached, self.loader.written) |
| 673 | data = bytearray(imp.get_magic()) |
Brett Cannon | c264e3e | 2012-01-25 18:58:03 -0500 | [diff] [blame] | 674 | data.extend(importlib._w_long(self.loader.source_mtime)) |
| 675 | data.extend(importlib._w_long(self.loader.source_size)) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 676 | data.extend(marshal.dumps(code_object)) |
| 677 | self.assertEqual(self.loader.written[self.cached], bytes(data)) |
| 678 | |
| 679 | def test_code_with_everything(self): |
| 680 | # When everything should work. |
| 681 | code_object = self.loader.get_code(self.name) |
| 682 | self.verify_code(code_object) |
| 683 | |
| 684 | def test_no_bytecode(self): |
| 685 | # If no bytecode exists then move on to the source. |
| 686 | self.loader.bytecode_path = "<does not exist>" |
| 687 | # Sanity check |
| 688 | with self.assertRaises(IOError): |
| 689 | bytecode_path = imp.cache_from_source(self.path) |
| 690 | self.loader.get_data(bytecode_path) |
| 691 | code_object = self.loader.get_code(self.name) |
| 692 | self.verify_code(code_object, bytecode_written=True) |
| 693 | |
| 694 | def test_code_bad_timestamp(self): |
| 695 | # Bytecode is only used when the timestamp matches the source EXACTLY. |
| 696 | for source_mtime in (0, 2): |
| 697 | assert source_mtime != self.loader.source_mtime |
| 698 | original = self.loader.source_mtime |
| 699 | self.loader.source_mtime = source_mtime |
| 700 | # If bytecode is used then EOFError would be raised by marshal. |
| 701 | self.loader.bytecode = self.loader.bytecode[8:] |
| 702 | code_object = self.loader.get_code(self.name) |
| 703 | self.verify_code(code_object, bytecode_written=True) |
| 704 | self.loader.source_mtime = original |
| 705 | |
| 706 | def test_code_bad_magic(self): |
| 707 | # Skip over bytecode with a bad magic number. |
| 708 | self.setUp(magic=b'0000') |
| 709 | # If bytecode is used then EOFError would be raised by marshal. |
| 710 | self.loader.bytecode = self.loader.bytecode[8:] |
| 711 | code_object = self.loader.get_code(self.name) |
| 712 | self.verify_code(code_object, bytecode_written=True) |
| 713 | |
| 714 | def test_dont_write_bytecode(self): |
| 715 | # Bytecode is not written if sys.dont_write_bytecode is true. |
| 716 | # Can assume it is false already thanks to the skipIf class decorator. |
| 717 | try: |
| 718 | sys.dont_write_bytecode = True |
| 719 | self.loader.bytecode_path = "<does not exist>" |
| 720 | code_object = self.loader.get_code(self.name) |
| 721 | self.assertNotIn(self.cached, self.loader.written) |
| 722 | finally: |
| 723 | sys.dont_write_bytecode = False |
| 724 | |
| 725 | def test_no_set_data(self): |
| 726 | # If set_data is not defined, one can still read bytecode. |
| 727 | self.setUp(magic=b'0000') |
| 728 | original_set_data = self.loader.__class__.set_data |
| 729 | try: |
| 730 | del self.loader.__class__.set_data |
| 731 | code_object = self.loader.get_code(self.name) |
| 732 | self.verify_code(code_object) |
| 733 | finally: |
| 734 | self.loader.__class__.set_data = original_set_data |
| 735 | |
| 736 | def test_set_data_raises_exceptions(self): |
| 737 | # Raising NotImplementedError or IOError is okay for set_data. |
| 738 | def raise_exception(exc): |
| 739 | def closure(*args, **kwargs): |
| 740 | raise exc |
| 741 | return closure |
| 742 | |
| 743 | self.setUp(magic=b'0000') |
Brett Cannon | 0cf9e6a | 2010-06-28 04:57:24 +0000 | [diff] [blame] | 744 | self.loader.set_data = raise_exception(NotImplementedError) |
| 745 | code_object = self.loader.get_code(self.name) |
| 746 | self.verify_code(code_object) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 747 | |
Brett Cannon | 418182e | 2010-07-03 22:32:41 +0000 | [diff] [blame] | 748 | |
| 749 | class SourceLoaderGetSourceTests(unittest.TestCase): |
| 750 | |
| 751 | """Tests for importlib.abc.SourceLoader.get_source().""" |
| 752 | |
| 753 | def test_default_encoding(self): |
| 754 | # Should have no problems with UTF-8 text. |
| 755 | name = 'mod' |
| 756 | mock = SourceOnlyLoaderMock('mod.file') |
| 757 | source = 'x = "ü"' |
| 758 | mock.source = source.encode('utf-8') |
| 759 | returned_source = mock.get_source(name) |
| 760 | self.assertEqual(returned_source, source) |
| 761 | |
| 762 | def test_decoded_source(self): |
| 763 | # Decoding should work. |
| 764 | name = 'mod' |
| 765 | mock = SourceOnlyLoaderMock("mod.file") |
| 766 | source = "# coding: Latin-1\nx='ü'" |
| 767 | assert source.encode('latin-1') != source.encode('utf-8') |
| 768 | mock.source = source.encode('latin-1') |
| 769 | returned_source = mock.get_source(name) |
| 770 | self.assertEqual(returned_source, source) |
| 771 | |
| 772 | def test_universal_newlines(self): |
| 773 | # PEP 302 says universal newlines should be used. |
| 774 | name = 'mod' |
| 775 | mock = SourceOnlyLoaderMock('mod.file') |
| 776 | source = "x = 42\r\ny = -13\r\n" |
| 777 | mock.source = source.encode('utf-8') |
| 778 | expect = io.IncrementalNewlineDecoder(None, True).decode(source) |
| 779 | self.assertEqual(mock.get_source(name), expect) |
| 780 | |
Nick Coghlan | 8a9080f | 2012-08-02 21:26:03 +1000 | [diff] [blame] | 781 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 782 | class AbstractMethodImplTests(unittest.TestCase): |
| 783 | |
| 784 | """Test the concrete abstractmethod implementations.""" |
| 785 | |
Nick Coghlan | 8a9080f | 2012-08-02 21:26:03 +1000 | [diff] [blame] | 786 | class MetaPathFinder(abc.MetaPathFinder): |
| 787 | def find_module(self, fullname, path): |
| 788 | super().find_module(fullname, path) |
| 789 | |
| 790 | class PathEntryFinder(abc.PathEntryFinder): |
| 791 | def find_module(self, _): |
| 792 | super().find_module(_) |
| 793 | |
| 794 | def find_loader(self, _): |
| 795 | super().find_loader(_) |
| 796 | |
| 797 | class Finder(abc.Finder): |
| 798 | def find_module(self, fullname, path): |
| 799 | super().find_module(fullname, path) |
| 800 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 801 | class Loader(abc.Loader): |
| 802 | def load_module(self, fullname): |
| 803 | super().load_module(fullname) |
Barry Warsaw | 0efcf99 | 2012-07-31 17:52:32 -0400 | [diff] [blame] | 804 | def module_repr(self, module): |
| 805 | super().module_repr(module) |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 806 | |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 807 | class ResourceLoader(Loader, abc.ResourceLoader): |
| 808 | def get_data(self, _): |
| 809 | super().get_data(_) |
| 810 | |
| 811 | class InspectLoader(Loader, abc.InspectLoader): |
| 812 | def is_package(self, _): |
| 813 | super().is_package(_) |
| 814 | |
| 815 | def get_code(self, _): |
| 816 | super().get_code(_) |
| 817 | |
| 818 | def get_source(self, _): |
| 819 | super().get_source(_) |
| 820 | |
| 821 | class ExecutionLoader(InspectLoader, abc.ExecutionLoader): |
| 822 | def get_filename(self, _): |
| 823 | super().get_filename(_) |
| 824 | |
| 825 | class SourceLoader(ResourceLoader, ExecutionLoader, abc.SourceLoader): |
| 826 | pass |
| 827 | |
| 828 | class PyLoader(ResourceLoader, InspectLoader, abc.PyLoader): |
| 829 | def source_path(self, _): |
| 830 | super().source_path(_) |
| 831 | |
| 832 | class PyPycLoader(PyLoader, abc.PyPycLoader): |
| 833 | def bytecode_path(self, _): |
| 834 | super().bytecode_path(_) |
| 835 | |
| 836 | def source_mtime(self, _): |
| 837 | super().source_mtime(_) |
| 838 | |
| 839 | def write_bytecode(self, _, _2): |
| 840 | super().write_bytecode(_, _2) |
| 841 | |
| 842 | def raises_NotImplementedError(self, ins, *args): |
| 843 | for method_name in args: |
| 844 | method = getattr(ins, method_name) |
| 845 | arg_count = len(inspect.getfullargspec(method)[0]) - 1 |
| 846 | args = [''] * arg_count |
| 847 | try: |
| 848 | method(*args) |
| 849 | except NotImplementedError: |
| 850 | pass |
| 851 | else: |
| 852 | msg = "{}.{} did not raise NotImplementedError" |
| 853 | self.fail(msg.format(ins.__class__.__name__, method_name)) |
| 854 | |
| 855 | def test_Loader(self): |
| 856 | self.raises_NotImplementedError(self.Loader(), 'load_module') |
| 857 | |
Brett Cannon | 61b1425 | 2010-07-03 21:48:25 +0000 | [diff] [blame] | 858 | # XXX misplaced; should be somewhere else |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 859 | def test_Finder(self): |
| 860 | self.raises_NotImplementedError(self.Finder(), 'find_module') |
| 861 | |
| 862 | def test_ResourceLoader(self): |
| 863 | self.raises_NotImplementedError(self.ResourceLoader(), 'load_module', |
| 864 | 'get_data') |
| 865 | |
| 866 | def test_InspectLoader(self): |
| 867 | self.raises_NotImplementedError(self.InspectLoader(), 'load_module', |
| 868 | 'is_package', 'get_code', 'get_source') |
| 869 | |
| 870 | def test_ExecutionLoader(self): |
| 871 | self.raises_NotImplementedError(self.ExecutionLoader(), 'load_module', |
| 872 | 'is_package', 'get_code', 'get_source', |
| 873 | 'get_filename') |
| 874 | |
| 875 | def test_SourceLoader(self): |
| 876 | ins = self.SourceLoader() |
| 877 | # Required abstractmethods. |
| 878 | self.raises_NotImplementedError(ins, 'get_filename', 'get_data') |
| 879 | # Optional abstractmethods. |
Antoine Pitrou | 5136ac0 | 2012-01-13 18:52:16 +0100 | [diff] [blame] | 880 | self.raises_NotImplementedError(ins,'path_stats', 'set_data') |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 881 | |
| 882 | def test_PyLoader(self): |
| 883 | self.raises_NotImplementedError(self.PyLoader(), 'source_path', |
| 884 | 'get_data', 'is_package') |
| 885 | |
| 886 | def test_PyPycLoader(self): |
| 887 | self.raises_NotImplementedError(self.PyPycLoader(), 'source_path', |
| 888 | 'source_mtime', 'bytecode_path', |
| 889 | 'write_bytecode') |
| 890 | |
| 891 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 892 | def test_main(): |
| 893 | from test.support import run_unittest |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 894 | run_unittest(PyLoaderTests, PyLoaderCompatTests, |
Brett Cannon | 418182e | 2010-07-03 22:32:41 +0000 | [diff] [blame] | 895 | PyLoaderInterfaceTests, |
Brett Cannon | 6919427 | 2009-07-20 04:23:48 +0000 | [diff] [blame] | 896 | PyPycLoaderTests, PyPycLoaderInterfaceTests, |
| 897 | SkipWritingBytecodeTests, RegeneratedBytecodeTests, |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 898 | BadBytecodeFailureTests, MissingPathsTests, |
| 899 | SourceOnlyLoaderTests, |
| 900 | SourceLoaderBytecodeTests, |
Brett Cannon | 418182e | 2010-07-03 22:32:41 +0000 | [diff] [blame] | 901 | SourceLoaderGetSourceTests, |
Brett Cannon | f23e374 | 2010-06-27 23:57:46 +0000 | [diff] [blame] | 902 | AbstractMethodImplTests) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 903 | |
| 904 | |
| 905 | if __name__ == '__main__': |
| 906 | test_main() |