python (3.12.0)
1 import contextlib
2 import sys
3 import unittest
4 import uuid
5 import pathlib
6
7 from . import data01
8 from . import zipdata01, zipdata02
9 from . import util
10 from importlib import resources, import_module
11 from test.support import import_helper, os_helper
12 from test.support.os_helper import unlink
13
14
15 class ESC[4;38;5;81mResourceTests:
16 # Subclasses are expected to set the `data` attribute.
17
18 def test_is_file_exists(self):
19 target = resources.files(self.data) / 'binary.file'
20 self.assertTrue(target.is_file())
21
22 def test_is_file_missing(self):
23 target = resources.files(self.data) / 'not-a-file'
24 self.assertFalse(target.is_file())
25
26 def test_is_dir(self):
27 target = resources.files(self.data) / 'subdirectory'
28 self.assertFalse(target.is_file())
29 self.assertTrue(target.is_dir())
30
31
32 class ESC[4;38;5;81mResourceDiskTests(ESC[4;38;5;149mResourceTests, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
33 def setUp(self):
34 self.data = data01
35
36
37 class ESC[4;38;5;81mResourceZipTests(ESC[4;38;5;149mResourceTests, ESC[4;38;5;149mutilESC[4;38;5;149m.ESC[4;38;5;149mZipSetup, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
38 pass
39
40
41 def names(traversable):
42 return {item.name for item in traversable.iterdir()}
43
44
45 class ESC[4;38;5;81mResourceLoaderTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
46 def test_resource_contents(self):
47 package = util.create_package(
48 file=data01, path=data01.__file__, contents=['A', 'B', 'C']
49 )
50 self.assertEqual(names(resources.files(package)), {'A', 'B', 'C'})
51
52 def test_is_file(self):
53 package = util.create_package(
54 file=data01, path=data01.__file__, contents=['A', 'B', 'C', 'D/E', 'D/F']
55 )
56 self.assertTrue(resources.files(package).joinpath('B').is_file())
57
58 def test_is_dir(self):
59 package = util.create_package(
60 file=data01, path=data01.__file__, contents=['A', 'B', 'C', 'D/E', 'D/F']
61 )
62 self.assertTrue(resources.files(package).joinpath('D').is_dir())
63
64 def test_resource_missing(self):
65 package = util.create_package(
66 file=data01, path=data01.__file__, contents=['A', 'B', 'C', 'D/E', 'D/F']
67 )
68 self.assertFalse(resources.files(package).joinpath('Z').is_file())
69
70
71 class ESC[4;38;5;81mResourceCornerCaseTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
72 def test_package_has_no_reader_fallback(self):
73 """
74 Test odd ball packages which:
75 # 1. Do not have a ResourceReader as a loader
76 # 2. Are not on the file system
77 # 3. Are not in a zip file
78 """
79 module = util.create_package(
80 file=data01, path=data01.__file__, contents=['A', 'B', 'C']
81 )
82 # Give the module a dummy loader.
83 module.__loader__ = object()
84 # Give the module a dummy origin.
85 module.__file__ = '/path/which/shall/not/be/named'
86 module.__spec__.loader = module.__loader__
87 module.__spec__.origin = module.__file__
88 self.assertFalse(resources.files(module).joinpath('A').is_file())
89
90
91 class ESC[4;38;5;81mResourceFromZipsTest01(ESC[4;38;5;149mutilESC[4;38;5;149m.ESC[4;38;5;149mZipSetupBase, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
92 ZIP_MODULE = zipdata01 # type: ignore
93
94 def test_is_submodule_resource(self):
95 submodule = import_module('ziptestdata.subdirectory')
96 self.assertTrue(resources.files(submodule).joinpath('binary.file').is_file())
97
98 def test_read_submodule_resource_by_name(self):
99 self.assertTrue(
100 resources.files('ziptestdata.subdirectory')
101 .joinpath('binary.file')
102 .is_file()
103 )
104
105 def test_submodule_contents(self):
106 submodule = import_module('ziptestdata.subdirectory')
107 self.assertEqual(
108 names(resources.files(submodule)), {'__init__.py', 'binary.file'}
109 )
110
111 def test_submodule_contents_by_name(self):
112 self.assertEqual(
113 names(resources.files('ziptestdata.subdirectory')),
114 {'__init__.py', 'binary.file'},
115 )
116
117 def test_as_file_directory(self):
118 with resources.as_file(resources.files('ziptestdata')) as data:
119 assert data.name == 'ziptestdata'
120 assert data.is_dir()
121 assert data.joinpath('subdirectory').is_dir()
122 assert len(list(data.iterdir()))
123 assert not data.parent.exists()
124
125
126 class ESC[4;38;5;81mResourceFromZipsTest02(ESC[4;38;5;149mutilESC[4;38;5;149m.ESC[4;38;5;149mZipSetupBase, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
127 ZIP_MODULE = zipdata02 # type: ignore
128
129 def test_unrelated_contents(self):
130 """
131 Test thata zip with two unrelated subpackages return
132 distinct resources. Ref python/importlib_resources#44.
133 """
134 self.assertEqual(
135 names(resources.files('ziptestdata.one')),
136 {'__init__.py', 'resource1.txt'},
137 )
138 self.assertEqual(
139 names(resources.files('ziptestdata.two')),
140 {'__init__.py', 'resource2.txt'},
141 )
142
143
144 @contextlib.contextmanager
145 def zip_on_path(dir):
146 data_path = pathlib.Path(zipdata01.__file__)
147 source_zip_path = data_path.parent.joinpath('ziptestdata.zip')
148 zip_path = pathlib.Path(dir) / f'{uuid.uuid4()}.zip'
149 zip_path.write_bytes(source_zip_path.read_bytes())
150 sys.path.append(str(zip_path))
151 import_module('ziptestdata')
152
153 try:
154 yield
155 finally:
156 with contextlib.suppress(ValueError):
157 sys.path.remove(str(zip_path))
158
159 with contextlib.suppress(KeyError):
160 del sys.path_importer_cache[str(zip_path)]
161 del sys.modules['ziptestdata']
162
163 with contextlib.suppress(OSError):
164 unlink(zip_path)
165
166
167 class ESC[4;38;5;81mDeletingZipsTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
168 """Having accessed resources in a zip file should not keep an open
169 reference to the zip.
170 """
171
172 def setUp(self):
173 self.fixtures = contextlib.ExitStack()
174 self.addCleanup(self.fixtures.close)
175
176 modules = import_helper.modules_setup()
177 self.addCleanup(import_helper.modules_cleanup, *modules)
178
179 temp_dir = self.fixtures.enter_context(os_helper.temp_dir())
180 self.fixtures.enter_context(zip_on_path(temp_dir))
181
182 def test_iterdir_does_not_keep_open(self):
183 [item.name for item in resources.files('ziptestdata').iterdir()]
184
185 def test_is_file_does_not_keep_open(self):
186 resources.files('ziptestdata').joinpath('binary.file').is_file()
187
188 def test_is_file_failure_does_not_keep_open(self):
189 resources.files('ziptestdata').joinpath('not-present').is_file()
190
191 @unittest.skip("Desired but not supported.")
192 def test_as_file_does_not_keep_open(self): # pragma: no cover
193 resources.as_file(resources.files('ziptestdata') / 'binary.file')
194
195 def test_entered_path_does_not_keep_open(self):
196 """
197 Mimic what certifi does on import to make its bundle
198 available for the process duration.
199 """
200 resources.as_file(resources.files('ziptestdata') / 'binary.file').__enter__()
201
202 def test_read_binary_does_not_keep_open(self):
203 resources.files('ziptestdata').joinpath('binary.file').read_bytes()
204
205 def test_read_text_does_not_keep_open(self):
206 resources.files('ziptestdata').joinpath('utf-8.file').read_text(
207 encoding='utf-8'
208 )
209
210
211 class ESC[4;38;5;81mResourceFromNamespaceTest01(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
212 site_dir = str(pathlib.Path(__file__).parent)
213
214 @classmethod
215 def setUpClass(cls):
216 sys.path.append(cls.site_dir)
217
218 @classmethod
219 def tearDownClass(cls):
220 sys.path.remove(cls.site_dir)
221
222 def test_is_submodule_resource(self):
223 self.assertTrue(
224 resources.files(import_module('namespacedata01'))
225 .joinpath('binary.file')
226 .is_file()
227 )
228
229 def test_read_submodule_resource_by_name(self):
230 self.assertTrue(
231 resources.files('namespacedata01').joinpath('binary.file').is_file()
232 )
233
234 def test_submodule_contents(self):
235 contents = names(resources.files(import_module('namespacedata01')))
236 try:
237 contents.remove('__pycache__')
238 except KeyError:
239 pass
240 self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})
241
242 def test_submodule_contents_by_name(self):
243 contents = names(resources.files('namespacedata01'))
244 try:
245 contents.remove('__pycache__')
246 except KeyError:
247 pass
248 self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})
249
250
251 if __name__ == '__main__':
252 unittest.main()