PhysLink — Development Guide
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Python | ≥ 3.10 | Tested on 3.12 in CI |
| uv | any | Recommended dependency manager |
| pip | any | Alternative to uv |
| git | any | |
| PyTorch | any (optional) | Required only for GPU training and adapter tests |
Local Setup
With uv (recommended)
git clone https://github.com/Denis-hamon/physlink.git
cd physlink
uv venv
uv pip install -e ".[dev]"
pre-commit install
With pip
git clone https://github.com/Denis-hamon/physlink.git
cd physlink
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pre-commit install
GPU support (optional)
pip install torch --extra-index-url https://download.pytorch.org/whl/cu121
Environment Verification
import physlink
report = physlink.doctor()
# Prints Go/No-Go diagnostic table to stdout
# Returns DiagnosticReport with verdict "GO" or "NO-GO"
Development Commands
Lint
ruff check src/
ruff check --fix src/ # auto-fix
Type Check
mypy --strict src/physlink/core/ # strict mode on core/
mypy src/physlink/adapters/ # relaxed (PyTorch stubs incomplete)
mypy src/physlink/utils/ # relaxed (matplotlib/PIL stubs incomplete)
Tests
# CPU suite (fast, no GPU required)
pytest -m "not gpu" tests/ -v
# All tests including GPU
pytest tests/ -v
# Specific test file
pytest tests/unit/core/test_spaces.py -v
# With coverage
pytest -m "not gpu" tests/ --cov=src/physlink --cov-report=term-missing
Performance Benchmarks
# Run benchmarks and compare vs baseline
pytest tests/perf/ --benchmark-compare=tests/perf/baselines/benchmark_baseline.json --benchmark-compare-fail=min:10%
# Generate a new baseline (Colab T4 GPU only)
pytest tests/perf/ --benchmark-json=tests/perf/baselines/benchmark_baseline.json
Documentation
# Build docs (strict — fails on warnings)
mkdocs build --strict
# Serve docs locally with live reload
mkdocs serve
# Then open http://127.0.0.1:8000
Pre-commit
pre-commit run --all-files # run ruff check + format on all files
Project Structure for Development
src/physlink/
├── core/ ← add new pure-Python primitives here
├── adapters/ ← add new ML backend adapters here (subclass BaseAdapter)
└── utils/ ← add standalone utilities here
Rule for adapters and utils: All ML framework imports (torch, matplotlib, PIL, etc.) must stay inside function bodies. Never import them at module level. This ensures import physlink works without these dependencies installed.
Rule for core/: Zero ML imports. mypy strict mode enforced. Every public class/function needs a Google-style docstring with Args, Returns, Raises, and Example sections.
Adding a New Adapter
- Create
src/physlink/adapters/my_adapter.py - Subclass
BaseAdapterand implementfit(),visualize(),export(),explain() - Import lazily:
import torchinsidefit()body, not at module level - Add to
src/physlink/__init__.pyif promoting to public API - Add unit tests in
tests/unit/adapters/test_my_adapter_cpu.py - GPU tests go in
tests/unit/adapters/test_my_adapter_gpu.pywith@pytest.mark.gpu
Common Development Tasks
Check that core/ has no torch imports
pytest tests/integration/test_core_no_torch_import.py -v
pytest tests/integration/test_core_boundary.py -v
Verify docstring completeness
pytest tests/integration/test_docstring_completeness.py -v
Validate CI config
pytest tests/integration/test_ci_pipeline_config.py -v
Validate API stability (no regression in public symbols)
pytest tests/integration/test_api_stability.py -v
Test Fixtures
tests/conftest.py provides:
@pytest.fixture
def synthetic_trajectories() -> list[dict]:
"""1000 numpy-only trajectories — no GPU required."""
rng = np.random.default_rng(42)
return [{"obs": rng.random(7), "action": rng.random(3)} for _ in range(1000)]
Use synthetic_trajectories in any test that needs trajectory data without a GPU.
mypy Configuration Notes
pyproject.toml has two [[tool.mypy.overrides]] blocks:
[[tool.mypy.overrides]]
module = "physlink.adapters.*"
ignore_missing_imports = true
strict = false # PyTorch stubs incomplete — ADR-002 defers to v0.3.0
[[tool.mypy.overrides]]
module = "physlink.utils.*"
ignore_missing_imports = true
# matplotlib/PIL have partial stubs
core/ runs under strict = true at the top level — no overrides.
IDE Setup
No special configuration required. The pyproject.toml covers ruff and mypy. If your IDE uses these tools natively (VS Code with Pylance + Ruff extension, PyCharm with mypy plugin), they will pick up the config automatically.
Recommended VS Code extensions:
- charliermarsh.ruff — linting and formatting
- ms-python.mypy-type-checker — type checking
- ms-python.python — Python language support