• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import abc
2import importlib
3import io
4import sys
5import types
6from pathlib import Path, PurePath
7
8from .. import data01
9from .. import zipdata01
10from importlib.abc import ResourceReader
11from test.support import import_helper
12
13
14from importlib.machinery import ModuleSpec
15
16
17class Reader(ResourceReader):
18    def __init__(self, **kwargs):
19        vars(self).update(kwargs)
20
21    def get_resource_reader(self, package):
22        return self
23
24    def open_resource(self, path):
25        self._path = path
26        if isinstance(self.file, Exception):
27            raise self.file
28        return self.file
29
30    def resource_path(self, path_):
31        self._path = path_
32        if isinstance(self.path, Exception):
33            raise self.path
34        return self.path
35
36    def is_resource(self, path_):
37        self._path = path_
38        if isinstance(self.path, Exception):
39            raise self.path
40
41        def part(entry):
42            return entry.split('/')
43
44        return any(
45            len(parts) == 1 and parts[0] == path_ for parts in map(part, self._contents)
46        )
47
48    def contents(self):
49        if isinstance(self.path, Exception):
50            raise self.path
51        yield from self._contents
52
53
54def create_package_from_loader(loader, is_package=True):
55    name = 'testingpackage'
56    module = types.ModuleType(name)
57    spec = ModuleSpec(name, loader, origin='does-not-exist', is_package=is_package)
58    module.__spec__ = spec
59    module.__loader__ = loader
60    return module
61
62
63def create_package(file=None, path=None, is_package=True, contents=()):
64    return create_package_from_loader(
65        Reader(file=file, path=path, _contents=contents),
66        is_package,
67    )
68
69
70class CommonTests(metaclass=abc.ABCMeta):
71    """
72    Tests shared by test_open, test_path, and test_read.
73    """
74
75    @abc.abstractmethod
76    def execute(self, package, path):
77        """
78        Call the pertinent legacy API function (e.g. open_text, path)
79        on package and path.
80        """
81
82    def test_package_name(self):
83        # Passing in the package name should succeed.
84        self.execute(data01.__name__, 'utf-8.file')
85
86    def test_package_object(self):
87        # Passing in the package itself should succeed.
88        self.execute(data01, 'utf-8.file')
89
90    def test_string_path(self):
91        # Passing in a string for the path should succeed.
92        path = 'utf-8.file'
93        self.execute(data01, path)
94
95    def test_pathlib_path(self):
96        # Passing in a pathlib.PurePath object for the path should succeed.
97        path = PurePath('utf-8.file')
98        self.execute(data01, path)
99
100    def test_importing_module_as_side_effect(self):
101        # The anchor package can already be imported.
102        del sys.modules[data01.__name__]
103        self.execute(data01.__name__, 'utf-8.file')
104
105    def test_non_package_by_name(self):
106        # The anchor package cannot be a module.
107        with self.assertRaises(TypeError):
108            self.execute(__name__, 'utf-8.file')
109
110    def test_non_package_by_package(self):
111        # The anchor package cannot be a module.
112        with self.assertRaises(TypeError):
113            module = sys.modules['test.test_importlib.resources.util']
114            self.execute(module, 'utf-8.file')
115
116    def test_missing_path(self):
117        # Attempting to open or read or request the path for a
118        # non-existent path should succeed if open_resource
119        # can return a viable data stream.
120        bytes_data = io.BytesIO(b'Hello, world!')
121        package = create_package(file=bytes_data, path=FileNotFoundError())
122        self.execute(package, 'utf-8.file')
123        self.assertEqual(package.__loader__._path, 'utf-8.file')
124
125    def test_extant_path(self):
126        # Attempting to open or read or request the path when the
127        # path does exist should still succeed. Does not assert
128        # anything about the result.
129        bytes_data = io.BytesIO(b'Hello, world!')
130        # any path that exists
131        path = __file__
132        package = create_package(file=bytes_data, path=path)
133        self.execute(package, 'utf-8.file')
134        self.assertEqual(package.__loader__._path, 'utf-8.file')
135
136    def test_useless_loader(self):
137        package = create_package(file=FileNotFoundError(), path=FileNotFoundError())
138        with self.assertRaises(FileNotFoundError):
139            self.execute(package, 'utf-8.file')
140
141
142class ZipSetupBase:
143    ZIP_MODULE = None
144
145    @classmethod
146    def setUpClass(cls):
147        data_path = Path(cls.ZIP_MODULE.__file__)
148        data_dir = data_path.parent
149        cls._zip_path = str(data_dir / 'ziptestdata.zip')
150        sys.path.append(cls._zip_path)
151        cls.data = importlib.import_module('ziptestdata')
152
153    @classmethod
154    def tearDownClass(cls):
155        try:
156            sys.path.remove(cls._zip_path)
157        except ValueError:
158            pass
159
160        try:
161            del sys.path_importer_cache[cls._zip_path]
162            del sys.modules[cls.data.__name__]
163        except KeyError:
164            pass
165
166        try:
167            del cls.data
168            del cls._zip_path
169        except AttributeError:
170            pass
171
172    def setUp(self):
173        modules = import_helper.modules_setup()
174        self.addCleanup(import_helper.modules_cleanup, *modules)
175
176
177class ZipSetup(ZipSetupBase):
178    ZIP_MODULE = zipdata01  # type: ignore
179