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