Skip to content

context

Extends the capellambse.model.diagram module with context diagrams.

Definitions of Custom Accessor- and Diagram-Classtypes based on Accessor and AbstractDiagram.

CollectorOutputData module-attribute 🔗

CollectorOutputData: TypeAlias = (
    ELKInputData | tuple[ELKInputData, ELKInputData | list[ELKInputEdge]]
)

The output of a collector or the input prepared for ELK.

CableTreeAccessor 🔗

CableTreeAccessor(dgcls: str, render_params: dict[str, Any] | None = None)

Bases: ContextAccessor

Provides access to the cable tree diagrams.

Source code in src/capellambse_context_diagrams/context.py
67
68
69
70
71
72
def __init__(
    self, dgcls: str, render_params: dict[str, t.Any] | None = None
) -> None:
    super().__init__()
    self._dgcls = dgcls
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a CableTreeView for the given model object.

Source code in src/capellambse_context_diagrams/context.py
210
211
212
213
214
215
216
217
218
219
220
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a CableTreeView for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, CableTreeViewDiagram)

CableTreeViewDiagram 🔗

CableTreeViewDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

An automatically generated CableTreeView.

Source code in src/capellambse_context_diagrams/context.py
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_port_labels": True,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE,
        "include_external_context": True,
        "collect": cable_tree.collector,
        "edge_direction": enums.EDGE_DIRECTION.TREE,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

ClassTreeAccessor 🔗

ClassTreeAccessor(diagclass: str, render_params: dict[str, Any] | None = None)

Bases: ContextAccessor

Provides access to the tree view diagrams.

Source code in src/capellambse_context_diagrams/context.py
144
145
146
147
148
def __init__(
    self, diagclass: str, render_params: dict[str, t.Any] | None = None
) -> None:
    self._dgcls = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a ClassTreeDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
150
151
152
153
154
155
156
157
158
159
160
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a ClassTreeDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, ClassTreeDiagram)

ClassTreeDiagram 🔗

ClassTreeDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

An automatically generated ClassTree Diagram.

This diagram is exclusively for Classes.

Source code in src/capellambse_context_diagrams/context.py
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
        "edgeRouting": "POLYLINE",
        "direction": "DOWN",
        "nodeSizeConstraints": "NODE_LABELS",
        "edgeLabelsSide": "SMART_DOWN",
        "partitioning": False,
        "depth": None,
        "super": "ROOT",
        "sub": "ROOT",
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.builder = tree_view.collector  # type: ignore[assignment]

name property 🔗

name: str

Returns the name of the diagram.

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

ContextAccessor 🔗

ContextAccessor(dgcls: str, render_params: dict[str, Any] | None = None)

Bases: Accessor

Provides access to the custom context diagrams.

Source code in src/capellambse_context_diagrams/context.py
67
68
69
70
71
72
def __init__(
    self, dgcls: str, render_params: dict[str, t.Any] | None = None
) -> None:
    super().__init__()
    self._dgcls = dgcls
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(obj: None, objtype: type[Any]) -> ContextAccessor
__get__(obj: T, objtype: type[T] | None = None) -> ContextDiagram
__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
80
81
82
83
84
85
86
87
88
def __get__(
    self, obj: m.T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, ContextDiagram)

ContextDiagram 🔗

