• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import sys
2import unittest
3import uuid
4import pathlib
5
6from . import data01
7from . import zipdata01, zipdata02
8from . import util
9from importlib import resources, import_module
10from test.support import import_helper
11from test.support.os_helper import unlink
12
13
14class ResourceTests:
15    # Subclasses are expected to set the `data` attribute.
16
17    def test_is_resource_good_path(self):
18        self.assertTrue(resources.is_resource(self.data, 'binary.file'))
19
20    def test_is_resource_missing(self):
21        self.assertFalse(resources.is_resource(self.data, 'not-a-file'))
22
23    def test_is_resource_subresource_directory(self):
24        # Directories are not resources.
25        self.assertFalse(resources.is_resource(self.data, 'subdirectory'))
26
27    def test_contents(self):
28        contents = set(resources.contents(self.data))
29        # There may be cruft in the directory listing of the data directory.
30        # It could have a __pycache__ directory,
31        # an artifact of the
32        # test suite importing these modules, which
33        # are not germane to this test, so just filter them out.
34        contents.discard('__pycache__')
35        self.assertEqual(
36            contents,
37            {
38                '__init__.py',
39                'subdirectory',
40                'utf-8.file',
41                'binary.file',
42                'utf-16.file',
43            },
44        )
45
46
47class ResourceDiskTests(ResourceTests, unittest.TestCase):
48    def setUp(self):
49        self.data = data01
50
51
52class ResourceZipTests(ResourceTests, util.ZipSetup, unittest.TestCase):
53    pass
54
55
56class ResourceLoaderTests(unittest.TestCase):
57    def test_resource_contents(self):
58        package = util.create_package(
59            file=data01, path=data01.__file__, contents=['A', 'B', 'C']
60        )
61        self.assertEqual(set(resources.contents(package)), {'A', 'B', 'C'})
62
63    def test_resource_is_resource(self):
64        package = util.create_package(
65            file=data01, path=data01.__file__, contents=['A', 'B', 'C', 'D/E', 'D/F']
66        )
67        self.assertTrue(resources.is_resource(package, 'B'))
68
69    def test_resource_directory_is_not_resource(self):
70        package = util.create_package(
71            file=data01, path=data01.__file__, contents=['A', 'B', 'C', 'D/E', 'D/F']
72        )
73        self.assertFalse(resources.is_resource(package, 'D'))
74
75    def test_resource_missing_is_not_resource(self):
76        package = util.create_package(
77            file=data01, path=data01.__file__, contents=['A', 'B', 'C', 'D/E', 'D/F']
78        )
79        self.assertFalse(resources.is_resource(package, 'Z'))
80
81
82class ResourceCornerCaseTests(unittest.TestCase):
83    def test_package_has_no_reader_fallback(self):
84        # Test odd ball packages which:
85        # 1. Do not have a ResourceReader as a loader
86        # 2. Are not on the file system
87        # 3. Are not in a zip file
88        module = util.create_package(
89            file=data01, path=data01.__file__, contents=['A', 'B', 'C']
90        )
91        # Give the module a dummy loader.
92        module.__loader__ = object()
93        # Give the module a dummy origin.
94        module.__file__ = '/path/which/shall/not/be/named'
95        module.__spec__.loader = module.__loader__
96        module.__spec__.origin = module.__file__
97        self.assertFalse(resources.is_resource(module, 'A'))
98
99
100class ResourceFromZipsTest01(util.ZipSetupBase, unittest.TestCase):
101    ZIP_MODULE = zipdata01  # type: ignore
102
103    def test_is_submodule_resource(self):
104        submodule = import_module('ziptestdata.subdirectory')
105        self.assertTrue(resources.is_resource(submodule, 'binary.file'))
106
107    def test_read_submodule_resource_by_name(self):
108        self.assertTrue(
109            resources.is_resource('ziptestdata.subdirectory', 'binary.file')
110        )
111
112    def test_submodule_contents(self):
113        submodule = import_module('ziptestdata.subdirectory')
114        self.assertEqual(
115            set(resources.contents(submodule)), {'__init__.py', 'binary.file'}
116        )
117
118    def test_submodule_contents_by_name(self):
119        self.assertEqual(
120            set(resources.contents('ziptestdata.subdirectory')),
121            {'__init__.py', 'binary.file'},
122        )
123
124
125class ResourceFromZipsTest02(util.ZipSetupBase, unittest.TestCase):
126    ZIP_MODULE = zipdata02  # type: ignore
127
128    def test_unrelated_contents(self):
129        """
130        Test thata zip with two unrelated subpackages return
131        distinct resources. Ref python/importlib_resources#44.
132        """
133        self.assertEqual(
134            set(resources.contents('ziptestdata.one')), {'__init__.py', 'resource1.txt'}
135        )
136        self.assertEqual(
137            set(resources.contents('ziptestdata.two')), {'__init__.py', 'resource2.txt'}
138        )
139
140
141class DeletingZipsTest(unittest.TestCase):
142    """Having accessed resources in a zip file should not keep an open
143    reference to the zip.
144    """
145
146    ZIP_MODULE = zipdata01
147
148    def setUp(self):
149        modules = import_helper.modules_setup()
150        self.addCleanup(import_helper.modules_cleanup, *modules)
151
152        data_path = pathlib.Path(self.ZIP_MODULE.__file__)
153        data_dir = data_path.parent
154        self.source_zip_path = data_dir / 'ziptestdata.zip'
155        self.zip_path = pathlib.Path(f'{uuid.uuid4()}.zip').absolute()
156        self.zip_path.write_bytes(self.source_zip_path.read_bytes())
157        sys.path.append(str(self.zip_path))
158        self.data = import_module('ziptestdata')
159
160    def tearDown(self):
161        try:
162            sys.path.remove(str(self.zip_path))
163        except ValueError:
164            pass
165
166        try:
167            del sys.path_importer_cache[str(self.zip_path)]
168            del sys.modules[self.data.__name__]
169        except KeyError:
170            pass
171
172        try:
173            unlink(self.zip_path)
174        except OSError:
175            # If the test fails, this will probably fail too
176            pass
177
178    def test_contents_does_not_keep_open(self):
179        c = resources.contents('ziptestdata')
180        self.zip_path.unlink()
181        del c
182
183    def test_is_resource_does_not_keep_open(self):
184        c = resources.is_resource('ziptestdata', 'binary.file')
185        self.zip_path.unlink()
186        del c
187
188    def test_is_resource_failure_does_not_keep_open(self):
189        c = resources.is_resource('ziptestdata', 'not-present')
190        self.zip_path.unlink()
191        del c
192
193    @unittest.skip("Desired but not supported.")
194    def test_path_does_not_keep_open(self):
195        c = resources.path('ziptestdata', 'binary.file')
196        self.zip_path.unlink()
197        del c
198
199    def test_entered_path_does_not_keep_open(self):
200        # This is what certifi does on import to make its bundle
201        # available for the process duration.
202        c = resources.path('ziptestdata', 'binary.file').__enter__()
203        self.zip_path.unlink()
204        del c
205
206    def test_read_binary_does_not_keep_open(self):
207        c = resources.read_binary('ziptestdata', 'binary.file')
208        self.zip_path.unlink()
209        del c
210
211    def test_read_text_does_not_keep_open(self):
212        c = resources.read_text('ziptestdata', 'utf-8.file', encoding='utf-8')
213        self.zip_path.unlink()
214        del c
215
216
217class ResourceFromNamespaceTest01(unittest.TestCase):
218    site_dir = str(pathlib.Path(__file__).parent)
219
220    @classmethod
221    def setUpClass(cls):
222        sys.path.append(cls.site_dir)
223
224    @classmethod
225    def tearDownClass(cls):
226        sys.path.remove(cls.site_dir)
227
228    def test_is_submodule_resource(self):
229        self.assertTrue(
230            resources.is_resource(import_module('namespacedata01'), 'binary.file')
231        )
232
233    def test_read_submodule_resource_by_name(self):
234        self.assertTrue(resources.is_resource('namespacedata01', 'binary.file'))
235
236    def test_submodule_contents(self):
237        contents = set(resources.contents(import_module('namespacedata01')))
238        try:
239            contents.remove('__pycache__')
240        except KeyError:
241            pass
242        self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})
243
244    def test_submodule_contents_by_name(self):
245        contents = set(resources.contents('namespacedata01'))
246        try:
247            contents.remove('__pycache__')
248        except KeyError:
249            pass
250        self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})
251
252
253if __name__ == '__main__':
254    unittest.main()
255