Take bin/fdp back from graphviz, and reach the CLI as python -m fdp - #18
Merged
Conversation
The `fdp` console script is not always reachable. Graphviz installs its force-directed layout engine at the same path -- bin/fdp, one of the eight engines it ships -- and conda has no conflict detection: conda-meta records graphviz as the owner and graphviz wins. Any environment containing cmflib pulls graphviz transitively (cmflib -> dvc -> pydot -> graphviz), so `fdp run` there silently invokes a graph layout tool. `python -m fdp` resolves through the installed package rather than PATH, so it works regardless. Additive: the console script is untouched. Sets sys.argv[0] so usage and error messages say "python -m fdp" rather than "__main__.py", which is what argparse would otherwise derive. A rename of the console script is planned for a major release; see docs/2026-09-02-fdp-cli-rename.md in the workspace. This is useful during that transition and afterwards. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kpkx3jFwQxuBRqoVcw6f27
graphviz ships `bin/fdp` -- a symlink to `dot` that dispatches on argv[0] --
and so do we. Anything pulling graphviz into an FDP environment lands a
second owner on `$PREFIX/bin/fdp`, and the CMF provenance stack does exactly
that: cmflib -> dvc -> pydot -> graphviz. Measured on pixi, on a clean env
with `fdp` and `cmflib`:
bin/fdp -> dot
$ fdp -V
fdp - graphviz version 14.1.2
The FDP CLI is not shadowed, it is *gone*: `fdp run python ...` becomes a
graph layout tool. There is nothing to warn the user with, because our entry
point is the file that got replaced -- which is why a deprecation notice
could never have worked here. This is what has blocked putting cmflib and
toksearch_cmf into the fdp-core metapackage.
Declaring graphviz as our own run dependency fixes it: the installer's
topological link order puts a dependency before its dependent, so graphviz
links first, `fdp` links last, and we take the file.
Whether that is a fix or an insurance policy depends on the installer, and
both are worth having:
pixi/rattler -- graphviz genuinely wins without this; the CLI is broken
today. With it we win from scratch (3/3 runs, deterministic), on an
incremental `pixi add cmflib`, and across a real graphviz 13.1.2 ->
14.1.2 upgrade. That last case means rattler respects existing file
ownership rather than merely link order. This is the path `fdp-install`
uses, so it is where most users live.
micromamba 2.9.0 -- already linked `fdp` last without this dependency
(graphviz at step 1193, fdp at 1266) and so already worked. Nothing
enforced that order though; it fell out of the solve. This makes it
guaranteed instead of lucky.
Nothing is lost on the graphviz side: `dot -Kfdp` is the documented
equivalent of its `fdp` binary.
This relies on installer behaviour that is not a documented guarantee, so it
ships with a recipe test rather than a comment alone. graphviz is now a run
dependency, so the test environment reproduces the collision for free; the
test fails loudly, naming the cause, if graphviz ever wins again. If it does,
the answer is to rename the CLI -- but until then no rename, no deprecation,
and no user-visible change.
Also asserts `python -m fdp` keeps working: it is the one entry point no
other package can take, and the fallback if this ever regresses.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kpkx3jFwQxuBRqoVcw6f27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
graphviz ships
bin/fdp— a symlink todotthat dispatches onargv[0]— and so do we. Anything that pulls graphviz into an FDP environment lands a second owner on$PREFIX/bin/fdp, and the CMF provenance stack does exactly that:cmflib -> dvc -> pydot -> graphviz.Measured on pixi, in a clean env with
fdpandcmflib:The FDP CLI isn't shadowed, it's gone —
fdp run python ...becomes a graph layout tool. This is what has blocked puttingcmflibandtoksearch_cmfinto thefdp-coremetapackage.It also rules out the obvious mitigation: a deprecation warning is unprintable here, because our entry point is the file that got replaced. The users who need the warning are exactly the ones who can never see it.
The fix
Declare
graphvizas our own run dependency. The installer's topological link order puts a dependency before its dependent, so graphviz links first,fdplinks last, and we take the file.Whether that's a fix or insurance depends on the installer, and both are worth having:
pixi add cmflib, and across a real graphviz 13.1.2 → 14.1.2 upgrade. That last case means rattler respects existing file ownership, not merely link order. This is thefdp-installpath, so it's where most users are.fdplast without this dependency (graphviz at step 1193, fdp at 1266), so it already worked. But nothing enforced that order; it fell out of the solve. This makes it guaranteed instead of lucky.Nothing is lost on the graphviz side:
dot -Kfdpis the documented equivalent of itsfdpbinary.Why a test, not just a comment
This relies on installer behaviour that isn't a documented guarantee, so it ships with a guard rather than a comment alone. Since graphviz is now a run dependency, the recipe's own test environment reproduces the collision for free — I confirmed graphviz 14.1.2 is actually present there, so the test isn't vacuous. It fails loudly and names the cause if graphviz ever wins again; if that happens, the answer is to rename the CLI.
The guard also asserts
python -m fdpworks — the one entry point no other package can take, and the fallback if this ever regresses.python -m fdpSecond commit adds
fdp/__main__.pyplus tests, so the CLI is reachable aspython -m fdp. Unclobberable by construction, and useful independently of any of the above.Verification
fdpbuilt with the fixfdp-corebuilt against released fdp 0.5.1bin/fdp resolves to: $PREFIX/bin/dot→ERROR: bin/fdp is graphviz's binaryfdp-corebuilt against this branchOK: bin/fdp is the FDP CLI alongside cmflibThe negative control does double duty: it proves the guard detects the real failure, and confirms that shipping cmflib in the metapackage with today's released
fdpwould break the CLI.Follow-on (not in this PR)
fdp-corehas a matching guard and amembers.yamlnote recording the coupling: itsfdppin must move to whatever release carries this change before cmflib is blessed, or the metapackage ships a brokenfdp. So this wants a release once merged.🤖 Generated with Claude Code
https://claude.ai/code/session_01Kpkx3jFwQxuBRqoVcw6f27