Browse Source
bpo-39791: Add files() to importlib.resources (GH-19722)
bpo-39791: Add files() to importlib.resources (GH-19722)
* bpo-39791: Update importlib.resources to support files() API (importlib_resources 1.5). * 📜🤖 Added by blurb_it. * Add some documentation about the new objects added. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>pull/20015/head
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 295 additions and 102 deletions
-
37Doc/library/importlib.rst
-
72Lib/importlib/_common.py
-
86Lib/importlib/abc.py
-
161Lib/importlib/resources.py
-
39Lib/test/test_importlib/test_files.py
-
1Lib/test/test_importlib/test_path.py
-
1Misc/NEWS.d/next/Library/2020-04-27-00-51-40.bpo-39791.wv8Dxn.rst
@ -0,0 +1,72 @@ |
|||
import os |
|||
import pathlib |
|||
import zipfile |
|||
import tempfile |
|||
import functools |
|||
import contextlib |
|||
|
|||
|
|||
def from_package(package): |
|||
""" |
|||
Return a Traversable object for the given package. |
|||
|
|||
""" |
|||
spec = package.__spec__ |
|||
return from_traversable_resources(spec) or fallback_resources(spec) |
|||
|
|||
|
|||
def from_traversable_resources(spec): |
|||
""" |
|||
If the spec.loader implements TraversableResources, |
|||
directly or implicitly, it will have a ``files()`` method. |
|||
""" |
|||
with contextlib.suppress(AttributeError): |
|||
return spec.loader.files() |
|||
|
|||
|
|||
def fallback_resources(spec): |
|||
package_directory = pathlib.Path(spec.origin).parent |
|||
try: |
|||
archive_path = spec.loader.archive |
|||
rel_path = package_directory.relative_to(archive_path) |
|||
return zipfile.Path(archive_path, str(rel_path) + '/') |
|||
except Exception: |
|||
pass |
|||
return package_directory |
|||
|
|||
|
|||
@contextlib.contextmanager |
|||
def _tempfile(reader, suffix=''): |
|||
# Not using tempfile.NamedTemporaryFile as it leads to deeper 'try' |
|||
# blocks due to the need to close the temporary file to work on Windows |
|||
# properly. |
|||
fd, raw_path = tempfile.mkstemp(suffix=suffix) |
|||
try: |
|||
os.write(fd, reader()) |
|||
os.close(fd) |
|||
yield pathlib.Path(raw_path) |
|||
finally: |
|||
try: |
|||
os.remove(raw_path) |
|||
except FileNotFoundError: |
|||
pass |
|||
|
|||
|
|||
@functools.singledispatch |
|||
@contextlib.contextmanager |
|||
def as_file(path): |
|||
""" |
|||
Given a Traversable object, return that object as a |
|||
path on the local file system in a context manager. |
|||
""" |
|||
with _tempfile(path.read_bytes, suffix=path.name) as local: |
|||
yield local |
|||
|
|||
|
|||
@as_file.register(pathlib.Path) |
|||
@contextlib.contextmanager |
|||
def _(path): |
|||
""" |
|||
Degenerate behavior for pathlib.Path objects. |
|||
""" |
|||
yield path |
|||
@ -0,0 +1,39 @@ |
|||
import typing |
|||
import unittest |
|||
|
|||
from importlib import resources |
|||
from importlib.abc import Traversable |
|||
from . import data01 |
|||
from . import util |
|||
|
|||
|
|||
class FilesTests: |
|||
def test_read_bytes(self): |
|||
files = resources.files(self.data) |
|||
actual = files.joinpath('utf-8.file').read_bytes() |
|||
assert actual == b'Hello, UTF-8 world!\n' |
|||
|
|||
def test_read_text(self): |
|||
files = resources.files(self.data) |
|||
actual = files.joinpath('utf-8.file').read_text() |
|||
assert actual == 'Hello, UTF-8 world!\n' |
|||
|
|||
@unittest.skipUnless( |
|||
hasattr(typing, 'runtime_checkable'), |
|||
"Only suitable when typing supports runtime_checkable", |
|||
) |
|||
def test_traversable(self): |
|||
assert isinstance(resources.files(self.data), Traversable) |
|||
|
|||
|
|||
class OpenDiskTests(FilesTests, unittest.TestCase): |
|||
def setUp(self): |
|||
self.data = data01 |
|||
|
|||
|
|||
class OpenZipTests(FilesTests, util.ZipSetup, unittest.TestCase): |
|||
pass |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
unittest.main() |
|||
@ -0,0 +1 @@ |
|||
Added ``files()`` function to importlib.resources with support for subdirectories in package data, matching backport in importlib_resources 1.5. |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue