From c9a1aae0de95987a559b3029501a92393de57ffe Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 12:11:53 -0400 Subject: [PATCH] Omit sentinel values from a namespace path. When editable installs create sentinels, as they are not a valid directory, they're unsuitable for constructing a `MultiplexedPath`. Filter them out. Fixes #311 --- importlib_resources/readers.py | 13 +++++++++---- importlib_resources/tests/test_files.py | 3 --- newsfragments/311.bugfix.rst | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 newsfragments/311.bugfix.rst diff --git a/importlib_resources/readers.py b/importlib_resources/readers.py index abfcde7..89f70de 100644 --- a/importlib_resources/readers.py +++ b/importlib_resources/readers.py @@ -5,6 +5,7 @@ import operator import re import warnings +from typing import Optional from . import abc @@ -135,19 +136,23 @@ class NamespaceReader(abc.TraversableResources): def __init__(self, namespace_path): if 'NamespacePath' not in str(namespace_path): raise ValueError('Invalid path') - self.path = MultiplexedPath(*map(self._resolve, namespace_path)) + self.path = MultiplexedPath(*filter(bool, map(self._resolve, namespace_path))) @classmethod - def _resolve(cls, path_str) -> abc.Traversable: + def _resolve(cls, path_str) -> Optional[abc.Traversable]: r""" 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`` or ``foo\baz.zip\inner_dir\sub``. + + path_str might also be a sentinel used by editable packages to + trigger other behaviors (see python/importlib_resources#311). + In that case, return None. """ - (dir,) = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir()) - return dir + dirs = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir()) + return next(dirs, None) @classmethod def _candidate_paths(cls, path_str): diff --git a/importlib_resources/tests/test_files.py b/importlib_resources/tests/test_files.py index c07975c..412a44d 100644 --- a/importlib_resources/tests/test_files.py +++ b/importlib_resources/tests/test_files.py @@ -8,8 +8,6 @@ import importlib import contextlib -import pytest - import importlib_resources as resources from ..abc import Traversable from . import util @@ -62,7 +60,6 @@ class OpenZipTests(FilesTests, util.ZipSetup, unittest.TestCase): class OpenNamespaceTests(FilesTests, util.DiskSetup, unittest.TestCase): MODULE = 'namespacedata01' - @pytest.mark.xfail(reason="#311") def test_non_paths_in_dunder_path(self): """ Non-path items in a namespace package's ``__path__`` are ignored. diff --git a/newsfragments/311.bugfix.rst b/newsfragments/311.bugfix.rst new file mode 100644 index 0000000..56655f7 --- /dev/null +++ b/newsfragments/311.bugfix.rst @@ -0,0 +1 @@ +Omit sentinel values from a namespace path. \ No newline at end of file