Skip to content

Commit 81e7f72

Browse files
committed
Merge branch 'feature/extensible-traversable' into 'master'
Extensibility support for traversable objects Closes python#77 See merge request python-devs/importlib_resources!85
2 parents 3090428 + 7146a45 commit 81e7f72

File tree

7 files changed

+64
-29
lines changed

7 files changed

+64
-29
lines changed

importlib_resources/_compat.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
from pathlib2 import Path, PurePath # type: ignore
99

1010

11+
try:
12+
from contextlib import suppress
13+
except ImportError:
14+
from contextlib2 import suppress # type: ignore
15+
16+
1117
try:
1218
from functools import singledispatch
1319
except ImportError:

importlib_resources/abc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,21 @@ def open(self, mode='r', *args, **kwargs):
116116
When opening as text, accepts encoding parameters such as those
117117
accepted by io.TextIOWrapper.
118118
"""
119+
120+
121+
class TraversableResources(ResourceReader):
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).isfile()
134+
135+
def contents(self):
136+
return (item.name for item in self.files().iterdir())

importlib_resources/docs/changelog.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
v1.3.0
66
======
7+
* Add extensibility support for non-standard loaders to supply
8+
``Traversable`` resources. Introduces a new abstract base
9+
class ``abc.TraversableResources`` that supersedes (but
10+
implements for compatibility) ``abc.ResourceReader``. Any
11+
loader that implements (implicitly or explicitly) the
12+
``TraversableResources.files`` method will be capable of
13+
supplying resources with subdirectory support. Closes #77.
714
* Preferred way to access ``as_file`` is now from top-level module.
815
``importlib_resources.trees.as_file`` is deprecated and discouraged.
916
Closes #86.

importlib_resources/docs/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ problems of ``pkg_resources``.
99

1010
In our terminology, a *resource* is a file tree that is located within an
1111
importable `Python package`_. Resources can live on the file system or in a
12-
zip file, with limited support for loader_ supporting the appropriate API for
13-
reading resources.
12+
zip file, with support for other loader_ classes that implement the appropriate
13+
API for reading resources.
1414

1515
``importlib_resources`` is a backport of Python 3.9's standard library
1616
`importlib.resources`_ module for Python 2.7, and 3.5 through 3.8. Users of

importlib_resources/docs/using.rst

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,6 @@ the ``data.one`` package, and
5555
``data`` package.
5656

5757

58-
Caveats
59-
=======
60-
61-
Subdirectory Access
62-
-------------------
63-
64-
Prior to importlib_resources 1.1 and the ``files()`` API, resources that were
65-
not direct descendents of a package's folder were inaccessible through the
66-
API, so in the example above ``resources1/resource1.1`` is not a resource of
67-
the ``data.one`` package and ``two/resource2.txt`` is not a resource of the
68-
``data`` package. Therefore, if subdirectory access is required, use the
69-
``files()`` API.
70-
71-
Resource Reader Support
72-
-----------------------
73-
74-
Due to the limitations on resource readers to access files beyond direct
75-
descendents of a package, the ``files()`` API does not rely
76-
on the importlib ResourceReader interface and thus only supports resources
77-
exposed by the built-in path and zipfile loaders. If support for arbitrary
78-
resource readers is required, the other API functions still support loading
79-
those resources.
80-
8158
Example
8259
=======
8360

@@ -186,6 +163,16 @@ manager.
186163
Both relative and absolute paths work for Python 3.7 and newer.
187164

188165

166+
Extending
167+
=========
168+
169+
Starting with Python 3.9 and ``importlib_resources`` 1.3, this package
170+
provides an interface for non-standard loaders, such as those used by
171+
executable bundlers, to supply resources. These loaders should subclass
172+
from the ``TraversableResources`` abstract class and implement the
173+
``files()`` method to return a ``Traversable`` object.
174+
175+
189176
.. rubric:: Footnotes
190177

191178
.. [#fn1] We're ignoring `PEP 420

importlib_resources/trees.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,29 @@
66

77
from ._compat import (
88
Path, package_spec, FileNotFoundError, ZipPath,
9-
singledispatch,
9+
singledispatch, suppress,
1010
)
1111

1212

1313
def from_package(package):
14-
"""Return a Traversable object for the given package"""
14+
"""
15+
Return a Traversable object for the given package.
16+
17+
"""
1518
spec = package_spec(package)
19+
return from_traversable_resources(spec) or fallback_resources(spec)
20+
21+
22+
def from_traversable_resources(spec):
23+
"""
24+
If the spec.loader implements TraversableResources,
25+
directly or implicitly, it will have a ``files()`` method.
26+
"""
27+
with suppress(AttributeError):
28+
return spec.loader.files()
29+
30+
31+
def fallback_resources(spec):
1632
package_directory = Path(spec.origin).parent
1733
try:
1834
archive_path = spec.loader.archive
@@ -44,7 +60,7 @@ def _tempfile(reader):
4460
@contextlib.contextmanager
4561
def as_file(path):
4662
"""
47-
Given a path-like object, return that object as a
63+
Given a Traversable object, return that object as a
4864
path on the local file system in a context manager.
4965
"""
5066
with _tempfile(path.read_bytes) as local:
@@ -55,6 +71,6 @@ def as_file(path):
5571
@contextlib.contextmanager
5672
def _(path):
5773
"""
58-
Degenerate behavior for pathlib.Path objects
74+
Degenerate behavior for pathlib.Path objects.
5975
"""
6076
yield path

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ install_requires =
2222
zipp >= 0.4; python_version < '3.8'
2323
singledispatch; python_version < '3.4'
2424
importlib_metadata; python_version < '3.8'
25+
contextlib2; python_version < '3'
2526
setup_requires = setuptools_scm[toml] >= 3.4.1
2627
packages = find:
2728

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy