python (3.11.7)
       1  from warnings import catch_warnings
       2  from test.test_importlib import abc, util
       3  
       4  machinery = util.import_importlib('importlib.machinery')
       5  
       6  import os.path
       7  import sys
       8  import types
       9  import unittest
      10  import warnings
      11  import importlib.util
      12  import importlib
      13  from test.support.script_helper import assert_python_failure
      14  
      15  
      16  class ESC[4;38;5;81mLoaderTests(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mLoaderTests):
      17  
      18      """Test load_module() for extension modules."""
      19  
      20      def setUp(self):
      21          if not self.machinery.EXTENSION_SUFFIXES:
      22              raise unittest.SkipTest("Requires dynamic loading support.")
      23          if util.EXTENSIONS.name in sys.builtin_module_names:
      24              raise unittest.SkipTest(
      25                  f"{util.EXTENSIONS.name} is a builtin module"
      26              )
      27          self.loader = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
      28                                                           util.EXTENSIONS.file_path)
      29  
      30      def load_module(self, fullname):
      31          with warnings.catch_warnings():
      32              warnings.simplefilter("ignore", DeprecationWarning)
      33              return self.loader.load_module(fullname)
      34  
      35      def test_load_module_API(self):
      36          # Test the default argument for load_module().
      37          with warnings.catch_warnings():
      38              warnings.simplefilter("ignore", DeprecationWarning)
      39              self.loader.load_module()
      40              self.loader.load_module(None)
      41              with self.assertRaises(ImportError):
      42                  self.load_module('XXX')
      43  
      44      def test_equality(self):
      45          other = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
      46                                                     util.EXTENSIONS.file_path)
      47          self.assertEqual(self.loader, other)
      48  
      49      def test_inequality(self):
      50          other = self.machinery.ExtensionFileLoader('_' + util.EXTENSIONS.name,
      51                                                     util.EXTENSIONS.file_path)
      52          self.assertNotEqual(self.loader, other)
      53  
      54      def test_module(self):
      55          with util.uncache(util.EXTENSIONS.name):
      56              module = self.load_module(util.EXTENSIONS.name)
      57              for attr, value in [('__name__', util.EXTENSIONS.name),
      58                                  ('__file__', util.EXTENSIONS.file_path),
      59                                  ('__package__', '')]:
      60                  self.assertEqual(getattr(module, attr), value)
      61              self.assertIn(util.EXTENSIONS.name, sys.modules)
      62              self.assertIsInstance(module.__loader__,
      63                                    self.machinery.ExtensionFileLoader)
      64  
      65      # No extension module as __init__ available for testing.
      66      test_package = None
      67  
      68      # No extension module in a package available for testing.
      69      test_lacking_parent = None
      70  
      71      def test_module_reuse(self):
      72          with util.uncache(util.EXTENSIONS.name):
      73              module1 = self.load_module(util.EXTENSIONS.name)
      74              module2 = self.load_module(util.EXTENSIONS.name)
      75              self.assertIs(module1, module2)
      76  
      77      # No easy way to trigger a failure after a successful import.
      78      test_state_after_failure = None
      79  
      80      def test_unloadable(self):
      81          name = 'asdfjkl;'
      82          with self.assertRaises(ImportError) as cm:
      83              self.load_module(name)
      84          self.assertEqual(cm.exception.name, name)
      85  
      86      def test_is_package(self):
      87          self.assertFalse(self.loader.is_package(util.EXTENSIONS.name))
      88          for suffix in self.machinery.EXTENSION_SUFFIXES:
      89              path = os.path.join('some', 'path', 'pkg', '__init__' + suffix)
      90              loader = self.machinery.ExtensionFileLoader('pkg', path)
      91              self.assertTrue(loader.is_package('pkg'))
      92  
      93  (Frozen_LoaderTests,
      94   Source_LoaderTests
      95   ) = util.test_both(LoaderTests, machinery=machinery)
      96  
      97  class ESC[4;38;5;81mMultiPhaseExtensionModuleTests(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mLoaderTests):
      98      # Test loading extension modules with multi-phase initialization (PEP 489).
      99  
     100      def setUp(self):
     101          if not self.machinery.EXTENSION_SUFFIXES:
     102              raise unittest.SkipTest("Requires dynamic loading support.")
     103          self.name = '_testmultiphase'
     104          if self.name in sys.builtin_module_names:
     105              raise unittest.SkipTest(
     106                  f"{self.name} is a builtin module"
     107              )
     108          finder = self.machinery.FileFinder(None)
     109          self.spec = importlib.util.find_spec(self.name)
     110          assert self.spec
     111          self.loader = self.machinery.ExtensionFileLoader(
     112              self.name, self.spec.origin)
     113  
     114      def load_module(self):
     115          # Load the module from the test extension.
     116          with warnings.catch_warnings():
     117              warnings.simplefilter("ignore", DeprecationWarning)
     118              return self.loader.load_module(self.name)
     119  
     120      def load_module_by_name(self, fullname):
     121          # Load a module from the test extension by name.
     122          origin = self.spec.origin
     123          loader = self.machinery.ExtensionFileLoader(fullname, origin)
     124          spec = importlib.util.spec_from_loader(fullname, loader)
     125          module = importlib.util.module_from_spec(spec)
     126          loader.exec_module(module)
     127          return module
     128  
     129      # No extension module as __init__ available for testing.
     130      test_package = None
     131  
     132      # No extension module in a package available for testing.
     133      test_lacking_parent = None
     134  
     135      # Handling failure on reload is the up to the module.
     136      test_state_after_failure = None
     137  
     138      def test_module(self):
     139          # Test loading an extension module.
     140          with util.uncache(self.name):
     141              module = self.load_module()
     142              for attr, value in [('__name__', self.name),
     143                                  ('__file__', self.spec.origin),
     144                                  ('__package__', '')]:
     145                  self.assertEqual(getattr(module, attr), value)
     146              with self.assertRaises(AttributeError):
     147                  module.__path__
     148              self.assertIs(module, sys.modules[self.name])
     149              self.assertIsInstance(module.__loader__,
     150                                    self.machinery.ExtensionFileLoader)
     151  
     152      def test_functionality(self):
     153          # Test basic functionality of stuff defined in an extension module.
     154          with util.uncache(self.name):
     155              module = self.load_module()
     156              self.assertIsInstance(module, types.ModuleType)
     157              ex = module.Example()
     158              self.assertEqual(ex.demo('abcd'), 'abcd')
     159              self.assertEqual(ex.demo(), None)
     160              with self.assertRaises(AttributeError):
     161                  ex.abc
     162              ex.abc = 0
     163              self.assertEqual(ex.abc, 0)
     164              self.assertEqual(module.foo(9, 9), 18)
     165              self.assertIsInstance(module.Str(), str)
     166              self.assertEqual(module.Str(1) + '23', '123')
     167              with self.assertRaises(module.error):
     168                  raise module.error()
     169              self.assertEqual(module.int_const, 1969)
     170              self.assertEqual(module.str_const, 'something different')
     171  
     172      def test_reload(self):
     173          # Test that reload didn't re-set the module's attributes.
     174          with util.uncache(self.name):
     175              module = self.load_module()
     176              ex_class = module.Example
     177              importlib.reload(module)
     178              self.assertIs(ex_class, module.Example)
     179  
     180      def test_try_registration(self):
     181          # Assert that the PyState_{Find,Add,Remove}Module C API doesn't work.
     182          with util.uncache(self.name):
     183              module = self.load_module()
     184              with self.subTest('PyState_FindModule'):
     185                  self.assertEqual(module.call_state_registration_func(0), None)
     186              with self.subTest('PyState_AddModule'):
     187                  with self.assertRaises(SystemError):
     188                      module.call_state_registration_func(1)
     189              with self.subTest('PyState_RemoveModule'):
     190                  with self.assertRaises(SystemError):
     191                      module.call_state_registration_func(2)
     192  
     193      def test_load_submodule(self):
     194          # Test loading a simulated submodule.
     195          module = self.load_module_by_name('pkg.' + self.name)
     196          self.assertIsInstance(module, types.ModuleType)
     197          self.assertEqual(module.__name__, 'pkg.' + self.name)
     198          self.assertEqual(module.str_const, 'something different')
     199  
     200      def test_load_short_name(self):
     201          # Test loading module with a one-character name.
     202          module = self.load_module_by_name('x')
     203          self.assertIsInstance(module, types.ModuleType)
     204          self.assertEqual(module.__name__, 'x')
     205          self.assertEqual(module.str_const, 'something different')
     206          self.assertNotIn('x', sys.modules)
     207  
     208      def test_load_twice(self):
     209          # Test that 2 loads result in 2 module objects.
     210          module1 = self.load_module_by_name(self.name)
     211          module2 = self.load_module_by_name(self.name)
     212          self.assertIsNot(module1, module2)
     213  
     214      def test_unloadable(self):
     215          # Test nonexistent module.
     216          name = 'asdfjkl;'
     217          with self.assertRaises(ImportError) as cm:
     218              self.load_module_by_name(name)
     219          self.assertEqual(cm.exception.name, name)
     220  
     221      def test_unloadable_nonascii(self):
     222          # Test behavior with nonexistent module with non-ASCII name.
     223          name = 'fo\xf3'
     224          with self.assertRaises(ImportError) as cm:
     225              self.load_module_by_name(name)
     226          self.assertEqual(cm.exception.name, name)
     227  
     228      def test_nonmodule(self):
     229          # Test returning a non-module object from create works.
     230          name = self.name + '_nonmodule'
     231          mod = self.load_module_by_name(name)
     232          self.assertNotEqual(type(mod), type(unittest))
     233          self.assertEqual(mod.three, 3)
     234  
     235      # issue 27782
     236      def test_nonmodule_with_methods(self):
     237          # Test creating a non-module object with methods defined.
     238          name = self.name + '_nonmodule_with_methods'
     239          mod = self.load_module_by_name(name)
     240          self.assertNotEqual(type(mod), type(unittest))
     241          self.assertEqual(mod.three, 3)
     242          self.assertEqual(mod.bar(10, 1), 9)
     243  
     244      def test_null_slots(self):
     245          # Test that NULL slots aren't a problem.
     246          name = self.name + '_null_slots'
     247          module = self.load_module_by_name(name)
     248          self.assertIsInstance(module, types.ModuleType)
     249          self.assertEqual(module.__name__, name)
     250  
     251      def test_bad_modules(self):
     252          # Test SystemError is raised for misbehaving extensions.
     253          for name_base in [
     254                  'bad_slot_large',
     255                  'bad_slot_negative',
     256                  'create_int_with_state',
     257                  'negative_size',
     258                  'export_null',
     259                  'export_uninitialized',
     260                  'export_raise',
     261                  'export_unreported_exception',
     262                  'create_null',
     263                  'create_raise',
     264                  'create_unreported_exception',
     265                  'nonmodule_with_exec_slots',
     266                  'exec_err',
     267                  'exec_raise',
     268                  'exec_unreported_exception',
     269                  ]:
     270              with self.subTest(name_base):
     271                  name = self.name + '_' + name_base
     272                  with self.assertRaises(SystemError):
     273                      self.load_module_by_name(name)
     274  
     275      def test_nonascii(self):
     276          # Test that modules with non-ASCII names can be loaded.
     277          # punycode behaves slightly differently in some-ASCII and no-ASCII
     278          # cases, so test both.
     279          cases = [
     280              (self.name + '_zkou\u0161ka_na\u010dten\xed', 'Czech'),
     281              ('\uff3f\u30a4\u30f3\u30dd\u30fc\u30c8\u30c6\u30b9\u30c8',
     282               'Japanese'),
     283              ]
     284          for name, lang in cases:
     285              with self.subTest(name):
     286                  module = self.load_module_by_name(name)
     287                  self.assertEqual(module.__name__, name)
     288                  self.assertEqual(module.__doc__, "Module named in %s" % lang)
     289  
     290  
     291  (Frozen_MultiPhaseExtensionModuleTests,
     292   Source_MultiPhaseExtensionModuleTests
     293   ) = util.test_both(MultiPhaseExtensionModuleTests, machinery=machinery)
     294  
     295  
     296  if __name__ == '__main__':
     297      unittest.main()