cpython/Lib/test/test_importlib/resources/test_files.py
Miss Islington (bot) 6e887411b6
[3.13] gh-123987: Fix NotADirectoryError in NamespaceReader when sentinel present (GH-124018) (#129319)
gh-123987: Fix NotADirectoryError in NamespaceReader when sentinel present (GH-124018)
(cherry picked from commit b543b32eff)

Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
2025-01-26 12:04:09 -05:00

159 lines
4.3 KiB
Python

import textwrap
import unittest
import warnings
import importlib
import contextlib
from importlib import resources
from importlib.resources.abc import Traversable
from . import util
@contextlib.contextmanager
def suppress_known_deprecation():
with warnings.catch_warnings(record=True) as ctx:
warnings.simplefilter('default', category=DeprecationWarning)
yield ctx
class FilesTests:
def test_read_bytes(self):
files = resources.files(self.data)
actual = files.joinpath('utf-8.file').read_bytes()
assert actual == b'Hello, UTF-8 world!\n'
def test_read_text(self):
files = resources.files(self.data)
actual = files.joinpath('utf-8.file').read_text(encoding='utf-8')
assert actual == 'Hello, UTF-8 world!\n'
def test_traversable(self):
assert isinstance(resources.files(self.data), Traversable)
def test_joinpath_with_multiple_args(self):
files = resources.files(self.data)
binfile = files.joinpath('subdirectory', 'binary.file')
self.assertTrue(binfile.is_file())
def test_old_parameter(self):
"""
Files used to take a 'package' parameter. Make sure anyone
passing by name is still supported.
"""
with suppress_known_deprecation():
resources.files(package=self.data)
class OpenDiskTests(FilesTests, util.DiskSetup, unittest.TestCase):
pass
class OpenZipTests(FilesTests, util.ZipSetup, unittest.TestCase):
pass
class OpenNamespaceTests(FilesTests, util.DiskSetup, unittest.TestCase):
MODULE = 'namespacedata01'
def test_non_paths_in_dunder_path(self):
"""
Non-path items in a namespace package's ``__path__`` are ignored.
As reported in python/importlib_resources#311, some tools
like Setuptools, when creating editable packages, will inject
non-paths into a namespace package's ``__path__``, a
sentinel like
``__editable__.sample_namespace-1.0.finder.__path_hook__``
to cause the ``PathEntryFinder`` to be called when searching
for packages. In that case, resources should still be loadable.
"""
import namespacedata01
namespacedata01.__path__.append(
'__editable__.sample_namespace-1.0.finder.__path_hook__'
)
resources.files(namespacedata01)
class OpenNamespaceZipTests(FilesTests, util.ZipSetup, unittest.TestCase):
ZIP_MODULE = 'namespacedata01'
class DirectSpec:
"""
Override behavior of ModuleSetup to write a full spec directly.
"""
MODULE = 'unused'
def load_fixture(self, name):
self.tree_on_path(self.spec)
class ModulesFiles:
spec = {
'mod.py': '',
'res.txt': 'resources are the best',
}
def test_module_resources(self):
"""
A module can have resources found adjacent to the module.
"""
import mod # type: ignore[import-not-found]
actual = resources.files(mod).joinpath('res.txt').read_text(encoding='utf-8')
assert actual == self.spec['res.txt']
class ModuleFilesDiskTests(DirectSpec, util.DiskSetup, ModulesFiles, unittest.TestCase):
pass
class ModuleFilesZipTests(DirectSpec, util.ZipSetup, ModulesFiles, unittest.TestCase):
pass
class ImplicitContextFiles:
set_val = textwrap.dedent(
"""
import importlib.resources as res
val = res.files().joinpath('res.txt').read_text(encoding='utf-8')
"""
)
spec = {
'somepkg': {
'__init__.py': set_val,
'submod.py': set_val,
'res.txt': 'resources are the best',
},
}
def test_implicit_files_package(self):
"""
Without any parameter, files() will infer the location as the caller.
"""
assert importlib.import_module('somepkg').val == 'resources are the best'
def test_implicit_files_submodule(self):
"""
Without any parameter, files() will infer the location as the caller.
"""
assert importlib.import_module('somepkg.submod').val == 'resources are the best'
class ImplicitContextFilesDiskTests(
DirectSpec, util.DiskSetup, ImplicitContextFiles, unittest.TestCase
):
pass
class ImplicitContextFilesZipTests(
DirectSpec, util.ZipSetup, ImplicitContextFiles, unittest.TestCase
):
pass
if __name__ == '__main__':
unittest.main()