mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	 d888ff5381
			
		
	
	
		d888ff5381
		
			
		
	
	
	
	
		
			
			This reverts commit 57316c52ba for files pertaining to importlib.metadata and importlib.resources.
		
	
			
		
			
				
	
	
		
			317 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			317 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import re
 | ||
| import json
 | ||
| import pickle
 | ||
| import textwrap
 | ||
| import unittest
 | ||
| import warnings
 | ||
| import importlib.metadata
 | ||
| 
 | ||
| try:
 | ||
|     import pyfakefs.fake_filesystem_unittest as ffs
 | ||
| except ImportError:
 | ||
|     from .stubs import fake_filesystem_unittest as ffs
 | ||
| 
 | ||
| from . import fixtures
 | ||
| from importlib.metadata import (
 | ||
|     Distribution,
 | ||
|     EntryPoint,
 | ||
|     PackageNotFoundError,
 | ||
|     distributions,
 | ||
|     entry_points,
 | ||
|     metadata,
 | ||
|     packages_distributions,
 | ||
|     version,
 | ||
| )
 | ||
| 
 | ||
| 
 | ||
| class BasicTests(fixtures.DistInfoPkg, unittest.TestCase):
 | ||
|     version_pattern = r'\d+\.\d+(\.\d)?'
 | ||
| 
 | ||
|     def test_retrieves_version_of_self(self):
 | ||
|         dist = Distribution.from_name('distinfo-pkg')
 | ||
|         assert isinstance(dist.version, str)
 | ||
|         assert re.match(self.version_pattern, dist.version)
 | ||
| 
 | ||
|     def test_for_name_does_not_exist(self):
 | ||
|         with self.assertRaises(PackageNotFoundError):
 | ||
|             Distribution.from_name('does-not-exist')
 | ||
| 
 | ||
|     def test_package_not_found_mentions_metadata(self):
 | ||
|         # When a package is not found, that could indicate that the
 | ||
|         # packgae is not installed or that it is installed without
 | ||
|         # metadata. Ensure the exception mentions metadata to help
 | ||
|         # guide users toward the cause. See #124.
 | ||
|         with self.assertRaises(PackageNotFoundError) as ctx:
 | ||
|             Distribution.from_name('does-not-exist')
 | ||
| 
 | ||
|         assert "metadata" in str(ctx.exception)
 | ||
| 
 | ||
|     def test_new_style_classes(self):
 | ||
|         self.assertIsInstance(Distribution, type)
 | ||
| 
 | ||
| 
 | ||
| class ImportTests(fixtures.DistInfoPkg, unittest.TestCase):
 | ||
|     def test_import_nonexistent_module(self):
 | ||
|         # Ensure that the MetadataPathFinder does not crash an import of a
 | ||
|         # non-existent module.
 | ||
|         with self.assertRaises(ImportError):
 | ||
|             importlib.import_module('does_not_exist')
 | ||
| 
 | ||
|     def test_resolve(self):
 | ||
|         ep = entry_points(group='entries')['main']
 | ||
|         self.assertEqual(ep.load().__name__, "main")
 | ||
| 
 | ||
|     def test_entrypoint_with_colon_in_name(self):
 | ||
|         ep = entry_points(group='entries')['ns:sub']
 | ||
|         self.assertEqual(ep.value, 'mod:main')
 | ||
| 
 | ||
|     def test_resolve_without_attr(self):
 | ||
|         ep = EntryPoint(
 | ||
|             name='ep',
 | ||
|             value='importlib.metadata',
 | ||
|             group='grp',
 | ||
|         )
 | ||
|         assert ep.load() is importlib.metadata
 | ||
| 
 | ||
| 
 | ||
| class NameNormalizationTests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
 | ||
|     @staticmethod
 | ||
|     def pkg_with_dashes(site_dir):
 | ||
|         """
 | ||
|         Create minimal metadata for a package with dashes
 | ||
|         in the name (and thus underscores in the filename).
 | ||
|         """
 | ||
|         metadata_dir = site_dir / 'my_pkg.dist-info'
 | ||
|         metadata_dir.mkdir()
 | ||
|         metadata = metadata_dir / 'METADATA'
 | ||
|         with metadata.open('w', encoding='utf-8') as strm:
 | ||
|             strm.write('Version: 1.0\n')
 | ||
|         return 'my-pkg'
 | ||
| 
 | ||
|     def test_dashes_in_dist_name_found_as_underscores(self):
 | ||
|         # For a package with a dash in the name, the dist-info metadata
 | ||
|         # uses underscores in the name. Ensure the metadata loads.
 | ||
|         pkg_name = self.pkg_with_dashes(self.site_dir)
 | ||
|         assert version(pkg_name) == '1.0'
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def pkg_with_mixed_case(site_dir):
 | ||
|         """
 | ||
|         Create minimal metadata for a package with mixed case
 | ||
|         in the name.
 | ||
|         """
 | ||
