Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ def locate_bitcode_lib(name: str) -> LocatedBitcodeLib:
"""
finder = _FindBitcodeLib(name)

# Path.absolute preserves symlink/.. traversal rather than normalizing it.
abs_path = finder.try_site_packages()
if abs_path is not None:
return LocatedBitcodeLib(
name=name,
abs_path=str(abs_path),
abs_path=str(abs_path.absolute()),
filename=finder.filename,
found_via="site-packages",
)
Expand All @@ -156,7 +157,7 @@ def locate_bitcode_lib(name: str) -> LocatedBitcodeLib:
if abs_path is not None:
return LocatedBitcodeLib(
name=name,
abs_path=str(abs_path),
abs_path=str(abs_path.absolute()),
filename=finder.filename,
found_via="conda",
)
Expand All @@ -165,7 +166,7 @@ def locate_bitcode_lib(name: str) -> LocatedBitcodeLib:
if abs_path is not None:
return LocatedBitcodeLib(
name=name,
abs_path=str(abs_path),
abs_path=str(abs_path.absolute()),
filename=finder.filename,
found_via="CUDA_PATH",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,12 @@ def locate_static_lib(name: str) -> LocatedStaticLib:
"""
finder = _FindStaticLib(name)

# Path.absolute preserves symlink/.. traversal rather than normalizing it.
abs_path = finder.try_site_packages()
if abs_path is not None:
return LocatedStaticLib(
name=name,
abs_path=str(abs_path),
abs_path=str(abs_path.absolute()),
filename=finder.filename,
found_via="site-packages",
)
Expand All @@ -155,7 +156,7 @@ def locate_static_lib(name: str) -> LocatedStaticLib:
if abs_path is not None:
return LocatedStaticLib(
name=name,
abs_path=str(abs_path),
abs_path=str(abs_path.absolute()),
filename=finder.filename,
found_via="conda",
)
Expand All @@ -164,7 +165,7 @@ def locate_static_lib(name: str) -> LocatedStaticLib:
if abs_path is not None:
return LocatedStaticLib(
name=name,
abs_path=str(abs_path),
abs_path=str(abs_path.absolute()),
filename=finder.filename,
found_via="CUDA_PATH",
)
Expand Down
62 changes: 62 additions & 0 deletions cuda_pathfinder/tests/test_find_bitcode_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,68 @@ def find_expected_sub_dir(sub_dir):
assert located_lib.found_via == "CUDA_PATH"


@pytest.mark.usefixtures("clear_find_bitcode_lib_cache")
@pytest.mark.parametrize("source", ("site-packages", "conda", "CUDA_PATH"))
@pytest.mark.agent_authored(model="gpt-6")
def test_locate_bitcode_lib_returns_absolute_path_for_relative_root(monkeypatch, tmp_path, source):
monkeypatch.chdir(tmp_path)
monkeypatch.delenv("CONDA_PREFIX", raising=False)
monkeypatch.delenv("CUDA_HOME", raising=False)
monkeypatch.delenv("CUDA_PATH", raising=False)

info = _bitcode_lib_info("device")
root = Path("relative-root")
if source == "site-packages":
lib_dir = root / Path(info["site_packages_dirs"][0])
monkeypatch.setattr(find_bitcode_lib_module, "find_sub_dirs_all_sitepackages", lambda _sub_dir: [str(lib_dir)])
else:
monkeypatch.setattr(find_bitcode_lib_module, "find_sub_dirs_all_sitepackages", lambda _sub_dir: [])
if source == "conda":
monkeypatch.setenv("CONDA_PREFIX", str(root))
lib_dir = _conda_anchor(root) / Path(info["rel_path"])
else:
monkeypatch.setenv("CUDA_HOME", str(root))
lib_dir = root / Path(info["rel_path"])

expected = tmp_path / lib_dir / info["filename"]
expected.parent.mkdir(parents=True)
expected.touch()
located = locate_bitcode_lib("device")
assert located.found_via == source
assert located.abs_path == str(expected)
assert find_bitcode_lib("device") == str(expected)

monkeypatch.chdir(tmp_path.parent)
assert Path(located.abs_path).is_file()
assert Path(find_bitcode_lib("device")).is_file()


@pytest.mark.skipif(os.name == "nt", reason="POSIX symlink parent traversal")
@pytest.mark.usefixtures("clear_find_bitcode_lib_cache")
@pytest.mark.agent_authored(model="gpt-6")
def test_locate_bitcode_lib_preserves_symlink_parent(monkeypatch, tmp_path):
monkeypatch.chdir(tmp_path)
monkeypatch.delenv("CONDA_PREFIX", raising=False)
monkeypatch.delenv("CUDA_PATH", raising=False)
monkeypatch.setenv("CUDA_HOME", "alias/..")
monkeypatch.setattr(find_bitcode_lib_module, "find_sub_dirs_all_sitepackages", lambda _sub_dir: [])

