diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2020-05-08 19:20:26 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-08 19:20:26 -0400 |
commit | 7f7e706d78ab968a1221c6179dfdba714860bd12 (patch) | |
tree | 1f1da103275c4c240e654785a976004100a169de /Lib/importlib/_common.py | |
parent | d10091aa171250c67a5079abfe26b8b3964ea39a (diff) | |
download | cpython-git-7f7e706d78ab968a1221c6179dfdba714860bd12.tar.gz |
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>
Diffstat (limited to 'Lib/importlib/_common.py')
-rw-r--r-- | Lib/importlib/_common.py | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/Lib/importlib/_common.py b/Lib/importlib/_common.py new file mode 100644 index 0000000000..ba7cbac3c9 --- /dev/null +++ b/Lib/importlib/_common.py @@ -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 |