From f08c66467d56c71f75c6659ede9177449fe9d2e6 Mon Sep 17 00:00:00 2001 From: William Schwartz Date: Sat, 16 Jan 2021 11:22:21 -0600 Subject: [3.8] bpo-42531: Teach importlib.resources.path to handle packages without __file__ (GH-23611) Fixes [bpo-42531]() for Python 3.8. The issue also applies to 3.7. If this PR looks like it'll be accepted, I can cherry-pick it to the 3.7 branch and submit a follow-up PR. Automerge-Triggered-By: GH:jaraco --- Lib/importlib/resources.py | 8 +++++--- Lib/test/test_importlib/test_path.py | 12 ++++++++++++ .../next/Library/2020-12-02-16-28-04.bpo-42531.2sLlFW.rst | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-02-16-28-04.bpo-42531.2sLlFW.rst diff --git a/Lib/importlib/resources.py b/Lib/importlib/resources.py index fc3a1c9..8d37d52c 100644 --- a/Lib/importlib/resources.py +++ b/Lib/importlib/resources.py @@ -193,9 +193,11 @@ def path(package: Package, resource: Resource) -> Iterator[Path]: _check_location(package) # Fall-through for both the lack of resource_path() *and* if # resource_path() raises FileNotFoundError. - package_directory = Path(package.__spec__.origin).parent - file_path = package_directory / resource - if file_path.exists(): + file_path = None + if package.__spec__.origin is not None: + package_directory = Path(package.__spec__.origin).parent + file_path = package_directory / resource + if file_path is not None and file_path.exists(): yield file_path else: with open_binary(package, resource) as fp: diff --git a/Lib/test/test_importlib/test_path.py b/Lib/test/test_importlib/test_path.py index 2d3dcda..5c5a8e3 100644 --- a/Lib/test/test_importlib/test_path.py +++ b/Lib/test/test_importlib/test_path.py @@ -1,3 +1,4 @@ +import io import unittest from importlib import resources @@ -27,6 +28,17 @@ class PathDiskTests(PathTests, unittest.TestCase): data = data01 +class PathMemoryTests(PathTests, unittest.TestCase): + def setUp(self): + file = io.BytesIO(b'Hello, UTF-8 world!\n') + self.addCleanup(file.close) + self.data = util.create_package( + file=file, path=FileNotFoundError("package exists only in memory") + ) + self.data.__spec__.origin = None + self.data.__spec__.has_location = False + + class PathZipTests(PathTests, util.ZipSetup, unittest.TestCase): def test_remove_in_context_manager(self): # It is not an error if the file that was temporarily stashed on the diff --git a/Misc/NEWS.d/next/Library/2020-12-02-16-28-04.bpo-42531.2sLlFW.rst b/Misc/NEWS.d/next/Library/2020-12-02-16-28-04.bpo-42531.2sLlFW.rst new file mode 100644 index 0000000..7927078 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-02-16-28-04.bpo-42531.2sLlFW.rst @@ -0,0 +1 @@ +:func:`importlib.resources.path` now works for :term:`package`\ s missing the optional :attr:`__file__` attribute (more specifically, packages whose :attr:`__spec__`\ ``.``\ :attr:`~importlib.machinery.ModuleSpec.origin` :keyword:`is` :data:`None`). \ No newline at end of file -- cgit v0.12