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._model.MelodyModel at 0x7118bcd06db0>
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)
Prof. A. P. W. B. Dumbledore
Prof. S. Snape
Harry J. Potter
R. Weasley
Voldemort
Multiport
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) |
is_abstract | False |
is_actor | True |
is_human | True |
layer | LogicalArchitecture "Logical Architecture" (853cb005-cba0-489b-8fe3-bb694ad4543b) |
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_value_packages | (Empty list) |
property_values | (Empty list) |
pvmt | Property Value Management for "Prof. S. Snape" (6f463eed-c77b-4568-8078-beec0536f243) |
realization_view | Realization view of Prof. S. Snape (uuid: 6f463eed-c77b-4568-8078-beec0536f243_realization_view) |
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) |
sid | |
state_machines | (Empty list) |
summary | |
traces | (Empty list) |
uuid | 6f463eed-c77b-4568-8078-beec0536f243 |
validation | <capellambse.extensions.validation._validate.ElementValidation object at 0x7118b7385400> |
visible_on_diagrams |
|
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.
[4]:
%pip install -q pandas openpyxl
Note: you may need to restart the kernel to use updated packages.
Now we can use it together with capellambse
:
[5]:
import pandas as pd
data = []
for actor in model.la.all_actors:
actor_functions = (
"; ".join(function.name for function in actor.allocated_functions)
or "no functions assigned"
)
data.append({"actor": actor.name, "functions": actor_functions})
df = pd.DataFrame(data)
df
[5]:
actor | functions | |
---|---|---|
0 | Prof. A. P. W. B. Dumbledore | manage the school; advise Harry |
1 | Prof. S. Snape | Teaching; maintain a layer of defense for the ... |
2 | Harry J. Potter | kill He Who Must Not Be Named |
3 | R. Weasley | assist Harry; break school rules |
4 | Voldemort | no functions assigned |
5 | Multiport | LAF 1 |
and any pandas.DataFrame
can always be turned into an Excel Spreadsheet, just like that:
[6]:
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.
[7]:
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.
[8]:
diagram = model.diagrams.by_name("[LAB] Wizzard Education")
diagram.nodes
[8]:
- "Hogwarts" (101ffa60-f8a2-4ea2-a0d8-d10910ceac06)
- "produce Great Wizards" (0e71a0d3-0a18-4671-bba0-71b5f88f95dd)
- "protect Students against the Death Eaters" (264fb47d-67b7-4bdc-8d06-8a0e5139edbf)
- "Campus" (a3194240-cd17-4998-8f8b-785233487ec3)
- "School" (018a8ae9-8e8e-4aea-8191-4abf844a79e3)
- "educate Wizards" (957c5799-1d4a-4ac0-b5de-33a65bf1519c)
- "Whomping Willow" (1188fc31-789b-424f-a2d4-06791873a351)
- "defend the surrounding area against Intruders" (7f2936ab-0b54-4e92-9f0c-85a9f0981959)
- "Prof. A. P. W. B. Dumbledore" (4c1f2b5d-0641-42c7-911f-7a42928580b8)
- "manage the school" (f708bc29-d69f-42a0-90cc-11fc01054cd0)
- "advise Harry" (beaf5ba4-8fa9-4342-911f-0266bb29be45)
- "Prof. S. Snape" (ccbad61a-39dc-4af8-8199-3fee30de2f1d)
- "Teaching" (a7acb298-d14b-4707-a419-fea272434541)
- "maintain a layer of defense for the Sorcerer's Stone" (4a2a7f3c-d223-4d44-94a7-50dd2906a70c)
- "Headmaster Responsibilities" (c0bc49e1-8043-4418-8c0a-de6c6b749eab)
- "Teacher Responsibilities" (9cbdd233-aff5-47dd-9bef-9be1277c77c3)
- "Harry J. Potter" (26543596-7646-4d81-8f15-c4e01ec930a7)
- "kill He Who Must Not Be Named" (aa9931e3-116c-461e-8215-6b9fdbdd4a1b)
- "R. Weasley" (4d31caaf-210e-4bdf-982e-cdecbc80c947)
- "assist Harry" (c1a42acc-1f53-42bb-8404-77a5c08c414b)
- "break school rules" (edbd1ad4-31c0-4d53-b856-3ffa60e0e99b)
- "Punishment" (85a1fb20-38ea-4d77-acd7-90a8c44dc695)
- "wizardry" (6545a77d-d224-4662-a5b2-3c016b78e33d)
- PortAllocation (a4e2bf11-0705-4f20-bf73-5fa5519954f7)
- PortAllocation (7d31ab50-63d6-46bb-bf53-1716175beae3)
- PortAllocation (317715cb-376c-4df6-a32c-433e3c081f8d)
- "Learning" (3b3fc202-be5c-49ae-bf2f-1d61daf3bb50)
- PortAllocation (c1019d06-f376-48e3-832e-634a8ec59463)
- PortAllocation (4cbdf5fd-7268-470b-9811-b62ad67fded1)
- "assistance" (241f3901-11f0-4b00-a903-ed158cce73de)
- "friendship" (1bbb9b2d-517c-4f77-a35c-b3aa3f9422b8)
- PortAllocation (18fa81ee-8b16-4815-86ea-0c287ace43d8)
- "Help for Harry" (d8655737-39ab-4482-a934-ee847c7ff6bd)
- "punish" (96a0cf4c-adfe-4490-92d1-bcf75ee77004)
- "educate & mature" (09efaeb7-2d50-40ed-a4da-46afcb9ca7a1)
- "Knowledge" (b1a817bc-40a9-4fc4-b62c-8dea4aa28915)
- PortAllocation (dda7a62a-f25f-46d8-8f05-867c616914c1)
- PortAllocation (fee1fff5-d751-401b-bb3c-2114a74f0c8a)
- PortAllocation (0f6e1aa0-942a-40a9-930f-c7df34b9d8eb)
- "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)
- "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.
[9]:
diagram
[9]:
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.
[10]:
# 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" font-family="\'Open Sans\',\'Segoe UI\',Ar ...
'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:
[11]:
diagram.save("[LAB] Wizzard Education.svg", "svg", pretty_print=True)
[12]:
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" font-family="'Open Sans','Segoe UI',Arial,sans-serif" font-size="10px" height="611" shape-rendering="geometricPrecision" version="1.1" viewBox="15 15 1162 611" width="1162">
<defs>
<symbol id="LogicalComponentSymbol" stroke="#000" stroke-width="2" viewBox="0 0 79 79">
<path d="M18 237h46v43H18z" fill="#dbe6f4" transform="translate(0 -218)"/>
<path d="M12 247h11v8H12z" fill="#dbe6f4" transform="translate(0 -218)"/>
<path d="M12 261h11v8H12z" 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" fill="#000" stroke-width="0.1"/>
</g>
...
Lets now try something else - we check if function port has any protocols (state machines) underneath:
[13]:
fnc = model.la.all_functions.by_name(
"defend the surrounding area against Intruders"
)
stms = fnc.outputs[0].state_machines
stms
[13]:
- StateMachine "FaultStates" (06cefb2b-534e-4453-9aba-fe53329197ad)
and we can also check what states it could have:
[14]:
stms[0].regions[0].states
[14]:
- "normal defence" (e494e247-efce-4258-9cc6-fd799dbb0adf)
- "erroneous defence" (81f3de46-4596-41b0-8569-c3c21161a2f6)
- "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.