real_root = tmp_path / "real"
(real_root / "child").mkdir(parents=True)
(tmp_path / "alias").symlink_to(real_root / "child", target_is_directory=True)
info = _bitcode_lib_info("device")
expected = real_root / info["rel_path"] / info["filename"]
expected.parent.mkdir(parents=True)
expected.touch()

located = locate_bitcode_lib("device")
assert Path(located.abs_path).is_absolute()
assert Path(located.abs_path).samefile(expected)
cached = find_bitcode_lib("device")
monkeypatch.chdir(tmp_path.parent)
assert Path(cached).samefile(expected)


@pytest.mark.usefixtures("clear_find_bitcode_lib_cache")
def test_find_bitcode_lib_not_found_error_includes_cuda_home_directory_listing(monkeypatch, tmp_path):
cuda_home = tmp_path / "cuda-home"
Expand Down
60 changes: 60 additions & 0 deletions cuda_pathfinder/tests/test_find_static_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,66 @@ def test_locate_static_lib_search_order(monkeypatch, tmp_path):
assert located_lib.found_via == "CUDA_PATH"


@pytest.mark.usefixtures("clear_find_static_lib_cache")
@pytest.mark.parametrize("source", ("site-packages", "conda", "CUDA_PATH"))
@pytest.mark.agent_authored(model="gpt-6")
def test_locate_static_lib_returns_absolute_path_for_relative_root(monkeypatch, tmp_path, source):
monkeypatch.chdir(tmp_path)
monkeypatch.delenv("CONDA_PREFIX", raising=False)
monkeypatch.delenv("CUDA_HOME", raising=False)
monkeypatch.delenv("CUDA_PATH", raising=False)

root = Path("relative-root")
if source == "site-packages":
lib_dir = root / Path(CUDADEVRT_INFO["site_packages_dirs"][0])
monkeypatch.setattr(find_static_lib_module, "find_sub_dirs_all_sitepackages", lambda _sub_dir: [str(lib_dir)])
else:
monkeypatch.setattr(find_static_lib_module, "find_sub_dirs_all_sitepackages", lambda _sub_dir: [])
if source == "conda":
monkeypatch.setenv("CONDA_PREFIX", str(root))
lib_dir = _conda_anchor(root) / Path(CUDADEVRT_INFO["conda_rel_paths"][0])
else:
monkeypatch.setenv("CUDA_HOME", str(root))
lib_dir = root / Path(CUDADEVRT_INFO["ctk_rel_paths"][0])

expected = tmp_path / lib_dir / CUDADEVRT_INFO["filename"]
expected.parent.mkdir(parents=True)
expected.touch()
located = locate_static_lib("cudadevrt")
assert located.found_via == source
assert located.abs_path == str(expected)
assert find_static_lib("cudadevrt") == str(expected)

monkeypatch.chdir(tmp_path.parent)
assert Path(located.abs_path).is_file()
assert Path(find_static_lib("cudadevrt")).is_file()


@pytest.mark.skipif(os.name == "nt", reason="POSIX symlink parent traversal")
@pytest.mark.usefixtures("clear_find_static_lib_cache")
@pytest.mark.agent_authored(model="gpt-6")
def test_locate_static_lib_preserves_symlink_parent(monkeypatch, tmp_path):
monkeypatch.chdir(tmp_path)
monkeypatch.delenv("CONDA_PREFIX", raising=False)
monkeypatch.delenv("CUDA_PATH", raising=False)
monkeypatch.setenv("CUDA_HOME", "alias/..")
monkeypatch.setattr(find_static_lib_module, "find_sub_dirs_all_sitepackages", lambda _sub_dir: [])

real_root = tmp_path / "real"
(real_root / "child").mkdir(parents=True)
(tmp_path / "alias").symlink_to(real_root / "child", target_is_directory=True)
expected = real_root / Path(CUDADEVRT_INFO["ctk_rel_paths"][0]) / CUDADEVRT_INFO["filename"]
expected.parent.mkdir(parents=True)
expected.touch()

located = locate_static_lib("cudadevrt")
assert Path(located.abs_path).is_absolute()
assert Path(located.abs_path).samefile(expected)
cached = find_static_lib("cudadevrt")
monkeypatch.chdir(tmp_path.parent)
assert Path(cached).samefile(expected)


@pytest.mark.usefixtures("clear_find_static_lib_cache")
def test_locate_static_lib_conda_rel_path_fallback(monkeypatch, tmp_path):
filename = CUDADEVRT_INFO["filename"]
Expand Down
Loading