♻️ refactor(core): reduce duplication and migrate to ty#548
Merged
gaborbernat merged 2 commits intotox-dev:mainfrom Mar 3, 2026
Merged
Conversation
The text and freeze renderers duplicated the same recursive traversal logic. Extracting _render_text_simple with frozen/bullet parameters lets freeze.py reuse text.py instead of maintaining its own copy. Similarly, both graphviz graph builders duplicated BFS depth computation and had mirrored if/else branches for depth-limited vs unlimited; a shared _compute_reachable_depths helper eliminates that. Edge label derivation was repeated inline across graphviz and mermaid renderers. Adding edge_label properties to DistPackage and ReqPackage centralizes this logic. The reverse() methods used O(n) linear scans via next(p for p in m ...) to deduplicate nodes. A dict index makes this O(1) per edge. __getitem__ returned None on missing keys via dict.get(), violating the Mapping protocol. Changed to dict.__getitem__ which raises KeyError as callers expect via Mapping.get(). Replaced mypy with ty following the tox-dev/tox pattern, cleaning up stale type: ignore comments that ty no longer needs. Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
Use setdefault to collapse the walrus+if node deduplication pattern in both reverse() methods. Remove the _render_text_without_unicode wrapper now that _render_text_simple handles both cases. Inline the dep_keys helper into a set comprehension and rename it to _get_root_keys since that better describes what callers actually need. Reorder module-level functions and methods so callers appear before callees — public entry points at the top, helpers below — matching topological usage order.
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.
Several renderers had duplicated logic that made changes error-prone and maintenance harder. The freeze renderer reimplemented the same recursive traversal as the non-unicode text renderer, differing only in the
frozenflag and bullet string. The graphviz forward and reverse graph builders each contained their own BFS depth computation with mirrored if/else branches for depth-limited vs unlimited traversal. Edge label derivation (version_spec or "any") was inlined identically across graphviz and mermaid renderers. These duplications meant any bug fix or behavior change had to be applied in multiple places, risking divergence.♻️ The text/freeze unification extracts
_render_text_simplewithfrozenandbulletparameters, lettingfreeze.pydrop from 40 lines to a single function call. The graphviz cleanup pulls BFS into a shared_compute_reachable_depthshelper and collapses each builder's branching into a single iteration that checksvisitedmembership when depth-limiting is active.edge_labelproperties onDistPackageandReqPackagereplace the repeated inline patterns across graphviz and mermaid. Thereverse()methods inPackageDAGandReversedPackageDAGusednext(p for p in m if p.key == v.key)for node deduplication — an O(n) linear scan per edge — replaced with a dict index for O(1) lookups.⚡
PackageDAG.__getitem__previously useddict.get(), silently returningNoneon missing keys and violating theMappingprotocol contract. It now delegates todict.__getitem__which raisesKeyError, matching what callers expect throughMapping.get(). The type checker has been migrated from mypy to ty, and staletype: ignorecomments that ty no longer needs have been cleaned up.