Matchify converts eligible if/elif/else chains into Python 3.10+
match statements. It uses LibCST so transformations preserve source formatting.
src/matchify/transform.pyorchestrates the LibCST transformation and exposestransform_code().src/matchify/compiler.pynormalizes complete chains and compiles them intomatchstatements.src/matchify/conditions.pyparses conditions into typed predicates.src/matchify/access_path.pymodels subjects and nested attribute/index paths.src/matchify/pattern_builder.pylowers predicates into pattern facts and residual guards.src/matchify/facts.pyandsrc/matchify/patterns.pydefine and render the pattern IR.src/matchify/safety.pychecks whether transformations preserve behavior.src/matchify/capture_patterns.pyturns eligible assignments into capture patterns.src/matchify/cli.pyimplements file processing and the CLI;src/matchify/__main__.pyis thepython -m matchifyentry point.
- Preserve runtime semantics. Be conservative when evaluation count/order, side effects, bindings, or pattern behavior are uncertain.
- Convert only complete chains with at least one
elif; leave unsupported conditions unchanged. - Conditions in a converted chain must resolve to a compatible match subject.
- Literal, singleton identity, class, sequence, OR, guard, nested, and capture patterns are supported where the builder and safety checks can prove them valid. Treat the behavior-focused tests as the authoritative specification.
- Non-literal expressions must not accidentally become capture patterns.
- A walrus expression that must execute as part of a condition belongs in a guard, not in the match subject or structural pattern.
- For
elif,cst.If.orelseis anothercst.If; forelse, it is acst.Elsewhosebodycontains the suite. - Use
.deep_equals()for structural CST comparisons. - Build a wildcard case with
cst.MatchAs(pattern=None, name=None). - Pass concrete pattern nodes such as
cst.MatchValuedirectly tocst.MatchCase.pattern;cst.MatchPatternis abstract.
-
Add a minimal behavior-focused regression test before or alongside a fix.
-
Make changes in the appropriate parsing, lowering, rendering, or safety layer rather than adding syntax-specific exceptions to orchestration code.
-
Exercise transformations through
transform_code(),convert_file(), or the CLI when practical. -
Run the focused test, then the full suite:
uv run pytest tests/test_transform.py -k <case> uv run pytest
The test suite is organized as follows:
tests/test_transform.pyandtests/test_edge_cases.py: source-to-source behavior and rejection cases.tests/test_cli.py: file processing and CLI behavior.tests/test_generated_roundtrip.py: generated programs whose runtime traces are compared before and after transformation.
Use textwrap.dedent() for multiline source fixtures and temporary directories
for filesystem tests. Test both successful conversions and nearby cases that
must remain unchanged.
For a complex generated-roundtrip failure, pysource-minimize can reduce a
reproducer. Use a precise checker that transforms the program and detects the
specific trace mismatch; broad checks can minimize to an unrelated failure.