ContextDiagram(
    class_: str,
    obj: ModelElement | Diagram,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: AbstractDiagram

An automatically generated context diagram.

ATTRIBUTE DESCRIPTION
target

The m.ModelElement from which the context is collected from.

TYPE: ModelElement

styleclass

The diagram class (for e.g. [LAB]).

render_styles

Dictionary with the ElkChildType in str format as keys and styling.Styler functions as values. An example is given by: styling.BLUE_ACTOR_FNCS

serializer

The serializer builds a Diagram via serializers.DiagramSerializer.make_diagram by converting every _elkjs.ELKOutputChild into a Box, Edge or Circle.

filters

A list of filter names that are applied during collection of context. Currently this is only done in exchange_data_collector.

TYPE: MutableSet[str]

Notes

The following render parameters are supported:

  • display_symbols_as_boxes: Display objects that are normally displayed as symbol as a simple box instead, with the symbol being the box' icon. This avoids the object of interest to become one giant, oversized symbol in the middle of the diagram, and instead keeps the symbol small and only enlarges the surrounding box.
  • display_parent_relation: Display objects with a parent relationship to the object of interest as the parent box.
  • display_derived_interfaces: Display derived objects collected from additional collectors beside the main collector for building the context.
  • slim_center_box: Minimal width for the center box, containing just the icon and the label. This is False if hierarchy was identified.
  • display_port_labels: Display port labels on the diagram.
  • port_label_position: Position of the port labels. See PORT_LABEL_POSITION.
  • transparent_background: Make the background transparent.
  • context_groups: Render context UUID groups in the class attribute of every context element when an SVG is rendered.
  • display_unused_ports: Display ports that are not connected to an edge.
  • edge_direction: Reroute direction of edges.
  • mode: Context collection mode.
  • display_actor_relation: Show the connections between the context actors.
  • hide_context_owner: Hide the context owner in the diagram.
  • include_children_context: Include the context of the target's children.
  • include_external_context: Include all children of external actors in context.
  • hide_functions: Hide functions from the diagram.
  • display_functional_parent_relation: Display the parent relation of functions within the context.
  • display_internal_relations: Show exchanges that connect to children of a box from the diagram. Only useful with BLACKBOX mode.
  • display_cyclic_relations: Show cyclic exchanges that connect either the box of interest or a child with itself or a child. Only useful with BLACKBOX mode and display_cyclic_relations turned on.
  • restrict_external_depth: In GREYBOX mode, restrict external components to the same depth as max_depth. This prevents showing deeply nested children from external components.
  • pvmt_styling: Style the diagram according to the PVMT group applied to the diagram elements.
  • child_shadow: Add a white background box (5px padding, 50% opacity) behind elements that have a parent box.

The following properties are used by the internal builders:

  • collect: A callable that yields model elements from a given context diagram.
  • is_portless: Boolean flag, if the diagram is portless.
Source code in src/capellambse_context_diagrams/context.py
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
def __init__(
    self,
    class_: str,
    obj: m.ModelElement | m.Diagram,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    super().__init__(obj._model)
    self.target = obj  # type: ignore[assignment]
    self.styleclass = class_

    self.render_styles = render_styles or {}
    self.serializer = serializers.DiagramSerializer(self)

    self._elk_input_data: CollectorOutputData | None = None
    self.__filters: cabc.MutableSet[str] = self.FilterSet(self)
    render_params = {
        "display_symbols_as_boxes": False,
        "display_parent_relation": False,
        "display_derived_interfaces": False,
        "slim_center_box": True,
        "display_port_labels": False,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE,
        "display_unused_ports": False,
        "transparent_background": False,
        "context_groups": False,
        "edge_direction": enums.EDGE_DIRECTION.SMART,
        "mode": enums.MODE.WHITEBOX,
        "display_actor_relation": False,
        "hide_context_owner": False,
        "include_children_context": True,
        "include_external_context": False,
        "include_interface": True,
        "hide_functions": False,
        "display_functional_parent_relation": False,
        "display_internal_relations": True,
        "display_cyclic_relations": False,
        "restrict_external_depth": True,
        "pvmt_styling": None,
        "child_shadow": False,
    }
    if not _generic.DIAGRAM_TYPE_TO_CONNECTOR_NAMES.get(self.type, ()):
        render_params |= {
            "collect": portless.collector,
            "is_portless": True,
        }
    else:
        render_params |= {
            "collect": default.collector,
            "is_portless": False,
        }
    self._default_render_parameters = (
        render_params | default_render_parameters
    )

    if standard_filter := STANDARD_FILTERS.get(class_):
        self.filters.add(standard_filter)
    if standard_styles := STANDARD_STYLES.get(class_):
        self.render_styles = standard_styles

    self.builder: cabc.Callable[
        [ContextDiagram, dict[str, t.Any]], CollectorOutputData
    ] = db.builder

name property 🔗

name: str

Returns the diagram name.

nodes property 🔗

nodes: ElementList

Return a list of all nodes visible in this diagram.

See Also

nodes

type property 🔗

type: DiagramType

Return the type of this diagram.

uuid property 🔗

uuid: str

Returns diagram UUID.

FilterSet 🔗

FilterSet(diagram: AbstractDiagram)

Bases: MutableSet

A set that stores filter_names and invalidates diagram cache.

Source code in src/capellambse_context_diagrams/context.py
551
552
553
554
555
556
def __init__(
    self,
    diagram: m.AbstractDiagram,
) -> None:
    self._set: set[str] = set()
    self._diagram = diagram

elk_input_data 🔗

elk_input_data(params: dict[str, Any]) -> CollectorOutputData

Return the collected ELK input data.

Source code in src/capellambse_context_diagrams/context.py
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
def elk_input_data(self, params: dict[str, t.Any]) -> CollectorOutputData:
    """Return the collected ELK input data."""
    params = self._default_render_parameters | params
    if "pvmt_styling" in params:
        params["pvmt_styling"] = styling.normalize_pvmt_styling(
            params["pvmt_styling"]  # type: ignore[arg-type]
        )

    for param_name in self._default_render_parameters:
        setattr(self, f"_{param_name}", params.pop(param_name))

    data: CollectorOutputData
    if data := params.get("elkdata", None):  # type: ignore[assignment]
        self._elk_input_data = data

    if self._elk_input_data is None:
        self._elk_input_data = self.builder(self, params)

    return self._elk_input_data

CustomDiagramType 🔗

Bases: Enum

Custom Diagram types.

DataFlowAccessor 🔗

DataFlowAccessor(diagclass: str, render_params: dict[str, Any] | None = None)

Bases: ContextAccessor

Source code in src/capellambse_context_diagrams/context.py
188
189
190
191
192
def __init__(
    self, diagclass: str, render_params: dict[str, t.Any] | None = None
) -> None:
    self._dgcls = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a DataFlowViewDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
194
195
196
197
198
199
200
201
202
203
204
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a DataFlowViewDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, DataFlowViewDiagram)

DataFlowViewDiagram 🔗

DataFlowViewDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

An automatically generated DataFlowViewDiagram.

Source code in src/capellambse_context_diagrams/context.py
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
        "display_parent_relation": True,
        "edge_direction": enums.EDGE_DIRECTION.NONE,
        "mode": enums.MODE.WHITEBOX,
        "collect": dataflow_view.collector,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.builder = dataflow.builder

name property 🔗

name: str

Returns the name of the diagram.

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

DiagramLayoutAccessor 🔗

DiagramLayoutAccessor(
    dgls_to_render_params: dict[DiagramType, dict[str, Any]] | None = None,
)

Bases: Accessor

Provides access to an ELK layout of a diagram.

Source code in src/capellambse_context_diagrams/context.py
226
227
228
229
230
231
232
233
def __init__(
    self,
    dgls_to_render_params: (
        dict[m.DiagramType, dict[str, t.Any]] | None
    ) = None,
) -> None:
    super().__init__()
    self._dgls_to_render_params = dgls_to_render_params or {}

ELKDiagram 🔗

ELKDiagram(
    class_: str,
    obj: Diagram,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

A former diagram layouted by ELKJS.

Source code in src/capellambse_context_diagrams/context.py
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
def __init__(
    self,
    class_: str,
    obj: m.Diagram,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "include_port_allocations": True,
        "hide_elements": set(),
        "pvmt_styling": None,
        "display_port_labels": False,
        "display_symbols_as_boxes": False,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )

    self.builder = diagram_view.build_from_diagram  # type: ignore[assignment]
    self.target: m.Diagram = obj  # type: ignore[assignment]

    self.__nodes: m.ElementList | None = None

name property 🔗

name: str

Returns the diagram name.

nodes property 🔗

nodes: ElementList

Return a list of all nodes visible in this diagram.

uuid property 🔗

uuid: str

Returns diagram UUID.

FunctionalChainContextAccessor 🔗

FunctionalChainContextAccessor(
    diagclass: dict[type[ModelElement], str],
    render_params: dict[str, Any] | None = None,
)

Bases: InterfaceContextAccessor

Provides access to the functional chain view diagrams.

Source code in src/capellambse_context_diagrams/context.py
105
106
107
108
109
110
111
def __init__(  # pylint: disable=super-init-not-called
    self,
    diagclass: dict[type[m.ModelElement], str],
    render_params: dict[str, t.Any] | None = None,
) -> None:
    self._dgclasses = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
266
267
268
269
270
271
272
273
274
275
276
def __get__(  # type: ignore
    self, obj: m.T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    assert isinstance(obj.layer, m.ModelElement)
    self._dgcls = self._dgclasses[obj.layer.__class__]
    return self._get(obj, FunctionalChainContextDiagram)

FunctionalChainContextDiagram 🔗

FunctionalChainContextDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

A custom Context Diagram exclusively for FunctionalChains.

Source code in src/capellambse_context_diagrams/context.py
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
        "display_parent_relation": True,
        "edge_direction": enums.EDGE_DIRECTION.SMART,
        "mode": enums.MODE.WHITEBOX,
        "collect": default.functional_chain_collector,
    } | default_render_parameters

    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )

    self.builder = fchain.builder

InterfaceContextAccessor 🔗

InterfaceContextAccessor(
    diagclass: dict[type[ModelElement], str],
    render_params: dict[str, Any] | None = None,
)

Bases: ContextAccessor

Provides access to the interface context diagrams.

Source code in src/capellambse_context_diagrams/context.py
105
106
107
108
109
110
111
def __init__(  # pylint: disable=super-init-not-called
    self,
    diagclass: dict[type[m.ModelElement], str],
    render_params: dict[str, t.Any] | None = None,
) -> None:
    self._dgclasses = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
113
114
115
116
117
118
119
120
121
122
123
def __get__(  # type: ignore
    self, obj: m.T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    assert isinstance(obj.parent, m.ModelElement)
    self._dgcls = self._dgclasses[obj.parent.__class__]
    return self._get(obj, InterfaceContextDiagram)

InterfaceContextDiagram 🔗

InterfaceContextDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

A Context Diagram exclusively for ComponentExchanges.

ATTRIBUTE DESCRIPTION
dangling_functional_exchanges

A list of dangling functional exchanges for which either the source or target function were not allocated to a Component, part of the context.

TYPE: list[AbstractExchange]

Notes

The following render parameters are available:

  • include_interface: Boolean flag to enable inclusion of the context diagram target: The interface ComponentExchange.
  • include_port_allocations: Boolean flag to enable rendering of port allocations.
  • hide_functions: Boolean flag to enable white box view: Only displaying Components or Entities.

In addition to all other render parameters of ContextDiagram.

Source code in src/capellambse_context_diagrams/context.py
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "include_interface": False,
        "include_port_allocations": False,
        "hide_functions": False,
        "display_symbols_as_boxes": True,
        "display_port_labels": False,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE,
        "display_parent_relation": True,
        "collect": exchanges.interface_context_collector,
        "hide_context_owner": True,
        "edge_direction": enums.EDGE_DIRECTION.RIGHT,
        "display_functional_parent_relation": True,
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.builder = interface.builder

PhysicalPortContextAccessor 🔗

PhysicalPortContextAccessor(
    dgcls: str, render_params: dict[str, Any] | None = None
)

Bases: ContextAccessor

Source code in src/capellambse_context_diagrams/context.py
67
68
69
70
71
72
def __init__(
    self, dgcls: str, render_params: dict[str, t.Any] | None = None
) -> None:
    super().__init__()
    self._dgcls = dgcls
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a ContextDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
127
128
129
130
131
132
133
134
135
136
137
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a ContextDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, PhysicalPortContextDiagram)

PhysicalPortContextDiagram 🔗

PhysicalPortContextDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

A custom Context Diagram exclusively for PhysicalPorts.

Source code in src/capellambse_context_diagrams/context.py
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "collect": default.physical_port_context_collector,
        "display_parent_relation": True,
        "edge_direction": enums.EDGE_DIRECTION.TREE,
        "display_port_labels": True,
        "port_label_position": _elkjs.PORT_LABEL_POSITION.OUTSIDE,
    } | default_render_parameters

    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )

