print
is a function in python 3 so you need to check for an ast.Expr
which contains an ast.Call
for which the ast.Name
has the id print
.
Here's a simple function:
def bar(x: str) -> None:
string = f"Hello {x}!" # ast.Assign
print(string) # ast.Expr
Heres's the full ast dump:
Module(body=[FunctionDef(name='bar', args=arguments(args=[arg(arg='x', annotation=Name(id='str', ctx=Load()))], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[Assign(targets=[Name(id='string', ctx=Store())], value=JoinedStr(values=[Str(s='Hello '), FormattedValue(value=Name(id='x', ctx=Load()), conversion=-1, format_spec=None), Str(s='!')])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Name(id='string', ctx=Load())], keywords=[]))], decorator_list=[], returns=NameConstant(value=None))])
The relevant part (for print
) is:
Expr(value=Call(func=Name(id='print', ctx=Load())
Below is a simple example with a node visitor (sublcassing ast.NodeVisitor
):
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import ast
import inspect
from typing import Callable
class MyNodeVisitor(ast.NodeVisitor):
def visit_Expr(self, node: ast.Expr):
"""Called when the visitor visits an ast.Expr"""
print(f"Found expression node at: line: {node.lineno}; col: {node.col_offset}")
# check "value" which must be an instance of "Call" for a 'print'
if not isinstance(node.value, ast.Call):
return
# now check the function itself.
func = node.value.func # ast.Name
if func.id == "print":
print("found a print")
def contains_print(f: Callable):
source = inspect.getsource(f)
node = ast.parse(source)
func_name = [_def.name for _def in node.body if isinstance(_def, ast.FunctionDef)][0]
print(f"{'-' * 79}\nvisiting function: {func_name}")
print(f"node dump: {ast.dump(node)}")
node_visitor = MyNodeVisitor()
node_visitor.visit(node)
def foo(x: int) -> int:
return x + 1
def bar(x: str) -> None:
string = f"Hello {x}!" # ast.Assign
print(string) # ast.Expr
def baz(x: float) -> float:
if x == 0.0:
print("oh noes!")
raise ValueError
return 10 / x
if __name__ == "__main__":
contains_print(bar)
contains_print(foo)
contains_print(baz)
Here the output (minus the ast dumps):
-------------------------------------------------------------------------------
visiting function: bar
Found expression node at: line: 3; col: 4
found a print
-------------------------------------------------------------------------------
visiting function: foo
-------------------------------------------------------------------------------
visiting function: baz
Found expression node at: line: 3; col: 8
found a print