buildzr 0.0.7__py3-none-any.whl → 0.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- buildzr/__about__.py +1 -1
- buildzr/dsl/dsl.py +294 -178
- buildzr/dsl/expression.py +50 -22
- buildzr/dsl/interfaces/__init__.py +0 -4
- buildzr/dsl/interfaces/interfaces.py +2 -37
- buildzr/dsl/relations.py +7 -76
- buildzr/encoders/encoder.py +24 -4
- {buildzr-0.0.7.dist-info → buildzr-0.0.8.dist-info}/METADATA +51 -66
- {buildzr-0.0.7.dist-info → buildzr-0.0.8.dist-info}/RECORD +11 -11
- {buildzr-0.0.7.dist-info → buildzr-0.0.8.dist-info}/WHEEL +1 -1
- {buildzr-0.0.7.dist-info → buildzr-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
buildzr/dsl/dsl.py
CHANGED
@@ -3,9 +3,10 @@ import buildzr
|
|
3
3
|
from .factory import GenerateId
|
4
4
|
from typing_extensions import (
|
5
5
|
Self,
|
6
|
-
TypeGuard,
|
7
6
|
TypeIs,
|
8
7
|
)
|
8
|
+
from collections import deque
|
9
|
+
from contextvars import ContextVar
|
9
10
|
from typing import (
|
10
11
|
Any,
|
11
12
|
Union,
|
@@ -16,33 +17,21 @@ from typing import (
|
|
16
17
|
Optional,
|
17
18
|
Generic,
|
18
19
|
TypeVar,
|
19
|
-
Protocol,
|
20
20
|
Callable,
|
21
21
|
Iterable,
|
22
22
|
Literal,
|
23
23
|
cast,
|
24
|
-
overload,
|
25
|
-
Sequence,
|
26
24
|
Type,
|
27
25
|
)
|
28
26
|
|
29
27
|
from buildzr.sinks.interfaces import Sink
|
30
|
-
|
31
28
|
from buildzr.dsl.interfaces import (
|
32
29
|
DslWorkspaceElement,
|
33
30
|
DslElement,
|
34
31
|
DslViewElement,
|
35
32
|
DslViewsElement,
|
36
|
-
DslFluentSink,
|
37
|
-
TSrc, TDst,
|
38
|
-
TParent, TChild,
|
39
33
|
)
|
40
34
|
from buildzr.dsl.relations import (
|
41
|
-
_is_software_fluent_relationship,
|
42
|
-
_is_container_fluent_relationship,
|
43
|
-
_Relationship,
|
44
|
-
_RelationshipDescription,
|
45
|
-
_FluentRelationship,
|
46
35
|
DslElementRelationOverrides,
|
47
36
|
)
|
48
37
|
|
@@ -58,6 +47,11 @@ class TypedDynamicAttribute(Generic[TypedModel]):
|
|
58
47
|
def __getattr__(self, name: str) -> TypedModel:
|
59
48
|
return cast(TypedModel, self._dynamic_attributes.get(name))
|
60
49
|
|
50
|
+
_current_workspace: ContextVar[Optional['Workspace']] = ContextVar('current_workspace', default=None)
|
51
|
+
_current_group_stack: ContextVar[List['Group']] = ContextVar('current_group', default=[])
|
52
|
+
_current_software_system: ContextVar[Optional['SoftwareSystem']] = ContextVar('current_software_system', default=None)
|
53
|
+
_current_container: ContextVar[Optional['Container']] = ContextVar('current_container', default=None)
|
54
|
+
|
61
55
|
class Workspace(DslWorkspaceElement):
|
62
56
|
"""
|
63
57
|
Represents a Structurizr workspace, which is a wrapper for a software architecture model, views, and documentation.
|
@@ -75,11 +69,21 @@ class Workspace(DslWorkspaceElement):
|
|
75
69
|
def children(self) -> Optional[List[Union['Person', 'SoftwareSystem']]]:
|
76
70
|
return self._children
|
77
71
|
|
78
|
-
def __init__(
|
72
|
+
def __init__(
|
73
|
+
self,
|
74
|
+
name: str,
|
75
|
+
description: str="",
|
76
|
+
scope: Literal['landscape', 'software_system', None]='software_system',
|
77
|
+
implied_relationships: bool=False,
|
78
|
+
group_separator: str='/',
|
79
|
+
) -> None:
|
80
|
+
|
79
81
|
self._m = buildzr.models.Workspace()
|
80
82
|
self._parent = None
|
81
83
|
self._children: Optional[List[Union['Person', 'SoftwareSystem']]] = []
|
82
84
|
self._dynamic_attrs: Dict[str, Union['Person', 'SoftwareSystem']] = {}
|
85
|
+
self._use_implied_relationships = implied_relationships
|
86
|
+
self._group_separator = group_separator
|
83
87
|
self.model.id = GenerateId.for_workspace()
|
84
88
|
self.model.name = name
|
85
89
|
self.model.description = description
|
@@ -102,58 +106,57 @@ class Workspace(DslWorkspaceElement):
|
|
102
106
|
scope=scope_mapper[scope],
|
103
107
|
)
|
104
108
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
*models: Union[
|
109
|
-
'Person',
|
110
|
-
'SoftwareSystem',
|
111
|
-
_FluentRelationship['SoftwareSystem'],
|
112
|
-
_FluentRelationship['Container'],
|
113
|
-
]
|
114
|
-
) -> None:
|
109
|
+
self.model.model.properties = {
|
110
|
+
'structurizr.groupSeparator': group_separator,
|
111
|
+
}
|
115
112
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
113
|
+
def __enter__(self) -> Self:
|
114
|
+
self._token = _current_workspace.set(self)
|
115
|
+
return self
|
116
|
+
|
117
|
+
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[Any]) -> None:
|
118
|
+
|
119
|
+
from buildzr.dsl.explorer import Explorer
|
120
|
+
|
121
|
+
# Process implied relationships:
|
122
|
+
# If we have relationship s >> do >> a.b, then create s >> do >> a.
|
123
|
+
# If we have relationship s.ss >> do >> a.b.c, then create s.ss >> do >> a.b and s.ss >> do >> a.
|
124
|
+
# And so on...
|
125
|
+
if self._use_implied_relationships:
|
126
|
+
explorer = Explorer(self)
|
127
|
+
relationships = list(explorer.walk_relationships())
|
128
|
+
for relationship in relationships:
|
129
|
+
source = relationship.source
|
130
|
+
destination = relationship.destination
|
131
|
+
destination_parent = destination.parent
|
132
|
+
|
133
|
+
while destination_parent is not None and \
|
134
|
+
isinstance(source, DslElement) and \
|
135
|
+
not isinstance(source.model, buildzr.models.Workspace) and \
|
136
|
+
not isinstance(destination_parent, DslWorkspaceElement):
|
137
|
+
|
138
|
+
if destination_parent is source.parent:
|
139
|
+
break
|
140
|
+
|
141
|
+
rels = source.model.relationships
|
142
|
+
|
143
|
+
if rels:
|
144
|
+
already_exists = any(
|
145
|
+
r.destinationId == destination_parent.model.id and
|
146
|
+
r.description == relationship.model.description and
|
147
|
+
r.technology == relationship.model.technology
|
148
|
+
for r in rels
|
149
|
+
)
|
150
|
+
if not already_exists:
|
151
|
+
r = source.uses(
|
152
|
+
destination_parent,
|
153
|
+
description=relationship.model.description,
|
154
|
+
technology=relationship.model.technology,
|
155
|
+
)
|
156
|
+
r.model.linkedRelationshipId = relationship.model.id
|
157
|
+
destination_parent = destination_parent.parent
|
158
|
+
|
159
|
+
_current_workspace.reset(self._token)
|
157
160
|
|
158
161
|
def person(self) -> TypedDynamicAttribute['Person']:
|
159
162
|
return TypedDynamicAttribute['Person'](self._dynamic_attrs)
|
@@ -161,34 +164,44 @@ class Workspace(DslWorkspaceElement):
|
|
161
164
|
def software_system(self) -> TypedDynamicAttribute['SoftwareSystem']:
|
162
165
|
return TypedDynamicAttribute['SoftwareSystem'](self._dynamic_attrs)
|
163
166
|
|
164
|
-
def
|
165
|
-
if isinstance(
|
166
|
-
self._m.model.people.append(
|
167
|
-
|
168
|
-
self.
|
169
|
-
|
170
|
-
|
171
|
-
self.
|
172
|
-
|
173
|
-
self.
|
174
|
-
|
175
|
-
self._dynamic_attrs[_child_name_transform(element.model.name)] = element
|
176
|
-
if element._label:
|
177
|
-
self._dynamic_attrs[_child_name_transform(element._label)] = element
|
178
|
-
self._children.append(element)
|
167
|
+
def add_model(self, model: Union['Person', 'SoftwareSystem']) -> None:
|
168
|
+
if isinstance(model, Person):
|
169
|
+
self._m.model.people.append(model._m)
|
170
|
+
model._parent = self
|
171
|
+
self._add_dynamic_attr(model.model.name, model)
|
172
|
+
self._children.append(model)
|
173
|
+
elif isinstance(model, SoftwareSystem):
|
174
|
+
self._m.model.softwareSystems.append(model._m)
|
175
|
+
model._parent = self
|
176
|
+
self._add_dynamic_attr(model.model.name, model)
|
177
|
+
self._children.append(model)
|
179
178
|
else:
|
180
|
-
raise ValueError('Invalid element type: Trying to add an element of type {} to a workspace.'.format(type(
|
179
|
+
raise ValueError('Invalid element type: Trying to add an element of type {} to a workspace.'.format(type(model)))
|
181
180
|
|
182
|
-
def
|
183
|
-
self,
|
184
|
-
*views: Union[
|
185
|
-
'SystemLandscapeView',
|
181
|
+
def apply_views( self, *views: Union[ 'SystemLandscapeView',
|
186
182
|
'SystemContextView',
|
187
183
|
'ContainerView',
|
188
184
|
'ComponentView',
|
189
185
|
]
|
190
|
-
) ->
|
191
|
-
|
186
|
+
) -> None:
|
187
|
+
Views(self).add_views(*views)
|
188
|
+
|
189
|
+
def to_json(self, path: str) -> None:
|
190
|
+
from buildzr.sinks.json_sink import JsonSink, JsonSinkConfig
|
191
|
+
sink = JsonSink()
|
192
|
+
sink.write(workspace=self.model, config=JsonSinkConfig(path=path))
|
193
|
+
|
194
|
+
def _add_dynamic_attr(self, name: str, model: Union['Person', 'SoftwareSystem']) -> None:
|
195
|
+
if isinstance(model, Person):
|
196
|
+
self._dynamic_attrs[_child_name_transform(name)] = model
|
197
|
+
if model._label:
|
198
|
+
self._dynamic_attrs[_child_name_transform(model._label)] = model
|
199
|
+
elif isinstance(model, SoftwareSystem):
|
200
|
+
self._dynamic_attrs[_child_name_transform(name)] = model
|
201
|
+
if model._label:
|
202
|
+
self._dynamic_attrs[_child_name_transform(model._label)] = model
|
203
|
+
else:
|
204
|
+
raise ValueError('Invalid element type: Trying to add an element of type {} to a workspace.'.format(type(model)))
|
192
205
|
|
193
206
|
def __getattr__(self, name: str) -> Union['Person', 'SoftwareSystem']:
|
194
207
|
return self._dynamic_attrs[name]
|
@@ -238,6 +251,7 @@ class SoftwareSystem(DslElementRelationOverrides[
|
|
238
251
|
|
239
252
|
def __init__(self, name: str, description: str="", tags: Set[str]=set(), properties: Dict[str, Any]=dict()) -> None:
|
240
253
|
self._m = buildzr.models.SoftwareSystem()
|
254
|
+
self.model.containers = []
|
241
255
|
self._parent: Optional[Workspace] = None
|
242
256
|
self._children: Optional[List['Container']] = []
|
243
257
|
self._sources: List[DslElement] = []
|
@@ -251,37 +265,41 @@ class SoftwareSystem(DslElementRelationOverrides[
|
|
251
265
|
self.model.tags = ','.join(self._tags)
|
252
266
|
self.model.properties = properties
|
253
267
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
if not self.model.containers:
|
259
|
-
self.model.containers = []
|
260
|
-
|
261
|
-
for child in containers:
|
262
|
-
if isinstance(child, Container):
|
263
|
-
self.add_element(child)
|
264
|
-
elif _is_container_fluent_relationship(child):
|
265
|
-
self.add_element(child._parent)
|
266
|
-
return _FluentRelationship['SoftwareSystem'](self)
|
268
|
+
workspace = _current_workspace.get()
|
269
|
+
if workspace is not None:
|
270
|
+
workspace.add_model(self)
|
271
|
+
workspace._add_dynamic_attr(self.model.name, self)
|
267
272
|
|
268
|
-
|
269
|
-
|
273
|
+
stack = _current_group_stack.get()
|
274
|
+
if stack:
|
275
|
+
stack[-1].add_element(self)
|
276
|
+
|
277
|
+
def __enter__(self) -> Self:
|
278
|
+
self._token = _current_software_system.set(self)
|
270
279
|
return self
|
271
280
|
|
281
|
+
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[Any]) -> None:
|
282
|
+
_current_software_system.reset(self._token)
|
283
|
+
|
272
284
|
def container(self) -> TypedDynamicAttribute['Container']:
|
273
285
|
return TypedDynamicAttribute['Container'](self._dynamic_attrs)
|
274
286
|
|
275
|
-
def
|
276
|
-
if isinstance(
|
277
|
-
self.model.containers.append(
|
278
|
-
|
279
|
-
self.
|
280
|
-
|
281
|
-
|
282
|
-
|
287
|
+
def add_container(self, container: 'Container') -> None:
|
288
|
+
if isinstance(container, Container):
|
289
|
+
self.model.containers.append(container.model)
|
290
|
+
container._parent = self
|
291
|
+
self._add_dynamic_attr(container.model.name, container)
|
292
|
+
self._children.append(container)
|
293
|
+
else:
|
294
|
+
raise ValueError('Invalid element type: Trying to add an element of type {} to a software system.'.format(type(container)))
|
295
|
+
|
296
|
+
def _add_dynamic_attr(self, name: str, model: 'Container') -> None:
|
297
|
+
if isinstance(model, Container):
|
298
|
+
self._dynamic_attrs[_child_name_transform(name)] = model
|
299
|
+
if model._label:
|
300
|
+
self._dynamic_attrs[_child_name_transform(model._label)] = model
|
283
301
|
else:
|
284
|
-
raise ValueError('Invalid element type: Trying to add an element of type {} to a software system.'.format(type(
|
302
|
+
raise ValueError('Invalid element type: Trying to add an element of type {} to a software system.'.format(type(model)))
|
285
303
|
|
286
304
|
def __getattr__(self, name: str) -> 'Container':
|
287
305
|
return self._dynamic_attrs[name]
|
@@ -292,6 +310,13 @@ class SoftwareSystem(DslElementRelationOverrides[
|
|
292
310
|
def __dir__(self) -> Iterable[str]:
|
293
311
|
return list(super().__dir__()) + list(self._dynamic_attrs.keys())
|
294
312
|
|
313
|
+
def labeled(self, label: str) -> 'SoftwareSystem':
|
314
|
+
self._label = label
|
315
|
+
workspace = _current_workspace.get()
|
316
|
+
if workspace is not None:
|
317
|
+
workspace._add_dynamic_attr(label, self)
|
318
|
+
return self
|
319
|
+
|
295
320
|
class Person(DslElementRelationOverrides[
|
296
321
|
'Person',
|
297
322
|
Union[
|
@@ -347,8 +372,19 @@ class Person(DslElementRelationOverrides[
|
|
347
372
|
self.model.tags = ','.join(self._tags)
|
348
373
|
self.model.properties = properties
|
349
374
|
|
375
|
+
workspace = _current_workspace.get()
|
376
|
+
if workspace is not None:
|
377
|
+
workspace.add_model(self)
|
378
|
+
|
379
|
+
stack = _current_group_stack.get()
|
380
|
+
if stack:
|
381
|
+
stack[-1].add_element(self)
|
382
|
+
|
350
383
|
def labeled(self, label: str) -> 'Person':
|
351
384
|
self._label = label
|
385
|
+
workspace = _current_workspace.get()
|
386
|
+
if workspace is not None:
|
387
|
+
workspace._add_dynamic_attr(label, self)
|
352
388
|
return self
|
353
389
|
|
354
390
|
class Container(DslElementRelationOverrides[
|
@@ -388,15 +424,9 @@ class Container(DslElementRelationOverrides[
|
|
388
424
|
def tags(self) -> Set[str]:
|
389
425
|
return self._tags
|
390
426
|
|
391
|
-
def contains(self, *components: 'Component') -> _FluentRelationship['Container']:
|
392
|
-
if not self.model.components:
|
393
|
-
self.model.components = []
|
394
|
-
for component in components:
|
395
|
-
self.add_element(component)
|
396
|
-
return _FluentRelationship['Container'](self)
|
397
|
-
|
398
427
|
def __init__(self, name: str, description: str="", technology: str="", tags: Set[str]=set(), properties: Dict[str, Any]=dict()) -> None:
|
399
428
|
self._m = buildzr.models.Container()
|
429
|
+
self.model.components = []
|
400
430
|
self._parent: Optional[SoftwareSystem] = None
|
401
431
|
self._children: Optional[List['Component']] = []
|
402
432
|
self._sources: List[DslElement] = []
|
@@ -412,23 +442,48 @@ class Container(DslElementRelationOverrides[
|
|
412
442
|
self.model.tags = ','.join(self._tags)
|
413
443
|
self.model.properties = properties
|
414
444
|
|
445
|
+
software_system = _current_software_system.get()
|
446
|
+
if software_system is not None:
|
447
|
+
software_system.add_container(self)
|
448
|
+
software_system._add_dynamic_attr(self.model.name, self)
|
449
|
+
|
450
|
+
stack = _current_group_stack.get()
|
451
|
+
if stack:
|
452
|
+
stack[-1].add_element(self)
|
453
|
+
|
454
|
+
def __enter__(self) -> Self:
|
455
|
+
self._token = _current_container.set(self)
|
456
|
+
return self
|
457
|
+
|
458
|
+
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[Any]) -> None:
|
459
|
+
_current_container.reset(self._token)
|
460
|
+
|
415
461
|
def labeled(self, label: str) -> 'Container':
|
416
462
|
self._label = label
|
463
|
+
software_system = _current_software_system.get()
|
464
|
+
if software_system is not None:
|
465
|
+
software_system._add_dynamic_attr(label, self)
|
417
466
|
return self
|
418
467
|
|
419
468
|
def component(self) -> TypedDynamicAttribute['Component']:
|
420
469
|
return TypedDynamicAttribute['Component'](self._dynamic_attrs)
|
421
470
|
|
422
|
-
def
|
423
|
-
if isinstance(
|
424
|
-
self.model.components.append(
|
425
|
-
|
426
|
-
self.
|
427
|
-
|
428
|
-
|
429
|
-
|
471
|
+
def add_component(self, component: 'Component') -> None:
|
472
|
+
if isinstance(component, Component):
|
473
|
+
self.model.components.append(component.model)
|
474
|
+
component._parent = self
|
475
|
+
self._add_dynamic_attr(component.model.name, component)
|
476
|
+
self._children.append(component)
|
477
|
+
else:
|
478
|
+
raise ValueError('Invalid element type: Trying to add an element of type {} to a container.'.format(type(component)))
|
479
|
+
|
480
|
+
def _add_dynamic_attr(self, name: str, model: 'Component') -> None:
|
481
|
+
if isinstance(model, Component):
|
482
|
+
self._dynamic_attrs[_child_name_transform(name)] = model
|
483
|
+
if model._label:
|
484
|
+
self._dynamic_attrs[_child_name_transform(model._label)] = model
|
430
485
|
else:
|
431
|
-
raise ValueError('Invalid element type: Trying to add an element of type {} to a container.'.format(type(
|
486
|
+
raise ValueError('Invalid element type: Trying to add an element of type {} to a container.'.format(type(model)))
|
432
487
|
|
433
488
|
def __getattr__(self, name: str) -> 'Component':
|
434
489
|
return self._dynamic_attrs[name]
|
@@ -491,8 +546,20 @@ class Component(DslElementRelationOverrides[
|
|
491
546
|
self.model.tags = ','.join(self._tags)
|
492
547
|
self.model.properties = properties
|
493
548
|
|
549
|
+
container = _current_container.get()
|
550
|
+
if container is not None:
|
551
|
+
container.add_component(self)
|
552
|
+
container._add_dynamic_attr(self.model.name, self)
|
553
|
+
|
554
|
+
stack = _current_group_stack.get()
|
555
|
+
if stack:
|
556
|
+
stack[-1].add_element(self)
|
557
|
+
|
494
558
|
def labeled(self, label: str) -> 'Component':
|
495
559
|
self._label = label
|
560
|
+
container = _current_container.get()
|
561
|
+
if container is not None:
|
562
|
+
container._add_dynamic_attr(label, self)
|
496
563
|
return self
|
497
564
|
|
498
565
|
class Group:
|
@@ -500,27 +567,53 @@ class Group:
|
|
500
567
|
def __init__(
|
501
568
|
self,
|
502
569
|
name: str,
|
503
|
-
|
504
|
-
Person,
|
505
|
-
SoftwareSystem,
|
506
|
-
_FluentRelationship[SoftwareSystem],
|
507
|
-
_FluentRelationship[Container],
|
508
|
-
]) -> None:
|
570
|
+
) -> None:
|
509
571
|
self._name = name
|
510
|
-
self._elements = elements
|
511
572
|
|
512
|
-
|
573
|
+
def add_element(
|
574
|
+
self,
|
575
|
+
model: Union[
|
576
|
+
'Person',
|
577
|
+
'SoftwareSystem',
|
578
|
+
'Container',
|
579
|
+
'Component',
|
580
|
+
],
|
581
|
+
group_separator: str="/",
|
582
|
+
) -> None:
|
513
583
|
|
514
|
-
|
515
|
-
self._workspace = workspace
|
584
|
+
separator = group_separator
|
516
585
|
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
sink.write(workspace=self._workspace.model, config=JsonSinkConfig(path=path))
|
586
|
+
workspace = _current_workspace.get()
|
587
|
+
if workspace is not None:
|
588
|
+
separator = workspace._group_separator
|
521
589
|
|
522
|
-
|
523
|
-
|
590
|
+
if len(separator) > 1:
|
591
|
+
raise ValueError('Group separator must be a single character.')
|
592
|
+
|
593
|
+
if separator in self._name:
|
594
|
+
raise ValueError('Group name cannot contain the group separator.')
|
595
|
+
|
596
|
+
stack = _current_group_stack.get()
|
597
|
+
|
598
|
+
index = next((i for i, group in enumerate(stack) if group._name == self._name), -1)
|
599
|
+
if index >= 0:
|
600
|
+
model.model.group = separator.join([group._name for group in stack[:index + 1]])
|
601
|
+
|
602
|
+
def __enter__(self) -> Self:
|
603
|
+
stack = _current_group_stack.get() # stack: a/b
|
604
|
+
stack.extend([self]) # stack: a/b -> a/b/self
|
605
|
+
self._token = _current_group_stack.set(stack)
|
606
|
+
return self
|
607
|
+
|
608
|
+
def __exit__(
|
609
|
+
self,
|
610
|
+
exc_type: Optional[Type[BaseException]],
|
611
|
+
exc_value: Optional[BaseException],
|
612
|
+
traceback: Optional[Any]
|
613
|
+
) -> None:
|
614
|
+
stack = _current_group_stack.get()
|
615
|
+
stack.pop() # stack: a/b/self -> a/b
|
616
|
+
_current_group_stack.reset(self._token)
|
524
617
|
|
525
618
|
_RankDirection = Literal['tb', 'bt', 'lr', 'rl']
|
526
619
|
|
@@ -607,10 +700,10 @@ class SystemLandscapeView(DslViewElement):
|
|
607
700
|
description: str,
|
608
701
|
auto_layout: _AutoLayout='tb',
|
609
702
|
title: Optional[str]=None,
|
610
|
-
include_elements: List[Callable[[Workspace, Element], bool]]=[],
|
611
|
-
exclude_elements: List[Callable[[Workspace, Element], bool]]=[],
|
612
|
-
include_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
613
|
-
exclude_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
703
|
+
include_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
704
|
+
exclude_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
705
|
+
include_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
706
|
+
exclude_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
614
707
|
properties: Optional[Dict[str, str]]=None,
|
615
708
|
) -> None:
|
616
709
|
self._m = buildzr.models.SystemLandscapeView()
|
@@ -628,6 +721,10 @@ class SystemLandscapeView(DslViewElement):
|
|
628
721
|
self._include_relationships = include_relationships
|
629
722
|
self._exclude_relationships = exclude_relationships
|
630
723
|
|
724
|
+
workspace = _current_workspace.get()
|
725
|
+
if workspace is not None:
|
726
|
+
workspace.apply_views(self)
|
727
|
+
|
631
728
|
def _on_added(self) -> None:
|
632
729
|
|
633
730
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
@@ -642,17 +739,17 @@ class SystemLandscapeView(DslViewElement):
|
|
642
739
|
|
643
740
|
workspace = self._parent._parent
|
644
741
|
|
645
|
-
include_view_elements_filter: List[Callable[[Workspace, Element], bool]] = [
|
742
|
+
include_view_elements_filter: List[Union[DslElement, Callable[[Workspace, Element], bool]]] = [
|
646
743
|
lambda w, e: e.type == Person,
|
647
744
|
lambda w, e: e.type == SoftwareSystem
|
648
745
|
]
|
649
746
|
|
650
|
-
exclude_view_elements_filter: List[Callable[[Workspace, Element], bool]] = [
|
747
|
+
exclude_view_elements_filter: List[Union[DslElement, Callable[[Workspace, Element], bool]]] = [
|
651
748
|
lambda w, e: e.type == Container,
|
652
749
|
lambda w, e: e.type == Component,
|
653
750
|
]
|
654
751
|
|
655
|
-
include_view_relationships_filter: List[Callable[[Workspace, Relationship], bool]] = [
|
752
|
+
include_view_relationships_filter: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]] = [
|
656
753
|
lambda w, r: r.source.type == Person,
|
657
754
|
lambda w, r: r.source.type == SoftwareSystem,
|
658
755
|
lambda w, r: r.destination.type == Person,
|
@@ -703,15 +800,15 @@ class SystemContextView(DslViewElement):
|
|
703
800
|
|
704
801
|
def __init__(
|
705
802
|
self,
|
706
|
-
software_system_selector: Callable[[Workspace], SoftwareSystem],
|
803
|
+
software_system_selector: Union[SoftwareSystem, Callable[[Workspace], SoftwareSystem]],
|
707
804
|
key: str,
|
708
805
|
description: str,
|
709
806
|
auto_layout: _AutoLayout='tb',
|
710
807
|
title: Optional[str]=None,
|
711
|
-
include_elements: List[Callable[[Workspace, Element], bool]]=[],
|
712
|
-
exclude_elements: List[Callable[[Workspace, Element], bool]]=[],
|
713
|
-
include_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
714
|
-
exclude_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
808
|
+
include_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
809
|
+
exclude_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
810
|
+
include_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
811
|
+
exclude_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
715
812
|
properties: Optional[Dict[str, str]]=None,
|
716
813
|
) -> None:
|
717
814
|
self._m = buildzr.models.SystemContextView()
|
@@ -730,20 +827,27 @@ class SystemContextView(DslViewElement):
|
|
730
827
|
self._include_relationships = include_relationships
|
731
828
|
self._exclude_relationships = exclude_relationships
|
732
829
|
|
830
|
+
workspace = _current_workspace.get()
|
831
|
+
if workspace is not None:
|
832
|
+
workspace.apply_views(self)
|
833
|
+
|
733
834
|
def _on_added(self) -> None:
|
734
835
|
|
735
836
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
736
837
|
from buildzr.models import ElementView, RelationshipView
|
737
838
|
|
738
|
-
|
839
|
+
if isinstance(self._selector, SoftwareSystem):
|
840
|
+
software_system = self._selector
|
841
|
+
else:
|
842
|
+
software_system = self._selector(self._parent._parent)
|
739
843
|
self._m.softwareSystemId = software_system.model.id
|
740
|
-
view_elements_filter: List[Callable[[Workspace, Element], bool]] = [
|
844
|
+
view_elements_filter: List[Union[DslElement, Callable[[Workspace, Element], bool]]] = [
|
741
845
|
lambda w, e: e == software_system,
|
742
846
|
lambda w, e: software_system.model.id in e.sources.ids,
|
743
847
|
lambda w, e: software_system.model.id in e.destinations.ids,
|
744
848
|
]
|
745
849
|
|
746
|
-
view_relationships_filter: List[Callable[[Workspace, Relationship], bool]] = [
|
850
|
+
view_relationships_filter: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]] = [
|
747
851
|
lambda w, r: software_system == r.source,
|
748
852
|
lambda w, r: software_system == r.destination,
|
749
853
|
]
|
@@ -789,15 +893,15 @@ class ContainerView(DslViewElement):
|
|
789
893
|
|
790
894
|
def __init__(
|
791
895
|
self,
|
792
|
-
software_system_selector: Callable[[Workspace], SoftwareSystem],
|
896
|
+
software_system_selector: Union[SoftwareSystem, Callable[[Workspace], SoftwareSystem]],
|
793
897
|
key: str,
|
794
898
|
description: str,
|
795
899
|
auto_layout: _AutoLayout='tb',
|
796
900
|
title: Optional[str]=None,
|
797
|
-
include_elements: List[Callable[[Workspace, Element], bool]]=[],
|
798
|
-
exclude_elements: List[Callable[[Workspace, Element], bool]]=[],
|
799
|
-
include_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
800
|
-
exclude_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
901
|
+
include_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
902
|
+
exclude_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
903
|
+
include_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
904
|
+
exclude_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
801
905
|
properties: Optional[Dict[str, str]]=None,
|
802
906
|
) -> None:
|
803
907
|
self._m = buildzr.models.ContainerView()
|
@@ -816,23 +920,30 @@ class ContainerView(DslViewElement):
|
|
816
920
|
self._include_relationships = include_relationships
|
817
921
|
self._exclude_relationships = exclude_relationships
|
818
922
|
|
923
|
+
workspace = _current_workspace.get()
|
924
|
+
if workspace is not None:
|
925
|
+
workspace.apply_views(self)
|
926
|
+
|
819
927
|
def _on_added(self) -> None:
|
820
928
|
|
821
929
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
822
930
|
from buildzr.models import ElementView, RelationshipView
|
823
931
|
|
824
|
-
|
932
|
+
if isinstance(self._selector, SoftwareSystem):
|
933
|
+
software_system = self._selector
|
934
|
+
else:
|
935
|
+
software_system = self._selector(self._parent._parent)
|
825
936
|
self._m.softwareSystemId = software_system.model.id
|
826
937
|
|
827
938
|
container_ids = { container.model.id for container in software_system.children}
|
828
939
|
|
829
|
-
view_elements_filter: List[Callable[[Workspace, Element], bool]] = [
|
940
|
+
view_elements_filter: List[Union[DslElement, Callable[[Workspace, Element], bool]]] = [
|
830
941
|
lambda w, e: e.parent == software_system,
|
831
942
|
lambda w, e: any(container_ids.intersection({ id for id in e.sources.ids })),
|
832
943
|
lambda w, e: any(container_ids.intersection({ id for id in e.destinations.ids })),
|
833
944
|
]
|
834
945
|
|
835
|
-
view_relationships_filter: List[Callable[[Workspace, Relationship], bool]] = [
|
946
|
+
view_relationships_filter: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]] = [
|
836
947
|
lambda w, r: software_system == r.source.parent,
|
837
948
|
lambda w, r: software_system == r.destination.parent,
|
838
949
|
]
|
@@ -878,15 +989,15 @@ class ComponentView(DslViewElement):
|
|
878
989
|
|
879
990
|
def __init__(
|
880
991
|
self,
|
881
|
-
container_selector: Callable[[Workspace], Container],
|
992
|
+
container_selector: Union[Container, Callable[[Workspace], Container]],
|
882
993
|
key: str,
|
883
994
|
description: str,
|
884
995
|
auto_layout: _AutoLayout='tb',
|
885
996
|
title: Optional[str]=None,
|
886
|
-
include_elements: List[Callable[[Workspace, Element], bool]]=[],
|
887
|
-
exclude_elements: List[Callable[[Workspace, Element], bool]]=[],
|
888
|
-
include_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
889
|
-
exclude_relationships: List[Callable[[Workspace, Relationship], bool]]=[],
|
997
|
+
include_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
998
|
+
exclude_elements: List[Union[DslElement, Callable[[Workspace, Element], bool]]]=[],
|
999
|
+
include_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
1000
|
+
exclude_relationships: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]]=[],
|
890
1001
|
properties: Optional[Dict[str, str]]=None,
|
891
1002
|
) -> None:
|
892
1003
|
self._m = buildzr.models.ComponentView()
|
@@ -905,23 +1016,30 @@ class ComponentView(DslViewElement):
|
|
905
1016
|
self._include_relationships = include_relationships
|
906
1017
|
self._exclude_relationships = exclude_relationships
|
907
1018
|
|
1019
|
+
workspace = _current_workspace.get()
|
1020
|
+
if workspace is not None:
|
1021
|
+
workspace.apply_views(self)
|
1022
|
+
|
908
1023
|
def _on_added(self) -> None:
|
909
1024
|
|
910
1025
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
911
1026
|
from buildzr.models import ElementView, RelationshipView
|
912
1027
|
|
913
|
-
|
1028
|
+
if isinstance(self._selector, Container):
|
1029
|
+
container = self._selector
|
1030
|
+
else:
|
1031
|
+
container = self._selector(self._parent._parent)
|
914
1032
|
self._m.containerId = container.model.id
|
915
1033
|
|
916
1034
|
component_ids = { component.model.id for component in container.children }
|
917
1035
|
|
918
|
-
view_elements_filter: List[Callable[[Workspace, Element], bool]] = [
|
1036
|
+
view_elements_filter: List[Union[DslElement, Callable[[Workspace, Element], bool]]] = [
|
919
1037
|
lambda w, e: e.parent == container,
|
920
1038
|
lambda w, e: any(component_ids.intersection({ id for id in e.sources.ids })),
|
921
1039
|
lambda w, e: any(component_ids.intersection({ id for id in e.destinations.ids })),
|
922
1040
|
]
|
923
1041
|
|
924
|
-
view_relationships_filter: List[Callable[[Workspace, Relationship], bool]] = [
|
1042
|
+
view_relationships_filter: List[Union[DslElement, Callable[[Workspace, Relationship], bool]]] = [
|
925
1043
|
lambda w, r: container == r.source.parent,
|
926
1044
|
lambda w, r: container == r.destination.parent,
|
927
1045
|
]
|
@@ -971,10 +1089,10 @@ class Views(DslViewsElement):
|
|
971
1089
|
self._parent = workspace
|
972
1090
|
self._parent._m.views = self._m
|
973
1091
|
|
974
|
-
def
|
1092
|
+
def add_views(
|
975
1093
|
self,
|
976
1094
|
*views: DslViewElement
|
977
|
-
) ->
|
1095
|
+
) -> None:
|
978
1096
|
|
979
1097
|
for view in views:
|
980
1098
|
if isinstance(view, SystemLandscapeView):
|
@@ -1008,8 +1126,6 @@ class Views(DslViewsElement):
|
|
1008
1126
|
else:
|
1009
1127
|
raise NotImplementedError("The view {0} is currently not supported", type(view))
|
1010
1128
|
|
1011
|
-
return _FluentSink(self._parent)
|
1012
|
-
|
1013
1129
|
def get_workspace(self) -> Workspace:
|
1014
1130
|
"""
|
1015
1131
|
Get the `Workspace` which contain this views definition.
|