ยปCore Development>Code coverage>Lib/test/test_pkgutil.py

Python code coverage for Lib/test/test_pkgutil.py

#countcontent
1n/afrom test.support import run_unittest, unload, check_warnings, CleanImport
2n/aimport unittest
3n/aimport sys
4n/aimport importlib
5n/afrom importlib.util import spec_from_file_location
6n/aimport pkgutil
7n/aimport os
8n/aimport os.path
9n/aimport tempfile
10n/aimport shutil
11n/aimport zipfile
12n/a
13n/a# Note: pkgutil.walk_packages is currently tested in test_runpy. This is
14n/a# a hack to get a major issue resolved for 3.3b2. Longer term, it should
15n/a# be moved back here, perhaps by factoring out the helper code for
16n/a# creating interesting package layouts to a separate module.
17n/a# Issue #15348 declares this is indeed a dodgy hack ;)
18n/a
19n/aclass PkgutilTests(unittest.TestCase):
20n/a
21n/a def setUp(self):
22n/a self.dirname = tempfile.mkdtemp()
23n/a self.addCleanup(shutil.rmtree, self.dirname)
24n/a sys.path.insert(0, self.dirname)
25n/a
26n/a def tearDown(self):
27n/a del sys.path[0]
28n/a
29n/a def test_getdata_filesys(self):
30n/a pkg = 'test_getdata_filesys'
31n/a
32n/a # Include a LF and a CRLF, to test that binary data is read back
33n/a RESOURCE_DATA = b'Hello, world!\nSecond line\r\nThird line'
34n/a
35n/a # Make a package with some resources
36n/a package_dir = os.path.join(self.dirname, pkg)
37n/a os.mkdir(package_dir)
38n/a # Empty init.py
39n/a f = open(os.path.join(package_dir, '__init__.py'), "wb")
40n/a f.close()
41n/a # Resource files, res.txt, sub/res.txt
42n/a f = open(os.path.join(package_dir, 'res.txt'), "wb")
43n/a f.write(RESOURCE_DATA)
44n/a f.close()
45n/a os.mkdir(os.path.join(package_dir, 'sub'))
46n/a f = open(os.path.join(package_dir, 'sub', 'res.txt'), "wb")
47n/a f.write(RESOURCE_DATA)
48n/a f.close()
49n/a
50n/a # Check we can read the resources
51n/a res1 = pkgutil.get_data(pkg, 'res.txt')
52n/a self.assertEqual(res1, RESOURCE_DATA)
53n/a res2 = pkgutil.get_data(pkg, 'sub/res.txt')
54n/a self.assertEqual(res2, RESOURCE_DATA)
55n/a
56n/a del sys.modules[pkg]
57n/a
58n/a def test_getdata_zipfile(self):
59n/a zip = 'test_getdata_zipfile.zip'
60n/a pkg = 'test_getdata_zipfile'
61n/a
62n/a # Include a LF and a CRLF, to test that binary data is read back
63n/a RESOURCE_DATA = b'Hello, world!\nSecond line\r\nThird line'
64n/a
65n/a # Make a package with some resources
66n/a zip_file = os.path.join(self.dirname, zip)
67n/a z = zipfile.ZipFile(zip_file, 'w')
68n/a
69n/a # Empty init.py
70n/a z.writestr(pkg + '/__init__.py', "")
71n/a # Resource files, res.txt, sub/res.txt
72n/a z.writestr(pkg + '/res.txt', RESOURCE_DATA)
73n/a z.writestr(pkg + '/sub/res.txt', RESOURCE_DATA)
74n/a z.close()
75n/a
76n/a # Check we can read the resources
77n/a sys.path.insert(0, zip_file)
78n/a res1 = pkgutil.get_data(pkg, 'res.txt')
79n/a self.assertEqual(res1, RESOURCE_DATA)
80n/a res2 = pkgutil.get_data(pkg, 'sub/res.txt')
81n/a self.assertEqual(res2, RESOURCE_DATA)
82n/a
83n/a names = []
84n/a for moduleinfo in pkgutil.iter_modules([zip_file]):
85n/a self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
86n/a names.append(moduleinfo.name)
87n/a self.assertEqual(names, ['test_getdata_zipfile'])
88n/a
89n/a del sys.path[0]
90n/a
91n/a del sys.modules[pkg]
92n/a
93n/a def test_unreadable_dir_on_syspath(self):
94n/a # issue7367 - walk_packages failed if unreadable dir on sys.path
95n/a package_name = "unreadable_package"
96n/a d = os.path.join(self.dirname, package_name)
97n/a # this does not appear to create an unreadable dir on Windows
98n/a # but the test should not fail anyway
99n/a os.mkdir(d, 0)
100n/a self.addCleanup(os.rmdir, d)
101n/a for t in pkgutil.walk_packages(path=[self.dirname]):
102n/a self.fail("unexpected package found")
103n/a
104n/a def test_walkpackages_filesys(self):
105n/a pkg1 = 'test_walkpackages_filesys'
106n/a pkg1_dir = os.path.join(self.dirname, pkg1)
107n/a os.mkdir(pkg1_dir)
108n/a f = open(os.path.join(pkg1_dir, '__init__.py'), "wb")
109n/a f.close()
110n/a os.mkdir(os.path.join(pkg1_dir, 'sub'))
111n/a f = open(os.path.join(pkg1_dir, 'sub', '__init__.py'), "wb")
112n/a f.close()
113n/a f = open(os.path.join(pkg1_dir, 'sub', 'mod.py'), "wb")
114n/a f.close()
115n/a
116n/a # Now, to juice it up, let's add the opposite packages, too.
117n/a pkg2 = 'sub'
118n/a pkg2_dir = os.path.join(self.dirname, pkg2)
119n/a os.mkdir(pkg2_dir)
120n/a f = open(os.path.join(pkg2_dir, '__init__.py'), "wb")
121n/a f.close()
122n/a os.mkdir(os.path.join(pkg2_dir, 'test_walkpackages_filesys'))
123n/a f = open(os.path.join(pkg2_dir, 'test_walkpackages_filesys', '__init__.py'), "wb")
124n/a f.close()
125n/a f = open(os.path.join(pkg2_dir, 'test_walkpackages_filesys', 'mod.py'), "wb")
126n/a f.close()
127n/a
128n/a expected = [
129n/a 'sub',
130n/a 'sub.test_walkpackages_filesys',
131n/a 'sub.test_walkpackages_filesys.mod',
132n/a 'test_walkpackages_filesys',
133n/a 'test_walkpackages_filesys.sub',
134n/a 'test_walkpackages_filesys.sub.mod',
135n/a ]
136n/a actual= [e[1] for e in pkgutil.walk_packages([self.dirname])]
137n/a self.assertEqual(actual, expected)
138n/a
139n/a for pkg in expected:
140n/a if pkg.endswith('mod'):
141n/a continue
142n/a del sys.modules[pkg]
143n/a
144n/a def test_walkpackages_zipfile(self):
145n/a """Tests the same as test_walkpackages_filesys, only with a zip file."""
146n/a
147n/a zip = 'test_walkpackages_zipfile.zip'
148n/a pkg1 = 'test_walkpackages_zipfile'
149n/a pkg2 = 'sub'
150n/a
151n/a zip_file = os.path.join(self.dirname, zip)
152n/a z = zipfile.ZipFile(zip_file, 'w')
153n/a z.writestr(pkg2 + '/__init__.py', "")
154n/a z.writestr(pkg2 + '/' + pkg1 + '/__init__.py', "")
155n/a z.writestr(pkg2 + '/' + pkg1 + '/mod.py', "")
156n/a z.writestr(pkg1 + '/__init__.py', "")
157n/a z.writestr(pkg1 + '/' + pkg2 + '/__init__.py', "")
158n/a z.writestr(pkg1 + '/' + pkg2 + '/mod.py', "")
159n/a z.close()
160n/a
161n/a sys.path.insert(0, zip_file)
162n/a expected = [
163n/a 'sub',
164n/a 'sub.test_walkpackages_zipfile',
165n/a 'sub.test_walkpackages_zipfile.mod',
166n/a 'test_walkpackages_zipfile',
167n/a 'test_walkpackages_zipfile.sub',
168n/a 'test_walkpackages_zipfile.sub.mod',
169n/a ]
170n/a actual= [e[1] for e in pkgutil.walk_packages([zip_file])]
171n/a self.assertEqual(actual, expected)
172n/a del sys.path[0]
173n/a
174n/a for pkg in expected:
175n/a if pkg.endswith('mod'):
176n/a continue
177n/a del sys.modules[pkg]
178n/a
179n/a
180n/a
181n/aclass PkgutilPEP302Tests(unittest.TestCase):
182n/a
183n/a class MyTestLoader(object):
184n/a def create_module(self, spec):
185n/a return None
186n/a
187n/a def exec_module(self, mod):
188n/a # Count how many times the module is reloaded
189n/a mod.__dict__['loads'] = mod.__dict__.get('loads', 0) + 1
190n/a
191n/a def get_data(self, path):
192n/a return "Hello, world!"
193n/a
194n/a class MyTestImporter(object):
195n/a def find_spec(self, fullname, path=None, target=None):
196n/a loader = PkgutilPEP302Tests.MyTestLoader()
197n/a return spec_from_file_location(fullname,
198n/a '<%s>' % loader.__class__.__name__,
199n/a loader=loader,
200n/a submodule_search_locations=[])
201n/a
202n/a def setUp(self):
203n/a sys.meta_path.insert(0, self.MyTestImporter())
204n/a
205n/a def tearDown(self):
206n/a del sys.meta_path[0]
207n/a
208n/a def test_getdata_pep302(self):
209n/a # Use a dummy finder/loader
210n/a self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!")
211n/a del sys.modules['foo']
212n/a
213n/a def test_alreadyloaded(self):
214n/a # Ensure that get_data works without reloading - the "loads" module
215n/a # variable in the example loader should count how many times a reload
216n/a # occurs.
217n/a import foo
218n/a self.assertEqual(foo.loads, 1)
219n/a self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!")
220n/a self.assertEqual(foo.loads, 1)
221n/a del sys.modules['foo']
222n/a
223n/a
224n/a# These tests, especially the setup and cleanup, are hideous. They
225n/a# need to be cleaned up once issue 14715 is addressed.
226n/aclass ExtendPathTests(unittest.TestCase):
227n/a def create_init(self, pkgname):
228n/a dirname = tempfile.mkdtemp()
229n/a sys.path.insert(0, dirname)
230n/a
231n/a pkgdir = os.path.join(dirname, pkgname)
232n/a os.mkdir(pkgdir)
233n/a with open(os.path.join(pkgdir, '__init__.py'), 'w') as fl:
234n/a fl.write('from pkgutil import extend_path\n__path__ = extend_path(__path__, __name__)\n')
235n/a
236n/a return dirname
237n/a
238n/a def create_submodule(self, dirname, pkgname, submodule_name, value):
239n/a module_name = os.path.join(dirname, pkgname, submodule_name + '.py')
240n/a with open(module_name, 'w') as fl:
241n/a print('value={}'.format(value), file=fl)
242n/a
243n/a def test_simple(self):
244n/a pkgname = 'foo'
245n/a dirname_0 = self.create_init(pkgname)
246n/a dirname_1 = self.create_init(pkgname)
247n/a self.create_submodule(dirname_0, pkgname, 'bar', 0)
248n/a self.create_submodule(dirname_1, pkgname, 'baz', 1)
249n/a import foo.bar
250n/a import foo.baz
251n/a # Ensure we read the expected values
252n/a self.assertEqual(foo.bar.value, 0)
253n/a self.assertEqual(foo.baz.value, 1)
254n/a
255n/a # Ensure the path is set up correctly
256n/a self.assertEqual(sorted(foo.__path__),
257n/a sorted([os.path.join(dirname_0, pkgname),
258n/a os.path.join(dirname_1, pkgname)]))
259n/a
260n/a # Cleanup
261n/a shutil.rmtree(dirname_0)
262n/a shutil.rmtree(dirname_1)
263n/a del sys.path[0]
264n/a del sys.path[0]
265n/a del sys.modules['foo']
266n/a del sys.modules['foo.bar']
267n/a del sys.modules['foo.baz']
268n/a
269n/a
270n/a # Another awful testing hack to be cleaned up once the test_runpy
271n/a # helpers are factored out to a common location
272n/a def test_iter_importers(self):
273n/a iter_importers = pkgutil.iter_importers
274n/a get_importer = pkgutil.get_importer
275n/a
276n/a pkgname = 'spam'
277n/a modname = 'eggs'
278n/a dirname = self.create_init(pkgname)
279n/a pathitem = os.path.join(dirname, pkgname)
280n/a fullname = '{}.{}'.format(pkgname, modname)
281n/a sys.modules.pop(fullname, None)
282n/a sys.modules.pop(pkgname, None)
283n/a try:
284n/a self.create_submodule(dirname, pkgname, modname, 0)
285n/a
286n/a importlib.import_module(fullname)
287n/a
288n/a importers = list(iter_importers(fullname))
289n/a expected_importer = get_importer(pathitem)
290n/a for finder in importers:
291n/a spec = pkgutil._get_spec(finder, fullname)
292n/a loader = spec.loader
293n/a try:
294n/a loader = loader.loader
295n/a except AttributeError:
296n/a # For now we still allow raw loaders from
297n/a # find_module().
298n/a pass
299n/a self.assertIsInstance(finder, importlib.machinery.FileFinder)
300n/a self.assertEqual(finder, expected_importer)
301n/a self.assertIsInstance(loader,
302n/a importlib.machinery.SourceFileLoader)
303n/a self.assertIsNone(pkgutil._get_spec(finder, pkgname))
304n/a
305n/a with self.assertRaises(ImportError):
306n/a list(iter_importers('invalid.module'))
307n/a
308n/a with self.assertRaises(ImportError):
309n/a list(iter_importers('.spam'))
310n/a finally:
311n/a shutil.rmtree(dirname)
312n/a del sys.path[0]
313n/a try:
314n/a del sys.modules['spam']
315n/a del sys.modules['spam.eggs']
316n/a except KeyError:
317n/a pass
318n/a
319n/a
320n/a def test_mixed_namespace(self):
321n/a pkgname = 'foo'
322n/a dirname_0 = self.create_init(pkgname)
323n/a dirname_1 = self.create_init(pkgname)
324n/a self.create_submodule(dirname_0, pkgname, 'bar', 0)
325n/a # Turn this into a PEP 420 namespace package
326n/a os.unlink(os.path.join(dirname_0, pkgname, '__init__.py'))
327n/a self.create_submodule(dirname_1, pkgname, 'baz', 1)
328n/a import foo.bar
329n/a import foo.baz
330n/a # Ensure we read the expected values
331n/a self.assertEqual(foo.bar.value, 0)
332n/a self.assertEqual(foo.baz.value, 1)
333n/a
334n/a # Ensure the path is set up correctly
335n/a self.assertEqual(sorted(foo.__path__),
336n/a sorted([os.path.join(dirname_0, pkgname),
337n/a os.path.join(dirname_1, pkgname)]))
338n/a
339n/a # Cleanup
340n/a shutil.rmtree(dirname_0)
341n/a shutil.rmtree(dirname_1)
342n/a del sys.path[0]
343n/a del sys.path[0]
344n/a del sys.modules['foo']
345n/a del sys.modules['foo.bar']
346n/a del sys.modules['foo.baz']
347n/a
348n/a # XXX: test .pkg files
349n/a
350n/a
351n/aclass NestedNamespacePackageTest(unittest.TestCase):
352n/a
353n/a def setUp(self):
354n/a self.basedir = tempfile.mkdtemp()
355n/a self.old_path = sys.path[:]
356n/a
357n/a def tearDown(self):
358n/a sys.path[:] = self.old_path
359n/a shutil.rmtree(self.basedir)
360n/a
361n/a def create_module(self, name, contents):
362n/a base, final = name.rsplit('.', 1)
363n/a base_path = os.path.join(self.basedir, base.replace('.', os.path.sep))
364n/a os.makedirs(base_path, exist_ok=True)
365n/a with open(os.path.join(base_path, final + ".py"), 'w') as f:
366n/a f.write(contents)
367n/a
368n/a def test_nested(self):
369n/a pkgutil_boilerplate = (
370n/a 'import pkgutil; '
371n/a '__path__ = pkgutil.extend_path(__path__, __name__)')
372n/a self.create_module('a.pkg.__init__', pkgutil_boilerplate)
373n/a self.create_module('b.pkg.__init__', pkgutil_boilerplate)
374n/a self.create_module('a.pkg.subpkg.__init__', pkgutil_boilerplate)
375n/a self.create_module('b.pkg.subpkg.__init__', pkgutil_boilerplate)
376n/a self.create_module('a.pkg.subpkg.c', 'c = 1')
377n/a self.create_module('b.pkg.subpkg.d', 'd = 2')
378n/a sys.path.insert(0, os.path.join(self.basedir, 'a'))
379n/a sys.path.insert(0, os.path.join(self.basedir, 'b'))
380n/a import pkg
381n/a self.addCleanup(unload, 'pkg')
382n/a self.assertEqual(len(pkg.__path__), 2)
383n/a import pkg.subpkg
384n/a self.addCleanup(unload, 'pkg.subpkg')
385n/a self.assertEqual(len(pkg.subpkg.__path__), 2)
386n/a from pkg.subpkg.c import c
387n/a from pkg.subpkg.d import d
388n/a self.assertEqual(c, 1)
389n/a self.assertEqual(d, 2)
390n/a
391n/a
392n/aclass ImportlibMigrationTests(unittest.TestCase):
393n/a # With full PEP 302 support in the standard import machinery, the
394n/a # PEP 302 emulation in this module is in the process of being
395n/a # deprecated in favour of importlib proper
396n/a
397n/a def check_deprecated(self):
398n/a return check_warnings(
399n/a ("This emulation is deprecated, use 'importlib' instead",
400n/a DeprecationWarning))
401n/a
402n/a def test_importer_deprecated(self):
403n/a with self.check_deprecated():
404n/a pkgutil.ImpImporter("")
405n/a
406n/a def test_loader_deprecated(self):
407n/a with self.check_deprecated():
408n/a pkgutil.ImpLoader("", "", "", "")
409n/a
410n/a def test_get_loader_avoids_emulation(self):
411n/a with check_warnings() as w:
412n/a self.assertIsNotNone(pkgutil.get_loader("sys"))
413n/a self.assertIsNotNone(pkgutil.get_loader("os"))
414n/a self.assertIsNotNone(pkgutil.get_loader("test.support"))
415n/a self.assertEqual(len(w.warnings), 0)
416n/a
417n/a @unittest.skipIf(__name__ == '__main__', 'not compatible with __main__')
418n/a def test_get_loader_handles_missing_loader_attribute(self):
419n/a global __loader__
420n/a this_loader = __loader__
421n/a del __loader__
422n/a try:
423n/a with check_warnings() as w:
424n/a self.assertIsNotNone(pkgutil.get_loader(__name__))
425n/a self.assertEqual(len(w.warnings), 0)
426n/a finally:
427n/a __loader__ = this_loader
428n/a
429n/a def test_get_loader_handles_missing_spec_attribute(self):
430n/a name = 'spam'
431n/a mod = type(sys)(name)
432n/a del mod.__spec__
433n/a with CleanImport(name):
434n/a sys.modules[name] = mod
435n/a loader = pkgutil.get_loader(name)
436n/a self.assertIsNone(loader)
437n/a
438n/a def test_get_loader_handles_spec_attribute_none(self):
439n/a name = 'spam'
440n/a mod = type(sys)(name)
441n/a mod.__spec__ = None
442n/a with CleanImport(name):
443n/a sys.modules[name] = mod
444n/a loader = pkgutil.get_loader(name)
445n/a self.assertIsNone(loader)
446n/a
447n/a def test_get_loader_None_in_sys_modules(self):
448n/a name = 'totally bogus'
449n/a sys.modules[name] = None
450n/a try:
451n/a loader = pkgutil.get_loader(name)
452n/a finally:
453n/a del sys.modules[name]
454n/a self.assertIsNone(loader)
455n/a
456n/a def test_find_loader_missing_module(self):
457n/a name = 'totally bogus'
458n/a loader = pkgutil.find_loader(name)
459n/a self.assertIsNone(loader)
460n/a
461n/a def test_find_loader_avoids_emulation(self):
462n/a with check_warnings() as w:
463n/a self.assertIsNotNone(pkgutil.find_loader("sys"))
464n/a self.assertIsNotNone(pkgutil.find_loader("os"))
465n/a self.assertIsNotNone(pkgutil.find_loader("test.support"))
466n/a self.assertEqual(len(w.warnings), 0)
467n/a
468n/a def test_get_importer_avoids_emulation(self):
469n/a # We use an illegal path so *none* of the path hooks should fire
470n/a with check_warnings() as w:
471n/a self.assertIsNone(pkgutil.get_importer("*??"))
472n/a self.assertEqual(len(w.warnings), 0)
473n/a
474n/a def test_iter_importers_avoids_emulation(self):
475n/a with check_warnings() as w:
476n/a for importer in pkgutil.iter_importers(): pass
477n/a self.assertEqual(len(w.warnings), 0)
478n/a
479n/a
480n/adef test_main():
481n/a run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests,
482n/a NestedNamespacePackageTest, ImportlibMigrationTests)
483n/a # this is necessary if test is run repeated (like when finding leaks)
484n/a import zipimport
485n/a import importlib
486n/a zipimport._zip_directory_cache.clear()
487n/a importlib.invalidate_caches()
488n/a
489n/a
490n/aif __name__ == '__main__':
491n/a test_main()