Skip to content

Commit cb4bbdd

Browse files
authored
Merge pull request #290 from python/bugfix/namespace-packages-in-zip
Fixed handling of namespace packages in zip files
2 parents fe9dbf6 + a9b0c92 commit cb4bbdd

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

importlib_resources/readers.py

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import collections
2+
import contextlib
23
import itertools
34
import pathlib
45
import operator
6+
import re
57

68
from . import abc
79

@@ -130,7 +132,33 @@ class NamespaceReader(abc.TraversableResources):
130132
def __init__(self, namespace_path):
131133
if 'NamespacePath' not in str(namespace_path):
132134
raise ValueError('Invalid path')
133-
self.path = MultiplexedPath(*list(namespace_path))
135+
self.path = MultiplexedPath(*map(self._resolve, namespace_path))
136+
137+
@classmethod
138+
def _resolve(cls, path_str) -> abc.Traversable:
139+
r"""
140+
Given an item from a namespace path, resolve it to a Traversable.
141+
142+
path_str might be a directory on the filesystem or a path to a
143+
zipfile plus the path within the zipfile, e.g. ``/foo/bar`` or
144+
``/foo/baz.zip/inner_dir`` or ``foo\baz.zip\inner_dir\sub``.
145+
"""
146+
(dir,) = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir())
147+
return dir
148+
149+
@classmethod
150+
def _candidate_paths(cls, path_str):
151+
yield pathlib.Path(path_str)
152+
yield from cls._resolve_zip_path(path_str)
153+
154+
@staticmethod
155+
def _resolve_zip_path(path_str):
156+
for match in reversed(list(re.finditer(r'[\\/]', path_str))):
157+
with contextlib.suppress(
158+
FileNotFoundError, IsADirectoryError, PermissionError
159+
):
160+
inner = path_str[match.end() :].replace('\\', '/') + '/'
161+
yield ZipPath(path_str[: match.start()], inner.lstrip('/'))
134162

135163
def resource_path(self, resource):
136164
"""

importlib_resources/tests/test_resource.py

-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import importlib_resources as resources
44
import pathlib
55

6-
import pytest
7-
86
from . import data01
97
from . import util
108
from importlib import import_module
@@ -211,7 +209,6 @@ def tearDownClass(cls):
211209
sys.path.remove(cls.site_dir)
212210

213211

214-
@pytest.mark.xfail
215212
class ResourceFromNamespaceZipTests(
216213
util.ZipSetupBase,
217214
ResourceFromNamespaceTests,

newsfragments/287.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Enabled support for resources in namespace packages in zip files.

0 commit comments

Comments
 (0)