Skip to content

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 Foo calls function Bar on line 14, then Foo has a Call reference to Bar, and Bar has a CallBy reference to Foo. In the API a reference is an understand.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, or None if 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), and ref.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