python (3.11.7)

(root)/
lib/
python3.11/
test/
test_modulefinder.py
       1  import os
       2  import errno
       3  import importlib.machinery
       4  import py_compile
       5  import shutil
       6  import unittest
       7  import tempfile
       8  
       9  from test import support
      10  
      11  import modulefinder
      12  
      13  # Each test description is a list of 5 items:
      14  #
      15  # 1. a module name that will be imported by modulefinder
      16  # 2. a list of module names that modulefinder is required to find
      17  # 3. a list of module names that modulefinder should complain
      18  #    about because they are not found
      19  # 4. a list of module names that modulefinder should complain
      20  #    about because they MAY be not found
      21  # 5. a string specifying packages to create; the format is obvious imo.
      22  #
      23  # Each package will be created in test_dir, and test_dir will be
      24  # removed after the tests again.
      25  # Modulefinder searches in a path that contains test_dir, plus
      26  # the standard Lib directory.
      27  
      28  maybe_test = [
      29      "a.module",
      30      ["a", "a.module", "sys",
      31       "b"],
      32      ["c"], ["b.something"],
      33      """\
      34  a/__init__.py
      35  a/module.py
      36                                  from b import something
      37                                  from c import something
      38  b/__init__.py
      39                                  from sys import *
      40  """,
      41  ]
      42  
      43  maybe_test_new = [
      44      "a.module",
      45      ["a", "a.module", "sys",
      46       "b", "__future__"],
      47      ["c"], ["b.something"],
      48      """\
      49  a/__init__.py
      50  a/module.py
      51                                  from b import something
      52                                  from c import something
      53  b/__init__.py
      54                                  from __future__ import absolute_import
      55                                  from sys import *
      56  """]
      57  
      58  package_test = [
      59      "a.module",
      60      ["a", "a.b", "a.c", "a.module", "mymodule", "sys"],
      61      ["blahblah", "c"], [],
      62      """\
      63  mymodule.py
      64  a/__init__.py
      65                                  import blahblah
      66                                  from a import b
      67                                  import c
      68  a/module.py
      69                                  import sys
      70                                  from a import b as x
      71                                  from a.c import sillyname
      72  a/b.py
      73  a/c.py
      74                                  from a.module import x
      75                                  import mymodule as sillyname
      76                                  from sys import version_info
      77  """]
      78  
      79  absolute_import_test = [
      80      "a.module",
      81      ["a", "a.module",
      82       "b", "b.x", "b.y", "b.z",
      83       "__future__", "sys", "gc"],
      84      ["blahblah", "z"], [],
      85      """\
      86  mymodule.py
      87  a/__init__.py
      88  a/module.py
      89                                  from __future__ import absolute_import
      90                                  import sys # sys
      91                                  import blahblah # fails
      92                                  import gc # gc
      93                                  import b.x # b.x
      94                                  from b import y # b.y
      95                                  from b.z import * # b.z.*
      96  a/gc.py
      97  a/sys.py
      98                                  import mymodule
      99  a/b/__init__.py
     100  a/b/x.py
     101  a/b/y.py
     102  a/b/z.py
     103  b/__init__.py
     104                                  import z
     105  b/unused.py
     106  b/x.py
     107  b/y.py
     108  b/z.py
     109  """]
     110  
     111  relative_import_test = [
     112      "a.module",
     113      ["__future__",
     114       "a", "a.module",
     115       "a.b", "a.b.y", "a.b.z",
     116       "a.b.c", "a.b.c.moduleC",
     117       "a.b.c.d", "a.b.c.e",
     118       "a.b.x",
     119       "gc"],
     120      [], [],
     121      """\
     122  mymodule.py
     123  a/__init__.py
     124                                  from .b import y, z # a.b.y, a.b.z
     125  a/module.py
     126                                  from __future__ import absolute_import # __future__
     127                                  import gc # gc
     128  a/gc.py
     129  a/sys.py
     130  a/b/__init__.py
     131                                  from ..b import x # a.b.x
     132                                  #from a.b.c import moduleC
     133                                  from .c import moduleC # a.b.moduleC
     134  a/b/x.py
     135  a/b/y.py
     136  a/b/z.py
     137  a/b/g.py
     138  a/b/c/__init__.py
     139                                  from ..c import e # a.b.c.e
     140  a/b/c/moduleC.py
     141                                  from ..c import d # a.b.c.d
     142  a/b/c/d.py
     143  a/b/c/e.py
     144  a/b/c/x.py
     145  """]
     146  
     147  relative_import_test_2 = [
     148      "a.module",
     149      ["a", "a.module",
     150       "a.sys",
     151       "a.b", "a.b.y", "a.b.z",
     152       "a.b.c", "a.b.c.d",
     153       "a.b.c.e",
     154       "a.b.c.moduleC",
     155       "a.b.c.f",
     156       "a.b.x",
     157       "a.another"],
     158      [], [],
     159      """\
     160  mymodule.py
     161  a/__init__.py
     162                                  from . import sys # a.sys
     163  a/another.py
     164  a/module.py
     165                                  from .b import y, z # a.b.y, a.b.z
     166  a/gc.py
     167  a/sys.py
     168  a/b/__init__.py
     169                                  from .c import moduleC # a.b.c.moduleC
     170                                  from .c import d # a.b.c.d
     171  a/b/x.py
     172  a/b/y.py
     173  a/b/z.py
     174  a/b/c/__init__.py
     175                                  from . import e # a.b.c.e
     176  a/b/c/moduleC.py
     177                                  #
     178                                  from . import f   # a.b.c.f
     179                                  from .. import x  # a.b.x
     180                                  from ... import another # a.another
     181  a/b/c/d.py
     182  a/b/c/e.py
     183  a/b/c/f.py
     184  """]
     185  
     186  relative_import_test_3 = [
     187      "a.module",
     188      ["a", "a.module"],
     189      ["a.bar"],
     190      [],
     191      """\
     192  a/__init__.py
     193                                  def foo(): pass
     194  a/module.py
     195                                  from . import foo
     196                                  from . import bar
     197  """]
     198  
     199  relative_import_test_4 = [
     200      "a.module",
     201      ["a", "a.module"],
     202      [],
     203      [],
     204      """\
     205  a/__init__.py
     206                                  def foo(): pass
     207  a/module.py
     208                                  from . import *
     209  """]
     210  
     211  bytecode_test = [
     212      "a",
     213      ["a"],
     214      [],
     215      [],
     216      ""
     217  ]
     218  
     219  syntax_error_test = [
     220      "a.module",
     221      ["a", "a.module", "b"],
     222      ["b.module"], [],
     223      """\
     224  a/__init__.py
     225  a/module.py
     226                                  import b.module
     227  b/__init__.py
     228  b/module.py
     229                                  ?  # SyntaxError: invalid syntax
     230  """]
     231  
     232  
     233  same_name_as_bad_test = [
     234      "a.module",
     235      ["a", "a.module", "b", "b.c"],
     236      ["c"], [],
     237      """\
     238  a/__init__.py
     239  a/module.py
     240                                  import c
     241                                  from b import c
     242  b/__init__.py
     243  b/c.py
     244  """]
     245  
     246  coding_default_utf8_test = [
     247      "a_utf8",
     248      ["a_utf8", "b_utf8"],
     249      [], [],
     250      """\
     251  a_utf8.py
     252                                  # use the default of utf8
     253                                  print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
     254                                  import b_utf8
     255  b_utf8.py
     256                                  # use the default of utf8
     257                                  print('Unicode test B code point 2090 \u2090 that is not valid in cp1252')
     258  """]
     259  
     260  coding_explicit_utf8_test = [
     261      "a_utf8",
     262      ["a_utf8", "b_utf8"],
     263      [], [],
     264      """\
     265  a_utf8.py
     266                                  # coding=utf8
     267                                  print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
     268                                  import b_utf8
     269  b_utf8.py
     270                                  # use the default of utf8
     271                                  print('Unicode test B code point 2090 \u2090 that is not valid in cp1252')
     272  """]
     273  
     274  coding_explicit_cp1252_test = [
     275      "a_cp1252",
     276      ["a_cp1252", "b_utf8"],
     277      [], [],
     278      b"""\
     279  a_cp1252.py
     280                                  # coding=cp1252
     281                                  # 0xe2 is not allowed in utf8
     282                                  print('CP1252 test P\xe2t\xe9')
     283                                  import b_utf8
     284  """ + """\
     285  b_utf8.py
     286                                  # use the default of utf8
     287                                  print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
     288  """.encode('utf-8')]
     289  
     290  def open_file(path):
     291      dirname = os.path.dirname(path)
     292      try:
     293          os.makedirs(dirname)
     294      except OSError as e:
     295          if e.errno != errno.EEXIST:
     296              raise
     297      return open(path, 'wb')
     298  
     299  
     300  def create_package(test_dir, source):
     301      ofi = None
     302      try:
     303          for line in source.splitlines():
     304              if type(line) != bytes:
     305                  line = line.encode('utf-8')
     306              if line.startswith(b' ') or line.startswith(b'\t'):
     307                  ofi.write(line.strip() + b'\n')
     308              else:
     309                  if ofi:
     310                      ofi.close()
     311                  if type(line) == bytes:
     312                      line = line.decode('utf-8')
     313                  ofi = open_file(os.path.join(test_dir, line.strip()))
     314      finally:
     315          if ofi:
     316              ofi.close()
     317  
     318  class ESC[4;38;5;81mModuleFinderTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     319      def setUp(self):
     320          self.test_dir = tempfile.mkdtemp()
     321          self.test_path = [self.test_dir, os.path.dirname(tempfile.__file__)]
     322  
     323      def tearDown(self):
     324          shutil.rmtree(self.test_dir)
     325  
     326      def _do_test(self, info, report=False, debug=0, replace_paths=[], modulefinder_class=modulefinder.ModuleFinder):
     327          import_this, modules, missing, maybe_missing, source = info
     328          create_package(self.test_dir, source)
     329          mf = modulefinder_class(path=self.test_path, debug=debug,
     330                                          replace_paths=replace_paths)
     331          mf.import_hook(import_this)
     332          if report:
     333              mf.report()
     334  ##            # This wouldn't work in general when executed several times:
     335  ##            opath = sys.path[:]
     336  ##            sys.path = self.test_path
     337  ##            try:
     338  ##                __import__(import_this)
     339  ##            except:
     340  ##                import traceback; traceback.print_exc()
     341  ##            sys.path = opath
     342  ##            return
     343          modules = sorted(set(modules))
     344          found = sorted(mf.modules)
     345          # check if we found what we expected, not more, not less
     346          self.assertEqual(found, modules)
     347  
     348          # check for missing and maybe missing modules
     349          bad, maybe = mf.any_missing_maybe()
     350          self.assertEqual(bad, missing)
     351          self.assertEqual(maybe, maybe_missing)
     352  
     353      def test_package(self):
     354          self._do_test(package_test)
     355  
     356      def test_maybe(self):
     357          self._do_test(maybe_test)
     358  
     359      def test_maybe_new(self):
     360          self._do_test(maybe_test_new)
     361  
     362      def test_absolute_imports(self):
     363          self._do_test(absolute_import_test)
     364  
     365      def test_relative_imports(self):
     366          self._do_test(relative_import_test)
     367  
     368      def test_relative_imports_2(self):
     369          self._do_test(relative_import_test_2)
     370  
     371      def test_relative_imports_3(self):
     372          self._do_test(relative_import_test_3)
     373  
     374      def test_relative_imports_4(self):
     375          self._do_test(relative_import_test_4)
     376  
     377      def test_syntax_error(self):
     378          self._do_test(syntax_error_test)
     379  
     380      def test_same_name_as_bad(self):
     381          self._do_test(same_name_as_bad_test)
     382  
     383      def test_bytecode(self):
     384          base_path = os.path.join(self.test_dir, 'a')
     385          source_path = base_path + importlib.machinery.SOURCE_SUFFIXES[0]
     386          bytecode_path = base_path + importlib.machinery.BYTECODE_SUFFIXES[0]
     387          with open_file(source_path) as file:
     388              file.write('testing_modulefinder = True\n'.encode('utf-8'))
     389          py_compile.compile(source_path, cfile=bytecode_path)
     390          os.remove(source_path)
     391          self._do_test(bytecode_test)
     392  
     393      def test_replace_paths(self):
     394          old_path = os.path.join(self.test_dir, 'a', 'module.py')
     395          new_path = os.path.join(self.test_dir, 'a', 'spam.py')
     396          with support.captured_stdout() as output:
     397              self._do_test(maybe_test, debug=2,
     398                            replace_paths=[(old_path, new_path)])
     399          output = output.getvalue()
     400          expected = "co_filename %r changed to %r" % (old_path, new_path)
     401          self.assertIn(expected, output)
     402  
     403      def test_extended_opargs(self):
     404          extended_opargs_test = [
     405              "a",
     406              ["a", "b"],
     407              [], [],
     408              """\
     409  a.py
     410                                  %r
     411                                  import b
     412  b.py
     413  """ % list(range(2**16))]  # 2**16 constants
     414          self._do_test(extended_opargs_test)
     415  
     416      def test_coding_default_utf8(self):
     417          self._do_test(coding_default_utf8_test)
     418  
     419      def test_coding_explicit_utf8(self):
     420          self._do_test(coding_explicit_utf8_test)
     421  
     422      def test_coding_explicit_cp1252(self):
     423          self._do_test(coding_explicit_cp1252_test)
     424  
     425      def test_load_module_api(self):
     426          class ESC[4;38;5;81mCheckLoadModuleApi(ESC[4;38;5;149mmodulefinderESC[4;38;5;149m.ESC[4;38;5;149mModuleFinder):
     427              def __init__(self, *args, **kwds):
     428                  super().__init__(*args, **kwds)
     429  
     430              def load_module(self, fqname, fp, pathname, file_info):
     431                  # confirm that the fileinfo is a tuple of 3 elements
     432                  suffix, mode, type = file_info
     433                  return super().load_module(fqname, fp, pathname, file_info)
     434  
     435          self._do_test(absolute_import_test, modulefinder_class=CheckLoadModuleApi)
     436  
     437  if __name__ == "__main__":
     438      unittest.main()