Repository navigation
Expand file tree
/
Copy pathtutorial.py
More file actions
111 lines (89 loc) · 5.33 KB
/
Copy pathtutorial.py
File metadata and controls
111 lines (89 loc) · 5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""SysML v2 SDK, Python: a first walk through a model.
Run from the repository root:
python examples/python/tutorial.py # reads examples/vehicle.sysml through the SysML Toolkit
python examples/python/tutorial.py --payload # reads examples/vehicle.full.json instead
The SysML Toolkit path needs the binding library built (see abi/README.md). The payload path needs
nothing but Python and two JSON files: a full-form export of the model, from any SysML v2 tool, and
the standard library as JSON, published with each SDK release. In this repository both are
generated by `python tools/export_example.py --library <sysml.library>`.
Everything you can navigate is spelled exactly as in the OMG specification: `ownedMember`,
`ownedFeature`, `qualifiedName`, `type`, `multiplicity`. If a member is not implemented by the
SysML Toolkit yet, reading it raises `NotImplementedInToolkit` naming the member; nothing is
silently empty.
"""
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "python")) # not needed once the package is installed
from sysml import Model, NotImplementedInToolkit, PayloadLibrary # noqa: E402
from sysml.classes import Definition, PartDefinition, PartUsage, Usage # noqa: E402
def load() -> Model:
if "--payload" in sys.argv:
# The model's references into the standard library resolve against the library JSON.
library = PayloadLibrary(json.loads((ROOT / "examples" / "sysml.library.full.json").read_text(encoding="utf-8")))
payload = json.loads((ROOT / "examples" / "vehicle.full.json").read_text(encoding="utf-8"))
return Model.from_full_json(payload, library=library)
return Model.from_toolkit(str(ROOT / "examples" / "vehicle.sysml"))
def main() -> None:
model = load()
# 1. Start at the top. A model has root namespaces; a package is what you wrote.
for root in model.roots:
for member in root.ownedMember:
print(f"package {member.declaredName}")
# 2. Find an element by its qualified name, exactly as it would be spelled in a model.
vehicles = model.resolve("Vehicles")
vehicle = model.resolve("Vehicles::Vehicle")
print(f"\n{vehicle.qualifiedName} is a {type(vehicle).__name__}")
# 3. The generated classes form the real metaclass hierarchy, so isinstance works.
definitions = [m for m in vehicles.ownedMember if isinstance(m, Definition)]
print("definitions:", ", ".join(d.declaredName for d in definitions))
# 4. Walk a definition's features. Each usage knows its declared type.
print(f"\nfeatures of {vehicle.declaredName}:")
for feature in vehicle.ownedFeature:
try:
types = ", ".join(t.declaredName for t in feature.type) or "untyped"
except NotImplementedInToolkit as e: # the SysML Toolkit cannot vouch for this value yet
types = f"({e})"
name = feature.declaredName or "(unnamed)" # a connector end has no name of its own
print(f" {type(feature).__name__:16s} {name:10s} : {types}")
# 5. Documentation is a member like any other: Documentation elements with a body.
for doc in vehicle.documentation:
print(f"\ndoc: {doc.body.strip()}")
# 6. Inheritance. Through the SysML Toolkit, inherited features are computed. A payload holds
# what the exporting tool wrote: this file was exported at the closure level, so it has them
# too; an export by the SysML Toolkit's command-line tool would list the owned side only.
# With the standard library, every part also inherits the library's features (`self`,
# `start`, ...); `isLibraryElement` tells them apart.
sports = model.resolve("Vehicles::SportsCar")
print(f"\n{sports.declaredName} owns: ", [f.declaredName for f in sports.ownedFeature])
try:
print(f"{sports.declaredName} inherits: ",
[f.declaredName for f in sports.inheritedFeature if not f.isLibraryElement])
except NotImplementedInToolkit as e:
print("inheritedFeature:", e)
# 7. Operations from the specification, on the SysML Toolkit path. A property and an
# operation are separate members: `name` is a property, `effectiveName()` the operation
# that derives it.
try:
inherited = sports.inheritedMemberships([], [], False)
print(f"\n{sports.effectiveName()} inherits the memberships of", [m.memberName for m in inherited])
except NotImplementedInToolkit as e:
print(f"\n(operations need the SysML Toolkit path) {e}")
# 8. A usage, and the definition it is typed by.
my_car = model.resolve("Vehicles::myCar")
assert isinstance(my_car, PartUsage)
try:
print(f"\n{my_car.qualifiedName} is typed by {[t.qualifiedName for t in my_car.type]}")
except NotImplementedInToolkit as e:
print(f"\n{my_car.qualifiedName}: {e}")
# 9. Honest refusal. Through the SysML Toolkit, a member it cannot vouch for yet says so
# instead of answering, as the reads above show where it does. Through a payload there is
# nobody to say so: the file holds what the exporting tool wrote.
print()
try:
print("partDefinition of myCar:", [d.qualifiedName for d in my_car.partDefinition])
except NotImplementedInToolkit as e:
print("not answered by the SysML Toolkit, and it says so:", e)
if __name__ == "__main__":
main()