buildzr 0.0.4__py3-none-any.whl → 0.0.6__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 +26 -34
- buildzr/dsl/interfaces/__init__.py +2 -0
- buildzr/dsl/interfaces/interfaces.py +37 -0
- buildzr/sinks/__init__.py +0 -0
- buildzr/sinks/interfaces.py +18 -0
- buildzr/sinks/json_sink.py +24 -0
- {buildzr-0.0.4.dist-info → buildzr-0.0.6.dist-info}/METADATA +5 -6
- {buildzr-0.0.4.dist-info → buildzr-0.0.6.dist-info}/RECORD +11 -8
- {buildzr-0.0.4.dist-info → buildzr-0.0.6.dist-info}/WHEEL +1 -1
- {buildzr-0.0.4.dist-info → buildzr-0.0.6.dist-info}/licenses/LICENSE.md +0 -0
buildzr/__about__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION = "0.0.
|
1
|
+
VERSION = "0.0.6"
|
buildzr/dsl/dsl.py
CHANGED
@@ -26,10 +26,14 @@ from typing import (
|
|
26
26
|
Type,
|
27
27
|
)
|
28
28
|
|
29
|
+
from buildzr.sinks.interfaces import Sink
|
30
|
+
|
29
31
|
from buildzr.dsl.interfaces import (
|
30
32
|
DslWorkspaceElement,
|
31
33
|
DslElement,
|
34
|
+
DslViewElement,
|
32
35
|
DslViewsElement,
|
36
|
+
DslFluentSink,
|
33
37
|
TSrc, TDst,
|
34
38
|
TParent, TChild,
|
35
39
|
)
|
@@ -45,20 +49,6 @@ from buildzr.dsl.relations import (
|
|
45
49
|
def _child_name_transform(name: str) -> str:
|
46
50
|
return name.lower().replace(' ', '_')
|
47
51
|
|
48
|
-
# TODO: Remove, not used.
|
49
|
-
# def _create_linked_relationship_from(
|
50
|
-
# relationship: '_Relationship[TSrc, TDst]') -> buildzr.models.Relationship:
|
51
|
-
|
52
|
-
# src = relationship.source
|
53
|
-
# dst = relationship.destination
|
54
|
-
|
55
|
-
# return buildzr.models.Relationship(
|
56
|
-
# id=GenerateId.for_relationship(),
|
57
|
-
# sourceId=str(src.model.id),
|
58
|
-
# destinationId=str(dst.parent.model.id),
|
59
|
-
# linkedRelationshipId=relationship.model.id,
|
60
|
-
# )
|
61
|
-
|
62
52
|
TypedModel = TypeVar('TypedModel')
|
63
53
|
class TypedDynamicAttribute(Generic[TypedModel]):
|
64
54
|
|
@@ -197,7 +187,7 @@ class Workspace(DslWorkspaceElement):
|
|
197
187
|
'ContainerView',
|
198
188
|
'ComponentView',
|
199
189
|
]
|
200
|
-
) -> '
|
190
|
+
) -> '_FluentSink':
|
201
191
|
return Views(self).contains(*views)
|
202
192
|
|
203
193
|
def __getattr__(self, name: str) -> Union['Person', 'SoftwareSystem']:
|
@@ -487,6 +477,16 @@ class Group:
|
|
487
477
|
self._name = name
|
488
478
|
self._elements = elements
|
489
479
|
|
480
|
+
class _FluentSink(DslFluentSink):
|
481
|
+
|
482
|
+
def __init__(self, workspace: Workspace) -> None:
|
483
|
+
self._workspace = workspace
|
484
|
+
|
485
|
+
def to_json(self, path: str) -> None:
|
486
|
+
from buildzr.sinks.json_sink import JsonSink, JsonSinkConfig
|
487
|
+
sink = JsonSink()
|
488
|
+
sink.write(workspace=self._workspace.model, config=JsonSinkConfig(path=path))
|
489
|
+
|
490
490
|
_RankDirection = Literal['tb', 'bt', 'lr', 'rl']
|
491
491
|
|
492
492
|
_AutoLayout = Optional[
|
@@ -554,7 +554,7 @@ def _auto_layout_to_model(auto_layout: _AutoLayout) -> buildzr.models.AutomaticL
|
|
554
554
|
|
555
555
|
return model
|
556
556
|
|
557
|
-
class SystemLandscapeView:
|
557
|
+
class SystemLandscapeView(DslViewElement):
|
558
558
|
|
559
559
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
560
560
|
|
@@ -649,7 +649,7 @@ class SystemLandscapeView:
|
|
649
649
|
for relationship_id in relationship_ids:
|
650
650
|
self._m.relationships.append(RelationshipView(id=relationship_id))
|
651
651
|
|
652
|
-
class SystemContextView:
|
652
|
+
class SystemContextView(DslViewElement):
|
653
653
|
|
654
654
|
"""
|
655
655
|
If no filter is applied, this view includes all elements that have a direct
|
@@ -700,9 +700,6 @@ class SystemContextView:
|
|
700
700
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
701
701
|
from buildzr.models import ElementView, RelationshipView
|
702
702
|
|
703
|
-
# TODO: Refactor below codes. Similar patterns may exists for other views.
|
704
|
-
# Maybe make the views a subclass of some abstract `BaseView` class?
|
705
|
-
|
706
703
|
software_system = self._selector(self._parent._parent)
|
707
704
|
self._m.softwareSystemId = software_system.model.id
|
708
705
|
view_elements_filter: List[Callable[[Workspace, Element], bool]] = [
|
@@ -711,10 +708,6 @@ class SystemContextView:
|
|
711
708
|
lambda w, e: software_system.model.id in e.destinations.ids,
|
712
709
|
]
|
713
710
|
|
714
|
-
# TODO: (Or, TOTHINK?) The code below includes all sources and all
|
715
|
-
# destinations of the subject software system. What if we want to
|
716
|
-
# exclude a source? Maybe the predicates in `elements` and
|
717
|
-
# `relationships` should be ANDed together afterall?
|
718
711
|
view_relationships_filter: List[Callable[[Workspace, Relationship], bool]] = [
|
719
712
|
lambda w, r: software_system == r.source,
|
720
713
|
lambda w, r: software_system == r.destination,
|
@@ -747,7 +740,7 @@ class SystemContextView:
|
|
747
740
|
for relationship_id in relationship_ids:
|
748
741
|
self._m.relationships.append(RelationshipView(id=relationship_id))
|
749
742
|
|
750
|
-
class ContainerView:
|
743
|
+
class ContainerView(DslViewElement):
|
751
744
|
|
752
745
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
753
746
|
|
@@ -836,7 +829,7 @@ class ContainerView:
|
|
836
829
|
for relationship_id in relationship_ids:
|
837
830
|
self._m.relationships.append(RelationshipView(id=relationship_id))
|
838
831
|
|
839
|
-
class ComponentView:
|
832
|
+
class ComponentView(DslViewElement):
|
840
833
|
|
841
834
|
from buildzr.dsl.expression import Expression, Element, Relationship
|
842
835
|
|
@@ -945,34 +938,33 @@ class Views(DslViewsElement):
|
|
945
938
|
|
946
939
|
def contains(
|
947
940
|
self,
|
948
|
-
*views:
|
949
|
-
|
950
|
-
SystemContextView,
|
951
|
-
ContainerView,
|
952
|
-
ComponentView,
|
953
|
-
]) -> Self:
|
941
|
+
*views: DslViewElement
|
942
|
+
) -> _FluentSink:
|
954
943
|
|
955
944
|
for view in views:
|
956
|
-
view._parent = self
|
957
945
|
if isinstance(view, SystemLandscapeView):
|
946
|
+
view._parent = self
|
958
947
|
view._on_added()
|
959
948
|
if self._m.systemLandscapeViews:
|
960
949
|
self._m.systemLandscapeViews.append(view.model)
|
961
950
|
else:
|
962
951
|
self._m.systemLandscapeViews = [view.model]
|
963
952
|
elif isinstance(view, SystemContextView):
|
953
|
+
view._parent = self
|
964
954
|
view._on_added()
|
965
955
|
if self._m.systemContextViews:
|
966
956
|
self._m.systemContextViews.append(view.model)
|
967
957
|
else:
|
968
958
|
self._m.systemContextViews = [view.model]
|
969
959
|
elif isinstance(view, ContainerView):
|
960
|
+
view._parent = self
|
970
961
|
view._on_added()
|
971
962
|
if self._m.containerViews:
|
972
963
|
self._m.containerViews.append(view.model)
|
973
964
|
else:
|
974
965
|
self._m.containerViews = [view.model]
|
975
966
|
elif isinstance(view, ComponentView):
|
967
|
+
view._parent = self
|
976
968
|
view._on_added()
|
977
969
|
if self._m.componentViews:
|
978
970
|
self._m.componentViews.append(view.model)
|
@@ -981,7 +973,7 @@ class Views(DslViewsElement):
|
|
981
973
|
else:
|
982
974
|
raise NotImplementedError("The view {0} is currently not supported", type(view))
|
983
975
|
|
984
|
-
return self
|
976
|
+
return _FluentSink(self._parent)
|
985
977
|
|
986
978
|
def get_workspace(self) -> Workspace:
|
987
979
|
"""
|
@@ -199,6 +199,36 @@ class DslFluentRelationship(ABC, Generic[TParent]):
|
|
199
199
|
def get(self) -> TParent:
|
200
200
|
pass
|
201
201
|
|
202
|
+
class DslFluentSink(ABC):
|
203
|
+
|
204
|
+
@abstractmethod
|
205
|
+
def to_json(self, path: str) -> None:
|
206
|
+
pass
|
207
|
+
|
208
|
+
class DslViewElement(ABC):
|
209
|
+
|
210
|
+
ViewModel = Union[
|
211
|
+
buildzr.models.SystemLandscapeView,
|
212
|
+
buildzr.models.SystemContextView,
|
213
|
+
buildzr.models.ContainerView,
|
214
|
+
buildzr.models.ComponentView,
|
215
|
+
buildzr.models.DynamicView,
|
216
|
+
buildzr.models.DeploymentView,
|
217
|
+
]
|
218
|
+
|
219
|
+
@property
|
220
|
+
@abstractmethod
|
221
|
+
def model(self) -> ViewModel:
|
222
|
+
pass
|
223
|
+
|
224
|
+
@property
|
225
|
+
@abstractmethod
|
226
|
+
def parent(self) -> 'DslViewsElement':
|
227
|
+
pass
|
228
|
+
|
229
|
+
def _on_added(self) -> None:
|
230
|
+
pass
|
231
|
+
|
202
232
|
class DslViewsElement(ABC):
|
203
233
|
|
204
234
|
@property
|
@@ -209,4 +239,11 @@ class DslViewsElement(ABC):
|
|
209
239
|
@property
|
210
240
|
@abstractmethod
|
211
241
|
def parent(self) -> DslWorkspaceElement:
|
242
|
+
pass
|
243
|
+
|
244
|
+
@abstractmethod
|
245
|
+
def contains(
|
246
|
+
self,
|
247
|
+
*views: Union[DslViewElement],
|
248
|
+
) -> DslFluentSink:
|
212
249
|
pass
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from typing import (
|
2
|
+
Optional,
|
3
|
+
Any,
|
4
|
+
TypedDict,
|
5
|
+
TypeVar,
|
6
|
+
Generic,
|
7
|
+
)
|
8
|
+
from dataclasses import dataclass
|
9
|
+
from abc import ABC, abstractmethod
|
10
|
+
from buildzr.models.models import Workspace
|
11
|
+
|
12
|
+
TConfig = TypeVar('TConfig')
|
13
|
+
|
14
|
+
class Sink(ABC, Generic[TConfig]):
|
15
|
+
|
16
|
+
@abstractmethod
|
17
|
+
def write(self, workspace: Workspace, config: Optional[TConfig]=None) -> None:
|
18
|
+
pass
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from typing import (
|
2
|
+
Optional,
|
3
|
+
)
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from buildzr.models.models import Workspace
|
6
|
+
from buildzr.encoders.encoder import JsonEncoder
|
7
|
+
from buildzr.sinks.interfaces import Sink
|
8
|
+
|
9
|
+
@dataclass
|
10
|
+
class JsonSinkConfig:
|
11
|
+
path: str
|
12
|
+
|
13
|
+
class JsonSink(Sink[JsonSinkConfig]):
|
14
|
+
|
15
|
+
def write(self, workspace: Workspace, config: Optional[JsonSinkConfig]=None) -> None:
|
16
|
+
if config is not None:
|
17
|
+
with open(config.path, 'w') as file:
|
18
|
+
file.write(JsonEncoder().encode(workspace))
|
19
|
+
else:
|
20
|
+
import os
|
21
|
+
workspace_name = workspace.name.replace(' ', '_').lower()
|
22
|
+
|
23
|
+
with open(os.path.join(os.curdir, f'{workspace_name}.json'), 'w') as file:
|
24
|
+
file.write(JsonEncoder().encode(workspace))
|
@@ -1,11 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: buildzr
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.6
|
4
4
|
Summary: Structurizr for the `buildzr`s 🧱⚒️
|
5
5
|
Project-URL: homepage, https://github.com/amirulmenjeni/buildzr
|
6
6
|
Project-URL: issues, https://github.com/amirulmenjeni/buildzr/issues
|
7
7
|
Author-email: Amirul Menjeni <amirulmenjeni@pm.me>
|
8
|
-
License-File: LICENSE.md
|
9
8
|
Keywords: architecture,buildzr,c4model,design,diagram,structurizr
|
10
9
|
Classifier: Development Status :: 3 - Alpha
|
11
10
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -118,15 +117,15 @@ w = Workspace('w')\
|
|
118
117
|
)\
|
119
118
|
.get_workspace()
|
120
119
|
|
121
|
-
#
|
122
|
-
|
123
|
-
json.dump(w.model, f, ensure_ascii=False, indent=4, cls=JsonEncoder)
|
120
|
+
# Save workspace to a JSON file following the Structurizr JSON schema.
|
121
|
+
w.to_json('workspace.json')
|
124
122
|
```
|
125
123
|
|
126
124
|
Here's a short breakdown on what's happening:
|
127
125
|
- In `Workspace(...).contains(...)` method, we define the _static_ C4 models (i.e., `Person`, `SoftwareSystem`, and the `Container`s in the software system).
|
128
126
|
- In the `Workspace(...).contains(...).where(...)`, we define the relationships between the C4 models in the workspace. We access the models via the `w` parameter in the `lambda` function, and create the relationships using the `>>` operators.
|
129
|
-
-
|
127
|
+
- Once we have all the models and their relationships defined, we use (and re-use!) the static models to create multiple views to tell different stories and show various narrative to help document your software architecture.
|
128
|
+
- Finally, we write the workspace definitions into a JSON file, which can be consumed by rendering tools, or used for further processing.
|
130
129
|
|
131
130
|
The JSON output can be found [here](examples/system_context_and_container_view.json). You can also try out https://structurizr.com/json to see how this workspace will be rendered.
|
132
131
|
|
@@ -1,20 +1,23 @@
|
|
1
|
-
buildzr/__about__.py,sha256=
|
1
|
+
buildzr/__about__.py,sha256=zSWM6APnGVgRI-TIdUtzLBHHIR2hrWqWRT-LJJe2kbQ,17
|
2
2
|
buildzr/__init__.py,sha256=hY-cOdjBQcz0v2m8cBF1oEJFIbcR3sWI-xww--0RKSo,99
|
3
3
|
buildzr/dsl/__init__.py,sha256=paxuMCCDuOs1eSvBPyuW5pv5j1UZD6TxRZcCzC2iKss,307
|
4
|
-
buildzr/dsl/dsl.py,sha256=
|
4
|
+
buildzr/dsl/dsl.py,sha256=B3mBXhrOFrv59GMLr8T2mZmJB17vcFx6M06Dr_SlaH8,34218
|
5
5
|
buildzr/dsl/explorer.py,sha256=numMPqD3RYJ1oeMgX5wYnT6aHRHmBN2EsFZFYRuFffA,2523
|
6
6
|
buildzr/dsl/expression.py,sha256=UinOUL3nJytZR8ylnVtVkJ0YoWoWspU9DQeDpg0nIEQ,6927
|
7
7
|
buildzr/dsl/relations.py,sha256=nfj0EZIo0RpQxe7Ng-40WHBOVom_aE20-45GzWMEvII,13723
|
8
8
|
buildzr/dsl/factory/__init__.py,sha256=niaYqvNPUWJejoPyRyABUtzVsoxaV8eSjzS9dta4bMI,30
|
9
9
|
buildzr/dsl/factory/gen_id.py,sha256=LnaeOCMngSvYkcGnuARjQYoUVWdcOoNHO2EHe6PMGco,538
|
10
|
-
buildzr/dsl/interfaces/__init__.py,sha256=
|
11
|
-
buildzr/dsl/interfaces/interfaces.py,sha256=
|
10
|
+
buildzr/dsl/interfaces/__init__.py,sha256=z8d8HzL64m8aT_HHM3mCVZoNwh_QhsYv0apGz-EX9Us,268
|
11
|
+
buildzr/dsl/interfaces/interfaces.py,sha256=UfysJ1X0RQiPAEl_kBlcoxuWEO-kmg3c3gveN6klUG8,5885
|
12
12
|
buildzr/encoders/__init__.py,sha256=suID63Ay-023T0uKD25EAoGYmAMTa9AKxIjioccpiPM,32
|
13
13
|
buildzr/encoders/encoder.py,sha256=9_FlQ3aYvz0EcN_G9A3bPdqxCTkLhc2OrYXSYti95f8,2237
|
14
14
|
buildzr/models/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
|
15
15
|
buildzr/models/generate.sh,sha256=924UoEXr5WBZ926TZfRgEQGHwBqtLGU5k0G2UfExLEg,1061
|
16
16
|
buildzr/models/models.py,sha256=0LhLG1wmbt4dvROV5MEBZLLoxPbMpkUsOqNz525cynE,42489
|
17
|
-
buildzr
|
18
|
-
buildzr
|
19
|
-
buildzr
|
20
|
-
buildzr-0.0.
|
17
|
+
buildzr/sinks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
+
buildzr/sinks/interfaces.py,sha256=LOZekP4WNjomD5J5f3FnZTwGj0aXMr6RbrvyFV5zn0E,383
|
19
|
+
buildzr/sinks/json_sink.py,sha256=onKOZTpwOQfeMEj1ONkuIEHBAQhx4yQSqqI_lgZBaP8,777
|
20
|
+
buildzr-0.0.6.dist-info/METADATA,sha256=V253gn2ANdye9PzqG50OnZh6AivL-omfUuBY10ue8q8,6237
|
21
|
+
buildzr-0.0.6.dist-info/WHEEL,sha256=3U_NnUcV_1B1kPkYaPzN-irRckL5VW_lytn0ytO_kRY,87
|
22
|
+
buildzr-0.0.6.dist-info/licenses/LICENSE.md,sha256=e8e6W6tL4MbBY-c-gXMgDbaMf_BnaQDQv4Yoy42b-CI,1070
|
23
|
+
buildzr-0.0.6.dist-info/RECORD,,
|
File without changes
|