RealizationViewContextAccessor 🔗

RealizationViewContextAccessor(
    diagclass: str, render_params: dict[str, Any] | None = None
)

Bases: ContextAccessor

Provides access to the realization view diagrams.

Source code in src/capellambse_context_diagrams/context.py
167
168
169
170
171
def __init__(
    self, diagclass: str, render_params: dict[str, t.Any] | None = None
) -> None:
    self._dgcls = diagclass
    self._default_render_params = render_params or {}

__get__ 🔗

__get__(
    obj: T | None, objtype: type | None = None
) -> m.Accessor | ContextDiagram

Make a RealizationViewDiagram for the given model object.

Source code in src/capellambse_context_diagrams/context.py
173
174
175
176
177
178
179
180
181
182
183
def __get__(  # type: ignore
    self,
    obj: m.T | None,
    objtype: type | None = None,
) -> m.Accessor | ContextDiagram:
    """Make a RealizationViewDiagram for the given model object."""
    del objtype
    if obj is None:  # pragma: no cover
        return self
    assert isinstance(obj, m.ModelElement)
    return self._get(obj, RealizationViewDiagram)

RealizationViewDiagram 🔗

RealizationViewDiagram(
    class_: str,
    obj: ModelElement,
    *,
    render_styles: dict[str, Styler] | None = None,
    default_render_parameters: dict[str, Any]
)

Bases: ContextDiagram

An automatically generated realization view diagram.

This diagram is exclusively for Activity, Functions, Entity and Components of all layers.

Source code in src/capellambse_context_diagrams/context.py
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
def __init__(
    self,
    class_: str,
    obj: m.ModelElement,
    *,
    render_styles: dict[str, styling.Styler] | None = None,
    default_render_parameters: dict[str, t.Any],
) -> None:
    default_render_parameters = {
        "display_symbols_as_boxes": True,
        "depth": 1,
        "search_direction": "ALL",
        "show_owners": True,
        "layer_sizing": "WIDTH",
    } | default_render_parameters
    super().__init__(
        class_,
        obj,
        render_styles=render_styles,
        default_render_parameters=default_render_parameters,
    )
    self.builder = realization_view.collector  # type: ignore[assignment]

name property 🔗

name: str

Returns the name of the diagram.

type property 🔗

type: CustomDiagramType

Return the type of this diagram.

uuid property 🔗

uuid: str

Returns the UUID of the diagram.

add_context 🔗

add_context(data: ELKOutputData, is_legend: bool = False) -> None

Add all connected nodes as context to all elements.

Source code in src/capellambse_context_diagrams/context.py
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
def add_context(data: _elkjs.ELKOutputData, is_legend: bool = False) -> None:
    """Add all connected nodes as context to all elements."""
    if is_legend:
        for child in data.children:
            if child.type == "node":
                child.context = [child.id]
        return

    ids: set[str] = set()

    def get_ids(
        obj: (
            _elkjs.ELKOutputNode
            | _elkjs.ELKOutputPort
            | _elkjs.ELKOutputJunction
            | _elkjs.ELKOutputEdge
        ),
    ) -> None:
        if obj.id and not obj.id.startswith("g_"):
            ids.add(obj.id)
        for child in getattr(obj, "children", []):
            if child.type in {"node", "port", "junction", "edge"}:
                assert child.type != "label"
                get_ids(child)

    def set_ids(
        obj: _elkjs.ELKOutputChild,
        ids: set[str],
    ) -> None:
        obj.context = list(ids)
        for child in getattr(obj, "children", []):
            set_ids(child, ids)

    for child in data.children:
        if child.type in {"node", "port", "junction", "edge"}:
            assert child.type != "label"
            get_ids(child)

    for child in data.children:
        set_ids(child, ids)

