(root)/
Python-3.11.7/
Lib/
test/
test_importlib/
test_main.py
       1  import re
       2  import json
       3  import pickle
       4  import unittest
       5  import warnings
       6  import importlib.metadata
       7  
       8  try:
       9      import pyfakefs.fake_filesystem_unittest as ffs
      10  except ImportError:
      11      from .stubs import fake_filesystem_unittest as ffs
      12  
      13  from . import fixtures
      14  from importlib.metadata import (
      15      Distribution,
      16      EntryPoint,
      17      PackageNotFoundError,
      18      _unique,
      19      distributions,
      20      entry_points,
      21      metadata,
      22      packages_distributions,
      23      version,
      24  )
      25  
      26  
      27  class ESC[4;38;5;81mBasicTests(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mDistInfoPkg, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      28      version_pattern = r'\d+\.\d+(\.\d)?'
      29  
      30      def test_retrieves_version_of_self(self):
      31          dist = Distribution.from_name('distinfo-pkg')
      32          assert isinstance(dist.version, str)
      33          assert re.match(self.version_pattern, dist.version)
      34  
      35      def test_for_name_does_not_exist(self):
      36          with self.assertRaises(PackageNotFoundError):
      37              Distribution.from_name('does-not-exist')
      38  
      39      def test_package_not_found_mentions_metadata(self):
      40          """
      41          When a package is not found, that could indicate that the
      42          packgae is not installed or that it is installed without
      43          metadata. Ensure the exception mentions metadata to help
      44          guide users toward the cause. See #124.
      45          """
      46          with self.assertRaises(PackageNotFoundError) as ctx:
      47              Distribution.from_name('does-not-exist')
      48  
      49          assert "metadata" in str(ctx.exception)
      50  
      51      def test_new_style_classes(self):
      52          self.assertIsInstance(Distribution, type)
      53  
      54      @fixtures.parameterize(
      55          dict(name=None),
      56          dict(name=''),
      57      )
      58      def test_invalid_inputs_to_from_name(self, name):
      59          with self.assertRaises(ValueError):
      60              Distribution.from_name(name)
      61  
      62  
      63  class ESC[4;38;5;81mImportTests(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mDistInfoPkg, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      64      def test_import_nonexistent_module(self):
      65          # Ensure that the MetadataPathFinder does not crash an import of a
      66          # non-existent module.
      67          with self.assertRaises(ImportError):
      68              importlib.import_module('does_not_exist')
      69  
      70      def test_resolve(self):
      71          ep = entry_points(group='entries')['main']
      72          self.assertEqual(ep.load().__name__, "main")
      73  
      74      def test_entrypoint_with_colon_in_name(self):
      75          ep = entry_points(group='entries')['ns:sub']
      76          self.assertEqual(ep.value, 'mod:main')
      77  
      78      def test_resolve_without_attr(self):
      79          ep = EntryPoint(
      80              name='ep',
      81              value='importlib.metadata',
      82              group='grp',
      83          )
      84          assert ep.load() is importlib.metadata
      85  
      86  
      87  class ESC[4;38;5;81mNameNormalizationTests(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mSiteDir, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      88      @staticmethod
      89      def make_pkg(name):
      90          """
      91          Create minimal metadata for a dist-info package with
      92          the indicated name on the file system.
      93          """
      94          return {
      95              f'{name}.dist-info': {
      96                  'METADATA': 'VERSION: 1.0\n',
      97              },
      98          }
      99  
     100      def test_dashes_in_dist_name_found_as_underscores(self):
     101          """
     102          For a package with a dash in the name, the dist-info metadata
     103          uses underscores in the name. Ensure the metadata loads.
     104          """
     105          fixtures.build_files(self.make_pkg('my_pkg'), self.site_dir)
     106          assert version('my-pkg') == '1.0'
     107  
     108      def test_dist_name_found_as_any_case(self):
     109          """
     110          Ensure the metadata loads when queried with any case.
     111          """
     112          pkg_name = 'CherryPy'
     113          fixtures.build_files(self.make_pkg(pkg_name), self.site_dir)
     114          assert version(pkg_name) == '1.0'
     115          assert version(pkg_name.lower()) == '1.0'
     116          assert version(pkg_name.upper()) == '1.0'
     117  
     118      def test_unique_distributions(self):
     119          """
     120          Two distributions varying only by non-normalized name on
     121          the file system should resolve as the same.
     122          """
     123          fixtures.build_files(self.make_pkg('abc'), self.site_dir)
     124          before = list(_unique(distributions()))
     125  
     126          alt_site_dir = self.fixtures.enter_context(fixtures.tempdir())
     127          self.fixtures.enter_context(self.add_sys_path(alt_site_dir))
     128          fixtures.build_files(self.make_pkg('ABC'), alt_site_dir)
     129          after = list(_unique(distributions()))
     130  
     131          assert len(after) == len(before)
     132  
     133  
     134  class ESC[4;38;5;81mNonASCIITests(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mSiteDir, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     135      @staticmethod
     136      def pkg_with_non_ascii_description(site_dir):
     137          """
     138          Create minimal metadata for a package with non-ASCII in
     139          the description.
     140          """
     141          contents = {
     142              'portend.dist-info': {
     143                  'METADATA': 'Description: pôrˈtend',
     144              },
     145          }
     146          fixtures.build_files(contents, site_dir)
     147          return 'portend'
     148  
     149      @staticmethod
     150      def pkg_with_non_ascii_description_egg_info(site_dir):
     151          """
     152          Create minimal metadata for an egg-info package with
     153          non-ASCII in the description.
     154          """
     155          contents = {
     156              'portend.dist-info': {
     157                  'METADATA': """
     158                  Name: portend
     159  
     160                  pôrˈtend""",
     161              },
     162          }
     163          fixtures.build_files(contents, site_dir)
     164          return 'portend'
     165  
     166      def test_metadata_loads(self):
     167          pkg_name = self.pkg_with_non_ascii_description(self.site_dir)
     168          meta = metadata(pkg_name)
     169          assert meta['Description'] == 'pôrˈtend'
     170  
     171      def test_metadata_loads_egg_info(self):
     172          pkg_name = self.pkg_with_non_ascii_description_egg_info(self.site_dir)
     173          meta = metadata(pkg_name)
     174          assert meta['Description'] == 'pôrˈtend'
     175  
     176  
     177  class ESC[4;38;5;81mDiscoveryTests(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mEggInfoPkg, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mDistInfoPkg, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     178      def test_package_discovery(self):
     179          dists = list(distributions())
     180          assert all(isinstance(dist, Distribution) for dist in dists)
     181          assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists)
     182          assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
     183  
     184      def test_invalid_usage(self):
     185          with self.assertRaises(ValueError):
     186              list(distributions(context='something', name='else'))
     187  
     188  
     189  class ESC[4;38;5;81mDirectoryTest(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mSiteDir, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     190      def test_egg_info(self):
     191          # make an `EGG-INFO` directory that's unrelated
     192          self.site_dir.joinpath('EGG-INFO').mkdir()
     193          # used to crash with `IsADirectoryError`
     194          with self.assertRaises(PackageNotFoundError):
     195              version('unknown-package')
     196  
     197      def test_egg(self):
     198          egg = self.site_dir.joinpath('foo-3.6.egg')
     199          egg.mkdir()
     200          with self.add_sys_path(egg):
     201              with self.assertRaises(PackageNotFoundError):
     202                  version('foo')
     203  
     204  
     205  class ESC[4;38;5;81mMissingSysPath(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     206      site_dir = '/does-not-exist'
     207  
     208      def test_discovery(self):
     209          """
     210          Discovering distributions should succeed even if
     211          there is an invalid path on sys.path.
     212          """
     213          importlib.metadata.distributions()
     214  
     215  
     216  class ESC[4;38;5;81mInaccessibleSysPath(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mffsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     217      site_dir = '/access-denied'
     218  
     219      def setUp(self):
     220          super().setUp()
     221          self.setUpPyfakefs()
     222          self.fs.create_dir(self.site_dir, perm_bits=000)
     223  
     224      def test_discovery(self):
     225          """
     226          Discovering distributions should succeed even if
     227          there is an invalid path on sys.path.
     228          """
     229          list(importlib.metadata.distributions())
     230  
     231  
     232  class ESC[4;38;5;81mTestEntryPoints(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     233      def __init__(self, *args):
     234          super().__init__(*args)
     235          self.ep = importlib.metadata.EntryPoint(
     236              name='name', value='value', group='group'
     237          )
     238  
     239      def test_entry_point_pickleable(self):
     240          revived = pickle.loads(pickle.dumps(self.ep))
     241          assert revived == self.ep
     242  
     243      def test_positional_args(self):
     244          """
     245          Capture legacy (namedtuple) construction, discouraged.
     246          """
     247          EntryPoint('name', 'value', 'group')
     248  
     249      def test_immutable(self):
     250          """EntryPoints should be immutable"""
     251          with self.assertRaises(AttributeError):
     252              self.ep.name = 'badactor'
     253  
     254      def test_repr(self):
     255          assert 'EntryPoint' in repr(self.ep)
     256          assert 'name=' in repr(self.ep)
     257          assert "'name'" in repr(self.ep)
     258  
     259      def test_hashable(self):
     260          """EntryPoints should be hashable"""
     261          hash(self.ep)
     262  
     263      def test_json_dump(self):
     264          """
     265          json should not expect to be able to dump an EntryPoint
     266          """
     267          with self.assertRaises(Exception):
     268              with warnings.catch_warnings(record=True):
     269                  json.dumps(self.ep)
     270  
     271      def test_module(self):
     272          assert self.ep.module == 'value'
     273  
     274      def test_attr(self):
     275          assert self.ep.attr is None
     276  
     277      def test_sortable(self):
     278          """
     279          EntryPoint objects are sortable, but result is undefined.
     280          """
     281          sorted(
     282              [
     283                  EntryPoint(name='b', value='val', group='group'),
     284                  EntryPoint(name='a', value='val', group='group'),
     285              ]
     286          )
     287  
     288  
     289  class ESC[4;38;5;81mFileSystem(
     290      ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mSiteDir, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mFileBuilder, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase
     291  ):
     292      def test_unicode_dir_on_sys_path(self):
     293          """
     294          Ensure a Unicode subdirectory of a directory on sys.path
     295          does not crash.
     296          """
     297          fixtures.build_files(
     298              {self.unicode_filename(): {}},
     299              prefix=self.site_dir,
     300          )
     301          list(distributions())
     302  
     303  
     304  class ESC[4;38;5;81mPackagesDistributionsPrebuiltTest(ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mZipFixtures, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     305      def test_packages_distributions_example(self):
     306          self._fixture_on_path('example-21.12-py3-none-any.whl')
     307          assert packages_distributions()['example'] == ['example']
     308  
     309      def test_packages_distributions_example2(self):
     310          """
     311          Test packages_distributions on a wheel built
     312          by trampolim.
     313          """
     314          self._fixture_on_path('example2-1.0.0-py3-none-any.whl')
     315          assert packages_distributions()['example2'] == ['example2']
     316  
     317  
     318  class ESC[4;38;5;81mPackagesDistributionsTest(
     319      ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mfixturesESC[4;38;5;149m.ESC[4;38;5;149mSiteDir, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase
     320  ):
     321      def test_packages_distributions_neither_toplevel_nor_files(self):
     322          """
     323          Test a package built without 'top-level.txt' or a file list.
     324          """
     325          fixtures.build_files(
     326              {
     327                  'trim_example-1.0.0.dist-info': {
     328                      'METADATA': """
     329                  Name: trim_example
     330                  Version: 1.0.0
     331                  """,
     332                  }
     333              },
     334              prefix=self.site_dir,
     335          )
     336          packages_distributions()