|         metadata_dir = site_dir / 'CherryPy.dist-info'
 | ||
|         metadata_dir.mkdir()
 | ||
|         metadata = metadata_dir / 'METADATA'
 | ||
|         with metadata.open('w', encoding='utf-8') as strm:
 | ||
|             strm.write('Version: 1.0\n')
 | ||
|         return 'CherryPy'
 | ||
| 
 | ||
|     def test_dist_name_found_as_any_case(self):
 | ||
|         # Ensure the metadata loads when queried with any case.
 | ||
|         pkg_name = self.pkg_with_mixed_case(self.site_dir)
 | ||
|         assert version(pkg_name) == '1.0'
 | ||
|         assert version(pkg_name.lower()) == '1.0'
 | ||
|         assert version(pkg_name.upper()) == '1.0'
 | ||
| 
 | ||
| 
 | ||
| class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
 | ||
|     @staticmethod
 | ||
|     def pkg_with_non_ascii_description(site_dir):
 | ||
|         """
 | ||
|         Create minimal metadata for a package with non-ASCII in
 | ||
|         the description.
 | ||
|         """
 | ||
|         metadata_dir = site_dir / 'portend.dist-info'
 | ||
|         metadata_dir.mkdir()
 | ||
|         metadata = metadata_dir / 'METADATA'
 | ||
|         with metadata.open('w', encoding='utf-8') as fp:
 | ||
|             fp.write('Description: pôrˈtend')
 | ||
|         return 'portend'
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def pkg_with_non_ascii_description_egg_info(site_dir):
 | ||
|         """
 | ||
|         Create minimal metadata for an egg-info package with
 | ||
|         non-ASCII in the description.
 | ||
|         """
 | ||
|         metadata_dir = site_dir / 'portend.dist-info'
 | ||
|         metadata_dir.mkdir()
 | ||
|         metadata = metadata_dir / 'METADATA'
 | ||
|         with metadata.open('w', encoding='utf-8') as fp:
 | ||
|             fp.write(
 | ||
|                 textwrap.dedent(
 | ||
|                     """
 | ||
|                 Name: portend
 | ||
| 
 | ||
|                 pôrˈtend
 | ||
|                 """
 | ||
|                 ).strip()
 | ||
|             )
 | ||
|         return 'portend'
 | ||
| 
 | ||
|     def test_metadata_loads(self):
 | ||
|         pkg_name = self.pkg_with_non_ascii_description(self.site_dir)
 | ||
|         meta = metadata(pkg_name)
 | ||
|         assert meta['Description'] == 'pôrˈtend'
 | ||
| 
 | ||
|     def test_metadata_loads_egg_info(self):
 | ||
|         pkg_name = self.pkg_with_non_ascii_description_egg_info(self.site_dir)
 | ||
|         meta = metadata(pkg_name)
 | ||
|         assert meta['Description'] == 'pôrˈtend'
 | ||
| 
 | ||
| 
 | ||
| class DiscoveryTests(fixtures.EggInfoPkg, fixtures.DistInfoPkg, unittest.TestCase):
 | ||
|     def test_package_discovery(self):
 | ||
|         dists = list(distributions())
 | ||
|         assert all(isinstance(dist, Distribution) for dist in dists)
 | ||
|         assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists)
 | ||
|         assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
 | ||
| 
 | ||
|     def test_invalid_usage(self):
 | ||
|         with self.assertRaises(ValueError):
 | ||
|             list(distributions(context='something', name='else'))
 | ||
| 
 | ||
| 
 | ||
| class DirectoryTest(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase):
 | ||
|     def test_egg_info(self):
 | ||
|         # make an `EGG-INFO` directory that's unrelated
 | ||
|         self.site_dir.joinpath('EGG-INFO').mkdir()
 | ||
|         # used to crash with `IsADirectoryError`
 | ||
|         with self.assertRaises(PackageNotFoundError):
 | ||
|             version('unknown-package')
 | ||
| 
 | ||
|     def test_egg(self):
 | ||
|         egg = self.site_dir.joinpath('foo-3.6.egg')
 | ||
|         egg.mkdir()
 | ||
|         with self.add_sys_path(egg):
 | ||
|             with self.assertRaises(PackageNotFoundError):
 | ||
|                 version('foo')
 | ||
| 
 | ||
| 
 | ||
| class MissingSysPath(fixtures.OnSysPath, unittest.TestCase):
 | ||
|     site_dir = '/does-not-exist'
 | ||
| 
 | ||
|     def test_discovery(self):
 | ||
|         """
 | ||
|         Discovering distributions should succeed even if
 | ||
|         there is an invalid path on sys.path.
 | ||
|         """
 | ||
|         importlib.metadata.distributions()
 | ||
| 
 | ||
| 
 | ||
| class InaccessibleSysPath(fixtures.OnSysPath, ffs.TestCase):
 | ||
|     site_dir = '/access-denied'
 | ||
| 
 | ||