adjust_layer_sizing 🔗

adjust_layer_sizing(
    data: ELKInputData,
    layout: ELKOutputData,
    layer_sizing: Literal["UNION", "WIDTH", "HEIGHT", "INDIVIDUAL"],
) -> None

Set nodeSize.minimum config in the layoutOptions.

Source code in src/capellambse_context_diagrams/context.py
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
def adjust_layer_sizing(
    data: _elkjs.ELKInputData,
    layout: _elkjs.ELKOutputData,
    layer_sizing: t.Literal["UNION", "WIDTH", "HEIGHT", "INDIVIDUAL"],
) -> None:
    """Set `nodeSize.minimum` config in the layoutOptions."""

    def calculate_min(key: t.Literal["width", "height"] = "width") -> float:
        return max(getattr(child.size, key) for child in layout.children)  # type: ignore[union-attr]

    if layer_sizing not in {"UNION", "WIDTH", "HEIGHT", "INDIVIDUAL"}:
        raise NotImplementedError(
            "For ``layer_sizing`` only UNION, WIDTH, HEIGHT or INDIVIDUAL is supported"
        )

    min_w = calculate_min() + 15.0 if layer_sizing in {"UNION", "WIDTH"} else 0
    min_h = (
        calculate_min("height") if layer_sizing in {"UNION", "HEIGHT"} else 0
    )
    for layer in data.children:
        layer.layoutOptions["nodeSize.minimum"] = f"({min_w},{min_h})"

