Model Class - Hierarchy & Query API Reference

Note

βš™οΈ New to this topic? Start with Element Hierarchies to understand how hierarchies work before exploring the full API reference.

The Model class provides comprehensive methods for managing element hierarchies, querying relationships, and organizing elements into parent-child structures with full round-trip XML preservation.

Hierarchy Management Methods

Creating Relationships

add_child(parent_uuid: str, child_uuid: str) None

Add a parent-child relationship between two elements.

Parameters:
  • parent_uuid – UUID of parent element

  • child_uuid – UUID of child element

Raises:
  • KeyError – If parent or child UUID not in model

  • ValueError – If child already has parent, cycle would be created, or max depth exceeded

Features: - Automatic cycle detection prevents invalid hierarchies - Max depth limit (default 5 levels) prevents pathological nesting - Synchronizes bidirectional maps (parent→children and child→parent)

Example:

process = model.add(ArchiType.BusinessProcess, 'Order Management')
func = model.add(ArchiType.BusinessFunction, 'Order Entry')
service = model.add(ArchiType.BusinessService, 'Form Service')

# Create hierarchy
model.add_child(process.uuid, func.uuid)
model.add_child(func.uuid, service.uuid)
remove_child(parent_uuid: str, child_uuid: str) None

Remove a parent-child relationship (orphan the child).

Parameters:
  • parent_uuid – UUID of parent element

  • child_uuid – UUID of child element

Raises:
  • KeyError – If parent or child UUID not in model

  • ValueError – If child is not actually a child of parent

Example:

model.remove_child(process.uuid, func.uuid)
# func is now orphaned (no parent)

Basic Hierarchy Queries

get_parent(elem_uuid: str) Element | None

Get the parent element of a given element.

Parameters:

elem_uuid – Element UUID

Returns:

Parent Element or None if root

Return type:

Optional[Element]

Example:

parent = model.get_parent(func.uuid)
if parent:
    print(f"Parent: {parent.name}")
else:
    print("Element is at root level")
get_children(elem_uuid: str) list[Element]

Get all direct children of a given element.

Parameters:

elem_uuid – Element UUID

Returns:

List of child Elements (empty if no children)

Return type:

list[Element]

Example:

children = model.get_children(process.uuid)
for child in children:
    print(f"Child: {child.name}")

Root and Leaf Queries

get_root_elements() list[Element]

Get all root elements (elements with no parent).

Returns:

List of root Elements

Return type:

list[Element]

Example:

roots = model.get_root_elements()
print(f"Found {len(roots)} root elements")
get_leaf_elements() list[Element]

Get all leaf elements (elements with no children).

Returns:

List of leaf Elements

Return type:

list[Element]

Example:

leaves = model.get_leaf_elements()
for leaf in leaves:
    print(f"Leaf: {leaf.name}")

Ancestry and Depth Methods

get_ancestors(elem_uuid: str) list[Element]

Get all ancestors of an element from the element itself to the root.

Parameters:

elem_uuid – Element UUID

Returns:

List of Elements [elem, parent, grandparent, …, root]

Return type:

list[Element]

Example:

ancestors = model.get_ancestors(service.uuid)
# Returns: [service, func, process]
for ancestor in ancestors:
    print(f"Ancestor: {ancestor.name}")
get_descendants(elem_uuid: str) list[Element]

Get all descendants of an element in breadth-first order.

Parameters:

elem_uuid – Element UUID

Returns:

List of descendant Elements (excludes the element itself)

Return type:

list[Element]

Example:

descendants = model.get_descendants(process.uuid)
# Returns all elements under process at any depth
for desc in descendants:
    print(f"Descendant: {desc.name}")
get_depth(elem_uuid: str) int

Get the nesting depth of an element (0 = root).

Parameters:

elem_uuid – Element UUID

Returns:

Depth level

Return type:

int

Example:

depth = model.get_depth(service.uuid)
if depth == 0:
    print("Root element")
