Commit 5ec0feee authored by Barry Warsaw's avatar Barry Warsaw Committed by GitHub

Implement the get_resource_reader() API for file system imports (#5168)

parent 21102f0d
......@@ -6,12 +6,11 @@ such it requires the injection of specific modules and attributes in order to
work. One should use importlib as the public-facing version of this module.
"""
#
# IMPORTANT: Whenever making changes to this module, be sure to run
# a top-level make in order to get the frozen version of the module
# updated. Not doing so will result in the Makefile to fail for
# all others who don't have a ./python around to freeze the module
# in the early stages of compilation.
# IMPORTANT: Whenever making changes to this module, be sure to run a top-level
# `make regen-importlib` followed by `make` in order to get the frozen version
# of the module updated. Not doing so will result in the Makefile to fail for
# all others who don't have a ./python around to freeze the module in the early
# stages of compilation.
#
# See importlib._setup() for what is injected into the global namespace.
......@@ -911,6 +910,33 @@ class FileLoader:
with _io.FileIO(path, 'r') as file:
return file.read()
# ResourceReader ABC API.
@_check_name
def get_resource_reader(self, module):
if self.is_package(module):
return self
return None
def open_resource(self, resource):
path = _path_join(_path_split(self.path)[0], resource)
return _io.FileIO(path, 'r')
def resource_path(self, resource):
if not self.is_resource(resource):
raise FileNotFoundError
path = _path_join(_path_split(self.path)[0], resource)
return path
def is_resource(self, name):
if path_sep in name:
return False
path = _path_join(_path_split(self.path)[0], name)
return _path_isfile(path)
def contents(self):
return iter(_os.listdir(_path_split(self.path)[0]))
class SourceFileLoader(FileLoader, SourceLoader):
......
......@@ -342,7 +342,7 @@ class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLo
_register(SourceLoader, machinery.SourceFileLoader)
class ResourceReader:
class ResourceReader(metaclass=abc.ABCMeta):
"""Abstract base class to provide resource-reading support.
......@@ -383,3 +383,6 @@ class ResourceReader:
def contents(self):
"""Return an iterator of strings over the contents of the package."""
return iter([])
_register(ResourceReader, machinery.SourceFileLoader)
......@@ -59,8 +59,10 @@ def _get_resource_reader(
# hook wants to create a weak reference to the object, but
# zipimport.zipimporter does not support weak references, resulting in a
# TypeError. That seems terrible.
if hasattr(package.__spec__.loader, 'open_resource'):
return cast(resources_abc.ResourceReader, package.__spec__.loader)
spec = package.__spec__
if hasattr(spec.loader, 'get_resource_reader'):
return cast(resources_abc.ResourceReader,
spec.loader.get_resource_reader(spec.name))
return None
......
import sys
import unittest
from importlib import resources
from . import data01
from . import zipdata02
from . import util
from importlib import resources
class ResourceTests:
......
......@@ -397,6 +397,9 @@ class CASEOKTestBase:
def create_package(file, path, is_package=True, contents=()):
class Reader(ResourceReader):
def get_resource_reader(self, package):
return self
def open_resource(self, path):
self._path = path
if isinstance(file, Exception):
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment