util.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import abc
  2. import importlib
  3. import io
  4. import sys
  5. import types
  6. import pathlib
  7. import contextlib
  8. from . import data01
  9. from ..abc import ResourceReader
  10. from ._compat import import_helper, os_helper
  11. from . import zip as zip_
  12. from importlib.machinery import ModuleSpec
  13. class Reader(ResourceReader):
  14. def __init__(self, **kwargs):
  15. vars(self).update(kwargs)
  16. def get_resource_reader(self, package):
  17. return self
  18. def open_resource(self, path):
  19. self._path = path
  20. if isinstance(self.file, Exception):
  21. raise self.file
  22. return self.file
  23. def resource_path(self, path_):
  24. self._path = path_
  25. if isinstance(self.path, Exception):
  26. raise self.path
  27. return self.path
  28. def is_resource(self, path_):
  29. self._path = path_
  30. if isinstance(self.path, Exception):
  31. raise self.path
  32. def part(entry):
  33. return entry.split('/')
  34. return any(
  35. len(parts) == 1 and parts[0] == path_ for parts in map(part, self._contents)
  36. )
  37. def contents(self):
  38. if isinstance(self.path, Exception):
  39. raise self.path
  40. yield from self._contents
  41. def create_package_from_loader(loader, is_package=True):
  42. name = 'testingpackage'
  43. module = types.ModuleType(name)
  44. spec = ModuleSpec(name, loader, origin='does-not-exist', is_package=is_package)
  45. module.__spec__ = spec
  46. module.__loader__ = loader
  47. return module
  48. def create_package(file=None, path=None, is_package=True, contents=()):
  49. return create_package_from_loader(
  50. Reader(file=file, path=path, _contents=contents),
  51. is_package,
  52. )
  53. class CommonTests(metaclass=abc.ABCMeta):
  54. """
  55. Tests shared by test_open, test_path, and test_read.
  56. """
  57. @abc.abstractmethod
  58. def execute(self, package, path):
  59. """
  60. Call the pertinent legacy API function (e.g. open_text, path)
  61. on package and path.
  62. """
  63. def test_package_name(self):
  64. """
  65. Passing in the package name should succeed.
  66. """
  67. self.execute(data01.__name__, 'utf-8.file')
  68. def test_package_object(self):
  69. """
  70. Passing in the package itself should succeed.
  71. """
  72. self.execute(data01, 'utf-8.file')
  73. def test_string_path(self):
  74. """
  75. Passing in a string for the path should succeed.
  76. """
  77. path = 'utf-8.file'
  78. self.execute(data01, path)
  79. def test_pathlib_path(self):
  80. """
  81. Passing in a pathlib.PurePath object for the path should succeed.
  82. """
  83. path = pathlib.PurePath('utf-8.file')
  84. self.execute(data01, path)
  85. def test_importing_module_as_side_effect(self):
  86. """
  87. The anchor package can already be imported.
  88. """
  89. del sys.modules[data01.__name__]
  90. self.execute(data01.__name__, 'utf-8.file')
  91. def test_missing_path(self):
  92. """
  93. Attempting to open or read or request the path for a
  94. non-existent path should succeed if open_resource
  95. can return a viable data stream.
  96. """
  97. bytes_data = io.BytesIO(b'Hello, world!')
  98. package = create_package(file=bytes_data, path=FileNotFoundError())
  99. self.execute(package, 'utf-8.file')
  100. self.assertEqual(package.__loader__._path, 'utf-8.file')
  101. def test_extant_path(self):
  102. # Attempting to open or read or request the path when the
  103. # path does exist should still succeed. Does not assert
  104. # anything about the result.
  105. bytes_data = io.BytesIO(b'Hello, world!')
  106. # any path that exists
  107. path = __file__
  108. package = create_package(file=bytes_data, path=path)
  109. self.execute(package, 'utf-8.file')
  110. self.assertEqual(package.__loader__._path, 'utf-8.file')
  111. def test_useless_loader(self):
  112. package = create_package(file=FileNotFoundError(), path=FileNotFoundError())
  113. with self.assertRaises(FileNotFoundError):
  114. self.execute(package, 'utf-8.file')
  115. class ZipSetupBase:
  116. ZIP_MODULE = 'data01'
  117. def setUp(self):
  118. self.fixtures = contextlib.ExitStack()
  119. self.addCleanup(self.fixtures.close)
  120. modules = import_helper.modules_setup()
  121. self.addCleanup(import_helper.modules_cleanup, *modules)
  122. temp_dir = self.fixtures.enter_context(os_helper.temp_dir())
  123. modules = pathlib.Path(temp_dir) / 'zipped modules.zip'
  124. src_path = pathlib.Path(__file__).parent.joinpath(self.ZIP_MODULE)
  125. self.fixtures.enter_context(
  126. import_helper.DirsOnSysPath(str(zip_.make_zip_file(src_path, modules)))
  127. )
  128. self.data = importlib.import_module(self.ZIP_MODULE)
  129. class ZipSetup(ZipSetupBase):
  130. pass