from collections import namedtuple
from brian2.utils.stringtools import deindent
__all__ = ["abstract_code_dependencies"]
allids = set()
read = set()
write = set()
funcs = set()
for node in ast.walk(parsed_code):
if node.__class__ is ast.Name:
if node.ctx.__class__ is ast.Store:
elif node.ctx.__class__ is ast.Load:
elif node.__class__ is ast.Call:
read = read - funcs
# check that there's no funky stuff going on with functions
raise SyntaxError("Cannot assign to functions in abstract code")
return allids, read, write, funcs
[docs]def abstract_code_dependencies(code, known_vars=None, known_funcs=None):
Analyses identifiers used in abstract code blocks
code : str
The abstract code block.
known_vars : set
The set of known variable names.
known_funcs : set
The set of known function names.
results : namedtuple with the following fields
The set of all identifiers that appear in this code block,
The set of values that are read, excluding functions.
The set of all values that are written to.
The set of all function names.
The set of all identifiers that appear in this code block and
The set of known values that are read, excluding functions.
The set of known values that are written to.
The set of known functions that are used.
The set of all unknown variables whose values are read. Equal
The set of all unknown variables written to. Equal to
The set of all unknown function names, equal to
The set of all unknown variables whose values are read before they
are written to. If this set is nonempty it usually indicates an
error, since a variable that is read should either have been
defined in the code block (in which case it will appear in
``newly_defined``) or already be known.
The set of all variable names which are newly defined in this
abstract code block.
if known_vars is None:
known_vars = set()
if known_funcs is None:
known_funcs = set()
if not isinstance(known_vars, set):
known_vars = set(known_vars)
if not isinstance(known_funcs, set):
known_funcs = set(known_funcs)
code = deindent(code, docstring=True)
parsed_code = ast.parse(code, mode="exec")
# Get the list of all variables that are read from and written to,
# ignoring the order
allids, read, write, funcs = get_read_write_funcs(parsed_code)
# Now check if there are any values that are unknown and read before
# they are written to
defined = known_vars.copy()
newly_defined = set()
undefined_read = set()
for line in parsed_code.body:
_, cur_read, cur_write, _ = get_read_write_funcs(line)
undef = cur_read - defined
undefined_read |= undef
newly_defined |= (cur_write - defined) - undefined_read
defined |= cur_write
# Return the results as a named tuple
results = dict(
unknown_read=read - known_vars,
unknown_write=write - known_vars,
unknown_funcs=funcs - known_funcs,
return namedtuple("AbstractCodeDependencies", list(results.keys()))(**results)