- Progress lines on stderr for each of the three graph resolutions (with package/missing counts and timing) so a slow remote no longer looks like a hang; -q suppresses them. stdout remains the clean report. - --verbose now streams Conan's output live via a tee instead of dumping it at the end. - Filter SyntaxWarning/DeprecationWarning before importing conans: Conan 1.x modules trip the stricter escape-sequence checks of recent Pythons and printed a screenful of noise on 3.14. - Drop the <3.12 requires-python ceiling. Conan 1.66 falls back to importlib where imp is missing; verified working on 3.14. Fix the Containerfile and docs that claimed otherwise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYNdaGDrpaqDyT8QtrTQbM
4.5 KiB
4.5 KiB
CLAUDE.md
Guidance for working on this repository. It records decisions made when the project was started (August 2026) that are not obvious from the code.
What this is
Small single-file Python utilities for Conan 1.x, targeting 1.66. Not
Conan 2. The first (and so far only) tool is conandeps.py; see README.md
for what it does and how it is used.
Hard constraints
- Conan 1.66 only. Use the
conans.client.conan_api.ConanAPIV1API and Conan 1 graph internals (Node.binary,Node.dependencies,conanfile.requires). Do not introduce Conan 2 APIs or a Conan 2 code path. - Python 3.8+. Conan 1.66 runs on new Pythons too (it falls back to
importlibwhereimpis gone) – verified on 3.14. It does emit SyntaxWarnings from its own modules there, whichconandeps.pysilences before importingconans; keepconansimports deferred so that filter is in place first.requires-pythoninpyproject.tomland the PEP 723 header must stay in sync. - All development runs inside the container. Use
./dev.sh <cmd>for every python/pytest/ruff/uv invocation. Never runconanagainst the host's~/.conan; neverpip installon the host. Rebuild the image with./dev.sh buildafter touchingContainerfile. - Never depend on the private remote. The real remote is called
knorand only exists on the machine where the tool is used. Tests must use the localconan_serverfixture intests/test_conandeps.py.
Design decisions (and why)
- Binary availability is computed via Conan's graph, not
conan search. The graph is built once per build type throughConanAPIV1.info()and each node'sbinarystatus is read. This honourspackage_id()overrides, options anddefault_package_id_modeexactly likeconan install. Do not replace this with settings-dict matching againstconan searchoutput. - "Missing" means missing for the exact profile. Not "no binary with that build_type at all".
- Overrides are parsed from Conan's WARN output. Conan 1 does not record
overrides on the graph;
Requirements.update()mutatesreq.refin place and only emits"<pkg>: requirement <old> overridden by <who> to <new>".conandepscaptures the output stream with a non-colouredConanOutputand matches_OVERRIDE_RE.test_overridespins this format – if a Conan patch release changes the wording, that test is the alarm. - Both explicit and implicit overrides are reported.
override=Truerequirements are collected fromconanfile.requiresto label an override as explicit; everything else parsed from the WARN lines is implicit. range_refis not a version range after an override. Conan reusesRequirement.range_refto hold the pre-override reference, so only treat it as a range whenreq.version_rangeis truthy.- Single file, stdlib + Conan only. No third-party deps beyond Conan.
Packaging is hatchling with
only-include = ["conandeps.py"]; the PEP 723 header makes the file usable viauv run conandeps.pywithout a checkout. - Exit codes:
0fine,1missing binaries,2Conan error. CI relies on this. - stdout is the report, stderr is progress. Graph resolution against a
remote takes a while; progress lines (
_progress) and--verboselive Conan output go to stderr only, so stdout can be redirected to a file.
Workflow
- Lint/format:
./dev.sh ruff check .and./dev.sh ruff format .(config inpyproject.toml, target py38, line length 100). Runshellcheck dev.shafter editing the wrapper. - Tests:
./dev.sh python -m pytest. The fixture spins upconan_serveron a free port with a pre-writtenserver.conf(the port cannot be given on the command line), creates fake packages whosebuild()does nothing, uploads them, then wipes the cache so binaries can only come from the remote. Fake recipes need--build=missingat create time because dependencies' binaries are deliberately incomplete. - Dependencies:
uv.lockis committed; regenerate with./dev.sh uv lockafter changingpyproject.toml. - Commits: atomic, no
--amend; run ruff + pytest + shellcheck before committing. Add a memory of anything a future session could not derive from the repository.
Adding another tool
Follow the conandeps.py pattern: one executable file with a module
docstring explaining how and why, a PEP 723 header, a main(argv) that
returns an exit code, a [project.scripts] entry, an only-include entry in
pyproject.toml, tests under tests/ using the shared conan_env fixture,
and a section in README.md.