Skip to content

Commit

Permalink
When constructing a MultiplexedPath, resolve submodule_search_locatio…
Browse files Browse the repository at this point in the history
…ns to Traversable objects. Closes #287.
  • Loading branch information
jaraco committed Sep 19, 2023
1 parent f004f04 commit 265fbb1
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 4 deletions.
28 changes: 27 additions & 1 deletion importlib_resources/readers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import collections
import contextlib
import itertools
import pathlib
import operator
import re

from . import abc

Expand Down Expand Up @@ -130,7 +132,31 @@ class NamespaceReader(abc.TraversableResources):
def __init__(self, namespace_path):
if 'NamespacePath' not in str(namespace_path):
raise ValueError('Invalid path')
self.path = MultiplexedPath(*list(namespace_path))
self.path = MultiplexedPath(*map(self._resolve, namespace_path))

@classmethod
def _resolve(cls, path_str) -> abc.Traversable:
"""
Given an item from a namespace path, resolve it to a Traversable.
path_str might be a directory on the filesystem or a path to a
zipfile plus the path within the zipfile, e.g. ``/foo/bar`` or
``/foo/baz.zip/inner_dir``.
"""
(dir,) = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir())
return dir

@classmethod
def _candidate_paths(cls, path_str):
yield pathlib.Path(path_str)
yield from cls._resolve_zip_path(path_str)

@staticmethod
def _resolve_zip_path(path_str):
for match in reversed(list(re.finditer('/', path_str))):
with contextlib.suppress(FileNotFoundError, IsADirectoryError):
inner = path_str[match.end() :]
yield ZipPath(path_str[: match.start()], inner + '/' * len(inner))

def resource_path(self, resource):
"""
Expand Down
3 changes: 0 additions & 3 deletions importlib_resources/tests/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import importlib_resources as resources
import pathlib

import pytest

from . import data01
from . import util
from importlib import import_module
Expand Down Expand Up @@ -211,7 +209,6 @@ def tearDownClass(cls):
sys.path.remove(cls.site_dir)


@pytest.mark.xfail
class ResourceFromNamespaceZipTests(
util.ZipSetupBase,
ResourceFromNamespaceTests,
Expand Down
1 change: 1 addition & 0 deletions newsfragments/287.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MultiplexedPath now expects Traversable paths, enabling support for resources in namespace packages in zip files (previously untested). String arguments to MultiplexedPath are now deprecated.

0 comments on commit 265fbb1

Please sign in to comment.