Skip to content

CST Transformer

Work in progress

These are rough notes, not a finished write-up.

How to replace a dictionary to a class in python

import sys

import libcst as cst

ALLOWED_KEYS = {"status", "task_output", "error"}


class DictToTaskResult(cst.CSTTransformer):
    def leave_Dict(self, original_node, updated_node):
        found: dict[str, cst.BaseExpression] = {}

        for element in updated_node.elements:
            # Reject **, comprehensions, etc.
            if element is None or element.key is None:
                return updated_node

            # Only allow string literal keys
            if not isinstance(element.key, cst.SimpleString):
                return updated_node

            key = element.key.evaluated_value
            if key not in ALLOWED_KEYS:
                # ❌ extra key like "job_id"
                return updated_node

            found[key] = element.value

        # Must have "status"
        if "status" not in found:
            return updated_node

        # Build TaskResult(...)
        args = [cst.Arg(keyword=cst.Name("status"), value=found["status"])]

        if "task_output" in found:
            args.append(cst.Arg(keyword=cst.Name("task_output"), value=found["task_output"]))

        if "error" in found:
            args.append(cst.Arg(keyword=cst.Name("error"), value=found["error"]))

        return cst.Call(
            func=cst.Name("TaskResult"),
            args=args,
        )


def transform_file(path: str) -> None:
    with open(path, "r", encoding="utf-8") as f:
        source = f.read()

    module = cst.parse_module(source)
    modified = module.visit(DictToTaskResult())

    if modified.code != source:
        print(f"✔ modified: {path}")

    with open(path, "w", encoding="utf-8") as f:
        f.write(modified.code)


def main() -> None:
    if len(sys.argv) < 2:
        print("Usage: replace_taskresult.py <file1.py> <file2.py> ...")
        sys.exit(1)

    for path in sys.argv[1:]:
        transform_file(path)


if __name__ == "__main__":
    main()