Skip to content

Commit 2b3a112

Browse files
committed
Fix file:// drive URLs on POSIX and .b2d detection with a query
file://C:/x names the host C:, which only Windows can reach, so POSIX now raises instead of silently producing a relative path. And the suffix check that routes .b2d stores to cache_storage= saw the query string, not the name; strip it (and any fragment) before comparing.
1 parent ff47bae commit 2b3a112

3 files changed

Lines changed: 20 additions & 3 deletions

File tree

src/blosc2/core.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,10 @@ def normalize_urlpath(urlpath: object) -> object:
629629
parsed = urllib.parse.urlparse(urlpath)
630630
netloc = "" if parsed.netloc.lower() in ("", "localhost") else parsed.netloc
631631
if re.fullmatch("[A-Za-z]:", netloc):
632+
if os.name != "nt":
633+
raise ValueError(
634+
f"{urlpath} names the host {netloc!r}; only Windows can reach one, as a drive"
635+
)
632636
# A Windows drive lands in netloc for the two-slash form, `file://C:/x`
633637
prefix = netloc
634638
elif not netloc:

src/blosc2/schunk.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ def _open_fsspec_url(urlpath: str, mode: str, offset: int, kwargs: dict):
20192019
requested = [k for k, v in kwargs.items() if v is not None]
20202020
if requested:
20212021
raise NotImplementedError(f"{', '.join(requested)} on an fsspec URL requires passing cache_storage=")
2022-
if urlpath.endswith(".b2d"):
2022+
if urlpath.split("?", 1)[0].split("#", 1)[0].endswith(".b2d"):
20232023
raise NotImplementedError(
20242024
"directory containers (.b2d, sparse frames) on an fsspec URL require "
20252025
"passing cache_storage= to fetch them locally first"

tests/test_fsspec.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ def test_dir_container_needs_cache():
136136
blosc2.open("memory://store.b2d")
137137

138138

139+
def test_dir_container_with_query_needs_cache():
140+
with pytest.raises(NotImplementedError, match="cache_storage"):
141+
blosc2.open("memory://store.b2d?version=1")
142+
143+
139144
def test_cached_open(tmp_path):
140145
a = blosc2.arange(10, dtype="i4")
141146
with fsspec.open("memory://c.b2nd", "wb") as f:
@@ -554,15 +559,23 @@ def test_zip_store_needs_cache(tmp_path):
554559
[
555560
("file:///tmp/a.b2nd", "/tmp/a.b2nd"),
556561
("file://localhost/tmp/a.b2nd", "/tmp/a.b2nd"),
557-
# A Windows drive lands in the netloc for the two-slash form
558-
("file://C:/data/a.b2nd", "C:"),
559562
],
560563
)
561564
def test_normalize_file_url(url, expected):
562565
# as_posix() because the separator is the platform's, the layout is not
563566
assert expected in pathlib.PurePath(blosc2.core.normalize_urlpath(url)).as_posix()
564567

565568

569+
def test_normalize_windows_drive_url():
570+
# file://C:/x names the host C:, which only Windows can reach, as a drive
571+
url = "file://C:/data/a.b2nd"
572+
if os.name == "nt":
573+
assert pathlib.PurePath(blosc2.core.normalize_urlpath(url)).as_posix() == "C:/data/a.b2nd"
574+
else:
575+
with pytest.raises(ValueError, match="C:"):
576+
blosc2.core.normalize_urlpath(url)
577+
578+
566579
def test_normalize_file_url_with_a_host():
567580
# A host authority is a UNC path, which only Windows can reach; concatenating
568581
# it without its two slashes would silently make it a relative path instead

0 commit comments

Comments
 (0)