Skip to content

Io primitives

io_primitives

Low-level I/O: libcst load/save + git mv with safety guard.

The proto reads with ast (fast, sufficient for analysis) but writes with libcst (preserves quote style, indentation, comments, trailing whitespace — everything ast.unparse silently loses). Migrating mutating helpers to libcst is what gives us back the triple-quoted strings, comments, and blank-line spacing that ast.unparse erases. axm-anvil itself works the same way under the hood.

cst_load(path)

Read path and parse it as a libcst Module. None on parse error.

Source code in packages/axm-audit/src/axm_audit/core/fix/io_primitives.py
Python
def cst_load(path: Path) -> cst.Module | None:
    """Read *path* and parse it as a libcst Module. None on parse error."""
    try:
        return cst.parse_module(path.read_text())
    except cst.ParserSyntaxError:
        return None

cst_save(path, module)

Write module back to path using its serialised form.

Source code in packages/axm-audit/src/axm_audit/core/fix/io_primitives.py
Python
def cst_save(path: Path, module: cst.Module) -> None:
    """Write *module* back to *path* using its serialised form."""
    path.write_text(module.code)

cst_top_level(module)

Return the module's top-level body as a mutable list.

Source code in packages/axm-audit/src/axm_audit/core/fix/io_primitives.py
Python
def cst_top_level(module: cst.Module) -> list[cst.BaseStatement]:
    """Return the module's top-level body as a mutable list."""
    return list(module.body)

cst_unwrap(stmt)

Unwrap a SimpleStatementLine to its first small statement, if any.

libcst wraps top-level small statements (imports, assigns) inside SimpleStatementLine. For comparisons / extraction we usually want the inner statement (Import, ImportFrom, Assign, …).

Source code in packages/axm-audit/src/axm_audit/core/fix/io_primitives.py
Python
def cst_unwrap(
    stmt: cst.BaseStatement,
) -> cst.BaseSmallStatement | cst.BaseCompoundStatement:
    """Unwrap a SimpleStatementLine to its first small statement, if any.

    libcst wraps top-level small statements (imports, assigns) inside
    ``SimpleStatementLine``. For comparisons / extraction we usually want
    the inner statement (Import, ImportFrom, Assign, …).
    """
    if isinstance(stmt, cst.SimpleStatementLine) and stmt.body:
        return stmt.body[0]
    return stmt  # type: ignore[return-value]