diff --git a/src/osekit/core/json_serializer.py b/src/osekit/core/json_serializer.py index fdbfc8b9..52b50dac 100644 --- a/src/osekit/core/json_serializer.py +++ b/src/osekit/core/json_serializer.py @@ -60,11 +60,14 @@ def _serialize_path(value: Path, root_path: Path) -> str: return str(value) anchor = _anchor.get() - if anchor is not None and not value.is_relative_to(anchor): + if anchor is not None and not value.resolve().is_relative_to(anchor.resolve()): # Path is outside the project: we store it as an absolute path. return value.as_posix() try: - return Path(os.path.relpath(path=value, start=root_path)).as_posix() + # Return value relative to the root_path + return Path( + os.path.relpath(path=value.resolve(), start=root_path.resolve()) + ).as_posix() except ValueError: # Value is not expressible as relative to root return value.as_posix() diff --git a/tests/test_serialization.py b/tests/test_serialization.py index 9bded198..385ba7ff 100644 --- a/tests/test_serialization.py +++ b/tests/test_serialization.py @@ -1052,14 +1052,34 @@ def test_spectro_dataset_serialization( """ -def can_symlink(tmp_path: Path) -> bool: +@pytest.fixture +def create_symlink(tmp_path: Path) -> tuple[Path, Path]: + real_root = tmp_path / "cocteau" + real_root.mkdir(parents=True, exist_ok=True) + + alias_root = tmp_path / "twins" + try: - test_link = tmp_path / "link_test" - test_link.symlink_to(tmp_path) - test_link.unlink() - except OSError: - return False - return True + alias_root.symlink_to(real_root) + except (OSError, NotImplementedError) as e: + pytest.skip(f"Symlink not permitted on this system:\n{e}") + + return real_root, alias_root + + +def test_serialize_path_with_symlink( + tmp_path: Path, + create_symlink: tuple[Path, Path], +) -> None: + real_root, alias_root = create_symlink + + target = "serpentskirt" + + target_path = alias_root / target + + result = _serialize_path(value=target_path, root_path=real_root) + + assert result == target def test_path_anchor() -> None: @@ -1136,6 +1156,21 @@ def test_serialize_path_within_anchor(tmp_path: Path) -> None: assert _serialize_path(value=value, root_path=root_path) == expected +def test_serialize_path_within_anchor_with_symlink( + tmp_path: Path, create_symlink: tuple[Path, Path] +) -> None: + real_root, alias_root = create_symlink + + target = "fun" + + value = alias_root / target + + with path_anchor(anchor=real_root): + # Anchor is real_root, which should also be alias_root + # So the path should be serialized as relative + assert _serialize_path(value=value, root_path=alias_root) == target + + def test_serialize_path_outside_anchor(tmp_path: Path) -> None: value = tmp_path / "fun" / "top.wav" anchor = tmp_path / "cool"