»Core Development>Code coverage>Lib/importlib/test/source/test_abc_loader.py

Python code coverage for Lib/importlib/test/source/test_abc_loader.py

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