Skip to content

Commit 3f49de3

Browse files
authored
Merge pull request #293 from sfc-gh-wzhao/wzhao-fix-files-not-a-directory-when-reading-submodule-of-a-zipped-namespace-package
Fix NotADirectory error when calling files on a subdirectory of a zipped namespace package
2 parents eec758b + 76145e2 commit 3f49de3

File tree

10 files changed

+65
-13
lines changed

10 files changed

+65
-13
lines changed

importlib_resources/readers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,10 @@ def _candidate_paths(cls, path_str):
156156
def _resolve_zip_path(path_str):
157157
for match in reversed(list(re.finditer(r'[\\/]', path_str))):
158158
with contextlib.suppress(
159-
FileNotFoundError, IsADirectoryError, PermissionError
159+
FileNotFoundError,
160+
IsADirectoryError,
161+
NotADirectoryError,
162+
PermissionError,
160163
):
161164
inner = path_str[match.end() :].replace('\\', '/') + '/'
162165
yield ZipPath(path_str[: match.start()], inner.lstrip('/'))
Binary file not shown.

importlib_resources/tests/namespacedata01/subdirectory/binary.file

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+


importlib_resources/tests/test_contents.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class ContentsZipTests(ContentsTests, util.ZipSetup, unittest.TestCase):
3131
class ContentsNamespaceTests(ContentsTests, unittest.TestCase):
3232
expected = {
3333
# no __init__ because of namespace design
34-
# no subdirectory as incidental difference in fixture
3534
'binary.file',
35+
'subdirectory',
3636
'utf-16.file',
3737
'utf-8.file',
3838
}

importlib_resources/tests/test_files.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ def setUp(self):
5858
self.data = namespacedata01
5959

6060

61+
class OpenNamespaceZipTests(FilesTests, util.ZipSetup, unittest.TestCase):
62+
ZIP_MODULE = 'namespacedata01'
63+
64+
6165
class SiteDir:
6266
def setUp(self):
6367
self.fixtures = contextlib.ExitStack()

importlib_resources/tests/test_open.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_open_binary(self):
2424
target = resources.files(self.data) / 'binary.file'
2525
with target.open('rb') as fp:
2626
result = fp.read()
27-
self.assertEqual(result, b'\x00\x01\x02\x03')
27+
self.assertEqual(result, bytes(range(4)))
2828

2929
def test_open_text_default_encoding(self):
3030
target = resources.files(self.data) / 'utf-8.file'
@@ -81,5 +81,9 @@ class OpenZipTests(OpenTests, util.ZipSetup, unittest.TestCase):
8181
pass
8282

8383

84+
class OpenNamespaceZipTests(OpenTests, util.ZipSetup, unittest.TestCase):
85+
ZIP_MODULE = 'namespacedata01'
86+
87+
8488
if __name__ == '__main__':
8589
unittest.main()

importlib_resources/tests/test_read.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def execute(self, package, path):
1919
class ReadTests:
2020
def test_read_bytes(self):
2121
result = resources.files(self.data).joinpath('binary.file').read_bytes()
22-
self.assertEqual(result, b'\0\1\2\3')
22+
self.assertEqual(result, bytes(range(4)))
2323

