Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e712a5b

Browse files
authoredDec 31, 2021
bpo-46118: Move importlib.resources to its own package. (python#30176)
* bpo-46118: Move importlib.resources to its own package. * Expand compatibility shims with documentation and explicit imports.
1 parent 2cf7d02 commit e712a5b

File tree

13 files changed

+409
-368
lines changed

13 files changed

+409
-368
lines changed
 

‎Lib/importlib/abc.py

Lines changed: 13 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,19 @@
1414
from ._abc import Loader
1515
import abc
1616
import warnings
17-
from typing import BinaryIO, Iterable, Text
18-
from typing import Protocol, runtime_checkable
17+
18+
# for compatibility with Python 3.10
19+
from .resources.abc import ResourceReader, Traversable, TraversableResources
20+
21+
22+
__all__ = [
23+
'Loader', 'Finder', 'MetaPathFinder', 'PathEntryFinder',
24+
'ResourceLoader', 'InspectLoader', 'ExecutionLoader',
25+
'FileLoader', 'SourceLoader',
26+
27+
# for compatibility with Python 3.10
28+
'ResourceReader', 'Traversable', 'TraversableResources',
29+
]
1930

2031

2132
def _register(abstract_cls, *classes):
@@ -307,136 +318,3 @@ def set_data(self, path, data):
307318
"""
308319

309320
_register(SourceLoader, machinery.SourceFileLoader)
310-
311-
312-
class ResourceReader(metaclass=abc.ABCMeta):
313-
"""Abstract base class for loaders to provide resource reading support."""
314-
315-
@abc.abstractmethod
316-
def open_resource(self, resource: Text) -> BinaryIO:
317-
"""Return an opened, file-like object for binary reading.
318-
319-
The 'resource' argument is expected to represent only a file name.
320-
If the resource cannot be found, FileNotFoundError is raised.
321-
"""
322-
# This deliberately raises FileNotFoundError instead of
323-
# NotImplementedError so that if this method is accidentally called,
324-
# it'll still do the right thing.
325-
raise FileNotFoundError
326-
327-
@abc.abstractmethod
328-
def resource_path(self, resource: Text) -> Text:
329-
"""Return the file system path to the specified resource.
330-
331-
The 'resource' argument is expected to represent only a file name.
332-
If the resource does not exist on the file system, raise
333-
FileNotFoundError.
334-
"""
335-
# This deliberately raises FileNotFoundError instead of
336-
# NotImplementedError so that if this method is accidentally called,
337-
# it'll still do the right thing.
338-
raise FileNotFoundError
339-
340-
@abc.abstractmethod
341-
def is_resource(self, path: Text) -> bool:
342-
"""Return True if the named 'path' is a resource.
343-
344-
Files are resources, directories are not.
345-
"""
346-
raise FileNotFoundError
347-
348-
@abc.abstractmethod
349-
def contents(self) -> Iterable[str]:
350-
"""Return an iterable of entries in `package`."""
351-
raise FileNotFoundError
352-
353-
354-
@runtime_checkable
355-
class Traversable(Protocol):
356-
"""
357-
An object with a subset of pathlib.Path methods suitable for
358-
traversing directories and opening files.
359-
"""
360-
361-
@abc.abstractmethod
362-
def iterdir(self):
363-
"""
364-
Yield Traversable objects in self
365-
"""
366-
367-
def read_bytes(self):
368-
"""
369-
Read contents of self as bytes
370-
"""
371-
with self.open('rb') as strm:
372-
return strm.read()
373-
374-
def read_text(self, encoding=None):
375-
"""
376-
Read contents of self as text
377-
"""
378-
with self.open(encoding=encoding) as strm:
379-
return strm.read()
380-
381-
@abc.abstractmethod
382-
def is_dir(self) -> bool:
383-
"""
384-
Return True if self is a directory
385-
"""
386-
387-
@abc.abstractmethod
388-
def is_file(self) -> bool:
389-
"""
390-
Return True if self is a file
391-
"""
392-
393-
@abc.abstractmethod
394-
def joinpath(self, child):
395-
"""
396-
Return Traversable child in self
397-
"""
398-
399-
def __truediv__(self, child):
400-
"""
401-
Return Traversable child in self
402-
"""
403-
return self.joinpath(child)
404-
405-
@abc.abstractmethod
406-
def open(self, mode='r', *args, **kwargs):
407-
"""
408-
mode may be 'r' or 'rb' to open as text or binary. Return a handle
409-
suitable for reading (same as pathlib.Path.open).
410-
411-
When opening as text, accepts encoding parameters such as those
412-
accepted by io.TextIOWrapper.
413-
"""
414-
415-
@abc.abstractproperty
416-
def name(self) -> str:
417-
"""
418-
The base name of this object without any parent references.
419-
"""
420-
421-
422-
class TraversableResources(ResourceReader):
423-
"""
424-
The required interface for providing traversable
425-
resources.
426-
"""
427-
428-
@abc.abstractmethod
429-
def files(self):
430-
"""Return a Traversable object for the loaded package."""
431-
432-
def open_resource(self, resource):
433-
return self.files().joinpath(resource).open('rb')
434-
435-
def resource_path(self, resource):
436-
raise FileNotFoundError(resource)
437-
438-
def is_resource(self, path):
439-
return self.files().joinpath(path).is_file()
440-
441-
def contents(self):
442-
return (item.name for item in self.files().iterdir())

‎Lib/importlib/readers.py

Lines changed: 9 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,12 @@
1-
import collections
2-
import operator
3-
import pathlib
4-
import zipfile
1+
"""
2+
Compatibility shim for .resources.readers as found on Python 3.10.
53
6-
from . import abc
4+
Consumers that can rely on Python 3.11 should use the other
5+
module directly.
6+
"""
77

8-
from ._itertools import unique_everseen
8+
from .resources.readers import (
9+
FileReader, ZipReader, MultiplexedPath, NamespaceReader,
10+
)
911

10-
11-
def remove_duplicates(items):
12-
return iter(collections.OrderedDict.fromkeys(items))
13-
14-
15-
class FileReader(abc.TraversableResources):
16-
def __init__(self, loader):
17-
self.path = pathlib.Path(loader.path).parent
18-
19-
def resource_path(self, resource):
20-
"""
21-
Return the file system path to prevent
22-
`resources.path()` from creating a temporary
23-
copy.
24-
"""
25-
return str(self.path.joinpath(resource))
26-
27-
def files(self):
28-
return self.path
29-
30-
31-
class ZipReader(abc.TraversableResources):
32-
def __init__(self, loader, module):
33-
_, _, name = module.rpartition('.')
34-
self.prefix = loader.prefix.replace('\\', '/') + name + '/'
35-
self.archive = loader.archive
36-
37-
def open_resource(self, resource):
38-
try:
39-
return super().open_resource(resource)
40-
except KeyError as exc:
41-
raise FileNotFoundError(exc.args[0])
42-
43-
def is_resource(self, path):
44-
# workaround for `zipfile.Path.is_file` returning true
45-
# for non-existent paths.
46-
target = self.files().joinpath(path)
47-
return target.is_file() and target.exists()
48-
49-
def files(self):
50-
return zipfile.Path(self.archive, self.prefix)
51-
52-
53-
class MultiplexedPath(abc.Traversable):
54-
"""
55-
Given a series of Traversable objects, implement a merged
56-
version of the interface across all objects. Useful for
57-
namespace packages which may be multihomed at a single
58-
name.
59-
"""
60-
61-
def __init__(self, *paths):
62-
self._paths = list(map(pathlib.Path, remove_duplicates(paths)))
63-
if not self._paths:
64-
message = 'MultiplexedPath must contain at least one path'
65-
raise FileNotFoundError(message)
66-
if not all(path.is_dir() for path in self._paths):
67-
raise NotADirectoryError('MultiplexedPath only supports directories')
68-
69-
def iterdir(self):
70-
files = (file for path in self._paths for file in path.iterdir())
71-
return unique_everseen(files, key=operator.attrgetter('name'))
72-
73-
def read_bytes(self):
74-
raise FileNotFoundError(f'{self} is not a file')
75-
76-
def read_text(self, *args, **kwargs):
77-
raise FileNotFoundError(f'{self} is not a file')
78-
79-
def is_dir(self):
80-
return True
81-
82-
def is_file(self):
83-
return False
84-
85-
def joinpath(self, child):
86-
# first try to find child in current paths
87-
for file in self.iterdir():
88-
if file.name == child:
89-
return file
90-
# if it does not exist, construct it with the first path
91-
return self._paths[0] / child
92-
93-
__truediv__ = joinpath
94-
95-
def open(self, *args, **kwargs):
96-
raise FileNotFoundError(f'{self} is not a file')
97-
98-
@property
99-
def name(self):
100-
return self._paths[0].name
101-
102-
def __repr__(self):
103-
paths = ', '.join(f"'{path}'" for path in self._paths)
104-
return f'MultiplexedPath({paths})'
105-
106-
107-
class NamespaceReader(abc.TraversableResources):
108-
def __init__(self, namespace_path):
109-
if 'NamespacePath' not in str(namespace_path):
110-
raise ValueError('Invalid path')
111-
self.path = MultiplexedPath(*list(namespace_path))
112-
113-
def resource_path(self, resource):
114-
"""
115-
Return the file system path to prevent
116-
`resources.path()` from creating a temporary
117-
copy.
118-
"""
119-
return str(self.path.joinpath(resource))
120-
121-
def files(self):
122-
return self.path
12+
__all__ = ['FileReader', 'ZipReader', 'MultiplexedPath', 'NamespaceReader']

‎Lib/importlib/resources.py renamed to ‎Lib/importlib/resources/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
Resource,
1818
)
1919

20-
from importlib.abc import ResourceReader
20+
from .abc import ResourceReader
2121

2222

2323
__all__ = [
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

‎Lib/importlib/resources/abc.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import abc
2+
from typing import BinaryIO, Iterable, Text
3+
from typing import runtime_checkable, Protocol
4+
5+
6+
class ResourceReader(metaclass=abc.ABCMeta):
7+
"""Abstract base class for loaders to provide resource reading support."""
8+
9+
@abc.abstractmethod
10+
def open_resource(self, resource: Text) -> BinaryIO:
11+
"""Return an opened, file-like object for binary reading.
12+
13+
The 'resource' argument is expected to represent only a file name.
14+
If the resource cannot be found, FileNotFoundError is raised.
15+
"""
16+
# This deliberately raises FileNotFoundError instead of
17+
# NotImplementedError so that if this method is accidentally called,
18+
# it'll still do the right thing.
19+
raise FileNotFoundError
20+
21+
@abc.abstractmethod
22+
def resource_path(self, resource: Text) -> Text:
23+
"""Return the file system path to the specified resource.
24+
25+
The 'resource' argument is expected to represent only a file name.
26+
If the resource does not exist on the file system, raise
27+
FileNotFoundError.
28+
"""
29+
# This deliberately raises FileNotFoundError instead of
30+
# NotImplementedError so that if this method is accidentally called,
31+
# it'll still do the right thing.
32+
raise FileNotFoundError
33+
34+
@abc.abstractmethod
35+
def is_resource(self, path: Text) -> bool:
36+
"""Return True if the named 'path' is a resource.
37+
38+
Files are resources, directories are not.
39+
"""
40+
raise FileNotFoundError
41+
42+
@abc.abstractmethod
43+
def contents(self) -> Iterable[str]:
44+
"""Return an iterable of entries in `package`."""
45+
raise FileNotFoundError
46+
47+
48+
@runtime_checkable
49+
class Traversable(Protocol):
50+
"""
51+
An object with a subset of pathlib.Path methods suitable for
52+
traversing directories and opening files.
53+
"""
54+
55+
@abc.abstractmethod
56+
def iterdir(self):
57+
"""
58+
Yield Traversable objects in self
59+
"""
60+
61+
def read_bytes(self):
62+
"""
63+
Read contents of self as bytes
64+
"""
65+
with self.open('rb') as strm:
66+
return strm.read()
67+
68+
def read_text(self, encoding=None):
69+
"""
70+
Read contents of self as text
71+
"""
72+
with self.open(encoding=encoding) as strm:
73+
return strm.read()
74+
75+
@abc.abstractmethod
76+
def is_dir(self) -> bool:
77+
"""
78+
Return True if self is a directory
79+
"""
80+
81+
@abc.abstractmethod
82+
def is_file(self) -> bool:
83+
"""
84+
Return True if self is a file
85+
"""
86+
87+
@abc.abstractmethod
88+
def joinpath(self, child):
89+
"""
90+
Return Traversable child in self
91+
"""
92+
93+
def __truediv__(self, child):
94+
"""
95+
Return Traversable child in self
96+
"""
97+
return self.joinpath(child)
98+
99+
@abc.abstractmethod
100+
def open(self, mode='r', *args, **kwargs):
101+
"""
102+
mode may be 'r' or 'rb' to open as text or binary. Return a handle
103+
suitable for reading (same as pathlib.Path.open).
104+
105+
When opening as text, accepts encoding parameters such as those
106+
accepted by io.TextIOWrapper.
107+
"""
108+
109+
@abc.abstractproperty
110+
def name(self) -> str:
111+
"""
112+
The base name of this object without any parent references.
113+
"""
114+
115+
116+
class TraversableResources(ResourceReader):
117+
"""
118+
The required interface for providing traversable
119+
resources.
120+
"""
121+
122+
@abc.abstractmethod
123+
def files(self):
124+
"""Return a Traversable object for the loaded package."""
125+
126+
def open_resource(self, resource):
127+
return self.files().joinpath(resource).open('rb')
128+
129+
def resource_path(self, resource):
130+
raise FileNotFoundError(resource)
131+
132+
def is_resource(self, path):
133+
return self.files().joinpath(path).is_file()
134+
135+
def contents(self):
136+
return (item.name for item in self.files().iterdir())

‎Lib/importlib/resources/readers.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import collections
2+
import operator
3+
import pathlib
4+
import zipfile
5+
6+
from . import abc
7+
8+
from ._itertools import unique_everseen
9+
10+
11+
def remove_duplicates(items):
12+
return iter(collections.OrderedDict.fromkeys(items))
13+
14+
15+
class FileReader(abc.TraversableResources):
16+
def __init__(self, loader):
17+
self.path = pathlib.Path(loader.path).parent
18+
19+
def resource_path(self, resource):
20+
"""
21+
Return the file system path to prevent
22+
`resources.path()` from creating a temporary
23+
copy.
24+
"""
25+
return str(self.path.joinpath(resource))
26+
27+
def files(self):
28+
return self.path
29+
30+
31+
class ZipReader(abc.TraversableResources):
32+
def __init__(self, loader, module):
33+
_, _, name = module.rpartition('.')
34+
self.prefix = loader.prefix.replace('\\', '/') + name + '/'
35+
self.archive = loader.archive
36+
37+
def open_resource(self, resource):
38+
try:
39+
return super().open_resource(resource)
40+
except KeyError as exc:
41+
raise FileNotFoundError(exc.args[0])
42+
43+
def is_resource(self, path):
44+
# workaround for `zipfile.Path.is_file` returning true
45+
# for non-existent paths.
46+
target = self.files().joinpath(path)
47+
return target.is_file() and target.exists()
48+
49+
def files(self):
50+
return zipfile.Path(self.archive, self.prefix)
51+
52+
53+
class MultiplexedPath(abc.Traversable):
54+
"""
55+
Given a series of Traversable objects, implement a merged
56+
version of the interface across all objects. Useful for
57+
namespace packages which may be multihomed at a single
58+
name.
59+
"""
60+
61+
def __init__(self, *paths):
62+
self._paths = list(map(pathlib.Path, remove_duplicates(paths)))
63+
if not self._paths:
64+
message = 'MultiplexedPath must contain at least one path'
65+
raise FileNotFoundError(message)
66+
if not all(path.is_dir() for path in self._paths):
67+
raise NotADirectoryError('MultiplexedPath only supports directories')
68+
69+
def iterdir(self):
70+
files = (file for path in self._paths for file in path.iterdir())
71+
return unique_everseen(files, key=operator.attrgetter('name'))
72+
73+
def read_bytes(self):
74+
raise FileNotFoundError(f'{self} is not a file')
75+
76+
def read_text(self, *args, **kwargs):
77+
raise FileNotFoundError(f'{self} is not a file')
78+
79+
def is_dir(self):
80+
return True
81+
82+
def is_file(self):
83+
return False
84+
85+
def joinpath(self, child):
86+
# first try to find child in current paths
87+
for file in self.iterdir():
88+
if file.name == child:
89+
return file
90+
# if it does not exist, construct it with the first path
91+
return self._paths[0] / child
92+
93+
__truediv__ = joinpath
94+
95+
def open(self, *args, **kwargs):
96+
raise FileNotFoundError(f'{self} is not a file')
97+
98+
@property
99+
def name(self):
100+
return self._paths[0].name
101+
102+
def __repr__(self):
103+
paths = ', '.join(f"'{path}'" for path in self._paths)
104+
return f'MultiplexedPath({paths})'
105+
106+
107+
class NamespaceReader(abc.TraversableResources):
108+
def __init__(self, namespace_path):
109+
if 'NamespacePath' not in str(namespace_path):
110+
raise ValueError('Invalid path')
111+
self.path = MultiplexedPath(*list(namespace_path))
112+
113+
def resource_path(self, resource):
114+
"""
115+
Return the file system path to prevent
116+
`resources.path()` from creating a temporary
117+
copy.
118+
"""
119+
return str(self.path.joinpath(resource))
120+
121+
def files(self):
122+
return self.path

‎Lib/importlib/resources/simple.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"""
2+
Interface adapters for low-level readers.
3+
"""
4+
5+
import abc
6+
import io
7+
import itertools
8+
from typing import BinaryIO, List
9+
10+
from .abc import Traversable, TraversableResources
11+
12+
13+
class SimpleReader(abc.ABC):
14+
"""
15+
The minimum, low-level interface required from a resource
16+
provider.
17+
"""
18+
19+
@abc.abstractproperty
20+
def package(self):
21+
# type: () -> str
22+
"""
23+
The name of the package for which this reader loads resources.
24+
"""
25+
26+
@abc.abstractmethod
27+
def children(self):
28+
# type: () -> List['SimpleReader']
29+
"""
30+
Obtain an iterable of SimpleReader for available
31+
child containers (e.g. directories).
32+
"""
33+
34+
@abc.abstractmethod
35+
def resources(self):
36+
# type: () -> List[str]
37+
"""
38+
Obtain available named resources for this virtual package.
39+
"""
40+
41+
@abc.abstractmethod
42+
def open_binary(self, resource):
43+
# type: (str) -> BinaryIO
44+
"""
45+
Obtain a File-like for a named resource.
46+
"""
47+
48+
@property
49+
def name(self):
50+
return self.package.split('.')[-1]
51+
52+
53+
class ResourceHandle(Traversable):
54+
"""
55+
Handle to a named resource in a ResourceReader.
56+
"""
57+
58+
def __init__(self, parent, name):
59+
# type: (ResourceContainer, str) -> None
60+
self.parent = parent
61+
self.name = name # type: ignore
62+
63+
def is_file(self):
64+
return True
65+
66+
def is_dir(self):
67+
return False
68+
69+
def open(self, mode='r', *args, **kwargs):
70+
stream = self.parent.reader.open_binary(self.name)
71+
if 'b' not in mode:
72+
stream = io.TextIOWrapper(*args, **kwargs)
73+
return stream
74+
75+
def joinpath(self, name):
76+
raise RuntimeError("Cannot traverse into a resource")
77+
78+
79+
class ResourceContainer(Traversable):
80+
"""
81+
Traversable container for a package's resources via its reader.
82+
"""
83+
84+
def __init__(self, reader):
85+
# type: (SimpleReader) -> None
86+
self.reader = reader
87+
88+
def is_dir(self):
89+
return True
90+
91+
def is_file(self):
92+
return False
93+
94+
def iterdir(self):
95+
files = (ResourceHandle(self, name) for name in self.reader.resources)
96+
dirs = map(ResourceContainer, self.reader.children())
97+
return itertools.chain(files, dirs)
98+
99+
def open(self, *args, **kwargs):
100+
raise IsADirectoryError()
101+
102+
def joinpath(self, name):
103+
return next(
104+
traversable for traversable in self.iterdir() if traversable.name == name
105+
)
106+
107+
108+
class TraversableReader(TraversableResources, SimpleReader):
109+
"""
110+
A TraversableResources based on SimpleReader. Resource providers
111+
may derive from this class to provide the TraversableResources
112+
interface by supplying the SimpleReader interface.
113+
"""
114+
115+
def files(self):
116+
return ResourceContainer(self)

‎Lib/importlib/simple.py

Lines changed: 10 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,14 @@
11
"""
2-
Interface adapters for low-level readers.
3-
"""
4-
5-
import abc
6-
import io
7-
import itertools
8-
from typing import BinaryIO, List
9-
10-
from .abc import Traversable, TraversableResources
11-
12-
13-
class SimpleReader(abc.ABC):
14-
"""
15-
The minimum, low-level interface required from a resource
16-
provider.
17-
"""
18-
19-
@abc.abstractproperty
20-
def package(self):
21-
# type: () -> str
22-
"""
23-
The name of the package for which this reader loads resources.
24-
"""
25-
26-
@abc.abstractmethod
27-
def children(self):
28-
# type: () -> List['SimpleReader']
29-
"""
30-
Obtain an iterable of SimpleReader for available
31-
child containers (e.g. directories).
32-
"""
33-
34-
@abc.abstractmethod
35-
def resources(self):
36-
# type: () -> List[str]
37-
"""
38-
Obtain available named resources for this virtual package.
39-
"""
40-
41-
@abc.abstractmethod
42-
def open_binary(self, resource):
43-
# type: (str) -> BinaryIO
44-
"""
45-
Obtain a File-like for a named resource.
46-
"""
47-
48-
@property
49-
def name(self):
50-
return self.package.split('.')[-1]
51-
52-
53-
class ResourceHandle(Traversable):
54-
"""
55-
Handle to a named resource in a ResourceReader.
56-
"""
57-
58-
def __init__(self, parent, name):
59-
# type: (ResourceContainer, str) -> None
60-
self.parent = parent
61-
self.name = name # type: ignore
62-
63-
def is_file(self):
64-
return True
65-
66-
def is_dir(self):
67-
return False
68-
69-
def open(self, mode='r', *args, **kwargs):
70-
stream = self.parent.reader.open_binary(self.name)
71-
if 'b' not in mode:
72-
stream = io.TextIOWrapper(*args, **kwargs)
73-
return stream
74-
75-
def joinpath(self, name):
76-
raise RuntimeError("Cannot traverse into a resource")
77-
78-
79-
class ResourceContainer(Traversable):
80-
"""
81-
Traversable container for a package's resources via its reader.
82-
"""
83-
84-
def __init__(self, reader):
85-
# type: (SimpleReader) -> None
86-
self.reader = reader
87-
88-
def is_dir(self):
89-
return True
90-
91-
def is_file(self):
92-
return False
93-
94-
def iterdir(self):
95-
files = (ResourceHandle(self, name) for name in self.reader.resources)
96-
dirs = map(ResourceContainer, self.reader.children())
97-
return itertools.chain(files, dirs)
98-
99-
def open(self, *args, **kwargs):
100-
raise IsADirectoryError()
101-
102-
def joinpath(self, name):
103-
return next(
104-
traversable for traversable in self.iterdir() if traversable.name == name
105-
)
2+
Compatibility shim for .resources.simple as found on Python 3.10.
1063
4+
Consumers that can rely on Python 3.11 should use the other
5+
module directly.
6+
"""
1077

108-
class TraversableReader(TraversableResources, SimpleReader):
109-
"""
110-
A TraversableResources based on SimpleReader. Resource providers
111-
may derive from this class to provide the TraversableResources
112-
interface by supplying the SimpleReader interface.
113-
"""
8+
from .resources.simple import (
9+
SimpleReader, ResourceHandle, ResourceContainer, TraversableReader,
10+
)
11411

115-
def files(self):
116-
return ResourceContainer(self)
12+
__all__ = [
13+
'SimpleReader', 'ResourceHandle', 'ResourceContainer', 'TraversableReader',
14+
]

‎Lib/test/test_importlib/test_compatibilty_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from importlib import resources
55

6-
from importlib._adapters import (
6+
from importlib.resources._adapters import (
77
CompatibilityFiles,
88
wrap_spec,
99
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Moved importlib.resources and its related functionality to a package.

0 commit comments

Comments
 (0)
Please sign in to comment.