diff --git a/src/numpydantic/serialization.py b/src/numpydantic/serialization.py index 059dfdd..1682a69 100644 --- a/src/numpydantic/serialization.py +++ b/src/numpydantic/serialization.py @@ -64,14 +64,20 @@ def _relativize_paths( ``relative_to`` directory, if provided in the context """ relative_to = Path(relative_to).resolve() - # pdb.set_trace() def _r_path(v: Any) -> Any: if not isinstance(v, (str, Path)): return v try: path = Path(v) - if not path.exists(): + resolved = path.resolve() + # skip things that are pathlike but either don't exist + # or that are at the filesystem root (eg like /data) + if ( + not path.exists() + or (resolved.is_dir() and str(resolved.parent) == resolved.root) + or relative_to.root != resolved.root + ): return v return str(relative_path(path, relative_to)) except (TypeError, ValueError): @@ -86,9 +92,7 @@ def _absolutize_paths(value: dict, skip: Iterable = tuple()) -> dict: return v try: path = Path(v) - # skip things that are pathlike but either don't exist - # or that are at the filesystem root (eg like /data) - if not path.exists() and path.parent != Path().root: + if not path.exists(): return v return str(path.resolve()) except (TypeError, ValueError): diff --git a/tests/test_serialization.py b/tests/test_serialization.py index ca65d53..6fc6dd3 100644 --- a/tests/test_serialization.py +++ b/tests/test_serialization.py @@ -10,7 +10,7 @@ from typing import Callable import numpy as np import json -from numpydantic.serialization import _walk_and_apply +from numpydantic.serialization import _walk_and_apply, _relativize_paths, relative_path pytestmark = pytest.mark.serialization @@ -56,7 +56,7 @@ def test_relative_to_path(hdf5_at_path, tmp_output_dir, model_blank): """ out_path = tmp_output_dir / "relative.h5" relative_to_path = Path(__file__) / "fake_dir" / "sub_fake_dir" - expected_path = "../../../__tmp__/relative.h5" + expected_path = Path("../../../__tmp__/relative.h5") hdf5_at_path(out_path) model = model_blank(array=(out_path, "/data")) @@ -69,13 +69,34 @@ def test_relative_to_path(hdf5_at_path, tmp_output_dir, model_blank): # should not be absolute assert not Path(file).is_absolute() # should be expected path and reach the file - assert file == expected_path + assert Path(file) == expected_path assert (relative_to_path / file).resolve() == out_path.resolve() # we shouldn't have touched `/data` even though it is pathlike assert data["path"] == "/data" +def test_relative_to_root_dir(): + """ + The relativize function should ignore paths that are directories + beneath the root directory (eg `/data`) even if they exist + + """ + root = Path().resolve().parents[-1] + test_path = None + for path in root.iterdir(): + if path.is_dir(): + test_path = path + + assert test_path is not None + + test_data = {"some_field": str(test_path)} + + walked = _relativize_paths(test_data, relative_to=".") + assert str(relative_path(test_path, Path(".").resolve())) != str(test_path) + assert walked["some_field"] == str(test_path) + + def test_absolute_path(hdf5_at_path, tmp_output_dir, model_blank): """ When told, we make paths absolute