diff --git a/snakebids/tests/strategies.py b/snakebids/tests/strategies.py index 1c1f0975..dbebb19c 100644 --- a/snakebids/tests/strategies.py +++ b/snakebids/tests/strategies.py @@ -61,7 +61,6 @@ def paths( max_segments: int | None = None, absolute: bool | None = None, resolve: bool = False, - scheme: bool | None = None, # for prefixing urls with e.g. "gs://..." ) -> st.SearchStrategy[Path]: paths = st.lists( st.text(path_characters, min_size=1), @@ -73,25 +72,6 @@ def paths( absolute_paths = paths.map(lambda p: Path("/", p)) - assert not ( - scheme and absolute - ), "Path schemes prepends relative path, so don't set absolute_paths=True!" - - # absolute path and path schemes are not compatible - # implicitly set the other if None is provided - if absolute and scheme is None: - scheme = False - elif scheme and absolute is None: - absolute = False - - if scheme is not False: - scheme_st = schemes() - if scheme is None: - # probabilistically return a schemed path - scheme_st = st.one_of(st.none(), scheme_st) - scheme_st = scheme_st.map(lambda s: "" if s is None else s) - relative_paths = st.tuples(scheme_st, relative_paths).map(lambda t: t[0] + t[1]) - if absolute: result = absolute_paths elif absolute is False: @@ -105,6 +85,30 @@ def paths( return result +def schemed_paths( + *, + min_segments: int = 0, + max_segments: int | None = None, +) -> st.SearchStrategy[str]: + """schemed paths are those beginning with scheme://. + + These paths are incompatible with paths() because pathlib.Path turns // into / + when parsing, and paths() returns Path objects by default. That's why we have a + separate function for schemed paths. + + This function returns un-schemed paths as well, occasionally + """ + scheme_st: st.SearchStrategy[str] = (st.none() | schemes()).map( + lambda s: "" if s is None else s + ) + paths_st: st.SearchStrategy[str] = paths( + min_segments=min_segments, + max_segments=max_segments, + absolute=False, + ).map(lambda p: str(p)) + return st.tuples(scheme_st, paths_st).map(lambda t: t[0] + t[1]) + + def bids_entity( *, blacklist_entities: Container[BidsEntity | str] | None = None, diff --git a/snakebids/tests/test_generate_inputs.py b/snakebids/tests/test_generate_inputs.py index a645bffb..73963292 100644 --- a/snakebids/tests/test_generate_inputs.py +++ b/snakebids/tests/test_generate_inputs.py @@ -1616,7 +1616,7 @@ class TestRecogPathSchemes: ) @pytest.mark.parametrize(("path", "path_type"), PATH_AND_TYPES) - def test_is_local_relative(self, path, path_type): + def test_is_local_relative(self, path: str, path_type: str): isnet = path_type == "NETWORK" is_local_relative = path_type == "RELATIVE" @@ -1633,11 +1633,11 @@ def test_is_local_relative(self, path, path_type): @pytest.mark.parametrize( ("path", "path_type"), [tup for tup in PATH_AND_TYPES if tup[1] == "RELATIVE"] ) - def test_path_subclassing(self, path, path_type): + def test_path_subclassing(self, path: str, path_type: str): # Google cloud is not posix, for mocking purpose however we just # need a class that is a subclass of Path class MockGCSPath(PosixPath): - def __init__(self, *pathsegments): + def __init__(self, *pathsegments: str): super().__init__(*pathsegments) def __str__(self): # __fspath__ calls __str__ by default