RedBaron Documentation

repository·master·Indexed 20 days ago

https://github.com/pycqa/redbaron

A Python library for programmatic source code modification and refactoring. Built on Baron's Full Syntax Tree (FST), RedBaron ensures lossless transformations that preserve original source code structure. It features a BeautifulSoup-inspired API for navigating and manipulating Python code, supporting Python 2 and Python 3 up to grammar version 3.7. Key functionality includes the .help() method for tree inspection, .dumps() for code generation, and specialized proxy lists (DotProxyList and LineProxyList) for intuitive code element manipulation.

Tokens
17.6K
Snippets
92
Records
99
Agent score
72%

What's inside RedBaron

  1. What is RedBaron?

    master

    RedBaron is a Python library designed for writing code that modifies source code (refactoring, tool building, or IDE integration).

    Key characteristics:

    • Lossless Modification: It is built on Baron, which uses a Full Syntax Tree (FST). This guarantees that ast_to_code(code_to_ast(source_code)) == source_code, meaning it only modifies the parts of the code you explicitly target.
    • Intuitive API: The API is heavily inspired by BeautifulSoup, making it simple and intuitive for navigating and manipulating Python source code.
    • Compatibility: The public API is guaranteed to be retro-compatible until version 2.0.
  2. Assigning different types to node attributes

    master

    RedBaron nodes are highly flexible when setting attributes. You can assign values using several different formats, and RedBaron will adapt accordingly:

    1. String: The string is parsed as Python code and converted into RedBaron nodes.
    2. FST Data (Dictionary): Passing a raw FST (Full Syntax Tree) dictionary will transform that data into a RedBaron object.
    3. RedBaron Node/List: You can pass existing node instances or lists of nodes directly.
    4. Mixed Content: For list attributes, you can mix FST dictionaries, strings, and existing nodes; RedBaron will parse/transform each element based on its type.
    from redbaron import RedBaron
    
    red = RedBaron("a = b")
    
    # 1. Data attribute (no parsing, just sets value)
    red.name.value = "something_else"
    
    # 2. Node attribute with a string (triggers parsing)
    red[0].value = "42 * pouet"
    
    # 3. Node attribute with FST data (transforms to RedBaron object)
    red[0].value = {"type": "name", "value": "pouet"}
    
    # 4. List attribute with mixed content
    red_list = RedBaron("[1, 2, 3]")
    red_list[0].value = [
        {"type": "name", "value": "pouet"}, # FST dict
        "pouet ,",                               # String (parsed)
        NameNode({"type": "name", "value": "plop"}) # Existing Node
    ]
  3. How CodeBlockNode handles indentation

    master

    A CodeBlockNode is a node type that contains an indented body (e.g., DefNode, IfNode, ClassNode). When setting the .value attribute, RedBaron automatically handles reindentation and formatting, so you don't have to manually manage whitespace or newlines.

    If you provide a string with incorrect indentation or missing newlines, RedBaron will adjust it to fit the block's context.

    red = RedBaron("def function():\n    pass\n")
    red[0].value = "stuff"  # RedBaron adds the first '\n' and sets indentation
    red[0].value = " some\n stuff"
  4. Navigate control structures intuitively with .next_intuitive()

    master

    Standard .next and .previous navigation follows the Full Syntax Tree (FST), which might not match human expectations for control structures. For example, .next on a TryNode returns the node after the entire try-except-else-finally block, rather than the first ExceptNode.

    To navigate logically through control structures like TryNode, IfNode, ElifNode, ElseNode, ForNode, and WhileNode, use .next_intuitive() and .previous_intuitive().

    Note on IfelseblockNode:

    • .next_intuitive() on an IfNode or ElifNode inside an IfelseblockNode will move to the next branch within that block.
    • Calling .next_intuitive() on the IfelseblockNode itself will jump to the first/last node inside the block.
    red = RedBaron("try:\n    pass\nexcept:\n    pass\nafter")
    # Standard navigation jumps over the whole block
    red.try_.next 
    
    # Intuitive navigation moves to the except block
    red.try_.next_intuitive
  5. Use DotProxyList to manipulate code elements like Python lists

    master

    RedBaron uses a DotProxyList (accessible via the .value attribute of certain nodes) that mimics the standard Python list API. This allows you to perform common list operations—such as appending, inserting, extending, popping, and slicing—directly on the code elements represented by the list. When you call these methods, RedBaron modifies the underlying AST and updates the code representation accordingly.

    from redbaron import RedBaron
    
    # Initialize RedBaron with a code snippet
    red = RedBaron("a.b(c).d[e]")
    
    # Access the list-like value of a node
    # Operations on .value will modify the code
    red[0].value.append("(stuff)")
  6. Understand EndlNode and formatting

    master

    An EndlNode represents a newline component (\n or \r\n).

    Crucial behavior: The EndlNode is responsible for holding the indentation after itself. Additionally, if a CommentNode appears immediately before an EndlNode, that comment will typically be stored in the formatting key of the EndlNode.

  7. How to query and modify nodes in RedBaron

    master

    RedBaron allows you to navigate the AST using BeautifulSoup-style queries and modify nodes by assigning new Python code (as strings) to their attributes.

    Querying

    Use .find() to locate a single node or .find_all() (or the shorthand ()) to find all matching nodes. Queries can use values, lambdas, regex, or globs.

    Modifying

    To change a node, assign a string containing the new code to the desired attribute (e.g., .value).

    Extending Source

    RedBaron objects support list-like operations such as .extend() to append new lines or code blocks to the existing source.

    from redbaron import RedBaron
    
    red = RedBaron("some_value = 42")
    
    # Querying: find an integer node with value 4
    # red.find("int", value=4)
    
    # Modifying: change the value of the first node
    red[0].value = "1 + 4"
    
    # Extending: add new lines of code
    red.extend(["\n", "INSTALLED_APPS = []"])
    
    # Complex query and modification
    # Find an assignment where the target is 'INSTALLED_APPS' and append to its value
    red.find("assignment", target=lambda x: x.dumps() == "INSTALLED_APPS").value.append("'django'")
    
    print(red.dumps())
  8. Understanding the Full Syntax Tree (FST) abstraction in RedBaron

    master

    RedBaron uses a Full Syntax Tree (FST) to represent Python code. Unlike the standard ast module, which removes formatting and certain structural details, an FST preserves the exact representation of your code, including its formatting.

    This makes RedBaron suitable for complex code manipulation tasks where you need to modify code and convert it back to a string without losing the original style or accidentally affecting non-target elements (like text inside strings).

    Use RedBaron when you need to perform:

    • Variable renaming without clashing with string literals.
    • Inlining functions or methods.
    • Extracting functions/methods from specific lines of code.
    • Splitting classes or files into new modules/classes.
    • Large-scale refactoring (e.g., converting ORMs).
    • Custom refactoring operations not supported by standard IDEs.
    • Code generation and deep code analysis that requires structural fidelity.
  9. Automatic assignment of .parent and .on_attribute

    master
    When you modify an attribute of a node or a node list, RedBaron automatically manages the relationship between the new content and the container. Specifically, it sets the .parent value of the new attribute (or the elements within a list) to the corresponding node. This automatic assignment works regardless of whether you use a string, an fst node, a node instance, or a node list.
  10. Use the different types of proxy lists

    master

    RedBaron provides four specialized proxy list types depending on the structure you are modifying:

    1. CommaProxyList: Used for comma-separated lists (e.g., [1, 2, 3]). This is the most common type.
    2. DotProxyList: Used for dot-separated sequences (atomtrailers) like a.b[plop].c(). It is intelligent enough to handle calls () and indexing [] without incorrectly adding extra dots.
    3. LineProxyList: Used for lines of code (e.g., function bodies or entire files). It manages end-of-line nodes and indentation automatically. It explicitly represents empty lines so you can manage spacing.
    4. DecoratorLineProxyList: Similar to LineProxyList but specifically handles the indentation of decorators. Note: You must include the @ symbol when appending a new decorator.
    # DotProxyList example
    red = RedBaron("a.b(c).d[e]")
    red[0].value.extend(["[stuff]", "f", "(g, h)"])
    
    # DecoratorLineProxyList example
    red = RedBaron("@plop\ndef stuff():\n    pass\n")
    red[0].decorators.append("@plouf")
  11. Manipulate IfelseblockNode (if/elif/else blocks)

    master

    An IfelseblockNode represents a complete conditional structure containing one or more IfNode, ElifNode, or ElseNode objects.

    When setting the .value attribute of an IfelseblockNode, RedBaron automatically handles:

    • Correct indentation for the input.
    • Right stripping.
    • Adding appropriate blank lines (2 lines if at the root of the file, 1 line if indented) when the block is followed by other statements.
    red = RedBaron("if a: pass\n")
    # Automatically handles indentation and spacing
    red[0].value = "if a:\n    pass\nelif b:\n    pass\n\n\n"
  12. Understand RedBaron node attribute types

    master

    RedBaron nodes have three types of attributes that can be accessed like standard object attributes. You can identify them in .help() output:

    1. Data attributes: Usually strings. In .help(), these are shown with an = sign (e.g., .value).
    2. Node attributes: These are other individual nodes. In .help(), these are shown with a -> followed by the attribute name (e.g., .target).
    3. Nodelist attributes: These are lists of other nodes. In .help(), these are shown with a -> followed by a series of names starting with * (e.g., .value in a list context).