{"id":775,"library":"libcst","title":"LibCST","description":"LibCST (Concrete Syntax Tree) is a Python library that parses Python 3.0 through 3.14 source code into a CST tree, preserving all formatting details like comments, whitespaces, and parentheses. It offers a compromise between an Abstract Syntax Tree (AST) and a traditional CST, designed for building automated refactoring (codemod) applications and linters. The current version is 1.8.6, and it maintains an active release cadence with frequent updates.","status":"active","version":"1.8.6","language":"python","source_language":"en","source_url":"https://github.com/Instagram/LibCST","tags":["CST","AST","code transformation","refactoring","linter","static analysis"],"install":[{"cmd":"pip install libcst","lang":"bash","label":"Install latest stable release"}],"dependencies":[{"reason":"Required for building from source if pre-built binary wheels are not available for your system. Binary wheels are provided for Linux/Windows x86/x64 and Mac x64/arm.","package":"Rust toolchain","optional":false}],"imports":[{"symbol":"libcst","correct":"import libcst as cst"},{"symbol":"CSTVisitor","correct":"from libcst import CSTVisitor"},{"symbol":"CSTTransformer","correct":"from libcst import CSTTransformer"},{"symbol":"parse_module","correct":"from libcst import parse_module"},{"note":"While `libcst.display.dump` was shown in older examples, `libcst.tool.dump` is the more consistent and often demonstrated path for displaying a concise CST representation.","wrong":"from libcst.display import dump","symbol":"dump","correct":"from libcst.tool import dump"}],"quickstart":{"code":"import libcst as cst\nfrom libcst import CSTTransformer, parse_module\nfrom libcst.tool import dump # For pretty-printing the CST\nfrom libcst.metadata import MetadataWrapper, QualifiedNameProvider\n\nclass MyTransformer(CSTTransformer):\n    METADATA_DEPENDENCIES = {QualifiedNameProvider}\n\n    def leave_Name(self, original_node, updated_node):\n        # Example: change all instances of 'old_var' to 'new_var'\n        if updated_node.value == 'old_var':\n            print(f\"Changing '{original_node.value}' to 'new_var' at {self.get_metadata(QualifiedNameProvider, original_node)}\")\n            return updated_node.with_changes(value='new_var')\n        return updated_node\n\n\nsource_code = \"\"\"\nimport os\n\ndef my_function(old_var):\n    x = old_var + 1\n    return x\n\nold_var = 10\n\"\"\"\n\n# Parse the module into a CST\ntree = parse_module(source_code)\n\n# Wrap the tree with metadata providers\nwrapper = MetadataWrapper(tree)\n\n# Apply the transformer\nmodified_tree = wrapper.visit(MyTransformer())\n\n# Generate the modified code\nmodified_code = modified_tree.code\n\nprint(\"Original Code:\\n\" + source_code)\nprint(\"\\nModified Code:\\n\" + modified_code)\nprint(\"\\nCST of Modified Code (dump):\\n\" + dump(modified_tree))\n","lang":"python","description":"This quickstart demonstrates parsing Python code, applying a `CSTTransformer` to modify a variable name (`old_var` to `new_var`), and then generating the modified code. It also shows how to use `libcst.tool.dump` for a concise representation of the CST and how to incorporate metadata providers."},"warnings":[{"fix":"Ensure your environment is set up to use the default native parser. If you encounter parsing issues or rely on the old parser, update your setup to use the native implementation. Install with pre-built binary wheels when possible to avoid Rust toolchain dependencies.","message":"LibCST transitioned to a new, Rust-based parser by default in version 1.0.0. The old pure-Python parser, previously accessible via `LIBCST_PARSER_TYPE=pure` environment variable, is scheduled for removal in future non-patch releases.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Always return `updated_node` (or a modified copy of it) from `leave_` methods in `CSTTransformer`. Utilize `with_changes()` for modifying existing nodes and `FlattenSentinel` for inserting or removing multiple nodes to preserve formatting. Avoid `isinstance` for traversal; prefer visitor methods like `visit_<NodeType>` or matchers.","message":"When programmatically modifying a CST, directly re-assigning nodes or performing in-place modifications can lead to unexpected loss of formatting (whitespace, comments). LibCST nodes are immutable.","severity":"gotcha","affected_versions":"All versions"},{"fix":"The easiest way to install Rust is via `rustup`. If you frequently build Python packages with native extensions, consider using an environment where Rust is pre-configured.","message":"Building LibCST from source (e.g., if a binary wheel is not available for your specific Python version or OS architecture) requires a recent Rust toolchain, including `cargo`, to be installed and available in your PATH.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Consider using `sys.modules` checks at runtime to prevent co-installation, or implement a build-time script using a LibCST transformer to rewrite internal import paths in your fork. Explicitly declare conflicts in `pyproject.toml` if such a feature becomes available in package managers.","message":"Forking and renaming a project that internally uses absolute imports from `libcst` can lead to conflicts if both the original `libcst` and your renamed fork are installed in the same environment.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use `from libcst.tool import dump` and then `print(dump(tree))` for a more concise and readable representation of the CST's essential elements, which is often more useful for understanding the tree's structure.","message":"When debugging CST structures, simply `print(tree)` might provide an overwhelming amount of detail including all whitespace and token information.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T18:53:58.709Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"fix":"Install the library using pip: `pip install libcst`","cause":"The `libcst` library is not installed in the Python environment.","error":"ModuleNotFoundError: No module named 'libcst'"},{"fix":"Ensure the input code is valid Python for the target version, upgrade `libcst` to a version that supports the syntax, or use `libcst.parse_module()` for full modules.","cause":"The input source code contains invalid Python syntax or uses Python features not yet supported by the installed `libcst` version, or the wrong parsing function (`parse_expression` instead of `parse_module`) was used.","error":"libcst._exceptions.ParserSyntaxError: Syntax Error @ X:Y. Incomplete input. Unexpectedly encountered '...'"},{"fix":"Ensure you have a compatible Rust toolchain installed (e.g., `rustup install stable` if using `rustup`) or use a Python version for which `libcst` provides prebuilt wheels, or explicitly install a `libcst` version compatible with your Python interpreter.","cause":"This error, often accompanied by Rust compilation messages, indicates compatibility issues between the `libcst` native parser (written in Rust) and the Python version or Rust toolchain being used, particularly with newer Python releases like 3.12+ where `libcst` might not have prebuilt wheels.","error":"Exception: Logic error, unexpected top level type!"},{"fix":"Access `code_for_node` through the `Module` object from which the node was parsed: `module.code_for_node(your_cst_node)`.","cause":"The `code_for_node` method is available on a `Module` object, not directly on individual `CSTNode` instances, as it requires the module's context (like indentation and newline formats) to correctly render code.","error":"AttributeError: 'CSTNode' object has no attribute 'code_for_node'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"1.8.6","cli_name":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.53,"mem_mb":7.5,"disk_size":"32.2M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.51,"mem_mb":7.5,"disk_size":"32.2M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.2,"import_time_s":0.29,"mem_mb":7.5,"disk_size":"33M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.3,"mem_mb":7.5,"disk_size":"33M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.91,"mem_mb":8.6,"disk_size":"35.9M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.06,"mem_mb":8.6,"disk_size":"35.9M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.2,"import_time_s":0.81,"mem_mb":8.6,"disk_size":"37M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.73,"mem_mb":8.6,"disk_size":"37M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.75,"mem_mb":8.4,"disk_size":"27.5M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.81,"mem_mb":8.4,"disk_size":"27.5M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.1,"import_time_s":0.81,"mem_mb":8.4,"disk_size":"29M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.77,"mem_mb":8.4,"disk_size":"29M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.64,"mem_mb":8.4,"disk_size":"27.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.68,"mem_mb":8.4,"disk_size":"27.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.3,"import_time_s":0.66,"mem_mb":8.4,"disk_size":"28M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.65,"mem_mb":8.4,"disk_size":"28M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.43,"mem_mb":8,"disk_size":"32.1M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.49,"mem_mb":8,"disk_size":"32.1M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.7,"import_time_s":0.45,"mem_mb":8,"disk_size":"33M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.4,"mem_mb":8,"disk_size":"33M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}