Basics — RedBaron 0.8 documentation

# Basics

RedBaron is very simple to use, you just need to import it and feed him with a string:

    from redbaron import RedBaron

    red = RedBaron("print('hello world!')")

But what you should be really doing is using RedBaron directly into a shell (I recommend IPython but bpython is cool too), it has been thought for it, like BeautifulSoup.

    In [1]: from redbaron import RedBaron

    In [2]: red = RedBaron("hello = 'Hello World!'\nprint(hello)")

    In [3]: red
    Out[3]:
    0   hello = 'Hello World!'
    1   print(hello)

As you can see, when displayed in a shell, a RedBaron instance renders to the actual content so you easily see what you are doing when playing interactively with it (just like a BeautifulSoup instance).

There are 2 families of Node in RedBaron: NodeList and standalone Node. Since a Python program is a list of operations, RedBaron will always be a list. This is why when displayed you see integers on the left, those are the index in the list of the nodes of the right, so as expected:

    In [4]: red[1]
    Out[4]: print(hello)

You get the print Node that was located at 2. As you can see, here we are on a standalone Node, so we don’t get the list of indexes of the left.

## .help()

Another useful function is `.help()`. It displays the RedBaron nodes tree helping you understand how is it composed and how you can use it:

    In [5]: red[0]
    Out[5]: hello = 'Hello World!'

    In [6]: red[0].help()
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode()
          # identifiers: name, name_, namenode
          value='hello'
      annotation ->
        None
      value ->
        StringNode()
          # identifiers: string, string_, stringnode
          value="'Hello World!'"

Here, as you can see, `hello = 'Hello World!'` is an `AssignmentNode` and it has 2 attributes: `target` and `value`. Those 2 attributes are 2 other nodes, a `NameNode` for the variable `hello` and a `StringNode` for the string. Those 2 nodes each have one attribute `value` that is their content.

One rule with Baron: every node has a value attribute that contains its value (in case of a node with multiple data, `value` points to the most obvious one, for example, in a function definition it’s the body of the function). The only exceptions are nodes where it doesn’t make any sense, for example a `PassNode` (representing the keyword `pass`) simply doesn’t contain anything.

Like the `repr`, `.help()` has also a display showing index number when called on a `NodeList`:

    In [7]: red.help()
    0 -----------------------------------------------------
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode()
          # identifiers: name, name_, namenode
          value='hello'
      annotation ->
        None
      value ->
        StringNode()
          # identifiers: string, string_, stringnode
          value="'Hello World!'"
    1 -----------------------------------------------------
    EndlNode()
      # identifiers: endl, endl_, endlnode
      value='\n'
      indent=''
    2 -----------------------------------------------------
    PrintNode()
      # identifiers: print, print_, printnode
      destination ->
        None
      value ->
        * AssociativeParenthesisNode()
            # identifiers: associative_parenthesis, associative_parenthesis_, associativeparenthesis, associativeparenthesisnode
            value ->
              NameNode() ...

The best way to understand how `.help()` works is to remember that RedBaron is mapping from Baron FST which is JSON. This means that RedBaron node can be composed of either: string, bool, numbers, list or other nodes and the key are always string.

### helpers

Some nodes come with helpers method, `.help()` displays them when they are present:

    In [8]: red = RedBaron("import a, b, c as d")

    In [9]: red.help(deep=1)
    0 -----------------------------------------------------
    ImportNode()
      # identifiers: import, import_, importnode
      # helpers: modules, names
      value ->
        * DottedAsNameNode() ...
        * DottedAsNameNode() ...
        * DottedAsNameNode() ...

You can read their documentation using the `?` magic of ipython:

    In [10]: print(red[0].names.__doc__)  # you can do "red[0].names?" in IPython shell
    return a list of string of new names inserted in the python context

    In [11]: red[0].names()
    Out[11]: ['a', 'b', 'd']

    In [12]: print(red[0].modules.__doc__)
    return a list of string of modules imported

    In [13]: red[0].modules()
    Out[13]: ['a', 'b', 'c']

If you come with cool helpers, don’t hesitate to propose them in a pull request!

### deep

`.help()` accept a deep argument on how far in the tree it should show the `.help()` of subnode. By default its value is `2`. You can pass the value `True` if you want to display the whole tree.

    In [14]: red = RedBaron("a = b if c else d")

    In [15]: red.help()
    0 -----------------------------------------------------
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode()
          # identifiers: name, name_, namenode
          value='a'
      annotation ->
        None
      value ->
        TernaryOperatorNode()
          # identifiers: ternary_operator, ternary_operator_, ternaryoperator, ternaryoperatornode
          first ->
            NameNode() ...
          value ->
            NameNode() ...
          second ->
            NameNode() ...

    In [16]: red.help(0)
    0 -----------------------------------------------------
    AssignmentNode() ...

    In [17]: red.help(deep=1)  # you can name the argument too
    0 -----------------------------------------------------
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode() ...
      annotation ->
        None
      value ->
        TernaryOperatorNode() ...

    In [18]: red.help(True)
    0 -----------------------------------------------------
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode()
          # identifiers: name, name_, namenode
          value='a'
      annotation ->
        None
      value ->
        TernaryOperatorNode()
          # identifiers: ternary_operator, ternary_operator_, ternaryoperator, ternaryoperatornode
          first ->
            NameNode()
              # identifiers: name, name_, namenode
              value='b'
          value ->
            NameNode()
              # identifiers: name, name_, namenode
              value='c'
          second ->
            NameNode()
              # identifiers: name, name_, namenode
              value='d'

