python3.2
3.2.2
|
00001 import importlib 00002 from importlib import abc 00003 00004 from .. import abc as testing_abc 00005 from .. import util 00006 from . import util as source_util 00007 00008 import imp 00009 import inspect 00010 import io 00011 import marshal 00012 import os 00013 import sys 00014 import types 00015 import unittest 00016 import warnings 00017 00018 00019 class SourceOnlyLoaderMock(abc.SourceLoader): 00020 00021 # Globals that should be defined for all modules. 00022 source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " 00023 b"repr(__loader__)])") 00024 00025 def __init__(self, path): 00026 self.path = path 00027 00028 def get_data(self, path): 00029 assert self.path == path 00030 return self.source 00031 00032 def get_filename(self, fullname): 00033 return self.path 00034 00035 00036 class SourceLoaderMock(SourceOnlyLoaderMock): 00037 00038 source_mtime = 1 00039 00040 def __init__(self, path, magic=imp.get_magic()): 00041 super().__init__(path) 00042 self.bytecode_path = imp.cache_from_source(self.path) 00043 data = bytearray(magic) 00044 data.extend(marshal._w_long(self.source_mtime)) 00045 code_object = compile(self.source, self.path, 'exec', 00046 dont_inherit=True) 00047 data.extend(marshal.dumps(code_object)) 00048 self.bytecode = bytes(data) 00049 self.written = {} 00050 00051 def get_data(self, path): 00052 if path == self.path: 00053 return super().get_data(path) 00054 elif path == self.bytecode_path: 00055 return self.bytecode 00056 else: 00057 raise IOError 00058 00059 def path_mtime(self, path): 00060 assert path == self.path 00061 return self.source_mtime 00062 00063 def set_data(self, path, data): 00064 self.written[path] = bytes(data) 00065 return path == self.bytecode_path 00066 00067 00068 class PyLoaderMock(abc.PyLoader): 00069 00070 # Globals that should be defined for all modules. 00071 source = (b"_ = '::'.join([__name__, __file__, __package__, " 00072 b"repr(__loader__)])") 00073 00074 def __init__(self, data): 00075 """Take a dict of 'module_name: path' pairings. 00076 00077 Paths should have no file extension, allowing packages to be denoted by 00078 ending in '__init__'. 00079 00080 """ 00081 self.module_paths = data 00082 self.path_to_module = {val:key for key,val in data.items()} 00083 00084 def get_data(self, path): 00085 if path not in self.path_to_module: 00086 raise IOError 00087 return self.source 00088 00089 def is_package(self, name): 00090 filename = os.path.basename(self.get_filename(name)) 00091 return os.path.splitext(filename)[0] == '__init__' 00092 00093 def source_path(self, name): 00094 try: 00095 return self.module_paths[name] 00096 except KeyError: 00097 raise ImportError 00098 00099 def get_filename(self, name): 00100 """Silence deprecation warning.""" 00101 with warnings.catch_warnings(record=True) as w: 00102 warnings.simplefilter("always") 00103 path = super().get_filename(name) 00104 assert len(w) == 1 00105 assert issubclass(w[0].category, PendingDeprecationWarning) 00106 return path 00107 00108 00109 class PyLoaderCompatMock(PyLoaderMock): 00110 00111 """Mock that matches what is suggested to have a loader that is compatible 00112 from Python 3.1 onwards.""" 00113 00114 def get_filename(self, fullname): 00115 try: 00116 return self.module_paths[fullname] 00117 except KeyError: 00118 raise ImportError 00119 00120 def source_path(self, fullname): 00121 try: 00122 return self.get_filename(fullname) 00123 except ImportError: 00124 return None 00125 00126 00127 class PyPycLoaderMock(abc.PyPycLoader, PyLoaderMock): 00128 00129 default_mtime = 1 00130 00131 def __init__(self, source, bc={}): 00132 """Initialize mock. 00133 00134 'bc' is a dict keyed on a module's name. The value is dict with 00135 possible keys of 'path', 'mtime', 'magic', and 'bc'. Except for 'path', 00136 each of those keys control if any part of created bytecode is to 00137 deviate from default values. 00138 00139 """ 00140 super().__init__(source) 00141 self.module_bytecode = {} 00142 self.path_to_bytecode = {} 00143 self.bytecode_to_path = {} 00144 for name, data in bc.items(): 00145 self.path_to_bytecode[data['path']] = name 00146 self.bytecode_to_path[name] = data['path'] 00147 magic = data.get('magic', imp.get_magic()) 00148 mtime = importlib._w_long(data.get('mtime', self.default_mtime)) 00149 if 'bc' in data: 00150 bc = data['bc'] 00151 else: 00152 bc = self.compile_bc(name) 00153 self.module_bytecode[name] = magic + mtime + bc 00154 00155 def compile_bc(self, name): 00156 source_path = self.module_paths.get(name, '<test>') or '<test>' 00157 code = compile(self.source, source_path, 'exec') 00158 return marshal.dumps(code) 00159 00160 def source_mtime(self, name): 00161 if name in self.module_paths: 00162 return self.default_mtime 00163 elif name in self.module_bytecode: 00164 return None 00165 else: 00166 raise ImportError 00167 00168 def bytecode_path(self, name): 00169 try: 00170 return self.bytecode_to_path[name] 00171 except KeyError: 00172 if name in self.module_paths: 00173 return None 00174 else: 00175 raise ImportError 00176 00177 def write_bytecode(self, name, bytecode): 00178 self.module_bytecode[name] = bytecode 00179 return True 00180 00181 def get_data(self, path): 00182 if path in self.path_to_module: 00183 return super().get_data(path) 00184 elif path in self.path_to_bytecode: 00185 name = self.path_to_bytecode[path] 00186 return self.module_bytecode[name] 00187 else: 00188 raise IOError 00189 00190 def is_package(self, name): 00191 try: 00192 return super().is_package(name) 00193 except TypeError: 00194 return '__init__' in self.bytecode_to_path[name] 00195 00196 def get_code(self, name): 00197 with warnings.catch_warnings(record=True) as w: 00198 warnings.simplefilter("always") 00199 code_object = super().get_code(name) 00200 assert len(w) == 1 00201 assert issubclass(w[0].category, PendingDeprecationWarning) 00202 return code_object 00203 00204 class PyLoaderTests(testing_abc.LoaderTests): 00205 00206 """Tests for importlib.abc.PyLoader.""" 00207 00208 mocker = PyLoaderMock 00209 00210 def eq_attrs(self, ob, **kwargs): 00211 for attr, val in kwargs.items(): 00212 found = getattr(ob, attr) 00213 self.assertEqual(found, val, 00214 "{} attribute: {} != {}".format(attr, found, val)) 00215 00216 def test_module(self): 00217 name = '<module>' 00218 path = os.path.join('', 'path', 'to', 'module') 00219 mock = self.mocker({name: path}) 00220 with util.uncache(name): 00221 module = mock.load_module(name) 00222 self.assertTrue(name in sys.modules) 00223 self.eq_attrs(module, __name__=name, __file__=path, __package__='', 00224 __loader__=mock) 00225 self.assertTrue(not hasattr(module, '__path__')) 00226 return mock, name 00227 00228 def test_package(self): 00229 name = '<pkg>' 00230 path = os.path.join('path', 'to', name, '__init__') 00231 mock = self.mocker({name: path}) 00232 with util.uncache(name): 00233 module = mock.load_module(name) 00234 self.assertTrue(name in sys.modules) 00235 self.eq_attrs(module, __name__=name, __file__=path, 00236 __path__=[os.path.dirname(path)], __package__=name, 00237 __loader__=mock) 00238 return mock, name 00239 00240 def test_lacking_parent(self): 00241 name = 'pkg.mod' 00242 path = os.path.join('path', 'to', 'pkg', 'mod') 00243 mock = self.mocker({name: path}) 00244 with util.uncache(name): 00245 module = mock.load_module(name) 00246 self.assertIn(name, sys.modules) 00247 self.eq_attrs(module, __name__=name, __file__=path, __package__='pkg', 00248 __loader__=mock) 00249 self.assertFalse(hasattr(module, '__path__')) 00250 return mock, name 00251 00252 def test_module_reuse(self): 00253 name = 'mod' 00254 path = os.path.join('path', 'to', 'mod') 00255 module = imp.new_module(name) 00256 mock = self.mocker({name: path}) 00257 with util.uncache(name): 00258 sys.modules[name] = module 00259 loaded_module = mock.load_module(name) 00260 self.assertTrue(loaded_module is module) 00261 self.assertTrue(sys.modules[name] is module) 00262 return mock, name 00263 00264 def test_state_after_failure(self): 00265 name = "mod" 00266 module = imp.new_module(name) 00267 module.blah = None 00268 mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) 00269 mock.source = b"1/0" 00270 with util.uncache(name): 00271 sys.modules[name] = module 00272 with self.assertRaises(ZeroDivisionError): 00273 mock.load_module(name) 00274 self.assertTrue(sys.modules[name] is module) 00275 self.assertTrue(hasattr(module, 'blah')) 00276 return mock 00277 00278 def test_unloadable(self): 00279 name = "mod" 00280 mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) 00281 mock.source = b"1/0" 00282 with util.uncache(name): 00283 with self.assertRaises(ZeroDivisionError): 00284 mock.load_module(name) 00285 self.assertTrue(name not in sys.modules) 00286 return mock 00287 00288 00289 class PyLoaderCompatTests(PyLoaderTests): 00290 00291 """Test that the suggested code to make a loader that is compatible from 00292 Python 3.1 forward works.""" 00293 00294 mocker = PyLoaderCompatMock 00295 00296 00297 class PyLoaderInterfaceTests(unittest.TestCase): 00298 00299 """Tests for importlib.abc.PyLoader to make sure that when source_path() 00300 doesn't return a path everything works as expected.""" 00301 00302 def test_no_source_path(self): 00303 # No source path should lead to ImportError. 00304 name = 'mod' 00305 mock = PyLoaderMock({}) 00306 with util.uncache(name), self.assertRaises(ImportError): 00307 mock.load_module(name) 00308 00309 def test_source_path_is_None(self): 00310 name = 'mod' 00311 mock = PyLoaderMock({name: None}) 00312 with util.uncache(name), self.assertRaises(ImportError): 00313 mock.load_module(name) 00314 00315 def test_get_filename_with_source_path(self): 00316 # get_filename() should return what source_path() returns. 00317 name = 'mod' 00318 path = os.path.join('path', 'to', 'source') 00319 mock = PyLoaderMock({name: path}) 00320 with util.uncache(name): 00321 self.assertEqual(mock.get_filename(name), path) 00322 00323 def test_get_filename_no_source_path(self): 00324 # get_filename() should raise ImportError if source_path returns None. 00325 name = 'mod' 00326 mock = PyLoaderMock({name: None}) 00327 with util.uncache(name), self.assertRaises(ImportError): 00328 mock.get_filename(name) 00329 00330 00331 class PyPycLoaderTests(PyLoaderTests): 00332 00333 """Tests for importlib.abc.PyPycLoader.""" 00334 00335 mocker = PyPycLoaderMock 00336 00337 @source_util.writes_bytecode_files 00338 def verify_bytecode(self, mock, name): 00339 assert name in mock.module_paths 00340 self.assertIn(name, mock.module_bytecode) 00341 magic = mock.module_bytecode[name][:4] 00342 self.assertEqual(magic, imp.get_magic()) 00343 mtime = importlib._r_long(mock.module_bytecode[name][4:8]) 00344 self.assertEqual(mtime, 1) 00345 bc = mock.module_bytecode[name][8:] 00346 self.assertEqual(bc, mock.compile_bc(name)) 00347 00348 def test_module(self): 00349 mock, name = super().test_module() 00350 self.verify_bytecode(mock, name) 00351 00352 def test_package(self): 00353 mock, name = super().test_package() 00354 self.verify_bytecode(mock, name) 00355 00356 def test_lacking_parent(self): 00357 mock, name = super().test_lacking_parent() 00358 self.verify_bytecode(mock, name) 00359 00360 def test_module_reuse(self): 00361 mock, name = super().test_module_reuse() 00362 self.verify_bytecode(mock, name) 00363 00364 def test_state_after_failure(self): 00365 super().test_state_after_failure() 00366 00367 def test_unloadable(self): 00368 super().test_unloadable() 00369 00370 00371 class PyPycLoaderInterfaceTests(unittest.TestCase): 00372 00373 """Test for the interface of importlib.abc.PyPycLoader.""" 00374 00375 def get_filename_check(self, src_path, bc_path, expect): 00376 name = 'mod' 00377 mock = PyPycLoaderMock({name: src_path}, {name: {'path': bc_path}}) 00378 with util.uncache(name): 00379 assert mock.source_path(name) == src_path 00380 assert mock.bytecode_path(name) == bc_path 00381 self.assertEqual(mock.get_filename(name), expect) 00382 00383 def test_filename_with_source_bc(self): 00384 # When source and bytecode paths present, return the source path. 00385 self.get_filename_check('source_path', 'bc_path', 'source_path') 00386 00387 def test_filename_with_source_no_bc(self): 00388 # With source but no bc, return source path. 00389 self.get_filename_check('source_path', None, 'source_path') 00390 00391 def test_filename_with_no_source_bc(self): 00392 # With not source but bc, return the bc path. 00393 self.get_filename_check(None, 'bc_path', 'bc_path') 00394 00395 def test_filename_with_no_source_or_bc(self): 00396 # With no source or bc, raise ImportError. 00397 name = 'mod' 00398 mock = PyPycLoaderMock({name: None}, {name: {'path': None}}) 00399 with util.uncache(name), self.assertRaises(ImportError): 00400 mock.get_filename(name) 00401 00402 00403 class SkipWritingBytecodeTests(unittest.TestCase): 00404 00405 """Test that bytecode is properly handled based on 00406 sys.dont_write_bytecode.""" 00407 00408 @source_util.writes_bytecode_files 00409 def run_test(self, dont_write_bytecode): 00410 name = 'mod' 00411 mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}) 00412 sys.dont_write_bytecode = dont_write_bytecode 00413 with util.uncache(name): 00414 mock.load_module(name) 00415 self.assertTrue((name in mock.module_bytecode) is not 00416 dont_write_bytecode) 00417 00418 def test_no_bytecode_written(self): 00419 self.run_test(True) 00420 00421 def test_bytecode_written(self): 00422 self.run_test(False) 00423 00424 00425 class RegeneratedBytecodeTests(unittest.TestCase): 00426 00427 """Test that bytecode is regenerated as expected.""" 00428 00429 @source_util.writes_bytecode_files 00430 def test_different_magic(self): 00431 # A different magic number should lead to new bytecode. 00432 name = 'mod' 00433 bad_magic = b'\x00\x00\x00\x00' 00434 assert bad_magic != imp.get_magic() 00435 mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, 00436 {name: {'path': os.path.join('path', 'to', 00437 'mod.bytecode'), 00438 'magic': bad_magic}}) 00439 with util.uncache(name): 00440 mock.load_module(name) 00441 self.assertTrue(name in mock.module_bytecode) 00442 magic = mock.module_bytecode[name][:4] 00443 self.assertEqual(magic, imp.get_magic()) 00444 00445 @source_util.writes_bytecode_files 00446 def test_old_mtime(self): 00447 # Bytecode with an older mtime should be regenerated. 00448 name = 'mod' 00449 old_mtime = PyPycLoaderMock.default_mtime - 1 00450 mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, 00451 {name: {'path': 'path/to/mod.bytecode', 'mtime': old_mtime}}) 00452 with util.uncache(name): 00453 mock.load_module(name) 00454 self.assertTrue(name in mock.module_bytecode) 00455 mtime = importlib._r_long(mock.module_bytecode[name][4:8]) 00456 self.assertEqual(mtime, PyPycLoaderMock.default_mtime) 00457 00458 00459 class BadBytecodeFailureTests(unittest.TestCase): 00460 00461 """Test import failures when there is no source and parts of the bytecode 00462 is bad.""" 00463 00464 def test_bad_magic(self): 00465 # A bad magic number should lead to an ImportError. 00466 name = 'mod' 00467 bad_magic = b'\x00\x00\x00\x00' 00468 bc = {name: 00469 {'path': os.path.join('path', 'to', 'mod'), 00470 'magic': bad_magic}} 00471 mock = PyPycLoaderMock({name: None}, bc) 00472 with util.uncache(name), self.assertRaises(ImportError): 00473 mock.load_module(name) 00474 00475 def test_no_bytecode(self): 00476 # Missing code object bytecode should lead to an EOFError. 00477 name = 'mod' 00478 bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b''}} 00479 mock = PyPycLoaderMock({name: None}, bc) 00480 with util.uncache(name), self.assertRaises(EOFError): 00481 mock.load_module(name) 00482 00483 def test_bad_bytecode(self): 00484 # Malformed code object bytecode should lead to a ValueError. 00485 name = 'mod' 00486 bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b'1234'}} 00487 mock = PyPycLoaderMock({name: None}, bc) 00488 with util.uncache(name), self.assertRaises(ValueError): 00489 mock.load_module(name) 00490 00491 00492 def raise_ImportError(*args, **kwargs): 00493 raise ImportError 00494 00495 class MissingPathsTests(unittest.TestCase): 00496 00497 """Test what happens when a source or bytecode path does not exist (either 00498 from *_path returning None or raising ImportError).""" 00499 00500 def test_source_path_None(self): 00501 # Bytecode should be used when source_path returns None, along with 00502 # __file__ being set to the bytecode path. 00503 name = 'mod' 00504 bytecode_path = 'path/to/mod' 00505 mock = PyPycLoaderMock({name: None}, {name: {'path': bytecode_path}}) 00506 with util.uncache(name): 00507 module = mock.load_module(name) 00508 self.assertEqual(module.__file__, bytecode_path) 00509 00510 # Testing for bytecode_path returning None handled by all tests where no 00511 # bytecode initially exists. 00512 00513 def test_all_paths_None(self): 00514 # If all *_path methods return None, raise ImportError. 00515 name = 'mod' 00516 mock = PyPycLoaderMock({name: None}) 00517 with util.uncache(name), self.assertRaises(ImportError): 00518 mock.load_module(name) 00519 00520 def test_source_path_ImportError(self): 00521 # An ImportError from source_path should trigger an ImportError. 00522 name = 'mod' 00523 mock = PyPycLoaderMock({}, {name: {'path': os.path.join('path', 'to', 00524 'mod')}}) 00525 with util.uncache(name), self.assertRaises(ImportError): 00526 mock.load_module(name) 00527 00528 def test_bytecode_path_ImportError(self): 00529 # An ImportError from bytecode_path should trigger an ImportError. 00530 name = 'mod' 00531 mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}) 00532 bad_meth = types.MethodType(raise_ImportError, mock) 00533 mock.bytecode_path = bad_meth 00534 with util.uncache(name), self.assertRaises(ImportError): 00535 mock.load_module(name) 00536 00537 00538 class SourceLoaderTestHarness(unittest.TestCase): 00539 00540 def setUp(self, *, is_package=True, **kwargs): 00541 self.package = 'pkg' 00542 if is_package: 00543 self.path = os.path.join(self.package, '__init__.py') 00544 self.name = self.package 00545 else: 00546 module_name = 'mod' 00547 self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) 00548 self.name = '.'.join([self.package, module_name]) 00549 self.cached = imp.cache_from_source(self.path) 00550 self.loader = self.loader_mock(self.path, **kwargs) 00551 00552 def verify_module(self, module): 00553 self.assertEqual(module.__name__, self.name) 00554 self.assertEqual(module.__file__, self.path) 00555 self.assertEqual(module.__cached__, self.cached) 00556 self.assertEqual(module.__package__, self.package) 00557 self.assertEqual(module.__loader__, self.loader) 00558 values = module._.split('::') 00559 self.assertEqual(values[0], self.name) 00560 self.assertEqual(values[1], self.path) 00561 self.assertEqual(values[2], self.cached) 00562 self.assertEqual(values[3], self.package) 00563 self.assertEqual(values[4], repr(self.loader)) 00564 00565 def verify_code(self, code_object): 00566 module = imp.new_module(self.name) 00567 module.__file__ = self.path 00568 module.__cached__ = self.cached 00569 module.__package__ = self.package 00570 module.__loader__ = self.loader 00571 module.__path__ = [] 00572 exec(code_object, module.__dict__) 00573 self.verify_module(module) 00574 00575 00576 class SourceOnlyLoaderTests(SourceLoaderTestHarness): 00577 00578 """Test importlib.abc.SourceLoader for source-only loading. 00579 00580 Reload testing is subsumed by the tests for 00581 importlib.util.module_for_loader. 00582 00583 """ 00584 00585 loader_mock = SourceOnlyLoaderMock 00586 00587 def test_get_source(self): 00588 # Verify the source code is returned as a string. 00589 # If an IOError is raised by get_data then raise ImportError. 00590 expected_source = self.loader.source.decode('utf-8') 00591 self.assertEqual(self.loader.get_source(self.name), expected_source) 00592 def raise_IOError(path): 00593 raise IOError 00594 self.loader.get_data = raise_IOError 00595 with self.assertRaises(ImportError): 00596 self.loader.get_source(self.name) 00597 00598 def test_is_package(self): 00599 # Properly detect when loading a package. 00600 self.setUp(is_package=True) 00601 self.assertTrue(self.loader.is_package(self.name)) 00602 self.setUp(is_package=False) 00603 self.assertFalse(self.loader.is_package(self.name)) 00604 00605 def test_get_code(self): 00606 # Verify the code object is created. 00607 code_object = self.loader.get_code(self.name) 00608 self.verify_code(code_object) 00609 00610 def test_load_module(self): 00611 # Loading a module should set __name__, __loader__, __package__, 00612 # __path__ (for packages), __file__, and __cached__. 00613 # The module should also be put into sys.modules. 00614 with util.uncache(self.name): 00615 module = self.loader.load_module(self.name) 00616 self.verify_module(module) 00617 self.assertEqual(module.__path__, [os.path.dirname(self.path)]) 00618 self.assertTrue(self.name in sys.modules) 00619 00620 def test_package_settings(self): 00621 # __package__ needs to be set, while __path__ is set on if the module 00622 # is a package. 00623 # Testing the values for a package are covered by test_load_module. 00624 self.setUp(is_package=False) 00625 with util.uncache(self.name): 00626 module = self.loader.load_module(self.name) 00627 self.verify_module(module) 00628 self.assertTrue(not hasattr(module, '__path__')) 00629 00630 def test_get_source_encoding(self): 00631 # Source is considered encoded in UTF-8 by default unless otherwise 00632 # specified by an encoding line. 00633 source = "_ = 'ü'" 00634 self.loader.source = source.encode('utf-8') 00635 returned_source = self.loader.get_source(self.name) 00636 self.assertEqual(returned_source, source) 00637 source = "# coding: latin-1\n_ = ü" 00638 self.loader.source = source.encode('latin-1') 00639 returned_source = self.loader.get_source(self.name) 00640 self.assertEqual(returned_source, source) 00641 00642 00643 @unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") 00644 class SourceLoaderBytecodeTests(SourceLoaderTestHarness): 00645 00646 """Test importlib.abc.SourceLoader's use of bytecode. 00647 00648 Source-only testing handled by SourceOnlyLoaderTests. 00649 00650 """ 00651 00652 loader_mock = SourceLoaderMock 00653 00654 def verify_code(self, code_object, *, bytecode_written=False): 00655 super().verify_code(code_object) 00656 if bytecode_written: 00657 self.assertIn(self.cached, self.loader.written) 00658 data = bytearray(imp.get_magic()) 00659 data.extend(marshal._w_long(self.loader.source_mtime)) 00660 data.extend(marshal.dumps(code_object)) 00661 self.assertEqual(self.loader.written[self.cached], bytes(data)) 00662 00663 def test_code_with_everything(self): 00664 # When everything should work. 00665 code_object = self.loader.get_code(self.name) 00666 self.verify_code(code_object) 00667 00668 def test_no_bytecode(self): 00669 # If no bytecode exists then move on to the source. 00670 self.loader.bytecode_path = "<does not exist>" 00671 # Sanity check 00672 with self.assertRaises(IOError): 00673 bytecode_path = imp.cache_from_source(self.path) 00674 self.loader.get_data(bytecode_path) 00675 code_object = self.loader.get_code(self.name) 00676 self.verify_code(code_object, bytecode_written=True) 00677 00678 def test_code_bad_timestamp(self): 00679 # Bytecode is only used when the timestamp matches the source EXACTLY. 00680 for source_mtime in (0, 2): 00681 assert source_mtime != self.loader.source_mtime 00682 original = self.loader.source_mtime 00683 self.loader.source_mtime = source_mtime 00684 # If bytecode is used then EOFError would be raised by marshal. 00685 self.loader.bytecode = self.loader.bytecode[8:] 00686 code_object = self.loader.get_code(self.name) 00687 self.verify_code(code_object, bytecode_written=True) 00688 self.loader.source_mtime = original 00689 00690 def test_code_bad_magic(self): 00691 # Skip over bytecode with a bad magic number. 00692 self.setUp(magic=b'0000') 00693 # If bytecode is used then EOFError would be raised by marshal. 00694 self.loader.bytecode = self.loader.bytecode[8:] 00695 code_object = self.loader.get_code(self.name) 00696 self.verify_code(code_object, bytecode_written=True) 00697 00698 def test_dont_write_bytecode(self): 00699 # Bytecode is not written if sys.dont_write_bytecode is true. 00700 # Can assume it is false already thanks to the skipIf class decorator. 00701 try: 00702 sys.dont_write_bytecode = True 00703 self.loader.bytecode_path = "<does not exist>" 00704 code_object = self.loader.get_code(self.name) 00705 self.assertNotIn(self.cached, self.loader.written) 00706 finally: 00707 sys.dont_write_bytecode = False 00708 00709 def test_no_set_data(self): 00710 # If set_data is not defined, one can still read bytecode. 00711 self.setUp(magic=b'0000') 00712 original_set_data = self.loader.__class__.set_data 00713 try: 00714 del self.loader.__class__.set_data 00715 code_object = self.loader.get_code(self.name) 00716 self.verify_code(code_object) 00717 finally: 00718 self.loader.__class__.set_data = original_set_data 00719 00720 def test_set_data_raises_exceptions(self): 00721 # Raising NotImplementedError or IOError is okay for set_data. 00722 def raise_exception(exc): 00723 def closure(*args, **kwargs): 00724 raise exc 00725 return closure 00726 00727 self.setUp(magic=b'0000') 00728 self.loader.set_data = raise_exception(NotImplementedError) 00729 code_object = self.loader.get_code(self.name) 00730 self.verify_code(code_object) 00731 00732 00733 class SourceLoaderGetSourceTests(unittest.TestCase): 00734 00735 """Tests for importlib.abc.SourceLoader.get_source().""" 00736 00737 def test_default_encoding(self): 00738 # Should have no problems with UTF-8 text. 00739 name = 'mod' 00740 mock = SourceOnlyLoaderMock('mod.file') 00741 source = 'x = "ü"' 00742 mock.source = source.encode('utf-8') 00743 returned_source = mock.get_source(name) 00744 self.assertEqual(returned_source, source) 00745 00746 def test_decoded_source(self): 00747 # Decoding should work. 00748 name = 'mod' 00749 mock = SourceOnlyLoaderMock("mod.file") 00750 source = "# coding: Latin-1\nx='ü'" 00751 assert source.encode('latin-1') != source.encode('utf-8') 00752 mock.source = source.encode('latin-1') 00753 returned_source = mock.get_source(name) 00754 self.assertEqual(returned_source, source) 00755 00756 def test_universal_newlines(self): 00757 # PEP 302 says universal newlines should be used. 00758 name = 'mod' 00759 mock = SourceOnlyLoaderMock('mod.file') 00760 source = "x = 42\r\ny = -13\r\n" 00761 mock.source = source.encode('utf-8') 00762 expect = io.IncrementalNewlineDecoder(None, True).decode(source) 00763 self.assertEqual(mock.get_source(name), expect) 00764 00765 class AbstractMethodImplTests(unittest.TestCase): 00766 00767 """Test the concrete abstractmethod implementations.""" 00768 00769 class Loader(abc.Loader): 00770 def load_module(self, fullname): 00771 super().load_module(fullname) 00772 00773 class Finder(abc.Finder): 00774 def find_module(self, _): 00775 super().find_module(_) 00776 00777 class ResourceLoader(Loader, abc.ResourceLoader): 00778 def get_data(self, _): 00779 super().get_data(_) 00780 00781 class InspectLoader(Loader, abc.InspectLoader): 00782 def is_package(self, _): 00783 super().is_package(_) 00784 00785 def get_code(self, _): 00786 super().get_code(_) 00787 00788 def get_source(self, _): 00789 super().get_source(_) 00790 00791 class ExecutionLoader(InspectLoader, abc.ExecutionLoader): 00792 def get_filename(self, _): 00793 super().get_filename(_) 00794 00795 class SourceLoader(ResourceLoader, ExecutionLoader, abc.SourceLoader): 00796 pass 00797 00798 class PyLoader(ResourceLoader, InspectLoader, abc.PyLoader): 00799 def source_path(self, _): 00800 super().source_path(_) 00801 00802 class PyPycLoader(PyLoader, abc.PyPycLoader): 00803 def bytecode_path(self, _): 00804 super().bytecode_path(_) 00805 00806 def source_mtime(self, _): 00807 super().source_mtime(_) 00808 00809 def write_bytecode(self, _, _2): 00810 super().write_bytecode(_, _2) 00811 00812 def raises_NotImplementedError(self, ins, *args): 00813 for method_name in args: 00814 method = getattr(ins, method_name) 00815 arg_count = len(inspect.getfullargspec(method)[0]) - 1 00816 args = [''] * arg_count 00817 try: 00818 method(*args) 00819 except NotImplementedError: 00820 pass 00821 else: 00822 msg = "{}.{} did not raise NotImplementedError" 00823 self.fail(msg.format(ins.__class__.__name__, method_name)) 00824 00825 def test_Loader(self): 00826 self.raises_NotImplementedError(self.Loader(), 'load_module') 00827 00828 # XXX misplaced; should be somewhere else 00829 def test_Finder(self): 00830 self.raises_NotImplementedError(self.Finder(), 'find_module') 00831 00832 def test_ResourceLoader(self): 00833 self.raises_NotImplementedError(self.ResourceLoader(), 'load_module', 00834 'get_data') 00835 00836 def test_InspectLoader(self): 00837 self.raises_NotImplementedError(self.InspectLoader(), 'load_module', 00838 'is_package', 'get_code', 'get_source') 00839 00840 def test_ExecutionLoader(self): 00841 self.raises_NotImplementedError(self.ExecutionLoader(), 'load_module', 00842 'is_package', 'get_code', 'get_source', 00843 'get_filename') 00844 00845 def test_SourceLoader(self): 00846 ins = self.SourceLoader() 00847 # Required abstractmethods. 00848 self.raises_NotImplementedError(ins, 'get_filename', 'get_data') 00849 # Optional abstractmethods. 00850 self.raises_NotImplementedError(ins,'path_mtime', 'set_data') 00851 00852 def test_PyLoader(self): 00853 self.raises_NotImplementedError(self.PyLoader(), 'source_path', 00854 'get_data', 'is_package') 00855 00856 def test_PyPycLoader(self): 00857 self.raises_NotImplementedError(self.PyPycLoader(), 'source_path', 00858 'source_mtime', 'bytecode_path', 00859 'write_bytecode') 00860 00861 00862 def test_main(): 00863 from test.support import run_unittest 00864 run_unittest(PyLoaderTests, PyLoaderCompatTests, 00865 PyLoaderInterfaceTests, 00866 PyPycLoaderTests, PyPycLoaderInterfaceTests, 00867 SkipWritingBytecodeTests, RegeneratedBytecodeTests, 00868 BadBytecodeFailureTests, MissingPathsTests, 00869 SourceOnlyLoaderTests, 00870 SourceLoaderBytecodeTests, 00871 SourceLoaderGetSourceTests, 00872 AbstractMethodImplTests) 00873 00874 00875 if __name__ == '__main__': 00876 test_main()