Move Element
This example demonstrates how to move an element from one parent to another in a SysML v2 model using Syside Automator.
The model contains a sensor system with two packages: Processing and Sensing. A
processor part usage is initially placed in Sensing but logically belongs in
Processing. The script extracts it from Sensing and appends it to
Processing, then prints the model before and after the move.
SensorSystem
├── Processing
│ ├── SignalProcessor
│ │ <─ ─ ┐
│ └── DataLogger ┆
└── Sensing ┆
├── TemperatureSensor ┆ Move here
├── PressureSensor ┆
└── processor ─ ─ ┘
Concepts Used
extract_elementremoves an element from its current parent without clearing its subtree, returning it as an orphan. The element can then be inserted elsewhere in the model tree.Warning
extract_elementcan only move elements within the same document. Attempting to insert an extracted element into a different document will fail.children.appendinserts the orphaned element under a new parent using the specified relationship type.After modification,
pprintserializes the updated model back to SysML text.
Warning
It is the caller’s responsibility to ensure that an extracted element is not leaked (i.e., it must be inserted into a new parent before the lock is released).
Example Model
package SensorSystem {
package Processing {
part def SignalProcessor;
part def DataLogger;
}
package Sensing {
part def TemperatureSensor;
part def PressureSensor;
// SignalProcessor belongs here conceptually, not in Processing
part processor : Processing::SignalProcessor;
}
}
Example Script
import pathlib
import syside
EXAMPLE_DIR = pathlib.Path(__file__).parent
MODEL_FILE_PATH = EXAMPLE_DIR / "example_model.sysml"
def print_package_members(package: syside.Package, indent: int = 0) -> None:
"""Print all direct children of a package by name."""
prefix = " " * indent
for member in package.children.elements:
name = member.declared_name or "<unnamed>"
print(f"{prefix}- {name} ({type(member).__name__})")
def main() -> None:
(model, diagnostics) = syside.load_model([MODEL_FILE_PATH])
assert not diagnostics.contains_errors(warnings_as_errors=True)
with model.user_docs[0].lock() as doc:
root = doc.root_node
# Locate the two packages and the element to move.
# next() with a generator expression is a common Python idiom for finding
# the first element that matches a condition. It raises StopIteration if
# no match is found, which is appropriate here since the model is known.
sensor_system = next(
e
for e in root.children.elements
if isinstance(e, syside.Package)
and e.declared_name == "SensorSystem"
)
processing_pkg = next(
e
for e in sensor_system.children.elements
if isinstance(e, syside.Package) and e.declared_name == "Processing"
)
sensing_pkg = next(
e
for e in sensor_system.children.elements
if isinstance(e, syside.Package) and e.declared_name == "Sensing"
)
processor_part = next(
e
for e in sensing_pkg.children.elements
if isinstance(e, syside.PartUsage)
and e.declared_name == "processor"
)
print("Before move:")
print(" Processing:")
print_package_members(processing_pkg, indent=2)
print(" Sensing:")
print_package_members(sensing_pkg, indent=2)
# Extract the element from its current parent without clearing its subtree,
# then append it to the new parent.
sensing_pkg.children.extract_element(processor_part)
processing_pkg.children.append(syside.OwningMembership, processor_part)
print("\nAfter move:")
print(" Processing:")
print_package_members(processing_pkg, indent=2)
print(" Sensing:")
print_package_members(sensing_pkg, indent=2)
# Serialize the updated model to SysML text
printer = syside.ModelPrinter.sysml()
cfg = syside.PrinterConfig(line_width=80, tab_width=4)
print("\nUpdated model:")
print(syside.pprint(root, printer, cfg))
if __name__ == "__main__":
main()
Output
Before move:
Processing:
- SignalProcessor (PartDefinition)
- DataLogger (PartDefinition)
Sensing:
- TemperatureSensor (PartDefinition)
- PressureSensor (PartDefinition)
- processor (PartUsage)
After move:
Processing:
- SignalProcessor (PartDefinition)
- DataLogger (PartDefinition)
- processor (PartUsage)
Sensing:
- TemperatureSensor (PartDefinition)
- PressureSensor (PartDefinition)
Updated model:
package SensorSystem {
package Processing {
part def SignalProcessor;
part def DataLogger;
part processor : Processing::SignalProcessor;
}
package Sensing {
part def TemperatureSensor;
part def PressureSensor;
}
}
Download
Download this example here.