2424
def test_read_text_default_encoding(self):
2525
result = (
@@ -60,13 +60,13 @@ class ReadZipTests(ReadTests, util.ZipSetup, unittest.TestCase):
6060
def test_read_submodule_resource(self):
6161
submodule = import_module('data01.subdirectory')
6262
result = resources.files(submodule).joinpath('binary.file').read_bytes()
63-
self.assertEqual(result, b'\0\1\2\3')
63+
self.assertEqual(result, bytes(range(4, 8)))
6464

6565
def test_read_submodule_resource_by_name(self):
6666
result = (
6767
resources.files('data01.subdirectory').joinpath('binary.file').read_bytes()
6868
)
69-
self.assertEqual(result, b'\0\1\2\3')
69+
self.assertEqual(result, bytes(range(4, 8)))
7070

7171

7272
class ReadNamespaceTests(ReadTests, unittest.TestCase):
@@ -76,5 +76,22 @@ def setUp(self):
7676
self.data = namespacedata01
7777

7878

79+
class ReadNamespaceZipTests(ReadTests, util.ZipSetup, unittest.TestCase):
80+
ZIP_MODULE = 'namespacedata01'
81+
82+
def test_read_submodule_resource(self):
83+
submodule = import_module('namespacedata01.subdirectory')
84+
result = resources.files(submodule).joinpath('binary.file').read_bytes()
85+
self.assertEqual(result, bytes(range(12, 16)))
86+
87+
def test_read_submodule_resource_by_name(self):
88+
result = (
89+
resources.files('namespacedata01.subdirectory')
90+
.joinpath('binary.file')
91+
.read_bytes()
92+
)
93+
self.assertEqual(result, bytes(range(12, 16)))
94+
95+
7996
if __name__ == '__main__':
8097
unittest.main()

importlib_resources/tests/test_reader.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ def test_iterdir(self):
2626
contents.remove('__pycache__')
2727
except (KeyError, ValueError):
2828
pass
29-
self.assertEqual(contents, {'binary.file', 'utf-16.file', 'utf-8.file'})
29+
self.assertEqual(
30+
contents, {'subdirectory', 'binary.file', 'utf-16.file', 'utf-8.file'}
31+
)
3032

3133
def test_iterdir_duplicate(self):
3234
data01 = pathlib.Path(__file__).parent.joinpath('data01')
@@ -66,10 +68,10 @@ def test_join_path(self):
6668
str(path.joinpath('binary.file'))[len(prefix) + 1 :],
6769
os.path.join('namespacedata01', 'binary.file'),
6870
)
69-
self.assertEqual(
70-
str(path.joinpath('subdirectory'))[len(prefix) + 1 :],
71-
os.path.join('data01', 'subdirectory'),
72-
)
71+
sub = path.joinpath('subdirectory')
72+
assert isinstance(sub, MultiplexedPath)
73+
assert 'namespacedata01' in str(sub)
74+
assert 'data01' in str(sub)
7375
self.assertEqual(
7476
str(path.joinpath('imaginary'))[len(prefix) + 1 :],
7577
os.path.join('namespacedata01', 'imaginary'),

importlib_resources/tests/test_resource.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,35 @@ def test_submodule_contents(self):
186186
contents.remove('__pycache__')
187187
except KeyError:
188188
pass
189-
self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})
189+
self.assertEqual(
190+
contents, {'subdirectory', 'binary.file', 'utf-8.file', 'utf-16.file'}
191+
)
190192

191193
def test_submodule_contents_by_name(self):
192194
contents = names(resources.files('namespacedata01'))
193195
try:
194196
contents.remove('__pycache__')
195197
except KeyError:
196198
pass
197-
self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})
199+
self.assertEqual(
200+
contents, {'subdirectory', 'binary.file', 'utf-8.file', 'utf-16.file'}
201+
)
202+
203+
def test_submodule_sub_contents(self):
204+
contents = names(resources.files(import_module('namespacedata01.subdirectory')))
205+
try:
206+
contents.remove('__pycache__')
207+
except KeyError:
208+
pass
209+
self.assertEqual(contents, {'binary.file'})
210+
211+
def test_submodule_sub_contents_by_name(self):
212+
contents = names(resources.files('namespacedata01.subdirectory'))
213+
try:
214+
contents.remove('__pycache__')
215+
except KeyError:
216+
pass
217+
self.assertEqual(contents, {'binary.file'})
198218

199219

200220
class ResourceFromNamespaceDiskTests(ResourceFromNamespaceTests, unittest.TestCase):

newsfragments/293.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed NotADirectoryError when calling files on a subdirectory of a namespace package.

0 commit comments

Comments
 (0)