1. Introduction¶
Welcome to the py-capella-mbse Showcase notebook. This notebook will show you some basic (and not so basic) things that you can get done using this library. For more advanced features have a look around the nearby notebooks.
The below code loads the library and one of the test models:
[1]:
import capellambse
path_to_model = "../../../tests/data/melodymodel/5_0/Melody Model Test.aird"
model = capellambse.MelodyModel(path_to_model)
model
[1]:
<capellambse.model.MelodyModel at 0x7f3f44f97970>
Let’s go to the first practical example of working with the library!
1.1. Example 1: Actor functions¶
The below code will print every Actor available in the Logical Architecture layer
[2]:
for actor in model.la.all_actors:
print(actor.name)
Multiport
Prof. S. Snape
Voldemort
R. Weasley
Prof. A. P. W. B. Dumbledore
Harry J. Potter
but we could also “zoom-in” to an actor of interest:
[3]:
model.la.all_actors.by_name("Prof. S. Snape")
[3]:
Prof. S. Snape (org.polarsys.capella.core.data.la:LogicalComponent)
allocated_functions |
|
---|---|
applied_property_value_groups |
|
applied_property_values | (Empty list) |
components | (Empty list) |
constraints | (Empty list) |
context_diagram | Context of Prof. S. Snape (uuid: 6f463eed-c77b-4568-8078-beec0536f243_context) |
description | Good guy and teacher of brewing arts. |
diagrams | (Empty list) |
exchanges | (Empty list) |
filtering_criteria | (Empty list) |
functions |
|
is_abstract | False |
is_actor | True |
is_human | True |
name | Prof. S. Snape |
owner | LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73) |
parent | LogicalComponentPkg "Structure" (84c0978d-9a32-4f5b-8013-5b0b6adbfd73) |
parts | Backreference to Part - omitted: can be slow to compute. Display this property directly to show. |
physical_links | (Empty list) |
physical_paths | (Empty list) |
physical_ports | (Empty list) |
ports |
|
progress_status | NOT_SET |
property_value_groups |
|
property_values | (Empty list) |
pvmt | <capellambse.extensions.pvmt.PropertyValueProxy object at 0x7f496cb3f010> |
realized_components | (Empty list) |
realized_system_components | (Empty list) |
realizing_components | Backreference to - omitted: can be slow to compute. Display this property directly to show. |
realizing_physical_components | Backreference to PhysicalComponent - omitted: can be slow to compute. Display this property directly to show. |
related_exchanges | Backreference to ComponentExchange - omitted: can be slow to compute. Display this property directly to show. |
requirements | (Empty list) |
state_machines | (Empty list) |
summary | None |
traces | (Empty list) |
uuid | 6f463eed-c77b-4568-8078-beec0536f243 |
xtype | org.polarsys.capella.core.data.la:LogicalComponent |
We can also turn the above data into a table, for example “actor function allocation”, using pandas
.
For this, we first make sure pandas itself is installed, as well as an extension we’ll use later.
[ ]:
%pip install -q pandas openpyxl
Now we can use it together with capellambse
:
[4]:
import pandas as pd
data = []
for actor in model.la.all_actors:
actor_functions = (
"; ".join(function.name for function in actor.functions)
or "no functions assigned"
)
data.append({"actor": actor.name, "functions": actor_functions})
df = pd.DataFrame(data)
df
[4]:
actor | functions | |
---|---|---|
0 | Multiport | LAF 1 |
1 | Prof. S. Snape | Teaching; maintain a layer of defense for the ... |
2 | Voldemort | no functions assigned |
3 | R. Weasley | assist Harry; break school rules |
4 | Prof. A. P. W. B. Dumbledore | manage the school; advise Harry |
5 | Harry J. Potter | kill He Who Must Not Be Named |
and any pandas.DataFrame
can always be turned into an Excel Spreadsheet, just like that:
[5]:
df.to_excel("01_intro_actor_functions.xlsx")
you can check the resulting file in the folder next to this notebook (right after you run the above cell)
Now that we’ve seen the basics, lets do something visually cool.
1.2. Example 2: working with diagrams¶
The below code will find some diagrams for us.
[6]:
for diagram in model.la.diagrams.by_type("LAB"):
print(diagram.name)
[LAB] Wizzard Education
[LAB] Test Component Port Filter
[LAB] Hidden Wizzard Education
We can analyze which model objects are shown in a particular diagram.
[7]:
diagram = model.diagrams.by_name("[LAB] Wizzard Education")
diagram.nodes
[7]:
- Part "Hogwarts" (101ffa60-f8a2-4ea2-a0d8-d10910ceac06)
- LogicalFunction "produce Great Wizards" (0e71a0d3-0a18-4671-bba0-71b5f88f95dd)
- LogicalFunction "protect Students against the Death Eaters" (264fb47d-67b7-4bdc-8d06-8a0e5139edbf)
- Part "Campus" (a3194240-cd17-4998-8f8b-785233487ec3)
- Part "School" (018a8ae9-8e8e-4aea-8191-4abf844a79e3)
- LogicalFunction "educate Wizards" (957c5799-1d4a-4ac0-b5de-33a65bf1519c)
- Part "Whomping Willow" (1188fc31-789b-424f-a2d4-06791873a351)
- LogicalFunction "defend the surrounding area against Intruders" (7f2936ab-0b54-4e92-9f0c-85a9f0981959)
- Part "Prof. A. P. W. B. Dumbledore" (4c1f2b5d-0641-42c7-911f-7a42928580b8)
- LogicalFunction "manage the school" (f708bc29-d69f-42a0-90cc-11fc01054cd0)
- LogicalFunction "advise Harry" (beaf5ba4-8fa9-4342-911f-0266bb29be45)
- Part "Prof. S. Snape" (ccbad61a-39dc-4af8-8199-3fee30de2f1d)
- LogicalFunction "Teaching" (a7acb298-d14b-4707-a419-fea272434541)
- LogicalFunction "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)
- ComponentExchange "Headmaster Responsibilities" (c0bc49e1-8043-4418-8c0a-de6c6b749eab)
- ComponentExchange "Teacher Responsibilities" (9cbdd233-aff5-47dd-9bef-9be1277c77c3)
- Part "Harry J. Potter" (26543596-7646-4d81-8f15-c4e01ec930a7)
- LogicalFunction "kill He Who Must Not Be Named" (aa9931e3-116c-461e-8215-6b9fdbdd4a1b)
- Part "R. Weasley" (4d31caaf-210e-4bdf-982e-cdecbc80c947)
- LogicalFunction "assist Harry" (c1a42acc-1f53-42bb-8404-77a5c08c414b)
- LogicalFunction "break school rules" (edbd1ad4-31c0-4d53-b856-3ffa60e0e99b)
- ComponentExchange "Punishment" (85a1fb20-38ea-4d77-acd7-90a8c44dc695)
- FunctionalExchange "wizardry" (6545a77d-d224-4662-a5b2-3c016b78e33d)
- PortAllocation "" (a4e2bf11-0705-4f20-bf73-5fa5519954f7)
- PortAllocation "" (7d31ab50-63d6-46bb-bf53-1716175beae3)
- PortAllocation "" (317715cb-376c-4df6-a32c-433e3c081f8d)
- ComponentExchange "Learning" (3b3fc202-be5c-49ae-bf2f-1d61daf3bb50)
- PortAllocation "" (c1019d06-f376-48e3-832e-634a8ec59463)
- PortAllocation "" (4cbdf5fd-7268-470b-9811-b62ad67fded1)
- FunctionalExchange "assistance" (241f3901-11f0-4b00-a903-ed158cce73de)
- FunctionalExchange "friendship" (1bbb9b2d-517c-4f77-a35c-b3aa3f9422b8)
- PortAllocation "" (18fa81ee-8b16-4815-86ea-0c287ace43d8)
- ComponentExchange "Help for Harry" (d8655737-39ab-4482-a934-ee847c7ff6bd)
- FunctionalExchange "punish" (96a0cf4c-adfe-4490-92d1-bcf75ee77004)
- FunctionalExchange "educate & mature" (09efaeb7-2d50-40ed-a4da-46afcb9ca7a1)
- FunctionalExchange "Knowledge" (b1a817bc-40a9-4fc4-b62c-8dea4aa28915)
- PortAllocation "" (dda7a62a-f25f-46d8-8f05-867c616914c1)
- PortAllocation "" (fee1fff5-d751-401b-bb3c-2114a74f0c8a)
- PortAllocation "" (0f6e1aa0-942a-40a9-930f-c7df34b9d8eb)
- ComponentExchange "Care" (c31491db-817d-44b3-a27c-67e9cc1e06a2)
- PortAllocation "" (98760017-b3a3-46ca-b1ef-87eee9ea1600)
- PortAllocation "" (74bd0ab3-6a28-4025-822e-90201445a56e)
- PortAllocation "" (3ed5ae4f-8a4e-4690-9088-655990a1b77b)
- PortAllocation "" (299b98b8-8716-4dbc-bc7e-4b9349778c26)
- PortAllocation "" (14cabdd9-c36f-4e01-ad09-110f906ad725)
- PortAllocation "" (6d882e28-4208-41d0-b8a5-3a19e1805a34)
- FunctionalExchange "educate" (cdc69c5e-ddd8-4e59-8b99-f510400650aa)
- PortAllocation "" (c90bb30d-e36b-46a3-a3a1-e39fdcb519be)
And again there are warnings - there are quite a few visual filters in Capella and we are not handling all of those yet but mostly those that are used in our projects. The filter coverage will eventally improve, stay tuned.
And finally, you can display the diagram right in the notebook.
[8]:
diagram
[8]:
We use SVG diagrams a lot since they look great in documentation, are zoomable and really light-weight. To make integrating them into a pipeline easier, we also support some derived formats, which you can access using .as_<format>
style attributes. With some additional dependencies set up (see the README), capellambse can also automatically convert these images to PNG format.
[9]:
# fmt: off
print(repr( diagram.as_svg )[:100], "...") # The raw SVG format as simple python `str`
print(repr( diagram.as_datauri_svg )[:100], "...") # An SVG, base64-encoded as `data:` URI
print(repr( diagram.as_html_img )[:100], "...") # An HTML `<img>` tag, using the above `data:` URI as `src`
print(repr( diagram.as_png )[:100], "...") # A raw PNG byte stream, which can be written to a `.png` file
'<svg baseProfile="full" class="LogicalArchitectureBlank" height="611" style="shape-rendering: geome ...
'data:image/svg+xml;base64,PHN2ZyBiYXNlUHJvZmlsZT0iZnVsbCIgY2xhc3M9IkxvZ2ljYWxBcmNoaXRlY3R1cmVCbGFua ...
Markup('<img src="data:image/svg+xml;base64,PHN2ZyBiYXNlUHJvZmlsZT0iZnVsbCIgY2xhc3M9IkxvZ2ljYWxBcmNo ...
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x04\x8a\x00\x00\x02c\x08\x02\x00\x00\x00\xec\xe8m\xd2\ ...
It’s also possible to directly save a diagram to a file by calling its save
method:
[10]:
diagram.save("[LAB] Wizzard Education.svg", "svg", pretty_print=True)
[11]:
with open("[LAB] Wizzard Education.svg") as f:
print(*f.readlines()[:10], "...", sep="")
<?xml version="1.0" encoding="utf-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" class="LogicalArchitectureBlank" height="611" style="shape-rendering: geometricPrecision; font-family: 'Segoe UI'; font-size: 8pt; cursor: pointer;" version="1.1" viewBox="15 15 1162 611" width="1162">
<defs>
<symbol id="LogicalComponentSymbol" style="stroke: #000; stroke-width: 2;" viewBox="0 0 79 79">
<path d="M18 237h46v43H18z" style="fill: #dbe6f4" transform="translate(0 -218)"/>
<path d="M12 247h11v8H12z" style="fill: #dbe6f4" transform="translate(0 -218)"/>
<path d="M12 261h11v8H12z" style="fill: #dbe6f4" transform="translate(0 -218)"/>
<g transform="scale(0.90705135,1.1024734)">
<path d="m 37.427456,20.821353 h 4.221475 V 50.90971 H 37.427456 Z M 39.538194,46.89517 H 56.75519 v 4.01454 H 39.538194 Z" style="fill: #000;stroke-width: 0.1;"/>
</g>
...
Lets now try something else - we check if function port has any protocols (state machines) underneath:
[12]:
fnc = model.la.all_functions.by_name(
"defend the surrounding area against Intruders"
)
stms = fnc.outputs[0].state_machines
stms
[12]:
- StateMachine "FaultStates" (06cefb2b-534e-4453-9aba-fe53329197ad)
and we can also check what states it could have:
[13]:
stms[0].regions[0].states
[13]:
- State "normal defence" (e494e247-efce-4258-9cc6-fd799dbb0adf)
- State "erroneous defence" (81f3de46-4596-41b0-8569-c3c21161a2f6)
- State "no defence" (5b6a03d8-0ef9-4b2b-9a50-a745f490d663)
This concludes our introduction. There is a lot more you can do with the library - feel free to explore the examples collection or create an issue to ask for a specific use-case example and you may see it around pretty soon.