Python API tutorial 3: entities, references, and filters¶
Almost everything Understand captures is expressed as entities and references. This tutorial explains both, then shows how kind filters narrow a query down to just what you need.
Entity vs. reference¶
- Entity — anything Understand captures information about: a file, a class, a variable, a function,
and so on. In the API an entity is an
understand.Ent. You can query its name, type, comments, kind, parent, parameters, and more. - Reference — a specific place in the code where two entities relate to each other. For example, if
function
Foocalls functionBaron line 14, thenFoohas a Call reference toBar, andBarhas a CallBy reference toFoo. In the API a reference is anunderstand.Ref, and it carries both entities plus the file, line, column, and reference kind.
References are stored in both directions, so every reference kind has an opposite: Define / DefineIn, Set / SetBy, Call / CallBy, and so on.
To list every entity in a project use db.ents(); to list every reference of an entity use
ent.refs(). Usually you don't want all of them — that's where kind filters come in.
Kind filters¶
A kind filter is a string that filters an Understand list. You already used one in the first script:
db.ents("file")
db.ents() with no filter returns every entity, from loop variables to namespaces. The "file"
string keeps only entities whose kind matches. You can combine terms with simple logic:
| Operator | Meaning |
|---|---|
~ |
NOT |
| space | AND |
, |
OR (top level) |
For example, all classes or functions:
db.ents("class, function")
Or all public, non-volatile functions defined in the project (an unresolved entity is one Understand
has a declaration for but no definition — printf is a common example):
db.ents("function public ~unresolved ~volatile")
Kind filters are used everywhere
The same filter syntax drives filters in the GUI, the API, and plugins. See the Kind Filters reference (also under Help → Python API Documentation) for the full grammar, and the Glossary entry for Kind.
Worked example: where each function is defined¶
List the file and line where each function in the project is defined:
import understand
db = understand.open("C:/projects/test.und")
ents = db.ents("function ~unknown ~unresolved")
for ent in sorted(ents, key=lambda ent: ent.longname()):
ref = ent.ref("definein")
if ref is None:
continue
print(ent.longname(), "(", ent.parameters(), ")")
print(" ", ref.file().relname(), "(", ref.line(), ")")
Reading it through:
db.ents("function ~unknown ~unresolved")gets every function that is actually defined in the project.ent.ref("definein")returns the single reference where the function is defined, orNoneif there isn't one — so we skip functions without a definition.ent.parameters()returns the function's parameter list as a string.ref.file().relname()is the file the reference is in (relative name), andref.line()is its line number.
ref() vs refs()
ent.ref(kind) returns a single Ref (or None) — handy when you expect exactly one, like a
definition. ent.refs(kind) returns a list of all matching references.
Next¶
You can now select entities and walk their references. Next you'll drop below the entity level into the raw token stream with lexers and lexemes.
← Tutorial 2: writing your first API script · → Tutorial 4: lexers and lexemes