pythonpython-3.xabstract-syntax-treenuke

Handling line continuation and escaped characters in Python


I am working with Python code captured from Nuke, a compositing software, which adds line continuation and escaped characters. The code typed in by the user in Nuke is as follows:

if nuke.frame()>1:
   ret=nuke.frame()/2
else:
   ret=nuke.frame()

To retrieve this code (which is stored in a node's knob in Nuke), i use the expression() method from Nuke's Python API, here's an example:

animation_curve = n['multiply'].animation(0)
code_string = animation_curve.expression()

The resulting code string is as follows:

[python -execlocal if\ nuke.frame()>1:\n\ \ \ ret=nuke.frame()/2\nelse:\n\ \ \ ret=nuke.frame()]

Then via regex pattern matching i capture only the code:

if\ nuke.frame()>1:\n\ \ \ ret=nuke.frame()/2\nelse:\n\ \ \ ret=nuke.frame()

My objective is to parse and execute this code string using the ast module in Python, taking into account the line continuation and escaped characters present. However, I am encountering difficulties due to the syntax error caused by the unexpected characters following the line continuation characters. When I try tree = ast.parse(code_string) I get:

    if\ nuke.frame()>1:\n\ \ \ ret=nuke.frame()/2\nelse:\n\ \ \ ret=nuke.frame()
                                                                               ^
SyntaxError: unexpected character after line continuation character

Note that I probably can't use .replace() to get rid of backslashes in the code because some code might actually have backslashes in it.. I also can't use exec() due to security risks.

I appreciate any insights, suggestions, or code examples that can guide me in correctly parsing and executing the Python code obtained from Nuke's animation expression. Thank you for your valuable assistance!


Solution

  • The trick here is that you have spaces that are escaped with backslashes "\ " and the ast package does not like them. I believe we can manually strip them out and things should hopefully work.

    Try:

    import ast
    
    text = "if\ nuke.frame()>1:\n\ \ \ ret=nuke.frame()/2\nelse:\n\ \ \ ret=nuke.frame()"
    parser = ast.parse(text.replace("\ ", " "))  # <---- Take care of the escaped spaces
    walker = ast.walk(parser)
    print(list(walker))