Skip to content

Commit 5ec0fee

Browse files
authored
Implement the get_resource_reader() API for file system imports (#5168)
1 parent 21102f0 commit 5ec0fee

File tree

6 files changed

+1351
-1258
lines changed

6 files changed

+1351
-1258
lines changed

Lib/importlib/_bootstrap_external.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
work. One should use importlib as the public-facing version of this module.
77
88
"""
9-
#
10-
# IMPORTANT: Whenever making changes to this module, be sure to run
11-
# a top-level make in order to get the frozen version of the module
12-
# updated. Not doing so will result in the Makefile to fail for
13-
# all others who don't have a ./python around to freeze the module
14-
# in the early stages of compilation.
9+
# IMPORTANT: Whenever making changes to this module, be sure to run a top-level
10+
# `make regen-importlib` followed by `make` in order to get the frozen version
11+
# of the module updated. Not doing so will result in the Makefile to fail for
12+
# all others who don't have a ./python around to freeze the module in the early
13+
# stages of compilation.
1514
#
1615

1716
# See importlib._setup() for what is injected into the global namespace.
@@ -911,6 +910,33 @@ def get_data(self, path):
911910
with _io.FileIO(path, 'r') as file:
912911
return file.read()
913912

913+
# ResourceReader ABC API.
914+
915+
@_check_name
916+
def get_resource_reader(self, module):
917+
if self.is_package(module):
918+
return self
919+
return None
920+
921+
def open_resource(self, resource):
922+
path = _path_join(_path_split(self.path)[0], resource)
923+
return _io.FileIO(path, 'r')
924+
925+
def resource_path(self, resource):
926+
if not self.is_resource(resource):
927+
raise FileNotFoundError
928+
path = _path_join(_path_split(self.path)[0], resource)
929+
return path
930+
931+
def is_resource(self, name):
932+
if path_sep in name:
933+
return False
934+
path = _path_join(_path_split(self.path)[0], name)
935+
return _path_isfile(path)
936+
937+
def contents(self):
938+
return iter(_os.listdir(_path_split(self.path)[0]))
939+
914940

915941
class SourceFileLoader(FileLoader, SourceLoader):
916942

Lib/importlib/abc.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ def set_data(self, path, data):
342342
_register(SourceLoader, machinery.SourceFileLoader)
343343

344344

345-
class ResourceReader:
345+
class ResourceReader(metaclass=abc.ABCMeta):
346346

347347
"""Abstract base class to provide resource-reading support.
348348
@@ -383,3 +383,6 @@ def is_resource(self, name):
383383
def contents(self):
384384
"""Return an iterator of strings over the contents of the package."""
385385
return iter([])
386+
387+
388+
_register(ResourceReader, machinery.SourceFileLoader)

Lib/importlib/resources.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ def _get_resource_reader(
5959
# hook wants to create a weak reference to the object, but
6060
# zipimport.zipimporter does not support weak references, resulting in a
6161
# TypeError. That seems terrible.
62-
if hasattr(package.__spec__.loader, 'open_resource'):
63-
return cast(resources_abc.ResourceReader, package.__spec__.loader)
62+
spec = package.__spec__
63+
if hasattr(spec.loader, 'get_resource_reader'):
64+
return cast(resources_abc.ResourceReader,
65+
spec.loader.get_resource_reader(spec.name))
6466
return None
6567

6668

Lib/test/test_importlib/test_resource.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import sys
22
import unittest
33

4-
from importlib import resources
54
from . import data01
65
from . import zipdata02
76
from . import util
7+
from importlib import resources
88

99

1010
class ResourceTests:

Lib/test/test_importlib/util.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ def caseok_env_changed(self, *, should_exist):
397397

398398
def create_package(file, path, is_package=True, contents=()):
399399
class Reader(ResourceReader):
400+
def get_resource_reader(self, package):
401+
return self
402+
400403
def open_resource(self, path):
401404
self._path = path
402405
if isinstance(file, Exception):

0 commit comments

Comments
 (0)