### with_formatting

`.help()` accepts the option `with_formatting` that is set at `False` by default. If set at `True` it will also display the attributes responsible for holding the formatting of the node (they are always node list):

    In [19]: red.help(with_formatting=True)
    0 -----------------------------------------------------
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode()
          # identifiers: name, name_, namenode
          value='a'
      annotation ->
        None
      value ->
        TernaryOperatorNode()
          # identifiers: ternary_operator, ternary_operator_, ternaryoperator, ternaryoperatornode
          first ->
            NameNode() ...
          value ->
            NameNode() ...
          second ->
            NameNode() ...
          first_formatting ->
            * SpaceNode() ...
          second_formatting ->
            * SpaceNode() ...
          third_formatting ->
            * SpaceNode() ...
          fourth_formatting ->
            * SpaceNode() ...
      annotation_first_formatting ->
      annotation_second_formatting ->
      first_formatting ->
        * SpaceNode()
            # identifiers: space, space_, spacenode
            value=' '
      second_formatting ->
        * SpaceNode()
            # identifiers: space, space_, spacenode
            value=' '

Those attributes are always surrounding syntax element of Python like `[](),.{}` or keywords. You should, normally, not have a lot of reasons to play with them. You can find a detailed version of each nodes here: Nodes References Page.

## nodes structure

Nodes can have 3 kind of attributes (which can be accessed like normal object attributes):

- data attributes, which are nearly always strings. They are shown with a `=` in `.help()`. `.value` here for example.

    In [20]: red = RedBaron("variable")

    In [21]: red[0].help()
    NameNode()
      # identifiers: name, name_, namenode
      value='variable'

    In [22]: red[0].value
    Out[22]: 'variable'

- node attributes, which are other nodes. They are shown with a `->` followed by the name of the other node at the next line in `.help()`. `.target` and `.value` here for example.

    In [23]: red = RedBaron("a = 1")

    In [24]: red[0].help()
    AssignmentNode()
      # identifiers: assign, assignment, assignment_, assignmentnode
      operator=''
      target ->
        NameNode()
          # identifiers: name, name_, namenode
          value='a'
      annotation ->
        None
      value ->
        IntNode()
          # identifiers: int, int_, intnode
          value='1'

    In [25]: red[0].target.help()
    NameNode()
      # identifiers: name, name_, namenode
      value='a'

- nodelist attributes, which are lists of other nodes. They are shown with a `->` followed by a series of names of the other nodes starting with a `*` for every item of the list. `.value` here for example:

    In [26]: red = RedBaron("[1, 2, 3]")

    In [27]: red[0].help()
    ListNode()
      # identifiers: list, list_, listnode
      value ->
        * IntNode()
            # identifiers: int, int_, intnode
            value='1'
        * IntNode()
            # identifiers: int, int_, intnode
            value='2'
        * IntNode()
            # identifiers: int, int_, intnode
            value='3'

    In [28]: red[0].value[0].help()
    IntNode()
      # identifiers: int, int_, intnode
      value='1'

## .dumps(), transform the tree into source code

To transform a RedBaron tree back into source code, use the `.dumps()` method. This will transform the current selection back into code.

    In [29]: red = RedBaron("a = 1")

    In [30]: red.dumps()
    Out[30]: 'a = 1'

    In [31]: red[0].target.dumps()
    Out[31]: 'a'

## .fst(), transform the RedBaron tree into Baron FST

To transform a RedBaron tree into Baron Full Syntax Tree, just use the `.fst()` method. This will transform the current selection into FST.

    In [32]: red = RedBaron("a = 1")

    In [33]: red.fst()
    Out[33]:
    [{'annotation': {},
      'annotation_first_formatting': [],
      'annotation_second_formatting': [],
      'first_formatting': [{'type': 'space', 'value': ' '}],
      'operator': '',
      'second_formatting': [{'type': 'space', 'value': ' '}],
      'target': {'type': 'name', 'value': 'a'},
      'type': 'assignment',
      'value': {'section': 'number', 'type': 'int', 'value': '1'}}]

    In [34]: red[0].target.fst()
    Out[34]: {'type': 'name', 'value': 'a'}

While I don’t see a lot of occasions where you might need this, this will allow you to better understand how Baron and RedBaron are working.

## .copy()

If you want to copy a RedBaron node you can use the `.copy()` method this way:

    In [35]: red = RedBaron("a = b")

    In [36]: red[0].target.copy()
    Out[36]: a

### Next

To learn how to find things in RedBaron read Querying.