else:
    print(f"Depth: {depth}")

Advanced Query Methods

Sibling Queries

get_siblings(elem_uuid: str) list[Element]

Get all sibling elements (elements with same parent).

Parameters:

elem_uuid – UUID of element to find siblings for

Returns:

List of sibling Elements (excludes elem_uuid itself)

Return type:

list[Element]

Raises:

KeyError – If element UUID not in model

Example:

# Create multiple functions under process
func1 = model.add(ArchiType.BusinessFunction, 'Order Entry')
func2 = model.add(ArchiType.BusinessFunction, 'Order Review')
model.add_child(process.uuid, func1.uuid)
model.add_child(process.uuid, func2.uuid)

# Get siblings of func1
siblings = model.get_siblings(func1.uuid)
# Returns: [func2]

Path-Based Hierarchy Queries

find_by_hierarchy_path(path: str) list[Element]

Find elements by hierarchy path with wildcard support.

Parameters:

path – Hierarchy path string starting with β€˜/’, levels separated by β€˜/’

Returns:

List of matching Elements

Return type:

list[Element]

Path Format: - Absolute paths: /Root, /Parent/Child/Grandchild - Wildcard suffix: /Parent/Child/* (matches all children of Child) - Wildcard in path: /Parent/*/Grandchild (matches any Child)

Examples:

# Get specific element by path
results = model.find_by_hierarchy_path('/Order Management')
# Returns: [order_management_elem]

# Get all children at specific depth
results = model.find_by_hierarchy_path('/Order Management/Order Entry')
# Returns: [order_entry_elem]

# Get all grandchildren (wildcard)
results = model.find_by_hierarchy_path('/Order Management/*')
# Returns: [func1, func2, func3, ...]

# Get deep descendants (wildcard in middle)
results = model.find_by_hierarchy_path('/Order Management/*/Services')
# Returns all Services under any function in Order Management

Performance Characteristics

Time Complexity:

  • add_child(): O(depth) - performs cycle detection

  • get_parent(): O(1) - direct map lookup

  • get_children(): O(n) - where n = number of children

  • get_ancestors(): O(depth) - walks parent chain

  • get_descendants(): O(m) - where m = number of descendants (BFS)

  • get_siblings(): O(n) - where n = number of siblings

  • find_by_hierarchy_path(): O(m) - where m = elements matching path

Performance on Large Models:

  • Cycle detection: <1ms (max depth 5)

  • All queries: <10ms on 1000+ element models

  • Memory: ~100 bytes per parent-child relationship

Round-Trip Preservation

All hierarchy relationships are automatically preserved during XML export/import:

import tempfile, os
from pyArchimate import Model, ArchiType

# Create model with hierarchy
m = Model('round-trip-test')
process = m.add(ArchiType.BusinessProcess, 'Process')
func = m.add(ArchiType.BusinessFunction, 'Function')
m.add_child(process.uuid, func.uuid)

# Export to XML
with tempfile.NamedTemporaryFile(suffix='.archimate', delete=False) as f:
    tmp_path = f.name
m.write(tmp_path)

# Import from XML
m2 = Model('reloaded')
m2.read(tmp_path)
os.unlink(tmp_path)

# Hierarchy is preserved exactly
process2 = m2.elems_dict[process.uuid]
func2 = m2.elems_dict[func.uuid]
parent = m2.get_parent(func2.uuid)
print(f"Parent preserved: {parent.uuid == process2.uuid}")
print(f"Child name: {func2.name}")
Parent preserved: True
Child name: Function

Constraints and Limits

Depth Limit: Maximum nesting depth is 5 levels (configurable) - Prevents stack overflow on deep traversals - Suitable for most enterprise architectures

Single Parent: Each element can have at most one parent - Creates tree structures (not DAGs) - Simplifies hierarchy management and visualization

Cycle Prevention: Automatic validation prevents circular relationships - add_child() rejects any relationship that would create a cycle - Ensures hierarchy validity at all times

See Also