calculate_label_position 🔗

calculate_label_position(
    x: float, y: float, width: float, height: float, padding: float = 10.0
) -> tuple[float, float, float]

Calculate the position of the label and tspan.

The function calculates the center of the rectangle and uses the rectangle's width and height to adjust its position within it. The text is assumed to be horizontally and vertically centered within the rectangle. The tspan y coordinate is for positioning the label right under the left side of the rectangle.

PARAMETER DESCRIPTION
x

The x coordinate of the label position.

TYPE: float

y

The y coordinate of the label position.

TYPE: float

width

Width of the label.

TYPE: float

height

Height of the label

TYPE: float

padding

The padding for the label.

TYPE: float DEFAULT: 10.0

RETURNS DESCRIPTION
position

A tuple containing the x- and y-coordinate for the text element and the adjusted y-coordinate for the tspan element.

Source code in src/capellambse_context_diagrams/context.py
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
def calculate_label_position(
    x: float,
    y: float,
    width: float,
    height: float,
    padding: float = 10.0,
) -> tuple[float, float, float]:
    """Calculate the position of the label and tspan.

    The function calculates the center of the rectangle and uses the
    rectangle's width and height to adjust its position within it. The
    text is assumed to be horizontally and vertically centered within
    the rectangle. The tspan y coordinate is for positioning the label
    right under the left side of the rectangle.

    Parameters
    ----------
    x
        The x coordinate of the label position.
    y
        The y coordinate of the label position.
    width
        Width of the label.
    height
        Height of the label
    padding
        The padding for the label.

    Returns
    -------
    position
        A tuple containing the x- and y-coordinate for the text element
        and the adjusted y-coordinate for the tspan element.
    """
    center_y = y + height / 2
    tspan_y = center_y - width / 2 + padding
    return (x + width / 2, center_y, tspan_y)

stack_diagrams 🔗

stack_diagrams(
    first: Diagram, second: Diagram, axis: Literal["x", "y"] = "x"
) -> None

Add the diagram elements from right to left inline.

Source code in src/capellambse_context_diagrams/context.py
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
def stack_diagrams(
    first: cdiagram.Diagram,
    second: cdiagram.Diagram,
    axis: t.Literal["x", "y"] = "x",
) -> None:
    """Add the diagram elements from ``right`` to left inline."""
    if first.viewport:
        offset = first.viewport.pos + first.viewport.size
        offset @= (1, 0) if axis == "x" else (0, 1)
        for element in second:
            new = copy.deepcopy(element)
            new.move(offset)
            first += new
    else:
        for element in second:
            new = copy.deepcopy(element)
            first += new

try_to_layout 🔗

try_to_layout(data: ELKInputData) -> _elkjs.ELKOutputData

Try calling elkjs, raise a JSONDecodeError if it fails.

Source code in src/capellambse_context_diagrams/context.py
1395
1396
1397
1398
1399
1400
1401
def try_to_layout(data: _elkjs.ELKInputData) -> _elkjs.ELKOutputData:
    """Try calling elkjs, raise a JSONDecodeError if it fails."""
    try:
        return _elkjs.elk_manager.call_elkjs(data)
    except json.JSONDecodeError as error:
        logger.error(json.dumps(data, indent=4))
        raise error