This notebook introduces abstract part def together with the flow-typed action def it performs; after running it you can state a system’s purpose as an executable functional construct, not a comment.
Chapter 1 builds the model of a toaster’s purpose and structure from first principles. This first notebook declares what the whole toasting system does: transform bread into toast, stated as typed input and output flows through an action the system performs. Subsequent notebooks add component types, specialization, and composition.
from pathlib import Path
import opensysml
from toaster.report import format_diagnostics
conn = opensysml.connect(version="v0.9.0")
# item def : a typed flow, carried in or out by the action def below
# spec: SysML v2 formal/2026-03-02 §8.3.10.2 (ItemDefinition)
BREAD_DEF = "item def Bread;"
print(BREAD_DEF)
TOAST_DEF = "item def Toast;"
print(TOAST_DEF)item def Bread;
item def Toast;
Bread and Toast are item definitions: typed flows with no mechanism, ready to be the in and out parameters of the action below.
# action def : typed in/out flows state the purpose without committing to a mechanism
# spec: SysML v2 formal/2026-03-02 §7.17.2 (ActionDefinition)
TOASTBREAD_DEF = """\
action def ToastBread {
doc /* Transform bread into toast acceptable to its user. */
in bread : Bread;
out toast : Toast;
}
"""
print(TOASTBREAD_DEF)action def ToastBread {
doc /* Transform bread into toast acceptable to its user. */
in bread : Bread;
out toast : Toast;
}
ToastBread states the purpose functionally: bread in, toast out. The doc keeps the acceptance language (“acceptable to its user”) as the seed of a measure of effectiveness Chapter 3 builds; the action names no mechanism and no part.
# abstract part def : no instance may be created directly, only its subtypes.
# perform ties this action to the whole that carries out the purpose.
# abstract modifier: the Editor API does not yet author it (https://github.com/Open-MBEE/toaster/issues/9 / https://github.com/Open-MBEE/OpenSysML/issues/595);
# it parses and loads correctly via conn.load_from_content(), confirmed in the next cell.
# spec: SysML v2 formal/2026-03-02 §7.3.3 (PartDefinition, AbstractClassifier), §7.17.6 (perform)
TOASTING_SYSTEM_DEF = """\
abstract part def ToastingSystem {
perform action toastBread : ToastBread;
}
"""
print(TOASTING_SYSTEM_DEF)abstract part def ToastingSystem {
perform action toastBread : ToastBread;
}
ToastingSystem performs ToastBread: the abstract subject carries out the stated purpose without committing to a mechanism or a concrete part.
TOASTER_INCREMENT = f"{BREAD_DEF}\n{TOAST_DEF}\n{TOASTBREAD_DEF}\n{TOASTING_SYSTEM_DEF}"
source = Path("../../models/ch01-cumulative.sysml").read_text()
model = conn.load_from_content(source, strict=False)
assert model.ok, f"Model failed: {format_diagnostics(model.diagnostics)}"The assembled increment loads against the cumulative model with no diagnostics: assert model.ok passes silently, confirming all four declarations resolve together. The next cell checks what happens when one does not.
# Negative control: doc requires /* */ delimiters, not a string literal.
bad_source = """
package Bad {
action def ToastBread {
doc "a plain string is not valid doc syntax";
}
}
"""
bad = conn.load_from_content(bad_source, strict=False)
assert not bad.ok
print("Expected error:", bad.diagnostics[0].message)Expected error: expected a /* ... */ comment body
A doc written as a quoted string rather than a /* */ comment block is a syntax error, reported in bad.diagnostics[0].
sym = model.find("ToasterDemo::ToastingSystem")
assert sym is not None
print(f"kind : {sym.kind}")
print(f"id : {sym.id}")kind : partDef
id : ToasterDemo::ToastingSystem
model.find() resolves ToastingSystem by its qualified name, confirming the abstract subject is indexed.
action_sym = model.find("ToasterDemo::ToastBread")
assert action_sym is not None
print(f"kind : {action_sym.kind}")
print(f"id : {action_sym.id}")
conn.close()kind : actionDef
id : ToasterDemo::ToastBread
The same lookup on ToastBread confirms the performed action is indexed too, separately from the part def that performs it.
The ToastBread and ToastingSystem declarations printed above loaded without error, and the two model.find() calls above confirm each is now part of the model, shown by the kind and id printed below each.
Try the chapter exercise in exercises/ch01/exercise.ipynb: declare item defs for a coffee maker’s flows, an action def with a doc and typed in/out flows, and an abstract part def that performs it, and verify it loads.