fix: keep GPU fingerprint import safe on CPU CI#6818
Conversation
vinhcafe25-ops
left a comment
There was a problem hiding this comment.
Code Review: PR #6818 — fix: keep GPU fingerprint import safe on CPU CI
Tier: Thorough — Line-by-line review. Core approach is sound; the test has a critical bug.
Finding 1 (🔴 Bug — Test): monkeypatch.setitem(sys.modules, "torch", None) does NOT simulate a missing torch
File: tests/test_gpu_fingerprint_import.py
monkeypatch.setitem(sys.modules, "torch", None)
monkeypatch.setitem(sys.modules, "torch.cuda", None)This does not cause import torch to raise ImportError. Python's import machinery checks sys.modules via key existence (name in sys.modules), not truthiness. Setting the entry to None means:
import torch→ finds key insys.modules→ returnsNone→ no ImportErrorimport torch.cuda→ finds key insys.modules→ returnsNone→ no ImportError- The
except ImportErrorblock is never reached - The
elsebranch runs →HAS_TORCH = True assert module.HAS_TORCH is False→ FAILS
The test should delete the keys from sys.modules instead, which is what actually happens on a machine without torch:
# Correct approach: remove from sys.modules so import raises ImportError
monkeypatch.delitem(sys.modules, "torch", raising=False)
monkeypatch.delitem(sys.modules, "torch.cuda", raising=False)Or use importlib mocking to make the import genuinely raise:
import builtins
original_import = builtins.__import__
def mock_import(name, *args, **kwargs):
if name in ("torch", "torch.cuda"):
raise ImportError(f"No module named '{name}'")
return original_import(name, *args, **kwargs)
monkeypatch.setattr(builtins, "__import__", mock_import)Impact: The test either never actually ran, or it "passes" by coincidence (e.g., torch was already imported in the test session and monkeypatch.setitem overwrites the real module, but the spec.loader.exec_module path might bypass sys.modules in some edge case). Either way, the test is not testing what it claims to test.
Finding 2 (🟡 Fragility): Both torch and torch.cuda share one except block
File: miners/gpu_fingerprint.py
try:
import torch
import torch.cuda
except ImportError:
torch = None
HAS_TORCH = False
else:
HAS_TORCH = TrueIf import torch succeeds but import torch.cuda fails (edge case: corrupted install), the except block sets torch = None, discarding the successfully-imported torch module. This is wasteful — torch could be used for CPU ops even without CUDA.
Better:
try:
import torch
except ImportError:
torch = None
HAS_TORCH = False
else:
try:
import torch.cuda
except ImportError:
pass # CUDA submodule missing, handled by check_requirements()
HAS_TORCH = TrueFinding 3 (🟡 Coverage gap): No test when torch IS available
The new test only covers the torch-missing path. Consider adding a second test that verifies the module behaves correctly when torch and torch.cuda are actually importable (e.g., with a mock that makes torch.cuda.is_available() return True). This would catch regressions in the happy path.
Finding 4 (🟢 Nit): from __future__ import annotations is unrelated
Added at the top of the file but not used by any change in this PR. This is PEP 604 style (str | None syntax). Fine if the project is standardizing, but it's unrelated noise in this diff.
What works well
check_requirements()pattern is clean — defers enforcement to call time, separating detection from actionrun_gpu_fingerprintguards withcheck_requirements()at the entry point- CLI
__main__block wraps the whole thing intry/except RuntimeErrorfor clean user-facing errors - Test uses
importlib.util.spec_from_file_locationcorrectly to avoid cached imports
Verdict
Request Changes — The test in test_gpu_fingerprint_import.py is broken: setting sys.modules["torch"] = None does not simulate a missing module. Fix the test approach to use delitem or builtins.__import__ mocking. The core gpu_fingerprint.py change is solid.
jaxint
left a comment
There was a problem hiding this comment.
Great contribution to the RustChain ecosystem!
jaxint
left a comment
There was a problem hiding this comment.
Thanks for this PR! The changes look good. 🎉
✅ Merging — this is the clean split I asked forExactly the |
Summary
Follow-up scope
This is the small GPU import-safety slice called out as acceptable in #6711.
It intentionally does not touch node/admin/auth endpoints, production security guards, or the repo-wide stale-test/admin-key baseline handled separately in #6788.
Validation
python3 -m py_compile miners/gpu_fingerprint.py tests/test_gpu_fingerprint_import.pyuv run --no-project --with pytest --with flask --with requests --with flask-cors --with httpx --with cryptography python -m pytest -q tests/test_gpu_fingerprint_import.py --tb=short -o addopts='' --basetemp=.pytest-tmp->1 passedgit diff --checkpython3 miners/gpu_fingerprint.py --jsonwithout torch -> exits1withERROR: PyTorch with CUDA support required. Install: pip install torchRefs #305.
Follow-up to #6711.
wallet: RTC47bc28896a1a4bf240d1fd780f4559b242bcd945