[Python-checkins] bpo-46118: Move importlib.resources to its own package. (#30176)

jaraco webhook-mailer at python.org
Thu Dec 30 21:00:57 EST 2021


https://github.com/python/cpython/commit/e712a5b277866a71c195f38c1b5d87d9126dba3e
commit: e712a5b277866a71c195f38c1b5d87d9126dba3e
branch: main
author: Jason R. Coombs <jaraco at jaraco.com>
committer: jaraco <jaraco at jaraco.com>
date: 2021-12-30T21:00:48-05:00
summary:

bpo-46118: Move importlib.resources to its own package. (#30176)

* bpo-46118: Move importlib.resources to its own package.

* Expand compatibility shims with documentation and explicit imports.

files:
A Lib/importlib/resources/__init__.py
A Lib/importlib/resources/_adapters.py
A Lib/importlib/resources/_common.py
A Lib/importlib/resources/_itertools.py
A Lib/importlib/resources/_legacy.py
A Lib/importlib/resources/abc.py
A Lib/importlib/resources/readers.py
A Lib/importlib/resources/simple.py
A Misc/NEWS.d/next/Library/2021-12-17-16-27-44.bpo-46118.euAy0E.rst
D Lib/importlib/_adapters.py
D Lib/importlib/_common.py
D Lib/importlib/_itertools.py
D Lib/importlib/_legacy.py
D Lib/importlib/resources.py
M Lib/importlib/abc.py
M Lib/importlib/readers.py
M Lib/importlib/simple.py
M Lib/test/test_importlib/test_compatibilty_files.py

diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
index f10441608ad71..3fa151f390ba7 100644
--- a/Lib/importlib/abc.py
+++ b/Lib/importlib/abc.py
@@ -14,8 +14,19 @@
 from ._abc import Loader
 import abc
 import warnings
-from typing import BinaryIO, Iterable, Text
-from typing import Protocol, runtime_checkable
+
+# for compatibility with Python 3.10
+from .resources.abc import ResourceReader, Traversable, TraversableResources
+
+
+__all__ = [
+    'Loader', 'Finder', 'MetaPathFinder', 'PathEntryFinder',
+    'ResourceLoader', 'InspectLoader', 'ExecutionLoader',
+    'FileLoader', 'SourceLoader',
+
+    # for compatibility with Python 3.10
+    'ResourceReader', 'Traversable', 'TraversableResources',
+]
 
 
 def _register(abstract_cls, *classes):
@@ -307,136 +318,3 @@ def set_data(self, path, data):
         """
 
 _register(SourceLoader, machinery.SourceFileLoader)
-
-
-class ResourceReader(metaclass=abc.ABCMeta):
-    """Abstract base class for loaders to provide resource reading support."""
-
-    @abc.abstractmethod
-    def open_resource(self, resource: Text) -> BinaryIO:
-        """Return an opened, file-like object for binary reading.
-
-        The 'resource' argument is expected to represent only a file name.
-        If the resource cannot be found, FileNotFoundError is raised.
-        """
-        # This deliberately raises FileNotFoundError instead of
-        # NotImplementedError so that if this method is accidentally called,
-        # it'll still do the right thing.
-        raise FileNotFoundError
-
-    @abc.abstractmethod
-    def resource_path(self, resource: Text) -> Text:
-        """Return the file system path to the specified resource.
-
-        The 'resource' argument is expected to represent only a file name.
-        If the resource does not exist on the file system, raise
-        FileNotFoundError.
-        """
-        # This deliberately raises FileNotFoundError instead of
-        # NotImplementedError so that if this method is accidentally called,
-        # it'll still do the right thing.
-        raise FileNotFoundError
-
-    @abc.abstractmethod
-    def is_resource(self, path: Text) -> bool:
-        """Return True if the named 'path' is a resource.
-
-        Files are resources, directories are not.
-        """
-        raise FileNotFoundError
-
-    @abc.abstractmethod
-    def contents(self) -> Iterable[str]:
-        """Return an iterable of entries in `package`."""
-        raise FileNotFoundError
-
-
- at runtime_checkable
-class Traversable(Protocol):
-    """
-    An object with a subset of pathlib.Path methods suitable for
-    traversing directories and opening files.
-    """
-
-    @abc.abstractmethod
-    def iterdir(self):
-        """
-        Yield Traversable objects in self
-        """
-
-    def read_bytes(self):
-        """
-        Read contents of self as bytes
-        """
-        with self.open('rb') as strm:
-            return strm.read()
-
-    def read_text(self, encoding=None):
-        """
-        Read contents of self as text
-        """
-        with self.open(encoding=encoding) as strm:
-            return strm.read()
-
-    @abc.abstractmethod
-    def is_dir(self) -> bool:
-        """
-        Return True if self is a directory
-        """
-
-    @abc.abstractmethod
-    def is_file(self) -> bool:
-        """
-        Return True if self is a file
-        """
-
-    @abc.abstractmethod
-    def joinpath(self, child):
-        """
-        Return Traversable child in self
-        """
-
-    def __truediv__(self, child):
-        """
-        Return Traversable child in self
-        """
-        return self.joinpath(child)
-
-    @abc.abstractmethod
-    def open(self, mode='r', *args, **kwargs):
-        """
-        mode may be 'r' or 'rb' to open as text or binary. Return a handle
-        suitable for reading (same as pathlib.Path.open).
-
-        When opening as text, accepts encoding parameters such as those
-        accepted by io.TextIOWrapper.
-        """
-
-    @abc.abstractproperty
-    def name(self) -> str:
-        """
-        The base name of this object without any parent references.
-        """
-
-
-class TraversableResources(ResourceReader):
-    """
-    The required interface for providing traversable
-    resources.
-    """
-
-    @abc.abstractmethod
-    def files(self):
-        """Return a Traversable object for the loaded package."""
-
-    def open_resource(self, resource):
-        return self.files().joinpath(resource).open('rb')
-
-    def resource_path(self, resource):
-        raise FileNotFoundError(resource)
-
-    def is_resource(self, path):
-        return self.files().joinpath(path).is_file()
-
-    def contents(self):
-        return (item.name for item in self.files().iterdir())
diff --git a/Lib/importlib/readers.py b/Lib/importlib/readers.py
index b470a2062b2b3..df7fb92e5cd9f 100644
--- a/Lib/importlib/readers.py
+++ b/Lib/importlib/readers.py
@@ -1,122 +1,12 @@
-import collections
-import operator
-import pathlib
-import zipfile
+"""
+Compatibility shim for .resources.readers as found on Python 3.10.
 
-from . import abc
+Consumers that can rely on Python 3.11 should use the other
+module directly.
+"""
 
-from ._itertools import unique_everseen
+from .resources.readers import (
+    FileReader, ZipReader, MultiplexedPath, NamespaceReader,
+)
 
-
-def remove_duplicates(items):
-    return iter(collections.OrderedDict.fromkeys(items))
-
-
-class FileReader(abc.TraversableResources):
-    def __init__(self, loader):
-        self.path = pathlib.Path(loader.path).parent
-
-    def resource_path(self, resource):
-        """
-        Return the file system path to prevent
-        `resources.path()` from creating a temporary
-        copy.
-        """
-        return str(self.path.joinpath(resource))
-
-    def files(self):
-        return self.path
-
-
-class ZipReader(abc.TraversableResources):
-    def __init__(self, loader, module):
-        _, _, name = module.rpartition('.')
-        self.prefix = loader.prefix.replace('\\', '/') + name + '/'
-        self.archive = loader.archive
-
-    def open_resource(self, resource):
-        try:
-            return super().open_resource(resource)
-        except KeyError as exc:
-            raise FileNotFoundError(exc.args[0])
-
-    def is_resource(self, path):
-        # workaround for `zipfile.Path.is_file` returning true
-        # for non-existent paths.
-        target = self.files().joinpath(path)
-        return target.is_file() and target.exists()
-
-    def files(self):
-        return zipfile.Path(self.archive, self.prefix)
-
-
-class MultiplexedPath(abc.Traversable):
-    """
-    Given a series of Traversable objects, implement a merged
-    version of the interface across all objects. Useful for
-    namespace packages which may be multihomed at a single
-    name.
-    """
-
-    def __init__(self, *paths):
-        self._paths = list(map(pathlib.Path, remove_duplicates(paths)))
-        if not self._paths:
-            message = 'MultiplexedPath must contain at least one path'
-            raise FileNotFoundError(message)
-        if not all(path.is_dir() for path in self._paths):
-            raise NotADirectoryError('MultiplexedPath only supports directories')
-
-    def iterdir(self):
-        files = (file for path in self._paths for file in path.iterdir())
-        return unique_everseen(files, key=operator.attrgetter('name'))
-
-    def read_bytes(self):
-        raise FileNotFoundError(f'{self} is not a file')
-
-    def read_text(self, *args, **kwargs):
-        raise FileNotFoundError(f'{self} is not a file')
-
-    def is_dir(self):
-        return True
-
-    def is_file(self):
-        return False
-
-    def joinpath(self, child):
-        # first try to find child in current paths
-        for file in self.iterdir():
-            if file.name == child:
-                return file
-        # if it does not exist, construct it with the first path
-        return self._paths[0] / child
-
-    __truediv__ = joinpath
-
-    def open(self, *args, **kwargs):
-        raise FileNotFoundError(f'{self} is not a file')
-
-    @property
-    def name(self):
-        return self._paths[0].name
-
-    def __repr__(self):
-        paths = ', '.join(f"'{path}'" for path in self._paths)
-        return f'MultiplexedPath({paths})'
-
-
-class NamespaceReader(abc.TraversableResources):
-    def __init__(self, namespace_path):
-        if 'NamespacePath' not in str(namespace_path):
-            raise ValueError('Invalid path')
-        self.path = MultiplexedPath(*list(namespace_path))
-
-    def resource_path(self, resource):
-        """
-        Return the file system path to prevent
-        `resources.path()` from creating a temporary
-        copy.
-        """
-        return str(self.path.joinpath(resource))
-
-    def files(self):
-        return self.path
+__all__ = ['FileReader', 'ZipReader', 'MultiplexedPath', 'NamespaceReader']
diff --git a/Lib/importlib/resources.py b/Lib/importlib/resources/__init__.py
similarity index 92%
rename from Lib/importlib/resources.py
rename to Lib/importlib/resources/__init__.py
index 5b3bc0228d9ac..34e3a9950cc55 100644
--- a/Lib/importlib/resources.py
+++ b/Lib/importlib/resources/__init__.py
@@ -17,7 +17,7 @@
     Resource,
 )
 
-from importlib.abc import ResourceReader
+from .abc import ResourceReader
 
 
 __all__ = [
diff --git a/Lib/importlib/_adapters.py b/Lib/importlib/resources/_adapters.py
similarity index 100%
rename from Lib/importlib/_adapters.py
rename to Lib/importlib/resources/_adapters.py
diff --git a/Lib/importlib/_common.py b/Lib/importlib/resources/_common.py
similarity index 100%
rename from Lib/importlib/_common.py
rename to Lib/importlib/resources/_common.py
diff --git a/Lib/importlib/_itertools.py b/Lib/importlib/resources/_itertools.py
similarity index 100%
rename from Lib/importlib/_itertools.py
rename to Lib/importlib/resources/_itertools.py
diff --git a/Lib/importlib/_legacy.py b/Lib/importlib/resources/_legacy.py
similarity index 100%
rename from Lib/importlib/_legacy.py
rename to Lib/importlib/resources/_legacy.py
diff --git a/Lib/importlib/resources/abc.py b/Lib/importlib/resources/abc.py
new file mode 100644
index 0000000000000..e9efdab5ea830
--- /dev/null
+++ b/Lib/importlib/resources/abc.py
@@ -0,0 +1,136 @@
+import abc
+from typing import BinaryIO, Iterable, Text
+from typing import runtime_checkable, Protocol
+
+
+class ResourceReader(metaclass=abc.ABCMeta):
+    """Abstract base class for loaders to provide resource reading support."""
+
+    @abc.abstractmethod
+    def open_resource(self, resource: Text) -> BinaryIO:
+        """Return an opened, file-like object for binary reading.
+
+        The 'resource' argument is expected to represent only a file name.
+        If the resource cannot be found, FileNotFoundError is raised.
+        """
+        # This deliberately raises FileNotFoundError instead of
+        # NotImplementedError so that if this method is accidentally called,
+        # it'll still do the right thing.
+        raise FileNotFoundError
+
+    @abc.abstractmethod
+    def resource_path(self, resource: Text) -> Text:
+        """Return the file system path to the specified resource.
+
+        The 'resource' argument is expected to represent only a file name.
+        If the resource does not exist on the file system, raise
+        FileNotFoundError.
+        """
+        # This deliberately raises FileNotFoundError instead of
+        # NotImplementedError so that if this method is accidentally called,
+        # it'll still do the right thing.
+        raise FileNotFoundError
+
+    @abc.abstractmethod
+    def is_resource(self, path: Text) -> bool:
+        """Return True if the named 'path' is a resource.
+
+        Files are resources, directories are not.
+        """
+        raise FileNotFoundError
+
+    @abc.abstractmethod
+    def contents(self) -> Iterable[str]:
+        """Return an iterable of entries in `package`."""
+        raise FileNotFoundError
+
+
+ at runtime_checkable
+class Traversable(Protocol):
+    """
+    An object with a subset of pathlib.Path methods suitable for
+    traversing directories and opening files.
+    """
+
+    @abc.abstractmethod
+    def iterdir(self):
+        """
+        Yield Traversable objects in self
+        """
+
+    def read_bytes(self):
+        """
+        Read contents of self as bytes
+        """
+        with self.open('rb') as strm:
+            return strm.read()
+
+    def read_text(self, encoding=None):
+        """
+        Read contents of self as text
+        """
+        with self.open(encoding=encoding) as strm:
+            return strm.read()
+
+    @abc.abstractmethod
+    def is_dir(self) -> bool:
+        """
+        Return True if self is a directory
+        """
+
+    @abc.abstractmethod
+    def is_file(self) -> bool:
+        """
+        Return True if self is a file
+        """
+
+    @abc.abstractmethod
+    def joinpath(self, child):
+        """
+        Return Traversable child in self
+        """
+
+    def __truediv__(self, child):
+        """
+        Return Traversable child in self
+        """
+        return self.joinpath(child)
+
+    @abc.abstractmethod
+    def open(self, mode='r', *args, **kwargs):
+        """
+        mode may be 'r' or 'rb' to open as text or binary. Return a handle
+        suitable for reading (same as pathlib.Path.open).
+
+        When opening as text, accepts encoding parameters such as those
+        accepted by io.TextIOWrapper.
+        """
+
+    @abc.abstractproperty
+    def name(self) -> str:
+        """
+        The base name of this object without any parent references.
+        """
+
+
+class TraversableResources(ResourceReader):
+    """
+    The required interface for providing traversable
+    resources.
+    """
+
+    @abc.abstractmethod
+    def files(self):
+        """Return a Traversable object for the loaded package."""
+
+    def open_resource(self, resource):
+        return self.files().joinpath(resource).open('rb')
+
+    def resource_path(self, resource):
+        raise FileNotFoundError(resource)
+
+    def is_resource(self, path):
+        return self.files().joinpath(path).is_file()
+
+    def contents(self):
+        return (item.name for item in self.files().iterdir())
diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py
new file mode 100644
index 0000000000000..b470a2062b2b3
--- /dev/null
+++ b/Lib/importlib/resources/readers.py
@@ -0,0 +1,122 @@
+import collections
+import operator
+import pathlib
+import zipfile
+
+from . import abc
+
+from ._itertools import unique_everseen
+
+
+def remove_duplicates(items):
+    return iter(collections.OrderedDict.fromkeys(items))
+
+
+class FileReader(abc.TraversableResources):
+    def __init__(self, loader):
+        self.path = pathlib.Path(loader.path).parent
+
+    def resource_path(self, resource):
+        """
+        Return the file system path to prevent
+        `resources.path()` from creating a temporary
+        copy.
+        """
+        return str(self.path.joinpath(resource))
+
+    def files(self):
+        return self.path
+
+
+class ZipReader(abc.TraversableResources):
+    def __init__(self, loader, module):
+        _, _, name = module.rpartition('.')
+        self.prefix = loader.prefix.replace('\\', '/') + name + '/'
+        self.archive = loader.archive
+
+    def open_resource(self, resource):
+        try:
+            return super().open_resource(resource)
+        except KeyError as exc:
+            raise FileNotFoundError(exc.args[0])
+
+    def is_resource(self, path):
+        # workaround for `zipfile.Path.is_file` returning true
+        # for non-existent paths.
+        target = self.files().joinpath(path)
+        return target.is_file() and target.exists()
+
+    def files(self):
+        return zipfile.Path(self.archive, self.prefix)
+
+
+class MultiplexedPath(abc.Traversable):
+    """
+    Given a series of Traversable objects, implement a merged
+    version of the interface across all objects. Useful for
+    namespace packages which may be multihomed at a single
+    name.
+    """
+
+    def __init__(self, *paths):
+        self._paths = list(map(pathlib.Path, remove_duplicates(paths)))
+        if not self._paths:
+            message = 'MultiplexedPath must contain at least one path'
+            raise FileNotFoundError(message)
+        if not all(path.is_dir() for path in self._paths):
+            raise NotADirectoryError('MultiplexedPath only supports directories')
+
+    def iterdir(self):
+        files = (file for path in self._paths for file in path.iterdir())
+        return unique_everseen(files, key=operator.attrgetter('name'))
+
+    def read_bytes(self):
+        raise FileNotFoundError(f'{self} is not a file')
+
+    def read_text(self, *args, **kwargs):
+        raise FileNotFoundError(f'{self} is not a file')
+
+    def is_dir(self):
+        return True
+
+    def is_file(self):
+        return False
+
+    def joinpath(self, child):
+        # first try to find child in current paths
+        for file in self.iterdir():
+            if file.name == child:
+                return file
+        # if it does not exist, construct it with the first path
+        return self._paths[0] / child
+
+    __truediv__ = joinpath
+
+    def open(self, *args, **kwargs):
+        raise FileNotFoundError(f'{self} is not a file')
+
+    @property
+    def name(self):
+        return self._paths[0].name
+
+    def __repr__(self):
+        paths = ', '.join(f"'{path}'" for path in self._paths)
+        return f'MultiplexedPath({paths})'
+
+
+class NamespaceReader(abc.TraversableResources):
+    def __init__(self, namespace_path):
+        if 'NamespacePath' not in str(namespace_path):
+            raise ValueError('Invalid path')
+        self.path = MultiplexedPath(*list(namespace_path))
+
+    def resource_path(self, resource):
+        """
+        Return the file system path to prevent
+        `resources.path()` from creating a temporary
+        copy.
+        """
+        return str(self.path.joinpath(resource))
+
+    def files(self):
+        return self.path
diff --git a/Lib/importlib/resources/simple.py b/Lib/importlib/resources/simple.py
new file mode 100644
index 0000000000000..da073cbdb11e6
--- /dev/null
+++ b/Lib/importlib/resources/simple.py
@@ -0,0 +1,116 @@
+"""
+Interface adapters for low-level readers.
+"""
+
+import abc
+import io
+import itertools
+from typing import BinaryIO, List
+
+from .abc import Traversable, TraversableResources
+
+
+class SimpleReader(abc.ABC):
+    """
+    The minimum, low-level interface required from a resource
+    provider.
+    """
+
+    @abc.abstractproperty
+    def package(self):
+        # type: () -> str
+        """
+        The name of the package for which this reader loads resources.
+        """
+
+    @abc.abstractmethod
+    def children(self):
+        # type: () -> List['SimpleReader']
+        """
+        Obtain an iterable of SimpleReader for available
+        child containers (e.g. directories).
+        """
+
+    @abc.abstractmethod
+    def resources(self):
+        # type: () -> List[str]
+        """
+        Obtain available named resources for this virtual package.
+        """
+
+    @abc.abstractmethod
+    def open_binary(self, resource):
+        # type: (str) -> BinaryIO
+        """
+        Obtain a File-like for a named resource.
+        """
+
+    @property
+    def name(self):
+        return self.package.split('.')[-1]
+
+
+class ResourceHandle(Traversable):
+    """
+    Handle to a named resource in a ResourceReader.
+    """
+
+    def __init__(self, parent, name):
+        # type: (ResourceContainer, str) -> None
+        self.parent = parent
+        self.name = name  # type: ignore
+
+    def is_file(self):
+        return True
+
+    def is_dir(self):
+        return False
+
+    def open(self, mode='r', *args, **kwargs):
+        stream = self.parent.reader.open_binary(self.name)
+        if 'b' not in mode:
+            stream = io.TextIOWrapper(*args, **kwargs)
+        return stream
+
+    def joinpath(self, name):
+        raise RuntimeError("Cannot traverse into a resource")
+
+
+class ResourceContainer(Traversable):
+    """
+    Traversable container for a package's resources via its reader.
+    """
+
+    def __init__(self, reader):
+        # type: (SimpleReader) -> None
+        self.reader = reader
+
+    def is_dir(self):
+        return True
+
+    def is_file(self):
+        return False
+
+    def iterdir(self):
+        files = (ResourceHandle(self, name) for name in self.reader.resources)
+        dirs = map(ResourceContainer, self.reader.children())
+        return itertools.chain(files, dirs)
+
+    def open(self, *args, **kwargs):
+        raise IsADirectoryError()
+
+    def joinpath(self, name):
+        return next(
+            traversable for traversable in self.iterdir() if traversable.name == name
+        )
+
+
+class TraversableReader(TraversableResources, SimpleReader):
+    """
+    A TraversableResources based on SimpleReader. Resource providers
+    may derive from this class to provide the TraversableResources
+    interface by supplying the SimpleReader interface.
+    """
+
+    def files(self):
+        return ResourceContainer(self)
diff --git a/Lib/importlib/simple.py b/Lib/importlib/simple.py
index da073cbdb11e6..845bb90364784 100644
--- a/Lib/importlib/simple.py
+++ b/Lib/importlib/simple.py
@@ -1,116 +1,14 @@
 """
-Interface adapters for low-level readers.
-"""
-
-import abc
-import io
-import itertools
-from typing import BinaryIO, List
-
-from .abc import Traversable, TraversableResources
-
-
-class SimpleReader(abc.ABC):
-    """
-    The minimum, low-level interface required from a resource
-    provider.
-    """
-
-    @abc.abstractproperty
-    def package(self):
-        # type: () -> str
-        """
-        The name of the package for which this reader loads resources.
-        """
-
-    @abc.abstractmethod
-    def children(self):
-        # type: () -> List['SimpleReader']
-        """
-        Obtain an iterable of SimpleReader for available
-        child containers (e.g. directories).
-        """
-
-    @abc.abstractmethod
-    def resources(self):
-        # type: () -> List[str]
-        """
-        Obtain available named resources for this virtual package.
-        """
-
-    @abc.abstractmethod
-    def open_binary(self, resource):
-        # type: (str) -> BinaryIO
-        """
-        Obtain a File-like for a named resource.
-        """
-
-    @property
-    def name(self):
-        return self.package.split('.')[-1]
-
-
-class ResourceHandle(Traversable):
-    """
-    Handle to a named resource in a ResourceReader.
-    """
-
-    def __init__(self, parent, name):
-        # type: (ResourceContainer, str) -> None
-        self.parent = parent
-        self.name = name  # type: ignore
-
-    def is_file(self):
-        return True
-
-    def is_dir(self):
-        return False
-
-    def open(self, mode='r', *args, **kwargs):
-        stream = self.parent.reader.open_binary(self.name)
-        if 'b' not in mode:
-            stream = io.TextIOWrapper(*args, **kwargs)
-        return stream
-
-    def joinpath(self, name):
-        raise RuntimeError("Cannot traverse into a resource")
-
-
-class ResourceContainer(Traversable):
-    """
-    Traversable container for a package's resources via its reader.
-    """
-
-    def __init__(self, reader):
-        # type: (SimpleReader) -> None
-        self.reader = reader
-
-    def is_dir(self):
-        return True
-
-    def is_file(self):
-        return False
-
-    def iterdir(self):
-        files = (ResourceHandle(self, name) for name in self.reader.resources)
-        dirs = map(ResourceContainer, self.reader.children())
-        return itertools.chain(files, dirs)
-
-    def open(self, *args, **kwargs):
-        raise IsADirectoryError()
-
-    def joinpath(self, name):
-        return next(
-            traversable for traversable in self.iterdir() if traversable.name == name
-        )
+Compatibility shim for .resources.simple as found on Python 3.10.
 
+Consumers that can rely on Python 3.11 should use the other
+module directly.
+"""
 
-class TraversableReader(TraversableResources, SimpleReader):
-    """
-    A TraversableResources based on SimpleReader. Resource providers
-    may derive from this class to provide the TraversableResources
-    interface by supplying the SimpleReader interface.
-    """
+from .resources.simple import (
+    SimpleReader, ResourceHandle, ResourceContainer, TraversableReader,
+)
 
-    def files(self):
-        return ResourceContainer(self)
+__all__ = [
+    'SimpleReader', 'ResourceHandle', 'ResourceContainer', 'TraversableReader',
+]
diff --git a/Lib/test/test_importlib/test_compatibilty_files.py b/Lib/test/test_importlib/test_compatibilty_files.py
index d703c060c4407..9a823f2d93058 100644
--- a/Lib/test/test_importlib/test_compatibilty_files.py
+++ b/Lib/test/test_importlib/test_compatibilty_files.py
@@ -3,7 +3,7 @@
 
 from importlib import resources
 
-from importlib._adapters import (
+from importlib.resources._adapters import (
     CompatibilityFiles,
     wrap_spec,
 )
diff --git a/Misc/NEWS.d/next/Library/2021-12-17-16-27-44.bpo-46118.euAy0E.rst b/Misc/NEWS.d/next/Library/2021-12-17-16-27-44.bpo-46118.euAy0E.rst
new file mode 100644
index 0000000000000..c53e5765b9785
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-12-17-16-27-44.bpo-46118.euAy0E.rst
@@ -0,0 +1 @@
+Moved importlib.resources and its related functionality to a package.



More information about the Python-checkins mailing list