diff --git a/fsspec/core.py b/fsspec/core.py index 881b07db3..a512c7080 100644 --- a/fsspec/core.py +++ b/fsspec/core.py @@ -699,7 +699,10 @@ def get_fs_token_paths( else: if ("w" in mode or "x" in mode) and expand: paths = _expand_paths(paths, name_function, num) - elif "*" in paths: + elif "*" in paths or "[" in paths: + # Not has_magic(): "?" is also the URL query delimiter, so + # treating it as a glob wildcard breaks paths like + # "https://host/f?x=1" (HTTPFileSystem excludes it too). paths = [f for f in sorted(fs.glob(paths)) if not fs.isdir(f)] else: paths = [paths] diff --git a/fsspec/tests/test_core.py b/fsspec/tests/test_core.py index 2424baba5..fff9bc4c0 100644 --- a/fsspec/tests/test_core.py +++ b/fsspec/tests/test_core.py @@ -92,6 +92,25 @@ def test_expand_fs_token_paths(mode): assert len(get_fs_token_paths("path", mode, num=2, expand=True)[-1]) == 2 +@pytest.mark.parametrize("pattern", ["apath*", "apath[12]"]) +def test_get_fs_token_paths_single_string_read_mode_globs(pattern): + d = str(tempfile.mkdtemp()) + for f in ["apath1", "apath2"]: + open(os.path.join(d, f), "w").write("test") + + _, _, paths = get_fs_token_paths(os.path.join(d, pattern), mode="rb") + + assert sorted(os.path.basename(p) for p in paths) == ["apath1", "apath2"] + + +def test_get_fs_token_paths_read_mode_keeps_question_mark_literal(): + # "?" is the URL query delimiter, so it must not be treated as a glob + # wildcard here; the path is passed through untouched rather than globbed. + url = "memory://host/file?download=1" + _, _, paths = get_fs_token_paths(url, mode="rb") + assert paths == ["/host/file?download=1"] + + def test_openfile_api(m): m.open("somepath", "wb").write(b"data") of = OpenFile(m, "somepath")