Skip to content

API reference

The API mirrors SciTools Understand's Python API. Where a method is implemented, it takes the same arguments and returns the same shape.

46 of the 49 public methods are implemented. The three that are not -- Db.close, Db.lookup_uniquename and Violation.add_fixit_hint -- have empty bodies and return None. Nothing raises NotImplementedError; earlier versions of this page said it did, and that was wrong. A caller cannot currently distinguish "not implemented" from "found nothing", which is the opposite of what this project argues for elsewhere and is on the roadmap.

import openunderstand.ounderstand as und
db = und.open("myproject.udb")

Filter strings

Several methods take a kindstring -- the same filter grammar Understand uses.

Syntax Meaning
"Class" kind name contains the word Class
"Static Method" contains both words
"Method ~Static" contains Method, does not contain Static
"Class,Interface" either alternative

Words match whole tokens of the kind name, so "Call" selects Java Call and Java Call Nondynamic alike. Matching is case-insensitive; entity names are not, because Java is not.


Module functions

open(dbname)Db

Open a database. Raises UnderstandError if the file does not exist or holds no project.

version()str

Build number of this module.

update_files(paths, source_root="")dict

Re-analyse the named .java files in the open database and return a summary of what changed. Not part of Understand's API: it is how this project keeps a database current without rebuilding it.

from openunderstand.oudb import api

db = api.open("myproject.udb")
api.update_files(["/project/src/Foo.java"], source_root="/project")

The list is expanded to every file that depends on one of those named -- a file depends on another when it references a type declared there -- because editing a base class changes what its subclasses inherit. Each file's previous contribution is deleted before it is re-analysed, so a renamed method does not survive under both names, and a path that no longer exists is purged rather than re-analysed.

The result reproduces what a full rebuild of the same source would write. It is much quicker: one file of the 85-file org.json benchmark takes about 1.2s against 14s for the whole project.


Db

ents([kindstring])list[Ent]

Every entity, or those whose kind matches the filter.

db.ents("Class")                 # all classes
db.ents("Method ~Static")        # instance methods only

ent_from_id(id)Ent

The entity with this database id.

lookup(name [, kindstring])list[Ent]

Entities whose name or long name matches the regular expression name. Pass a compiled pattern for case-insensitive search:

db.lookup(re.compile("json", re.I), "Class")

name()str

The project name.

language()str

"Java".

relative_file_name(ent)str

A file entity's path relative to the project root.

close()

Release the database.

Not implemented: lookup_uniquename, metric, metrics, root_archs.


Ent

An entity: a file, class, method, variable, parameter, package.

Identity

Method Returns
name() getValue
longname() org.json.CDL.getValue
simplename() name without any qualification
id() database id
kind() the entity's Kind
kindname() Java Method Private Member
language() "Java"
parent() enclosing entity, or None — a method's class, a top-level type's file, a lambda's method
type() declared type, for variables and methods
value() initialiser text, for variables
contents() source text of the declaration

refs([refkindstring [, entkindstring [, unique]]])list[Ref]

References whose scope is this entity.

cls.refs()                          # everything
cls.refs("Define")                  # what it defines
cls.refs("Define", "Method")        # the methods it defines
cls.refs("Call", "", True)          # one reference per called entity

unique keeps the first reference to each distinct entity.

ref(...)Ref | None

The first result of refs(...), or None.

ents(refkindstring [, entkindstring])list[Ent]

The entities on the far side of matching references -- refs() with the references thrown away.

filerefs([refkindstring [, entkindstring [, unique]]])list[Ref]

References in this file entity.

metric(names)dict

Metric values. Ent.metric() dispatches through a chain with no fallback, so an unrecognised name is simply absent from the returned dictionary. That matches Understand's documented behaviour -- its own docs say an unavailable metric's value is None -- but it is silence, not refusal.

cls.metric(["CountDeclMethodAll", "Cyclomatic"])
# {'CountDeclMethodAll': 12, 'Cyclomatic': 34}

metrics()list[str]

Names accepted by metric(). 67 names, scoped to the entity's kind, because Understand answers a metric only for the kinds it is defined on. The list is deduplicated and ordered. Names outside the kind's set are absent from the result rather than raising.

Not implemented: comments, depends, dependsby, draw, freetext, ib, lexer, parameters, parsetime, uniquename.


Ref

One place an entity appears.

Method Returns
kind() the reference's Kind
kindname() Java Call
ent() the entity referred to
scope() the entity referring
file() the file entity it occurs in
line() 1-based line
column() 1-based column
isforward() whether this is the forward direction

Every reference is stored twice, once in each direction, at the same file, line and column. Java Call and Java Callby are the same fact read from opposite ends.


Kind

Method Returns
name() / longname() Java Call
check(kindstring) whether this kind matches a filter
inv() the inverse reference kind; raises for an entity kind
Kind.list_entity([filter]) all entity kinds (static)
Kind.list_reference([filter]) all reference kinds (static)

See Kinds for the full vocabulary.


Differences from Understand

These are deliberate and measured, not accidental:

  • Long names carry no parameter list -- as in Understand, where println.print also names two entities. Overloads are told apart by declaration position, so they are separate entities here too.
  • External types are not resolved. No JDK or third-party jars are analysed, so java.lang.String exists as an unresolved entity with no members.
  • Java 8 only. The grammar predates records, sealed types, var, text blocks and yield. Files using them fail to parse and contribute nothing.
  • Coverage is partial. Parity reports exactly how partial, per kind, against the real tool.