NEWS

Finds every possible change in Python source and applies candidates one at a time without losing formatting or comments.

On this page 3 sections

Mutation testing checks a test suite by making small changes to a program and seeing whether the tests notice. To do this well, a tool must find every place where a change is possible, then apply and test one change at a time. Ordinary syntax-tree transformers usually rewrite every matching piece in one pass, so they do not provide this separation by themselves.

LibCST represents Python code as a tree while preserving its formatting and comments. It can rewrite that tree, but it does not number all possible edits so that a caller can choose exactly one. Complete mutation-testing systems such as mutmut also run tests and manage sessions. A smaller library is useful when another system already handles those jobs.

cstvis is a Python library built on LibCST for exactly that workflow. It finds and records every place where a requested source-code change can happen, then applies any one of those changes to the original file. The release is available on GitHub.

Discovering independent transformations

cstvis does not replace LibCST’s parser or transformation API. It coordinates potential edits so that a caller can enumerate them first and apply a selected one later.

A function registered with @changer.converter handles the LibCST node type named by its first annotation. Filters remove ineligible occurrences. iterate_coordinates() returns the remaining source ranges, and apply_coordinate() applies one range to the untouched module.

from libcst import Add, Subtract
from cstvis import Changer

changer = Changer("total = left + right")

@changer.converter
def replace_add(node: Add, context):
    return Subtract(
        whitespace_before=node.whitespace_before,
        whitespace_after=node.whitespace_after,
    )

coordinate = next(changer.iterate_coordinates())
print(changer.apply_coordinate(coordinate))
#> total = left - right

Two additions therefore produce two candidates, each applied separately to the original source.

Context includes the coordinate, the comment on the node’s first line, and parsed metacode directives, so converters can use local rules without implementing comment lookup.

Comparison with other transformation tools

Direct LibCST codemods remain better for complex, multi-pass refactoring.

Bowler and RedBaron provide higher-level lossless refactoring workflows. Standard ast.NodeTransformer is simpler when preserving formatting and comments does not matter.

cstvis solves a narrower problem: it registers LibCST changes by type, gives them access to source comments, and applies each candidate independently through an API that is not tied to a particular test runner.

Intended use

cstvis does not walk directories, store sessions, run tests, or distribute jobs. It allows one converter for each exact kind of syntax-tree element and always applies the selected change to the original source. Another system can treat each possible change as a separate job.