Search code examples
pythonregexparsingstring-operations

How do I check if a line is a valid function call in python?


Background: I'm currently creating a line-magic for ipython. This magic shall only work for lines, where the return value of a function is assigned to a variable.

I'm looking for a way to make sure, that a line is a valid function-call + assignment in python.

e.g. the following shall be accepted:

a = b()
a,b = c(d,e="f")
a = b(c()+c)

and the following shall be declined:

a = def fun() # no function call
b(a=2) # no assignment
a = b + c # no function call 
a = b() + c() # top-level on right-hand-side must be function call

If the line is no valid python at all, I don't care whether it passes, as this will be handled at another stage.


Solution

  • You could use Python's own parser, accessible through the ast module, to directly inspect each statement to see if it's an assignment whose right-hand-side is a call.

    import ast
    
    def is_call_assignment(line):
        try:
            node = ast.parse(line)
        except SyntaxError:
            return False
        if not isinstance(node, ast.Module):
            return False
        if len(node.body) != 1 or not isinstance(node.body[0], ast.Assign):
            return False
        statement = node.body[0]
        return isinstance(statement.value, ast.Call)
    
    
    test_cases = [
        'a = b()',
        'a,b = c(d,e="f")',
        'a = b(c()+c)',
        'a = def fun()',
        'b(a=2)',
        'a = b + c',
        'a = b() + c()'
    ]
    
    for line in test_cases:
        print(line)
        print(is_call_assignment(line))
        print("")
    

    Result:

    a = b()
    True
    
    a,b = c(d,e="f")
    True
    
    a = b(c()+c)
    True
    
    a = def fun()
    False
    
    b(a=2)
    False
    
    a = b + c
    False
    
    a = b() + c()
    False