40
40
gen_link_text ,
41
41
gen_struct_element ,
42
42
get_impl_comp_from_real_iface ,
43
- get_interface ,
43
+ get_interface_from_component ,
44
+ get_interface_from_int ,
44
45
get_logical_interface_real ,
46
+ get_module ,
45
47
get_real_interface_logical ,
46
48
)
47
49
@@ -81,12 +83,83 @@ def scripts_directory_hash():
81
83
# ╰──────────────────────────────────────────────────────────────────────────────╯
82
84
83
85
84
- def draw_component (
85
- need : dict ,
86
- all_needs : dict ,
87
- proc_real_interfaces : dict [str , str ] | None = None ,
88
- proc_logical_interfaces : dict [str , str ] | None = None ,
89
- ) -> tuple [str , str , dict [str , str ], dict [str , str ]]:
86
+ def draw_comp_incl_impl_int (
87
+ need : dict [str , str ],
88
+ all_needs : dict [str , dict ],
89
+ proc_impl_interfaces : dict [str , str ],
90
+ proc_used_interfaces : dict [str , list ],
91
+ ) -> tuple [str , str , dict [str , str ], dict [str , list ]]:
92
+ # Draw outer component
93
+ structure_text = f"{ gen_struct_element ('component' , need )} {{\n "
94
+ linkage_text = ""
95
+
96
+ # Draw inner (sub)components recursively
97
+ for need_inc in need .get ("includes" , []):
98
+ curr_need = all_needs .get (need_inc , {})
99
+
100
+ # check for misspelled include
101
+ if not curr_need :
102
+ logger .info (f"{ need } : include { need_inc } could not be found" )
103
+ continue
104
+
105
+ if curr_need ["type" ] != "comp_arc_sta" :
106
+ continue
107
+
108
+ sub_structure , sub_linkage , proc_impl_interfaces , proc_used_interfaces = (
109
+ draw_comp_incl_impl_int (
110
+ curr_need , all_needs , proc_impl_interfaces , proc_used_interfaces
111
+ )
112
+ )
113
+
114
+ structure_text += sub_structure
115
+ linkage_text += sub_linkage
116
+
117
+ # close outer component
118
+ structure_text += f"}} /' { need ['title' ]} '/ \n \n "
119
+
120
+ # Find implemented real interfaces inside the module/component
121
+ local_impl_interfaces = get_interface_from_component (need , "implements" , all_needs )
122
+ local_used_interfaces = get_interface_from_component (need , "uses" , all_needs )
123
+
124
+ # Add all interfaces which are implemented by component to global list
125
+ # and provide implementation
126
+ for iface in local_impl_interfaces :
127
+ # check for misspelled implements
128
+ if not all_needs .get (iface , []):
129
+ logger .info (f"{ need } : implements { iface } could not be found" )
130
+ continue
131
+
132
+ if not (interface := proc_impl_interfaces .get (iface , [])):
133
+ structure_text += gen_interface_element (iface , all_needs , True )
134
+ linkage_text += f"{
135
+ gen_link_text (
136
+ need ,
137
+ '-u->' ,
138
+ all_needs [iface ],
139
+ 'implements' ,
140
+ )
141
+ } \n "
142
+ proc_impl_interfaces [iface ] = need ["id" ]
143
+
144
+ # Add all elements which are used by component to global list
145
+ for iface in local_used_interfaces :
146
+ # check for misspelled used
147
+ if not all_needs .get (iface , []):
148
+ logger .info (f"{ need } : uses { iface } could not be found" )
149
+ continue
150
+
151
+ if not (interface := proc_used_interfaces .get (iface , [])):
152
+ proc_used_interfaces [iface ] = [need ["id" ]]
153
+ else :
154
+ proc_used_interfaces [iface ].append (need ["id" ])
155
+
156
+ return structure_text , linkage_text , proc_impl_interfaces , proc_used_interfaces
157
+
158
+
159
+ def draw_module (
160
+ need : dict [str , str ],
161
+ all_needs : dict [str , dict ],
162
+ ) -> tuple [str , str ]:
90
163
"""
91
164
Drawing and parsing function of a component.
92
165
@@ -139,76 +212,99 @@ def draw_component(
139
212
(Structure Text, Linkage Text, Processed (Real Interfaces),
140
213
Processed Logical Interfaces)
141
214
"""
142
- proc_real_interfaces = proc_real_interfaces or dict ()
143
- proc_logical_interfaces = proc_logical_interfaces or dict ()
215
+ # Store all Elements which have already been processed
216
+ proc_impl_interfaces = dict ()
217
+ proc_used_interfaces = dict ()
218
+ proc_logical_interfaces = dict ()
219
+
144
220
linkage_text = ""
145
221
146
- # Draw outer component
147
- structure_text = f"{ gen_struct_element ('component ' , need )} {{\n "
222
+ # Draw outer module
223
+ structure_text = f"{ gen_struct_element ('package ' , need )} {{\n "
148
224
149
- # Process includes: Draw inner (sub) components recursively
225
+ # Draw inner components recursively
150
226
for need_inc in need .get ("includes" , []):
151
- curr_need = all_needs [ need_inc ]
227
+ curr_need = all_needs . get ( need_inc , {})
152
228
153
- if "comp_arc_sta" in curr_need ["type" ]:
154
- sub_structure , sub_links , proc_real_interfaces , proc_logical_interfaces = (
155
- draw_component (
156
- curr_need , all_needs , proc_real_interfaces , proc_logical_interfaces
157
- )
158
- )
159
- else :
229
+ # check for misspelled include
230
+ if not curr_need :
231
+ logger .info (f"{ need } : include { need_inc } could not be found" )
160
232
continue
161
233
234
+ if curr_need ["type" ] not in ["comp_arc_sta" , "mod_view_sta" ]:
235
+ continue
236
+
237
+ sub_structure , sub_linkage , proc_impl_interfaces , proc_used_interfaces = (
238
+ draw_comp_incl_impl_int (
239
+ curr_need , all_needs , proc_impl_interfaces , proc_used_interfaces
240
+ )
241
+ )
242
+
162
243
structure_text += sub_structure
163
- linkage_text += sub_links
244
+ linkage_text += sub_linkage
164
245
165
- # close component
246
+ # close outer component
166
247
structure_text += f"}} /' { need ['title' ]} '/ \n \n "
167
248
168
- local_interfaces = dict ()
169
- # Fill proc_real_interfaces with relation to implements and uses
170
- for interface in need .get ("implements" , []):
171
- iface = get_interface (interface , all_needs )
172
- if iface not in local_interfaces :
173
- local_interfaces [iface ] = "implements"
174
-
175
- for interface in need .get ("uses" , []):
176
- iface = get_interface (interface , all_needs )
177
- if iface not in local_interfaces :
178
- local_interfaces [iface ] = "uses"
179
-
180
- for iface in local_interfaces :
181
- # Draw interfaces
182
- if iface not in proc_real_interfaces :
183
- structure_text += gen_interface_element (iface , all_needs , True )
184
- proc_logical_interfaces [iface ] = get_logical_interface_real (
185
- iface , all_needs
186
- )
187
- proc_real_interfaces [iface ] = local_interfaces [iface ]
249
+ # Add logical interfaces only to implemented interfaces
250
+ for iface , component in proc_impl_interfaces .items ():
251
+ if not (proc_logical_interfaces .get (iface , [])):
252
+ # Currently only one Logical Interface per Real Interface supported
253
+ logical_iface_tmp = get_logical_interface_real (iface , all_needs )
254
+ assert (
255
+ len (logical_iface_tmp ) == 1
256
+ ), "only one logical interface per real interface supported"
257
+ if logical_iface_tmp :
258
+ logical_iface = logical_iface_tmp [0 ]
259
+ proc_logical_interfaces [logical_iface ] = iface
260
+
261
+ structure_text += gen_interface_element (logical_iface , all_needs , True )
262
+
263
+ linkage_text += f"{
264
+ gen_link_text (
265
+ all_needs [iface ],
266
+ '-u->' ,
267
+ all_needs [logical_iface ],
268
+ 'implements' ,
269
+ )
270
+ } \n "
271
+ else :
272
+ print (f"{ iface } : Not connected to any virtual interface" )
188
273
189
- # Draw connection between real components and interfaces
190
- linkage_text += f"{
191
- gen_link_text (
192
- need ['title' ], '-->' , all_needs [iface ]['title' ], local_interfaces [iface ]
193
- )
194
- } \n "
274
+ # Add all interfaces which are used by component
275
+ for iface , comps in proc_used_interfaces .items ():
276
+ if iface not in proc_impl_interfaces :
277
+ # Add implementing components and modules
278
+ impl_comp_str = get_impl_comp_from_real_iface (iface , all_needs )
195
279
196
- # Draw connection between real interfaces and logical interfaces
197
- # if link exists
198
- if interfaces := proc_logical_interfaces [iface ]:
199
- linkage_text += f"{
200
- gen_link_text (
201
- all_needs [iface ]['title' ],
202
- '-->' ,
203
- all_needs [interfaces ]['title' ],
204
- 'implements' ,
205
- )
206
- } \n "
280
+ impl_comp = all_needs .get (impl_comp_str , {}) if impl_comp_str else ""
281
+
282
+ if impl_comp :
283
+ retval = get_module (impl_comp_str , all_needs )
284
+ structure_text += retval [2 ] # module open
285
+ structure_text += retval [0 ] # rest open
286
+
287
+ structure_text += retval [1 ] # rest close
288
+ structure_text += gen_interface_element (iface , all_needs , True )
289
+ structure_text += retval [3 ] # module close
290
+
291
+ # Draw connection between implementing components and interface
292
+ linkage_text += f"{ gen_link_text (impl_comp , '-u->' , all_needs [iface ], 'implements' )} \n "
293
+
294
+ else :
295
+ # Add only interface if component not defined
296
+ print (f"{ iface } : No implementing component defined" )
297
+ structure_text += gen_interface_element (iface , all_needs , True )
298
+
299
+ # Interface can be used by multiple components
300
+ for comp in comps :
301
+ # Draw connection between used interfaces and components
302
+ linkage_text += f"{ gen_link_text (all_needs [comp ], '-d[#green]->' , all_needs [iface ], 'uses' )} \n "
207
303
208
304
# Remove duplicate links
209
305
linkage_text = "\n " .join (set (linkage_text .split ("\n " ))) + "\n "
210
306
211
- return structure_text , linkage_text , proc_real_interfaces , proc_logical_interfaces
307
+ return structure_text , linkage_text
212
308
213
309
214
310
# ╭──────────────────────────────────────────────────────────────────────────────╮
@@ -224,49 +320,55 @@ def __call__(self, need, all_needs: dict) -> str:
224
320
interfacelist = []
225
321
impl_comp = dict ()
226
322
227
- structure_text = "allowmixing\n "
228
- structure_text += f'actor "Feature User" as { gen_alias ("Feature User" )} \n '
323
+ structure_text = (
324
+ f'actor "Feature User" as { gen_alias ({"id" : "Feature_User" })} \n '
325
+ )
229
326
230
327
# Define Feature as a package
231
- structure_text += f"{ gen_struct_element ('package' , need )} {{\n "
328
+ # structure_text += f"{gen_struct_element('package', need)} {{\n"
232
329
233
330
# Add logical Interfaces / Interface Operations (aka includes)
234
331
for need_inc in need .get ("includes" , []):
235
332
# Generate list of interfaces since both interfaces
236
333
# and interface operations can be included
237
- iface = get_interface (need_inc , all_needs )
238
- interfacelist .append (iface ) if iface not in interfacelist else None
334
+ iface = get_interface_from_int (need_inc , all_needs )
335
+ if iface not in interfacelist :
336
+ interfacelist .append (iface )
239
337
240
338
for iface in interfacelist :
241
339
structure_text += gen_interface_element (iface , all_needs , True )
242
340
243
341
# Determine Components which implement the interfaces
244
342
real_iface = get_real_interface_logical (iface , all_needs )
245
- impl_comp [iface ] = get_impl_comp_from_real_iface (real_iface [0 ], all_needs )
343
+ if real_iface :
344
+ comps = get_impl_comp_from_real_iface (real_iface [0 ], all_needs )
246
345
247
- if imcomp := impl_comp [iface ]:
346
+ if comps :
347
+ impl_comp [iface ] = comps
348
+
349
+ if imcomp := impl_comp .get (iface ):
248
350
structure_text += (
249
- f"{ gen_struct_element ('component' , all_needs [imcomp [ 0 ] ])} \n "
351
+ f"{ gen_struct_element ('component' , all_needs [imcomp ])} \n "
250
352
)
251
353
252
354
# Close Package
253
- structure_text += f"}} /' { need ['title' ]} '/ \n \n "
355
+ # structure_text += f"}} /' {need['title']} '/ \n\n"
254
356
255
357
link_text = ""
256
358
257
359
for iface in interfacelist :
258
360
# Add relation between Actor and Interfaces
259
361
link_text += f"{
260
- gen_link_text ('Feature User' , '-d->' , all_needs [iface ][ 'title' ], 'use' )
362
+ gen_link_text ({ 'id' : 'Feature_User' } , '-d->' , all_needs [iface ], 'use' )
261
363
} \n "
262
364
263
365
# Add relation between interface and component
264
- if imcomp := impl_comp [ iface ] :
366
+ if imcomp := impl_comp . get ( iface ) :
265
367
link_text += f"{
266
368
gen_link_text (
267
- all_needs [imcomp [ 0 ]][ 'title' ],
268
- '-->' ,
269
- all_needs [iface ][ 'title' ] ,
369
+ all_needs [imcomp ],
370
+ '-u ->' ,
371
+ all_needs [iface ],
270
372
'implements' ,
271
373
)
272
374
} \n "
@@ -276,20 +378,25 @@ def __call__(self, need, all_needs: dict) -> str:
276
378
return gen_header () + structure_text + link_text
277
379
278
380
381
+ class draw_full_module :
382
+ def __repr__ (self ):
383
+ return "draw_full_module" + " in " + scripts_directory_hash ()
384
+
385
+ def __call__ (self , need , all_needs ) -> str :
386
+ structure_text , linkage_text = draw_module (need , all_needs )
387
+
388
+ return gen_header () + structure_text + linkage_text
389
+
390
+
279
391
class draw_full_component :
280
392
def __repr__ (self ):
281
393
return "draw_full_component" + " in " + scripts_directory_hash ()
282
394
283
395
def __call__ (self , need , all_needs ) -> str :
284
396
structure_text , linkage_text , processed_interfaces , logical_interfacelist = (
285
- draw_component (need , all_needs , dict (), dict ())
397
+ draw_comp_incl_impl_int (need , all_needs , dict (), dict ())
286
398
)
287
399
288
- # Draw Logical Interfaces
289
- for iface in logical_interfacelist :
290
- if log_int := logical_interfacelist [iface ]:
291
- structure_text += gen_interface_element (log_int , all_needs , True )
292
-
293
400
return gen_header () + structure_text + linkage_text
294
401
295
402
@@ -305,6 +412,7 @@ def __call__(self, need, all_needs) -> str:
305
412
306
413
draw_uml_function_context = {
307
414
"draw_interface" : draw_full_interface (),
415
+ "draw_module" : draw_full_module (),
308
416
"draw_component" : draw_full_component (),
309
417
"draw_feature" : draw_full_feature (),
310
418
}
0 commit comments