| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | import abc | 
					
						
							|  |  |  | import importlib | 
					
						
							|  |  |  | import io | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import types | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  | import pathlib | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  | import contextlib | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-27 04:54:31 -04:00
										 |  |  | from importlib.resources.abc import ResourceReader | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  | from test.support import import_helper, os_helper | 
					
						
							|  |  |  | from . import zip as zip_ | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  | from . import _path | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from importlib.machinery import ModuleSpec | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Reader(ResourceReader): | 
					
						
							|  |  |  |     def __init__(self, **kwargs): | 
					
						
							|  |  |  |         vars(self).update(kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_resource_reader(self, package): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def open_resource(self, path): | 
					
						
							|  |  |  |         self._path = path | 
					
						
							|  |  |  |         if isinstance(self.file, Exception): | 
					
						
							|  |  |  |             raise self.file | 
					
						
							|  |  |  |         return self.file | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def resource_path(self, path_): | 
					
						
							|  |  |  |         self._path = path_ | 
					
						
							|  |  |  |         if isinstance(self.path, Exception): | 
					
						
							|  |  |  |             raise self.path | 
					
						
							|  |  |  |         return self.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_resource(self, path_): | 
					
						
							|  |  |  |         self._path = path_ | 
					
						
							|  |  |  |         if isinstance(self.path, Exception): | 
					
						
							|  |  |  |             raise self.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def part(entry): | 
					
						
							|  |  |  |             return entry.split('/') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return any( | 
					
						
							|  |  |  |             len(parts) == 1 and parts[0] == path_ for parts in map(part, self._contents) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def contents(self): | 
					
						
							|  |  |  |         if isinstance(self.path, Exception): | 
					
						
							|  |  |  |             raise self.path | 
					
						
							|  |  |  |         yield from self._contents | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def create_package_from_loader(loader, is_package=True): | 
					
						
							|  |  |  |     name = 'testingpackage' | 
					
						
							|  |  |  |     module = types.ModuleType(name) | 
					
						
							|  |  |  |     spec = ModuleSpec(name, loader, origin='does-not-exist', is_package=is_package) | 
					
						
							|  |  |  |     module.__spec__ = spec | 
					
						
							|  |  |  |     module.__loader__ = loader | 
					
						
							|  |  |  |     return module | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def create_package(file=None, path=None, is_package=True, contents=()): | 
					
						
							|  |  |  |     return create_package_from_loader( | 
					
						
							|  |  |  |         Reader(file=file, path=path, _contents=contents), | 
					
						
							|  |  |  |         is_package, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  | class CommonTestsBase(metaclass=abc.ABCMeta): | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Tests shared by test_open, test_path, and test_read. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abc.abstractmethod | 
					
						
							|  |  |  |     def execute(self, package, path): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Call the pertinent legacy API function (e.g. open_text, path) | 
					
						
							|  |  |  |         on package and path. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_package_name(self): | 
					
						
							| 
									
										
										
										
											2023-02-18 16:29:22 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Passing in the package name should succeed. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         self.execute(self.data.__name__, 'utf-8.file') | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_package_object(self): | 
					
						
							| 
									
										
										
										
											2023-02-18 16:29:22 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Passing in the package itself should succeed. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         self.execute(self.data, 'utf-8.file') | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_string_path(self): | 
					
						
							| 
									
										
										
										
											2023-02-18 16:29:22 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Passing in a string for the path should succeed. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  |         path = 'utf-8.file' | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         self.execute(self.data, path) | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_pathlib_path(self): | 
					
						
							| 
									
										
										
										
											2023-02-18 16:29:22 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Passing in a pathlib.PurePath object for the path should succeed. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-01-01 11:07:32 -05:00
										 |  |  |         path = pathlib.PurePath('utf-8.file') | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         self.execute(self.data, path) | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_importing_module_as_side_effect(self): | 
					
						
							| 
									
										
										
										
											2023-02-18 16:29:22 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         The anchor package can already be imported. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         del sys.modules[self.data.__name__] | 
					
						
							|  |  |  |         self.execute(self.data.__name__, 'utf-8.file') | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_missing_path(self): | 
					
						
							| 
									
										
										
										
											2023-02-18 16:29:22 -05:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Attempting to open or read or request the path for a | 
					
						
							|  |  |  |         non-existent path should succeed if open_resource | 
					
						
							|  |  |  |         can return a viable data stream. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  |         bytes_data = io.BytesIO(b'Hello, world!') | 
					
						
							|  |  |  |         package = create_package(file=bytes_data, path=FileNotFoundError()) | 
					
						
							|  |  |  |         self.execute(package, 'utf-8.file') | 
					
						
							|  |  |  |         self.assertEqual(package.__loader__._path, 'utf-8.file') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_extant_path(self): | 
					
						
							|  |  |  |         # Attempting to open or read or request the path when the | 
					
						
							|  |  |  |         # path does exist should still succeed. Does not assert | 
					
						
							|  |  |  |         # anything about the result. | 
					
						
							|  |  |  |         bytes_data = io.BytesIO(b'Hello, world!') | 
					
						
							|  |  |  |         # any path that exists | 
					
						
							|  |  |  |         path = __file__ | 
					
						
							|  |  |  |         package = create_package(file=bytes_data, path=path) | 
					
						
							|  |  |  |         self.execute(package, 'utf-8.file') | 
					
						
							|  |  |  |         self.assertEqual(package.__loader__._path, 'utf-8.file') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_useless_loader(self): | 
					
						
							|  |  |  |         package = create_package(file=FileNotFoundError(), path=FileNotFoundError()) | 
					
						
							|  |  |  |         with self.assertRaises(FileNotFoundError): | 
					
						
							|  |  |  |             self.execute(package, 'utf-8.file') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  | fixtures = dict( | 
					
						
							|  |  |  |     data01={ | 
					
						
							|  |  |  |         '__init__.py': '', | 
					
						
							|  |  |  |         'binary.file': bytes(range(4)), | 
					
						
							| 
									
										
										
										
											2024-09-12 10:14:46 -04:00
										 |  |  |         'utf-16.file': '\ufeffHello, UTF-16 world!\n'.encode('utf-16-le'), | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         'utf-8.file': 'Hello, UTF-8 world!\n'.encode('utf-8'), | 
					
						
							|  |  |  |         'subdirectory': { | 
					
						
							|  |  |  |             '__init__.py': '', | 
					
						
							|  |  |  |             'binary.file': bytes(range(4, 8)), | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     data02={ | 
					
						
							|  |  |  |         '__init__.py': '', | 
					
						
							|  |  |  |         'one': {'__init__.py': '', 'resource1.txt': 'one resource'}, | 
					
						
							|  |  |  |         'two': {'__init__.py': '', 'resource2.txt': 'two resource'}, | 
					
						
							|  |  |  |         'subdirectory': {'subsubdir': {'resource.txt': 'a resource'}}, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     namespacedata01={ | 
					
						
							|  |  |  |         'binary.file': bytes(range(4)), | 
					
						
							| 
									
										
										
										
											2024-09-12 10:14:46 -04:00
										 |  |  |         'utf-16.file': '\ufeffHello, UTF-16 world!\n'.encode('utf-16-le'), | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         'utf-8.file': 'Hello, UTF-8 world!\n'.encode('utf-8'), | 
					
						
							|  |  |  |         'subdirectory': { | 
					
						
							|  |  |  |             'binary.file': bytes(range(12, 16)), | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ModuleSetup: | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  |     def setUp(self): | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  |         self.fixtures = contextlib.ExitStack() | 
					
						
							|  |  |  |         self.addCleanup(self.fixtures.close) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.fixtures.enter_context(import_helper.isolated_modules()) | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |         self.data = self.load_fixture(self.MODULE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def load_fixture(self, module): | 
					
						
							|  |  |  |         self.tree_on_path({module: fixtures[module]}) | 
					
						
							|  |  |  |         return importlib.import_module(module) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ZipSetup(ModuleSetup): | 
					
						
							|  |  |  |     MODULE = 'data01' | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |     def tree_on_path(self, spec): | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  |         temp_dir = self.fixtures.enter_context(os_helper.temp_dir()) | 
					
						
							|  |  |  |         modules = pathlib.Path(temp_dir) / 'zipped modules.zip' | 
					
						
							|  |  |  |         self.fixtures.enter_context( | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  |             import_helper.DirsOnSysPath(str(zip_.make_zip_file(spec, modules))) | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | class DiskSetup(ModuleSetup): | 
					
						
							|  |  |  |     MODULE = 'data01' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tree_on_path(self, spec): | 
					
						
							|  |  |  |         temp_dir = self.fixtures.enter_context(os_helper.temp_dir()) | 
					
						
							|  |  |  |         _path.build(spec, pathlib.Path(temp_dir)) | 
					
						
							|  |  |  |         self.fixtures.enter_context(import_helper.DirsOnSysPath(temp_dir)) | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 22:33:07 -04:00
										 |  |  | class CommonTests(DiskSetup, CommonTestsBase): | 
					
						
							| 
									
										
										
										
											2024-06-04 02:36:28 -04:00
										 |  |  |     pass |