Skip to content

Commit a117244

Browse files
committed
Fix #1056: Decode URL-escaped paths for local filesystems
This commit patches _init_filesystem() in util.py to detect whether a protocol is local and decode url-encoded paths using urllib.parse.unquote.
1 parent c269768 commit a117244

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

malariagen_data/util.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,21 @@ def _init_filesystem(url, **kwargs):
494494
# Process the URL using fsspec.
495495
fs, path = url_to_fs(url, **storage_options)
496496

497+
# Decode URL-encoded paths for local filesystems.
498+
protocol = getattr(fs, "protocol", None)
499+
if isinstance(protocol, str):
500+
protocols = {protocol}
501+
elif isinstance(protocol, (tuple, list)):
502+
protocols = set(protocol)
503+
else:
504+
protocols = set()
505+
506+
is_local = bool(protocols.intersection({"file", "local"})) or fs.__class__.__name__ == "LocalFileSystem"
507+
508+
if is_local:
509+
from urllib.parse import unquote
510+
path = unquote(path)
511+
497512
# Path compatibility, fsspec/gcsfs behaviour varies between versions.
498513
while path.endswith("/"):
499514
path = path[:-1]

tests/test_util_filesystem.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import os
2+
import pytest
3+
from pathlib import Path
4+
from malariagen_data.util import _init_filesystem
5+
6+
def test_init_filesystem_decodes_file_uri_escaped_path(tmp_path):
7+
dir_with_space = tmp_path / "dir with space's"
8+
dir_with_space.mkdir()
9+
file_path = dir_with_space / "v3-config.json"
10+
file_path.write_text('{"foo": "bar"}')
11+
12+
uri = dir_with_space.as_uri()
13+
14+
fs, path = _init_filesystem(uri)
15+
16+
assert "%20" in uri
17+
assert "%20" not in path
18+
assert "%27" not in path
19+
20+
# Using local path with os.path.join should now succeed
21+
with fs.open(os.path.join(path, "v3-config.json"), "r") as f:
22+
assert f.read() == '{"foo": "bar"}'
23+
24+
25+
def test_init_filesystem_plain_local_path_unchanged(tmp_path):
26+
dir_with_space = tmp_path / "dir with space's"
27+
dir_with_space.mkdir()
28+
file_path = dir_with_space / "v3-config.json"
29+
file_path.write_text('{"foo": "bar"}')
30+
31+
uri = str(dir_with_space)
32+
33+
fs, path = _init_filesystem(uri)
34+
35+
with fs.open(os.path.join(path, "v3-config.json"), "r") as f:
36+
assert f.read() == '{"foo": "bar"}'

0 commit comments

Comments
 (0)