module documentation

Utilities for comparing two versions of a module symbol table. The goal is to find which AST nodes have externally visible changes, so that we can fire triggers and re-process other parts of the program that are stale because of the changes. Only look at detail at definitions at the current module -- don't recurse into other modules. A summary of the module contents: * snapshot_symbol_table(...) creates an opaque snapshot description of a module/class symbol table (recursing into nested class symbol tables). * compare_symbol_table_snapshots(...) compares two snapshots for the same module id and returns fully qualified names of differences (which act as triggers). To compare two versions of a module symbol table, take snapshots of both versions and compare the snapshots. The use of snapshots makes it easy to compare two versions of the *same* symbol table that is being mutated. Summary of how this works for certain kinds of differences: * If a symbol table node is deleted or added (only present in old/new version of the symbol table), it is considered different, of course. * If a symbol table node refers to a different sort of thing in the new version, it is considered different (for example, if a class is replaced with a function). * If the signature of a function has changed, it is considered different. * If the type of a variable changes, it is considered different. * If the MRO of a class changes, or a non-generic class is turned into a generic class, the class is considered different (there are other such "big" differences that cause a class to be considered changed). However, just changes to attributes or methods don't generally constitute a difference at the class level -- these are handled at attribute level (say, 'mod.Cls.method' is different rather than 'mod.Cls' being different). * If an imported name targets a different name (say, 'from x import y' is replaced with 'from z import y'), the name in the module is considered different. If the target of an import continues to have the same name, but it's specifics change, this doesn't mean that the imported name is treated as changed. Say, there is 'from x import y' in 'm', and the type of 'x.y' has changed. This doesn't mean that that 'm.y' is considered changed. Instead, processing the difference in 'm' will be handled through fine-grained dependencies.

Class SnapshotTypeVisitor Creates a read-only, self-contained snapshot of a type object.
Function compare_symbol_table_snapshots Return names that are different in two snapshots of a symbol table.
Function encode_optional_str Undocumented
Function snapshot_definition Create a snapshot description of a symbol table node.
Function snapshot_optional_type Undocumented
Function snapshot_simple_type Undocumented
Function snapshot_symbol_table Create a snapshot description that represents the state of a symbol table.
Function snapshot_type Create a snapshot representation of a type using nested tuples.
Function snapshot_types Undocumented
Function snapshot_untyped_signature Create a snapshot of the signature of a function that has no explicit signature.
Type Alias Primitive Undocumented
Type Alias SnapshotItem Undocumented
Type Alias SymbolSnapshot Undocumented
def compare_symbol_table_snapshots(name_prefix: str, snapshot1: dict[str, SymbolSnapshot], snapshot2: dict[str, SymbolSnapshot]) -> set[str]: (source)

Return names that are different in two snapshots of a symbol table. Only shallow (intra-module) differences are considered. References to things defined outside the module are compared based on the name of the target only. Recurse into class symbol tables (if the class is defined in the target module). Return a set of fully-qualified names (e.g., 'mod.func' or 'mod.Class.method').

def encode_optional_str(s: str|None) -> str: (source)

Undocumented

def snapshot_definition(node: SymbolNode|None, common: SymbolSnapshot) -> SymbolSnapshot: (source)

Create a snapshot description of a symbol table node. The representation is nested tuples and dicts. Only externally visible attributes are included.

def snapshot_optional_type(typ: Type|None) -> SnapshotItem: (source)

Undocumented

def snapshot_simple_type(typ: Type) -> SnapshotItem: (source)

Undocumented

def snapshot_symbol_table(name_prefix: str, table: SymbolTable) -> dict[str, SymbolSnapshot]: (source)

Create a snapshot description that represents the state of a symbol table. The snapshot has a representation based on nested tuples and dicts that makes it easy and fast to find differences. Only "shallow" state is included in the snapshot -- references to things defined in other modules are represented just by the names of the targets.

def snapshot_type(typ: Type) -> SnapshotItem: (source)

Create a snapshot representation of a type using nested tuples.

def snapshot_types(types: Sequence[Type]) -> SnapshotItem: (source)

Undocumented

def snapshot_untyped_signature(func: OverloadedFuncDef|FuncItem) -> SymbolSnapshot: (source)

Create a snapshot of the signature of a function that has no explicit signature. If the arguments to a function without signature change, it must be considered as different. We have this special casing since we don't store the implicit signature anywhere, and we'd rather not construct new Callable objects in this module (the idea is to only read properties of the AST here).

Primitive: _TypeAlias = (source)

Undocumented

Value
Union[str, float, int, bool]
SnapshotItem: _TypeAlias = (source)

Undocumented

Value
Tuple[Union[Primitive, SnapshotItem], ...]
SymbolSnapshot: _TypeAlias = (source)

Undocumented

Value
Tuple[object, ...]