blob: 0d0bcd1b6a286b655bae72e7ea9611eb7e9b4f1b [file] [log] [blame]
Brett Cannon100883f2013-04-09 16:59:39 -04001import importlib
Brett Cannonef888022013-06-15 18:39:21 -04002import importlib.util
Brett Cannon2a922ed2009-03-09 03:35:50 +00003from importlib import abc
4from importlib import machinery
Brett Cannon100883f2013-04-09 16:59:39 -04005
Brett Cannon0dbb4c72013-05-31 18:56:47 -04006import contextlib
Brett Cannon64ef00f2009-07-20 03:19:18 +00007import inspect
Brett Cannon100883f2013-04-09 16:59:39 -04008import io
9import marshal
10import os
11import sys
Brett Cannon0dbb4c72013-05-31 18:56:47 -040012from test import support
Brett Cannonef888022013-06-15 18:39:21 -040013import types
Brett Cannon2a922ed2009-03-09 03:35:50 +000014import unittest
Brett Cannon3b62ca82013-05-27 21:11:04 -040015from unittest import mock
Brett Cannon2a922ed2009-03-09 03:35:50 +000016
Brett Cannon100883f2013-04-09 16:59:39 -040017from . import util
Brett Cannon2a922ed2009-03-09 03:35:50 +000018
Brett Cannon9ffe85e2013-05-26 16:45:10 -040019##### Inheritance ##############################################################
Brett Cannon64ef00f2009-07-20 03:19:18 +000020class InheritanceTests:
Brett Cannon2a922ed2009-03-09 03:35:50 +000021
Brett Cannon64ef00f2009-07-20 03:19:18 +000022 """Test that the specified class is a subclass/superclass of the expected
23 classes."""
Brett Cannon2a922ed2009-03-09 03:35:50 +000024
Brett Cannon64ef00f2009-07-20 03:19:18 +000025 subclasses = []
26 superclasses = []
Brett Cannon2a922ed2009-03-09 03:35:50 +000027
Brett Cannon64ef00f2009-07-20 03:19:18 +000028 def __init__(self, *args, **kwargs):
29 super().__init__(*args, **kwargs)
30 assert self.subclasses or self.superclasses, self.__class__
31 self.__test = getattr(abc, self.__class__.__name__)
Brett Cannon2a922ed2009-03-09 03:35:50 +000032
Brett Cannon64ef00f2009-07-20 03:19:18 +000033 def test_subclasses(self):
34 # Test that the expected subclasses inherit.
35 for subclass in self.subclasses:
36 self.assertTrue(issubclass(subclass, self.__test),
37 "{0} is not a subclass of {1}".format(subclass, self.__test))
38
39 def test_superclasses(self):
40 # Test that the class inherits from the expected superclasses.
41 for superclass in self.superclasses:
42 self.assertTrue(issubclass(self.__test, superclass),
43 "{0} is not a superclass of {1}".format(superclass, self.__test))
44
45
Nick Coghlan8a9080f2012-08-02 21:26:03 +100046class MetaPathFinder(InheritanceTests, unittest.TestCase):
Brett Cannon64ef00f2009-07-20 03:19:18 +000047
Nick Coghlan8a9080f2012-08-02 21:26:03 +100048 superclasses = [abc.Finder]
Brett Cannon64ef00f2009-07-20 03:19:18 +000049 subclasses = [machinery.BuiltinImporter, machinery.FrozenImporter,
Nick Coghlanff794862012-08-02 21:45:24 +100050 machinery.PathFinder, machinery.WindowsRegistryFinder]
Brett Cannon64ef00f2009-07-20 03:19:18 +000051
Brett Cannonf4dc9202012-08-10 12:21:12 -040052
Nick Coghlan8a9080f2012-08-02 21:26:03 +100053class PathEntryFinder(InheritanceTests, unittest.TestCase):
54
55 superclasses = [abc.Finder]
56 subclasses = [machinery.FileFinder]
Brett Cannon64ef00f2009-07-20 03:19:18 +000057
Brett Cannonf4dc9202012-08-10 12:21:12 -040058
Brett Cannon64ef00f2009-07-20 03:19:18 +000059class ResourceLoader(InheritanceTests, unittest.TestCase):
60
61 superclasses = [abc.Loader]
62
63
64class InspectLoader(InheritanceTests, unittest.TestCase):
65
66 superclasses = [abc.Loader]
Andrew Svetlov90a654b2012-11-05 09:34:46 +020067 subclasses = [machinery.BuiltinImporter,
Brett Cannon938d44d2012-04-22 19:58:33 -040068 machinery.FrozenImporter, machinery.ExtensionFileLoader]
Brett Cannon64ef00f2009-07-20 03:19:18 +000069
70
Brett Cannon69194272009-07-20 04:23:48 +000071class ExecutionLoader(InheritanceTests, unittest.TestCase):
72
73 superclasses = [abc.InspectLoader]
Brett Cannon69194272009-07-20 04:23:48 +000074
75
Brett Cannon938d44d2012-04-22 19:58:33 -040076class FileLoader(InheritanceTests, unittest.TestCase):
77
78 superclasses = [abc.ResourceLoader, abc.ExecutionLoader]
Marc-Andre Lemburg4fe29c92012-04-25 02:31:37 +020079 subclasses = [machinery.SourceFileLoader, machinery.SourcelessFileLoader]
Brett Cannon938d44d2012-04-22 19:58:33 -040080
81
Brett Cannonb7183d82010-06-28 05:46:25 +000082class SourceLoader(InheritanceTests, unittest.TestCase):
83
84 superclasses = [abc.ResourceLoader, abc.ExecutionLoader]
Brett Cannon938d44d2012-04-22 19:58:33 -040085 subclasses = [machinery.SourceFileLoader]
Brett Cannonb7183d82010-06-28 05:46:25 +000086
87
Brett Cannon9ffe85e2013-05-26 16:45:10 -040088##### Default return values ####################################################
Brett Cannon100883f2013-04-09 16:59:39 -040089class MetaPathFinderSubclass(abc.MetaPathFinder):
90
91 def find_module(self, fullname, path):
92 return super().find_module(fullname, path)
93
94
95class MetaPathFinderDefaultsTests(unittest.TestCase):
96
97 ins = MetaPathFinderSubclass()
98
99 def test_find_module(self):
100 # Default should return None.
101 self.assertIsNone(self.ins.find_module('something', None))
102
103 def test_invalidate_caches(self):
104 # Calling the method is a no-op.
105 self.ins.invalidate_caches()
106
107
108class PathEntryFinderSubclass(abc.PathEntryFinder):
109
110 def find_loader(self, fullname):
111 return super().find_loader(fullname)
112
113
114class PathEntryFinderDefaultsTests(unittest.TestCase):
115
116 ins = PathEntryFinderSubclass()
117
118 def test_find_loader(self):
119 self.assertEqual((None, []), self.ins.find_loader('something'))
120
121 def find_module(self):
122 self.assertEqual(None, self.ins.find_module('something'))
123
124 def test_invalidate_caches(self):
125 # Should be a no-op.
126 self.ins.invalidate_caches()
127
128
129class LoaderSubclass(abc.Loader):
130
131 def load_module(self, fullname):
132 return super().load_module(fullname)
133
134
135class LoaderDefaultsTests(unittest.TestCase):
136
137 ins = LoaderSubclass()
138
139 def test_load_module(self):
140 with self.assertRaises(ImportError):
141 self.ins.load_module('something')
142
143 def test_module_repr(self):
Brett Cannonef888022013-06-15 18:39:21 -0400144 mod = types.ModuleType('blah')
Brett Cannon100883f2013-04-09 16:59:39 -0400145 with self.assertRaises(NotImplementedError):
146 self.ins.module_repr(mod)
147 original_repr = repr(mod)
148 mod.__loader__ = self.ins
149 # Should still return a proper repr.
150 self.assertTrue(repr(mod))
151
152
153class ResourceLoaderSubclass(LoaderSubclass, abc.ResourceLoader):
154
155 def get_data(self, path):
156 return super().get_data(path)
157
158
159class ResourceLoaderDefaultsTests(unittest.TestCase):
160
161 ins = ResourceLoaderSubclass()
162
163 def test_get_data(self):
164 with self.assertRaises(IOError):
165 self.ins.get_data('/some/path')
166
167
168class InspectLoaderSubclass(LoaderSubclass, abc.InspectLoader):
169
170 def is_package(self, fullname):
171 return super().is_package(fullname)
172
Brett Cannon100883f2013-04-09 16:59:39 -0400173 def get_source(self, fullname):
174 return super().get_source(fullname)
175
176
177class InspectLoaderDefaultsTests(unittest.TestCase):
178
179 ins = InspectLoaderSubclass()
180
181 def test_is_package(self):
182 with self.assertRaises(ImportError):
183 self.ins.is_package('blah')
184
Brett Cannon100883f2013-04-09 16:59:39 -0400185 def test_get_source(self):
186 with self.assertRaises(ImportError):
187 self.ins.get_source('blah')
188
189
190class ExecutionLoaderSubclass(InspectLoaderSubclass, abc.ExecutionLoader):
191
192 def get_filename(self, fullname):
193 return super().get_filename(fullname)
194
195
196class ExecutionLoaderDefaultsTests(unittest.TestCase):
197
198 ins = ExecutionLoaderSubclass()
199
200 def test_get_filename(self):
201 with self.assertRaises(ImportError):
202 self.ins.get_filename('blah')
203
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400204##### Loader concrete methods ##################################################
205class LoaderConcreteMethodTests(unittest.TestCase):
206
207 def test_init_module_attrs(self):
208 loader = LoaderSubclass()
Brett Cannonef888022013-06-15 18:39:21 -0400209 module = types.ModuleType('blah')
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400210 loader.init_module_attrs(module)
211 self.assertEqual(module.__loader__, loader)
212
Brett Cannon100883f2013-04-09 16:59:39 -0400213
Brett Cannon9ffe85e2013-05-26 16:45:10 -0400214##### InspectLoader concrete methods ###########################################
Brett Cannon3b62ca82013-05-27 21:11:04 -0400215class InspectLoaderSourceToCodeTests(unittest.TestCase):
Brett Cannon9ffe85e2013-05-26 16:45:10 -0400216
217 def source_to_module(self, data, path=None):
218 """Help with source_to_code() tests."""
Brett Cannonef888022013-06-15 18:39:21 -0400219 module = types.ModuleType('blah')
Brett Cannon9ffe85e2013-05-26 16:45:10 -0400220 loader = InspectLoaderSubclass()
221 if path is None:
222 code = loader.source_to_code(data)
223 else:
224 code = loader.source_to_code(data, path)
225 exec(code, module.__dict__)
226 return module
227
228 def test_source_to_code_source(self):
229 # Since compile() can handle strings, so should source_to_code().
230 source = 'attr = 42'
231 module = self.source_to_module(source)
232 self.assertTrue(hasattr(module, 'attr'))
233 self.assertEqual(module.attr, 42)
234
235 def test_source_to_code_bytes(self):
236 # Since compile() can handle bytes, so should source_to_code().
237 source = b'attr = 42'
238 module = self.source_to_module(source)
239 self.assertTrue(hasattr(module, 'attr'))
240 self.assertEqual(module.attr, 42)
241
242 def test_source_to_code_path(self):
243 # Specifying a path should set it for the code object.
244 path = 'path/to/somewhere'
245 loader = InspectLoaderSubclass()
246 code = loader.source_to_code('', path)
247 self.assertEqual(code.co_filename, path)
248
249 def test_source_to_code_no_path(self):
250 # Not setting a path should still work and be set to <string> since that
251 # is a pre-existing practice as a default to compile().
252 loader = InspectLoaderSubclass()
253 code = loader.source_to_code('')
254 self.assertEqual(code.co_filename, '<string>')
255
256
Brett Cannon3b62ca82013-05-27 21:11:04 -0400257class InspectLoaderGetCodeTests(unittest.TestCase):
258
259 def test_get_code(self):
260 # Test success.
Brett Cannonef888022013-06-15 18:39:21 -0400261 module = types.ModuleType('blah')
Brett Cannon3b62ca82013-05-27 21:11:04 -0400262 with mock.patch.object(InspectLoaderSubclass, 'get_source') as mocked:
263 mocked.return_value = 'attr = 42'
264 loader = InspectLoaderSubclass()
265 code = loader.get_code('blah')
266 exec(code, module.__dict__)
267 self.assertEqual(module.attr, 42)
268
269 def test_get_code_source_is_None(self):
270 # If get_source() is None then this should be None.
271 with mock.patch.object(InspectLoaderSubclass, 'get_source') as mocked:
272 mocked.return_value = None
273 loader = InspectLoaderSubclass()
274 code = loader.get_code('blah')
275 self.assertIsNone(code)
276
277 def test_get_code_source_not_found(self):
278 # If there is no source then there is no code object.
279 loader = InspectLoaderSubclass()
280 with self.assertRaises(ImportError):
281 loader.get_code('blah')
282
283
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400284class InspectLoaderInitModuleTests(unittest.TestCase):
285
286 @staticmethod
287 def mock_is_package(return_value):
288 return mock.patch.object(InspectLoaderSubclass, 'is_package',
289 return_value=return_value)
290
291 def init_module_attrs(self, name):
292 loader = InspectLoaderSubclass()
Brett Cannonef888022013-06-15 18:39:21 -0400293 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400294 loader.init_module_attrs(module)
295 self.assertEqual(module.__loader__, loader)
296 return module
297
298 def test_package(self):
299 # If a package, then __package__ == __name__, __path__ == []
300 with self.mock_is_package(True):
301 name = 'blah'
302 module = self.init_module_attrs(name)
303 self.assertEqual(module.__package__, name)
304 self.assertEqual(module.__path__, [])
305
306 def test_toplevel(self):
307 # If a module is top-level, __package__ == ''
308 with self.mock_is_package(False):
309 name = 'blah'
310 module = self.init_module_attrs(name)
311 self.assertEqual(module.__package__, '')
312
313 def test_submodule(self):
314 # If a module is contained within a package then set __package__ to the
315 # package name.
316 with self.mock_is_package(False):
317 name = 'pkg.mod'
318 module = self.init_module_attrs(name)
319 self.assertEqual(module.__package__, 'pkg')
320
321 def test_is_package_ImportError(self):
322 # If is_package() raises ImportError, __package__ should be None and
323 # __path__ should not be set.
324 with self.mock_is_package(False) as mocked_method:
325 mocked_method.side_effect = ImportError
326 name = 'mod'
327 module = self.init_module_attrs(name)
328 self.assertIsNone(module.__package__)
329 self.assertFalse(hasattr(module, '__path__'))
330
331
332class InspectLoaderLoadModuleTests(unittest.TestCase):
333
334 """Test InspectLoader.load_module()."""
335
336 module_name = 'blah'
337
338 def setUp(self):
339 support.unload(self.module_name)
340 self.addCleanup(support.unload, self.module_name)
341
342 def mock_get_code(self):
343 return mock.patch.object(InspectLoaderSubclass, 'get_code')
344
345 def test_get_code_ImportError(self):
346 # If get_code() raises ImportError, it should propagate.
347 with self.mock_get_code() as mocked_get_code:
348 mocked_get_code.side_effect = ImportError
349 with self.assertRaises(ImportError):
350 loader = InspectLoaderSubclass()
351 loader.load_module(self.module_name)
352
353 def test_get_code_None(self):
354 # If get_code() returns None, raise ImportError.
355 with self.mock_get_code() as mocked_get_code:
356 mocked_get_code.return_value = None
357 with self.assertRaises(ImportError):
358 loader = InspectLoaderSubclass()
359 loader.load_module(self.module_name)
360
361 def test_module_returned(self):
362 # The loaded module should be returned.
363 code = compile('attr = 42', '<string>', 'exec')
364 with self.mock_get_code() as mocked_get_code:
365 mocked_get_code.return_value = code
366 loader = InspectLoaderSubclass()
367 module = loader.load_module(self.module_name)
368 self.assertEqual(module, sys.modules[self.module_name])
369
370
Brett Cannon3b62ca82013-05-27 21:11:04 -0400371##### ExecutionLoader concrete methods #########################################
372class ExecutionLoaderGetCodeTests(unittest.TestCase):
373
374 def mock_methods(self, *, get_source=False, get_filename=False):
375 source_mock_context, filename_mock_context = None, None
376 if get_source:
377 source_mock_context = mock.patch.object(ExecutionLoaderSubclass,
378 'get_source')
379 if get_filename:
380 filename_mock_context = mock.patch.object(ExecutionLoaderSubclass,
381 'get_filename')
382 return source_mock_context, filename_mock_context
383
384 def test_get_code(self):
385 path = 'blah.py'
386 source_mock_context, filename_mock_context = self.mock_methods(
387 get_source=True, get_filename=True)
388 with source_mock_context as source_mock, filename_mock_context as name_mock:
389 source_mock.return_value = 'attr = 42'
390 name_mock.return_value = path
391 loader = ExecutionLoaderSubclass()
392 code = loader.get_code('blah')
393 self.assertEqual(code.co_filename, path)
Brett Cannonef888022013-06-15 18:39:21 -0400394 module = types.ModuleType('blah')
Brett Cannon3b62ca82013-05-27 21:11:04 -0400395 exec(code, module.__dict__)
396 self.assertEqual(module.attr, 42)
397
398 def test_get_code_source_is_None(self):
399 # If get_source() is None then this should be None.
400 source_mock_context, _ = self.mock_methods(get_source=True)
401 with source_mock_context as mocked:
402 mocked.return_value = None
403 loader = ExecutionLoaderSubclass()
404 code = loader.get_code('blah')
405 self.assertIsNone(code)
406
407 def test_get_code_source_not_found(self):
408 # If there is no source then there is no code object.
409 loader = ExecutionLoaderSubclass()
410 with self.assertRaises(ImportError):
411 loader.get_code('blah')
412
413 def test_get_code_no_path(self):
414 # If get_filename() raises ImportError then simply skip setting the path
415 # on the code object.
416 source_mock_context, filename_mock_context = self.mock_methods(
417 get_source=True, get_filename=True)
418 with source_mock_context as source_mock, filename_mock_context as name_mock:
419 source_mock.return_value = 'attr = 42'
420 name_mock.side_effect = ImportError
421 loader = ExecutionLoaderSubclass()
422 code = loader.get_code('blah')
423 self.assertEqual(code.co_filename, '<string>')
Brett Cannonef888022013-06-15 18:39:21 -0400424 module = types.ModuleType('blah')
Brett Cannon3b62ca82013-05-27 21:11:04 -0400425 exec(code, module.__dict__)
426 self.assertEqual(module.attr, 42)
427
428
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400429class ExecutionLoaderInitModuleTests(unittest.TestCase):
430
431 @staticmethod
432 @contextlib.contextmanager
433 def mock_methods(is_package, filename):
434 is_package_manager = InspectLoaderInitModuleTests.mock_is_package(is_package)
435 get_filename_manager = mock.patch.object(ExecutionLoaderSubclass,
436 'get_filename', return_value=filename)
437 with is_package_manager as mock_is_package:
438 with get_filename_manager as mock_get_filename:
439 yield {'is_package': mock_is_package,
440 'get_filename': mock_get_filename}
441
442 def test_toplevel(self):
443 # Verify __loader__, __file__, and __package__; no __path__.
444 name = 'blah'
445 path = os.path.join('some', 'path', '{}.py'.format(name))
446 with self.mock_methods(False, path):
447 loader = ExecutionLoaderSubclass()
Brett Cannonef888022013-06-15 18:39:21 -0400448 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400449 loader.init_module_attrs(module)
450 self.assertIs(module.__loader__, loader)
451 self.assertEqual(module.__file__, path)
452 self.assertEqual(module.__package__, '')
453 self.assertFalse(hasattr(module, '__path__'))
454
455 def test_package(self):
456 # Verify __loader__, __file__, __package__, and __path__.
457 name = 'pkg'
458 path = os.path.join('some', 'pkg', '__init__.py')
459 with self.mock_methods(True, path):
460 loader = ExecutionLoaderSubclass()
Brett Cannonef888022013-06-15 18:39:21 -0400461 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400462 loader.init_module_attrs(module)
463 self.assertIs(module.__loader__, loader)
464 self.assertEqual(module.__file__, path)
465 self.assertEqual(module.__package__, 'pkg')
466 self.assertEqual(module.__path__, [os.path.dirname(path)])
467
468 def test_submodule(self):
469 # Verify __package__ and not __path__; test_toplevel() takes care of
470 # other attributes.
471 name = 'pkg.submodule'
472 path = os.path.join('some', 'pkg', 'submodule.py')
473 with self.mock_methods(False, path):
474 loader = ExecutionLoaderSubclass()
Brett Cannonef888022013-06-15 18:39:21 -0400475 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400476 loader.init_module_attrs(module)
477 self.assertEqual(module.__package__, 'pkg')
478 self.assertEqual(module.__file__, path)
479 self.assertFalse(hasattr(module, '__path__'))
480
481 def test_get_filename_ImportError(self):
482 # If get_filename() raises ImportError, don't set __file__.
483 name = 'blah'
484 path = 'blah.py'
485 with self.mock_methods(False, path) as mocked_methods:
486 mocked_methods['get_filename'].side_effect = ImportError
487 loader = ExecutionLoaderSubclass()
Brett Cannonef888022013-06-15 18:39:21 -0400488 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400489 loader.init_module_attrs(module)
490 self.assertFalse(hasattr(module, '__file__'))
491
Brett Cannon3b62ca82013-05-27 21:11:04 -0400492
Brett Cannon9ffe85e2013-05-26 16:45:10 -0400493##### SourceLoader concrete methods ############################################
Brett Cannon100883f2013-04-09 16:59:39 -0400494class SourceOnlyLoaderMock(abc.SourceLoader):
495
496 # Globals that should be defined for all modules.
497 source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, "
498 b"repr(__loader__)])")
499
500 def __init__(self, path):
501 self.path = path
502
503 def get_data(self, path):
504 if path != self.path:
505 raise IOError
506 return self.source
507
508 def get_filename(self, fullname):
509 return self.path
510
511 def module_repr(self, module):
512 return '<module>'
513
514
515class SourceLoaderMock(SourceOnlyLoaderMock):
516
517 source_mtime = 1
518
Brett Cannonef888022013-06-15 18:39:21 -0400519 def __init__(self, path, magic=importlib.util.MAGIC_NUMBER):
Brett Cannon100883f2013-04-09 16:59:39 -0400520 super().__init__(path)
Brett Cannonef888022013-06-15 18:39:21 -0400521 self.bytecode_path = importlib.util.cache_from_source(self.path)
Brett Cannon100883f2013-04-09 16:59:39 -0400522 self.source_size = len(self.source)
523 data = bytearray(magic)
524 data.extend(importlib._w_long(self.source_mtime))
525 data.extend(importlib._w_long(self.source_size))
526 code_object = compile(self.source, self.path, 'exec',
527 dont_inherit=True)
528 data.extend(marshal.dumps(code_object))
529 self.bytecode = bytes(data)
530 self.written = {}
531
532 def get_data(self, path):
533 if path == self.path:
534 return super().get_data(path)
535 elif path == self.bytecode_path:
536 return self.bytecode
537 else:
538 raise OSError
539
540 def path_stats(self, path):
541 if path != self.path:
542 raise IOError
543 return {'mtime': self.source_mtime, 'size': self.source_size}
544
545 def set_data(self, path, data):
546 self.written[path] = bytes(data)
547 return path == self.bytecode_path
548
549
550class SourceLoaderTestHarness(unittest.TestCase):
551
552 def setUp(self, *, is_package=True, **kwargs):
553 self.package = 'pkg'
554 if is_package:
555 self.path = os.path.join(self.package, '__init__.py')
556 self.name = self.package
557 else:
558 module_name = 'mod'
559 self.path = os.path.join(self.package, '.'.join(['mod', 'py']))
560 self.name = '.'.join([self.package, module_name])
Brett Cannonef888022013-06-15 18:39:21 -0400561 self.cached = importlib.util.cache_from_source(self.path)
Brett Cannon100883f2013-04-09 16:59:39 -0400562 self.loader = self.loader_mock(self.path, **kwargs)
563
564 def verify_module(self, module):
565 self.assertEqual(module.__name__, self.name)
566 self.assertEqual(module.__file__, self.path)
567 self.assertEqual(module.__cached__, self.cached)
568 self.assertEqual(module.__package__, self.package)
569 self.assertEqual(module.__loader__, self.loader)
570 values = module._.split('::')
571 self.assertEqual(values[0], self.name)
572 self.assertEqual(values[1], self.path)
573 self.assertEqual(values[2], self.cached)
574 self.assertEqual(values[3], self.package)
575 self.assertEqual(values[4], repr(self.loader))
576
577 def verify_code(self, code_object):
Brett Cannonef888022013-06-15 18:39:21 -0400578 module = types.ModuleType(self.name)
Brett Cannon100883f2013-04-09 16:59:39 -0400579 module.__file__ = self.path
580 module.__cached__ = self.cached
581 module.__package__ = self.package
582 module.__loader__ = self.loader
583 module.__path__ = []
584 exec(code_object, module.__dict__)
585 self.verify_module(module)
586
587
588class SourceOnlyLoaderTests(SourceLoaderTestHarness):
589
590 """Test importlib.abc.SourceLoader for source-only loading.
591
592 Reload testing is subsumed by the tests for
593 importlib.util.module_for_loader.
594
595 """
596
597 loader_mock = SourceOnlyLoaderMock
598
599 def test_get_source(self):
600 # Verify the source code is returned as a string.
601 # If an OSError is raised by get_data then raise ImportError.
602 expected_source = self.loader.source.decode('utf-8')
603 self.assertEqual(self.loader.get_source(self.name), expected_source)
604 def raise_OSError(path):
605 raise OSError
606 self.loader.get_data = raise_OSError
607 with self.assertRaises(ImportError) as cm:
608 self.loader.get_source(self.name)
609 self.assertEqual(cm.exception.name, self.name)
610
611 def test_is_package(self):
612 # Properly detect when loading a package.
613 self.setUp(is_package=False)
614 self.assertFalse(self.loader.is_package(self.name))
615 self.setUp(is_package=True)
616 self.assertTrue(self.loader.is_package(self.name))
617 self.assertFalse(self.loader.is_package(self.name + '.__init__'))
618
619 def test_get_code(self):
620 # Verify the code object is created.
621 code_object = self.loader.get_code(self.name)
622 self.verify_code(code_object)
623
624 def test_source_to_code(self):
625 # Verify the compiled code object.
626 code = self.loader.source_to_code(self.loader.source, self.path)
627 self.verify_code(code)
628
629 def test_load_module(self):
630 # Loading a module should set __name__, __loader__, __package__,
631 # __path__ (for packages), __file__, and __cached__.
632 # The module should also be put into sys.modules.
633 with util.uncache(self.name):
634 module = self.loader.load_module(self.name)
635 self.verify_module(module)
636 self.assertEqual(module.__path__, [os.path.dirname(self.path)])
637 self.assertIn(self.name, sys.modules)
638
639 def test_package_settings(self):
640 # __package__ needs to be set, while __path__ is set on if the module
641 # is a package.
642 # Testing the values for a package are covered by test_load_module.
643 self.setUp(is_package=False)
644 with util.uncache(self.name):
645 module = self.loader.load_module(self.name)
646 self.verify_module(module)
647 self.assertTrue(not hasattr(module, '__path__'))
648
649 def test_get_source_encoding(self):
650 # Source is considered encoded in UTF-8 by default unless otherwise
651 # specified by an encoding line.
652 source = "_ = 'ü'"
653 self.loader.source = source.encode('utf-8')
654 returned_source = self.loader.get_source(self.name)
655 self.assertEqual(returned_source, source)
656 source = "# coding: latin-1\n_ = ü"
657 self.loader.source = source.encode('latin-1')
658 returned_source = self.loader.get_source(self.name)
659 self.assertEqual(returned_source, source)
660
661
662@unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true")
663class SourceLoaderBytecodeTests(SourceLoaderTestHarness):
664
665 """Test importlib.abc.SourceLoader's use of bytecode.
666
667 Source-only testing handled by SourceOnlyLoaderTests.
668
669 """
670
671 loader_mock = SourceLoaderMock
672
673 def verify_code(self, code_object, *, bytecode_written=False):
674 super().verify_code(code_object)
675 if bytecode_written:
676 self.assertIn(self.cached, self.loader.written)
Brett Cannonef888022013-06-15 18:39:21 -0400677 data = bytearray(importlib.util.MAGIC_NUMBER)
Brett Cannon100883f2013-04-09 16:59:39 -0400678 data.extend(importlib._w_long(self.loader.source_mtime))
679 data.extend(importlib._w_long(self.loader.source_size))
680 data.extend(marshal.dumps(code_object))
681 self.assertEqual(self.loader.written[self.cached], bytes(data))
682
683 def test_code_with_everything(self):
684 # When everything should work.
685 code_object = self.loader.get_code(self.name)
686 self.verify_code(code_object)
687
688 def test_no_bytecode(self):
689 # If no bytecode exists then move on to the source.
690 self.loader.bytecode_path = "<does not exist>"
691 # Sanity check
692 with self.assertRaises(OSError):
Brett Cannonef888022013-06-15 18:39:21 -0400693 bytecode_path = importlib.util.cache_from_source(self.path)
Brett Cannon100883f2013-04-09 16:59:39 -0400694 self.loader.get_data(bytecode_path)
695 code_object = self.loader.get_code(self.name)
696 self.verify_code(code_object, bytecode_written=True)
697
698 def test_code_bad_timestamp(self):
699 # Bytecode is only used when the timestamp matches the source EXACTLY.
700 for source_mtime in (0, 2):
701 assert source_mtime != self.loader.source_mtime
702 original = self.loader.source_mtime
703 self.loader.source_mtime = source_mtime
704 # If bytecode is used then EOFError would be raised by marshal.
705 self.loader.bytecode = self.loader.bytecode[8:]
706 code_object = self.loader.get_code(self.name)
707 self.verify_code(code_object, bytecode_written=True)
708 self.loader.source_mtime = original
709
710 def test_code_bad_magic(self):
711 # Skip over bytecode with a bad magic number.
712 self.setUp(magic=b'0000')
713 # If bytecode is used then EOFError would be raised by marshal.
714 self.loader.bytecode = self.loader.bytecode[8:]
715 code_object = self.loader.get_code(self.name)
716 self.verify_code(code_object, bytecode_written=True)
717
718 def test_dont_write_bytecode(self):
719 # Bytecode is not written if sys.dont_write_bytecode is true.
720 # Can assume it is false already thanks to the skipIf class decorator.
721 try:
722 sys.dont_write_bytecode = True
723 self.loader.bytecode_path = "<does not exist>"
724 code_object = self.loader.get_code(self.name)
725 self.assertNotIn(self.cached, self.loader.written)
726 finally:
727 sys.dont_write_bytecode = False
728
729 def test_no_set_data(self):
730 # If set_data is not defined, one can still read bytecode.
731 self.setUp(magic=b'0000')
732 original_set_data = self.loader.__class__.set_data
733 try:
734 del self.loader.__class__.set_data
735 code_object = self.loader.get_code(self.name)
736 self.verify_code(code_object)
737 finally:
738 self.loader.__class__.set_data = original_set_data
739
740 def test_set_data_raises_exceptions(self):
741 # Raising NotImplementedError or OSError is okay for set_data.
742 def raise_exception(exc):
743 def closure(*args, **kwargs):
744 raise exc
745 return closure
746
747 self.setUp(magic=b'0000')
748 self.loader.set_data = raise_exception(NotImplementedError)
749 code_object = self.loader.get_code(self.name)
750 self.verify_code(code_object)
751
752
753class SourceLoaderGetSourceTests(unittest.TestCase):
754
755 """Tests for importlib.abc.SourceLoader.get_source()."""
756
757 def test_default_encoding(self):
758 # Should have no problems with UTF-8 text.
759 name = 'mod'
760 mock = SourceOnlyLoaderMock('mod.file')
761 source = 'x = "ü"'
762 mock.source = source.encode('utf-8')
763 returned_source = mock.get_source(name)
764 self.assertEqual(returned_source, source)
765
766 def test_decoded_source(self):
767 # Decoding should work.
768 name = 'mod'
769 mock = SourceOnlyLoaderMock("mod.file")
770 source = "# coding: Latin-1\nx='ü'"
771 assert source.encode('latin-1') != source.encode('utf-8')
772 mock.source = source.encode('latin-1')
773 returned_source = mock.get_source(name)
774 self.assertEqual(returned_source, source)
775
776 def test_universal_newlines(self):
777 # PEP 302 says universal newlines should be used.
778 name = 'mod'
779 mock = SourceOnlyLoaderMock('mod.file')
780 source = "x = 42\r\ny = -13\r\n"
781 mock.source = source.encode('utf-8')
782 expect = io.IncrementalNewlineDecoder(None, True).decode(source)
783 self.assertEqual(mock.get_source(name), expect)
Brett Cannon2a922ed2009-03-09 03:35:50 +0000784
785
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400786class SourceLoaderInitModuleAttrTests(unittest.TestCase):
787
788 """Tests for importlib.abc.SourceLoader.init_module_attrs()."""
789
790 def test_init_module_attrs(self):
Brett Cannonef888022013-06-15 18:39:21 -0400791 # If __file__ set, __cached__ == importlib.util.cached_from_source(__file__).
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400792 name = 'blah'
793 path = 'blah.py'
794 loader = SourceOnlyLoaderMock(path)
Brett Cannonef888022013-06-15 18:39:21 -0400795 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400796 loader.init_module_attrs(module)
797 self.assertEqual(module.__loader__, loader)
798 self.assertEqual(module.__package__, '')
799 self.assertEqual(module.__file__, path)
Brett Cannonef888022013-06-15 18:39:21 -0400800 self.assertEqual(module.__cached__, importlib.util.cache_from_source(path))
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400801
802 @mock.patch('importlib._bootstrap.cache_from_source')
803 def test_cache_from_source_NotImplementedError(self, mock_cache_from_source):
Brett Cannonef888022013-06-15 18:39:21 -0400804 # If importlib.util.cache_from_source() raises NotImplementedError don't set
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400805 # __cached__.
806 mock_cache_from_source.side_effect = NotImplementedError
807 name = 'blah'
808 path = 'blah.py'
809 loader = SourceOnlyLoaderMock(path)
Brett Cannonef888022013-06-15 18:39:21 -0400810 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400811 loader.init_module_attrs(module)
812 self.assertEqual(module.__file__, path)
813 self.assertFalse(hasattr(module, '__cached__'))
814
815 def test_no_get_filename(self):
816 # No __file__, no __cached__.
817 with mock.patch.object(SourceOnlyLoaderMock, 'get_filename') as mocked:
818 mocked.side_effect = ImportError
819 name = 'blah'
820 loader = SourceOnlyLoaderMock('blah.py')
Brett Cannonef888022013-06-15 18:39:21 -0400821 module = types.ModuleType(name)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400822 loader.init_module_attrs(module)
823 self.assertFalse(hasattr(module, '__file__'))
824 self.assertFalse(hasattr(module, '__cached__'))
825
826
Brett Cannon9ffe85e2013-05-26 16:45:10 -0400827
Brett Cannon2a922ed2009-03-09 03:35:50 +0000828if __name__ == '__main__':
Brett Cannon100883f2013-04-09 16:59:39 -0400829 unittest.main()