| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- import os
- import errno
- import importlib.machinery
- import py_compile
- import shutil
- import unittest
- import tempfile
- from test import support
- import modulefinder
- # Each test description is a list of 5 items:
- #
- # 1. a module name that will be imported by modulefinder
- # 2. a list of module names that modulefinder is required to find
- # 3. a list of module names that modulefinder should complain
- # about because they are not found
- # 4. a list of module names that modulefinder should complain
- # about because they MAY be not found
- # 5. a string specifying packages to create; the format is obvious imo.
- #
- # Each package will be created in test_dir, and test_dir will be
- # removed after the tests again.
- # Modulefinder searches in a path that contains test_dir, plus
- # the standard Lib directory.
- maybe_test = [
- "a.module",
- ["a", "a.module", "sys",
- "b"],
- ["c"], ["b.something"],
- """\
- a/__init__.py
- a/module.py
- from b import something
- from c import something
- b/__init__.py
- from sys import *
- """,
- ]
- maybe_test_new = [
- "a.module",
- ["a", "a.module", "sys",
- "b", "__future__"],
- ["c"], ["b.something"],
- """\
- a/__init__.py
- a/module.py
- from b import something
- from c import something
- b/__init__.py
- from __future__ import absolute_import
- from sys import *
- """]
- package_test = [
- "a.module",
- ["a", "a.b", "a.c", "a.module", "mymodule", "sys"],
- ["blahblah", "c"], [],
- """\
- mymodule.py
- a/__init__.py
- import blahblah
- from a import b
- import c
- a/module.py
- import sys
- from a import b as x
- from a.c import sillyname
- a/b.py
- a/c.py
- from a.module import x
- import mymodule as sillyname
- from sys import version_info
- """]
- absolute_import_test = [
- "a.module",
- ["a", "a.module",
- "b", "b.x", "b.y", "b.z",
- "__future__", "sys", "gc"],
- ["blahblah", "z"], [],
- """\
- mymodule.py
- a/__init__.py
- a/module.py
- from __future__ import absolute_import
- import sys # sys
- import blahblah # fails
- import gc # gc
- import b.x # b.x
- from b import y # b.y
- from b.z import * # b.z.*
- a/gc.py
- a/sys.py
- import mymodule
- a/b/__init__.py
- a/b/x.py
- a/b/y.py
- a/b/z.py
- b/__init__.py
- import z
- b/unused.py
- b/x.py
- b/y.py
- b/z.py
- """]
- relative_import_test = [
- "a.module",
- ["__future__",
- "a", "a.module",
- "a.b", "a.b.y", "a.b.z",
- "a.b.c", "a.b.c.moduleC",
- "a.b.c.d", "a.b.c.e",
- "a.b.x",
- "gc"],
- [], [],
- """\
- mymodule.py
- a/__init__.py
- from .b import y, z # a.b.y, a.b.z
- a/module.py
- from __future__ import absolute_import # __future__
- import gc # gc
- a/gc.py
- a/sys.py
- a/b/__init__.py
- from ..b import x # a.b.x
- #from a.b.c import moduleC
- from .c import moduleC # a.b.moduleC
- a/b/x.py
- a/b/y.py
- a/b/z.py
- a/b/g.py
- a/b/c/__init__.py
- from ..c import e # a.b.c.e
- a/b/c/moduleC.py
- from ..c import d # a.b.c.d
- a/b/c/d.py
- a/b/c/e.py
- a/b/c/x.py
- """]
- relative_import_test_2 = [
- "a.module",
- ["a", "a.module",
- "a.sys",
- "a.b", "a.b.y", "a.b.z",
- "a.b.c", "a.b.c.d",
- "a.b.c.e",
- "a.b.c.moduleC",
- "a.b.c.f",
- "a.b.x",
- "a.another"],
- [], [],
- """\
- mymodule.py
- a/__init__.py
- from . import sys # a.sys
- a/another.py
- a/module.py
- from .b import y, z # a.b.y, a.b.z
- a/gc.py
- a/sys.py
- a/b/__init__.py
- from .c import moduleC # a.b.c.moduleC
- from .c import d # a.b.c.d
- a/b/x.py
- a/b/y.py
- a/b/z.py
- a/b/c/__init__.py
- from . import e # a.b.c.e
- a/b/c/moduleC.py
- #
- from . import f # a.b.c.f
- from .. import x # a.b.x
- from ... import another # a.another
- a/b/c/d.py
- a/b/c/e.py
- a/b/c/f.py
- """]
- relative_import_test_3 = [
- "a.module",
- ["a", "a.module"],
- ["a.bar"],
- [],
- """\
- a/__init__.py
- def foo(): pass
- a/module.py
- from . import foo
- from . import bar
- """]
- relative_import_test_4 = [
- "a.module",
- ["a", "a.module"],
- [],
- [],
- """\
- a/__init__.py
- def foo(): pass
- a/module.py
- from . import *
- """]
- bytecode_test = [
- "a",
- ["a"],
- [],
- [],
- ""
- ]
- syntax_error_test = [
- "a.module",
- ["a", "a.module", "b"],
- ["b.module"], [],
- """\
- a/__init__.py
- a/module.py
- import b.module
- b/__init__.py
- b/module.py
- ? # SyntaxError: invalid syntax
- """]
- same_name_as_bad_test = [
- "a.module",
- ["a", "a.module", "b", "b.c"],
- ["c"], [],
- """\
- a/__init__.py
- a/module.py
- import c
- from b import c
- b/__init__.py
- b/c.py
- """]
- coding_default_utf8_test = [
- "a_utf8",
- ["a_utf8", "b_utf8"],
- [], [],
- """\
- a_utf8.py
- # use the default of utf8
- print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
- import b_utf8
- b_utf8.py
- # use the default of utf8
- print('Unicode test B code point 2090 \u2090 that is not valid in cp1252')
- """]
- coding_explicit_utf8_test = [
- "a_utf8",
- ["a_utf8", "b_utf8"],
- [], [],
- """\
- a_utf8.py
- # coding=utf8
- print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
- import b_utf8
- b_utf8.py
- # use the default of utf8
- print('Unicode test B code point 2090 \u2090 that is not valid in cp1252')
- """]
- coding_explicit_cp1252_test = [
- "a_cp1252",
- ["a_cp1252", "b_utf8"],
- [], [],
- b"""\
- a_cp1252.py
- # coding=cp1252
- # 0xe2 is not allowed in utf8
- print('CP1252 test P\xe2t\xe9')
- import b_utf8
- """ + """\
- b_utf8.py
- # use the default of utf8
- print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
- """.encode('utf-8')]
- def open_file(path):
- dirname = os.path.dirname(path)
- try:
- os.makedirs(dirname)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- return open(path, 'wb')
- def create_package(test_dir, source):
- ofi = None
- try:
- for line in source.splitlines():
- if type(line) != bytes:
- line = line.encode('utf-8')
- if line.startswith(b' ') or line.startswith(b'\t'):
- ofi.write(line.strip() + b'\n')
- else:
- if ofi:
- ofi.close()
- if type(line) == bytes:
- line = line.decode('utf-8')
- ofi = open_file(os.path.join(test_dir, line.strip()))
- finally:
- if ofi:
- ofi.close()
- class ModuleFinderTest(unittest.TestCase):
- def setUp(self):
- self.test_dir = tempfile.mkdtemp()
- self.test_path = [self.test_dir, os.path.dirname(tempfile.__file__)]
- def tearDown(self):
- shutil.rmtree(self.test_dir)
- def _do_test(self, info, report=False, debug=0, replace_paths=[], modulefinder_class=modulefinder.ModuleFinder):
- import_this, modules, missing, maybe_missing, source = info
- create_package(self.test_dir, source)
- mf = modulefinder_class(path=self.test_path, debug=debug,
- replace_paths=replace_paths)
- mf.import_hook(import_this)
- if report:
- mf.report()
- ## # This wouldn't work in general when executed several times:
- ## opath = sys.path[:]
- ## sys.path = self.test_path
- ## try:
- ## __import__(import_this)
- ## except:
- ## import traceback; traceback.print_exc()
- ## sys.path = opath
- ## return
- modules = sorted(set(modules))
- found = sorted(mf.modules)
- # check if we found what we expected, not more, not less
- self.assertEqual(found, modules)
- # check for missing and maybe missing modules
- bad, maybe = mf.any_missing_maybe()
- self.assertEqual(bad, missing)
- self.assertEqual(maybe, maybe_missing)
- def test_package(self):
- self._do_test(package_test)
- def test_maybe(self):
- self._do_test(maybe_test)
- def test_maybe_new(self):
- self._do_test(maybe_test_new)
- def test_absolute_imports(self):
- self._do_test(absolute_import_test)
- def test_relative_imports(self):
- self._do_test(relative_import_test)
- def test_relative_imports_2(self):
- self._do_test(relative_import_test_2)
- def test_relative_imports_3(self):
- self._do_test(relative_import_test_3)
- def test_relative_imports_4(self):
- self._do_test(relative_import_test_4)
- def test_syntax_error(self):
- self._do_test(syntax_error_test)
- def test_same_name_as_bad(self):
- self._do_test(same_name_as_bad_test)
- def test_bytecode(self):
- base_path = os.path.join(self.test_dir, 'a')
- source_path = base_path + importlib.machinery.SOURCE_SUFFIXES[0]
- bytecode_path = base_path + importlib.machinery.BYTECODE_SUFFIXES[0]
- with open_file(source_path) as file:
- file.write('testing_modulefinder = True\n'.encode('utf-8'))
- py_compile.compile(source_path, cfile=bytecode_path)
- os.remove(source_path)
- self._do_test(bytecode_test)
- def test_replace_paths(self):
- old_path = os.path.join(self.test_dir, 'a', 'module.py')
- new_path = os.path.join(self.test_dir, 'a', 'spam.py')
- with support.captured_stdout() as output:
- self._do_test(maybe_test, debug=2,
- replace_paths=[(old_path, new_path)])
- output = output.getvalue()
- expected = "co_filename %r changed to %r" % (old_path, new_path)
- self.assertIn(expected, output)
- def test_extended_opargs(self):
- extended_opargs_test = [
- "a",
- ["a", "b"],
- [], [],
- """\
- a.py
- %r
- import b
- b.py
- """ % list(range(2**16))] # 2**16 constants
- self._do_test(extended_opargs_test)
- def test_coding_default_utf8(self):
- self._do_test(coding_default_utf8_test)
- def test_coding_explicit_utf8(self):
- self._do_test(coding_explicit_utf8_test)
- def test_coding_explicit_cp1252(self):
- self._do_test(coding_explicit_cp1252_test)
- def test_load_module_api(self):
- class CheckLoadModuleApi(modulefinder.ModuleFinder):
- def __init__(self, *args, **kwds):
- super().__init__(*args, **kwds)
- def load_module(self, fqname, fp, pathname, file_info):
- # confirm that the fileinfo is a tuple of 3 elements
- suffix, mode, type = file_info
- return super().load_module(fqname, fp, pathname, file_info)
- self._do_test(absolute_import_test, modulefinder_class=CheckLoadModuleApi)
- if __name__ == "__main__":
- unittest.main()
|