|     def setUp(self):
 | ||
|         super().setUp()
 | ||
|         self.setUpPyfakefs()
 | ||
|         self.fs.create_dir(self.site_dir, perm_bits=000)
 | ||
| 
 | ||
|     def test_discovery(self):
 | ||
|         """
 | ||
|         Discovering distributions should succeed even if
 | ||
|         there is an invalid path on sys.path.
 | ||
|         """
 | ||
|         list(importlib.metadata.distributions())
 | ||
| 
 | ||
| 
 | ||
| class TestEntryPoints(unittest.TestCase):
 | ||
|     def __init__(self, *args):
 | ||
|         super().__init__(*args)
 | ||
|         self.ep = importlib.metadata.EntryPoint(
 | ||
|             name='name', value='value', group='group'
 | ||
|         )
 | ||
| 
 | ||
|     def test_entry_point_pickleable(self):
 | ||
|         revived = pickle.loads(pickle.dumps(self.ep))
 | ||
|         assert revived == self.ep
 | ||
| 
 | ||
|     def test_positional_args(self):
 | ||
|         """
 | ||
|         Capture legacy (namedtuple) construction, discouraged.
 | ||
|         """
 | ||
|         EntryPoint('name', 'value', 'group')
 | ||
| 
 | ||
|     def test_immutable(self):
 | ||
|         """EntryPoints should be immutable"""
 | ||
|         with self.assertRaises(AttributeError):
 | ||
|             self.ep.name = 'badactor'
 | ||
| 
 | ||
|     def test_repr(self):
 | ||
|         assert 'EntryPoint' in repr(self.ep)
 | ||
|         assert 'name=' in repr(self.ep)
 | ||
|         assert "'name'" in repr(self.ep)
 | ||
| 
 | ||
|     def test_hashable(self):
 | ||
|         # EntryPoints should be hashable.
 | ||
|         hash(self.ep)
 | ||
| 
 | ||
|     def test_json_dump(self):
 | ||
|         # json should not expect to be able to dump an EntryPoint.
 | ||
|         with self.assertRaises(Exception):
 | ||
|             with warnings.catch_warnings(record=True):
 | ||
|                 json.dumps(self.ep)
 | ||
| 
 | ||
|     def test_module(self):
 | ||
|         assert self.ep.module == 'value'
 | ||
| 
 | ||
|     def test_attr(self):
 | ||
|         assert self.ep.attr is None
 | ||
| 
 | ||
|     def test_sortable(self):
 | ||
|         # EntryPoint objects are sortable, but result is undefined.
 | ||
|         sorted(
 | ||
|             [
 | ||
|                 EntryPoint(name='b', value='val', group='group'),
 | ||
|                 EntryPoint(name='a', value='val', group='group'),
 | ||
|             ]
 | ||
|         )
 | ||
| 
 | ||
| 
 | ||
| class FileSystem(
 | ||
|     fixtures.OnSysPath, fixtures.SiteDir, fixtures.FileBuilder, unittest.TestCase
 | ||
| ):
 | ||
|     def test_unicode_dir_on_sys_path(self):
 | ||
|         # Ensure a Unicode subdirectory of a directory on sys.path
 | ||
|         # does not crash.
 | ||
|         fixtures.build_files(
 | ||
|             {self.unicode_filename(): {}},
 | ||
|             prefix=self.site_dir,
 | ||
|         )
 | ||
|         list(distributions())
 | ||
| 
 | ||
| 
 | ||
| class PackagesDistributionsPrebuiltTest(fixtures.ZipFixtures, unittest.TestCase):
 | ||
|     def test_packages_distributions_example(self):
 | ||
|         self._fixture_on_path('example-21.12-py3-none-any.whl')
 | ||
|         assert packages_distributions()['example'] == ['example']
 | ||
| 
 | ||
|     def test_packages_distributions_example2(self):
 | ||
|         """
 | ||
|         Test packages_distributions on a wheel built
 | ||
|         by trampolim.
 | ||
|         """
 | ||
|         self._fixture_on_path('example2-1.0.0-py3-none-any.whl')
 | ||
|         assert packages_distributions()['example2'] == ['example2']
 | ||
| 
 | ||
| 
 | ||
| class PackagesDistributionsTest(
 | ||
|     fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase
 | ||
| ):
 | ||
|     def test_packages_distributions_neither_toplevel_nor_files(self):
 | ||
|         """
 | ||
|         Test a package built without 'top-level.txt' or a file list.
 | ||
|         """
 | ||
|         fixtures.build_files(
 | ||
|             {
 | ||
|                 'trim_example-1.0.0.dist-info': {
 | ||
|                     'METADATA': """
 | ||
|                 Name: trim_example
 | ||
|                 Version: 1.0.0
 | ||
|                 """,
 | ||
|                 }
 | ||
|             },
 | ||
|             prefix=self.site_dir,
 | ||
|         )
 | ||
|         packages_distributions()
 |