diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index f5f56817141..a7af7b07467 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -31,13 +31,13 @@ # --------------------------------------------------------------------------- -@dataclass +@dataclass(frozen=True) class LocatedHeaderDir: abs_path: str | None found_via: str def __post_init__(self) -> None: - self.abs_path = _abs_norm(self.abs_path) + object.__setattr__(self, "abs_path", _abs_norm(self.abs_path)) #: Type alias for a header find step callable. diff --git a/cuda_pathfinder/docs/source/release/1.6.1-notes.rst b/cuda_pathfinder/docs/source/release/1.6.1-notes.rst index 4b6e7a0a55e..9a4da0ab77c 100644 --- a/cuda_pathfinder/docs/source/release/1.6.1-notes.rst +++ b/cuda_pathfinder/docs/source/release/1.6.1-notes.rst @@ -35,6 +35,12 @@ Highlights architecture-specific executable targets using the native Windows machine architecture. +* Make ``LocatedHeaderDir`` immutable, matching ``LocatedStaticLib`` and + ``LocatedBitcodeLib``. ``locate_nvidia_header_directory`` is + ``functools.cache``-backed, so writing to a returned object previously + changed what every later lookup of that ``libname`` returned. The type is + now hashable as well. + Internal maintenance -------------------- diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index 3e045dae265..6136011f180 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -11,6 +11,7 @@ # sudo apt install libnvshmem3-cuda-12 libnvshmem3-dev-cuda-12 # sudo apt install libnvshmem3-cuda-13 libnvshmem3-dev-cuda-13 +import dataclasses import functools import glob import importlib.metadata @@ -264,3 +265,33 @@ def test_locate_ctk_headers_canary_probe_errors_are_not_masked(monkeypatch, mock locate_nvidia_header_directory("cudart") with pytest.raises(RuntimeError, match="canary probe failed"): find_nvidia_header_directory("cudart") + + +@pytest.mark.agent_authored(model="claude-opus-5") +@pytest.mark.usefixtures("clear_locate_nvidia_header_cache") +def test_located_header_dir_is_immutable(tmp_path, monkeypatch, mocker): + cuda_home = tmp_path / "cuda-home" + expected_hdr_dir = _create_ctk_header(cuda_home, "cudart") + + monkeypatch.delenv("CONDA_PREFIX", raising=False) + monkeypatch.setenv("CUDA_HOME", str(cuda_home)) + monkeypatch.delenv("CUDA_PATH", raising=False) + mocker.patch.object(find_nvidia_headers_module, "find_sub_dirs_all_sitepackages", return_value=[]) + + first = locate_nvidia_header_directory("cudart") + assert first is not None + assert first.abs_path == expected_hdr_dir + + with pytest.raises(dataclasses.FrozenInstanceError): + first.abs_path = str(tmp_path / "somewhere-else") + + assert locate_nvidia_header_directory("cudart").abs_path == expected_hdr_dir + assert find_nvidia_header_directory("cudart") == expected_hdr_dir + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_located_header_dir_is_hashable(tmp_path): + include_dir = str(tmp_path / "include") + hdr_dir = LocatedHeaderDir(abs_path=include_dir, found_via="conda") + assert hdr_dir in {hdr_dir} + assert hdr_dir == LocatedHeaderDir(abs_path=include_dir, found_via="conda")