Template building utilities

astcheck includes some utilities for building AST templates to check against.

astcheck.must_exist(node, path)

Checker function for an item or list that must exist

This matches any value except None and the empty list.

For instance, to match for loops with an else clause:

ast.For(orelse=astcheck.must_exist)
astcheck.must_not_exist(node, path)

Checker function for things that must not exist

This accepts only None and the empty list.

For instance, to check that a function has no decorators:

ast.FunctionDef(decorator_list=astcheck.must_not_exist)
class astcheck.name_or_attr(name)

Checker for ast.Name or ast.Attribute

These are often used in similar ways - depending on how you do imports, objects will be referenced as names or as attributes of a module. By using this function to build your template, you can allow either. For instance, this will match both f() and mod.f():

ast.Call(func=astcheck.name_or_attr('f'))
class astcheck.single_assign(target=None, value=None)

Checker for ast.Assign or ast.AnnAssign

Assign is a plain assignment. This will match only assignments to a single target (a = 1 but not a = b = 1). AnnAssign is an annotated assignment, like a: int = 7. target and value may be AST nodes to check, so this would match any assignment to a:

astcheck.single_assign(target=ast.Name(id='a'))

Annotated assignments don’t necessarily have a value: a: int is parsed as an AnnAssign node. Use must_exist() to avoid matching these:

astcheck.single_assign(target=ast.Name(id='a'), value=astcheck.must_exist)
class astcheck.listmiddle

Helper to check only the beginning and/or end of a list. Instantiate it and add lists to it to match them at the start or the end. E.g. to test the final return statement of a function, while ignoring any other code in the function:

template = ast.FunctionDef(name="myfunc",
     body= astcheck.listmiddle()+[ast.Return(value=ast.Name(id="retval"))]
)

sample = ast.parse("""
def myfunc():
    retval = do_something() * 7
    return retval
""")

astcheck.assert_ast_like(sample.body[0], template)