1+ from functools import partial
2+ from pathlib import Path
3+ from urllib .request import urlretrieve
4+
5+ import yaml
6+ from diagrams import Cluster , Diagram
7+ from diagrams .aws .compute import Outposts , EC2 , AutoScaling
8+ from diagrams .aws .cost import CostExplorer
9+ from diagrams .aws .database import Timestream , Redshift
10+ from diagrams .aws .management import CommandLineInterface
11+ from diagrams .custom import Custom
12+
13+ root_dir = Path (__file__ ).parent .parent .parent .parent
14+
15+ source_nodes = {
16+ 'pyhdx' : Timestream ,
17+ 'pdb' : Redshift
18+ }
19+
20+ transform_nodes = {
21+ 'table_source' : Outposts ,
22+ 'cross_section' : AutoScaling ,
23+ }
24+ TRANSFORM_DEFAULT = EC2
25+
26+ opts_nodes = {}
27+
28+ OPTS_DEFAULT = CostExplorer
29+
30+ view_nodes = {
31+ 'ngl_colors' : partial (Custom , icon_path = 'molstar.png' ),
32+ 'logging' : CommandLineInterface
33+ }
34+
35+ hv_logo_url = 'https://holoviews.org/_static/logo.png'
36+ hv_icon = "holoviews.png"
37+ urlretrieve (hv_logo_url , hv_icon )
38+ VIEW_DEFAULT = partial (Custom , icon_path = hv_icon )
39+
40+ sources = {}
41+ transforms = {}
42+ opts = {}
43+ views = {}
44+
45+ cluster_attr = {
46+ "fontsize" : "20" ,
47+ "bgcolor" : "#e3e5e6" ,
48+ }
49+
50+ diagram_attr = {
51+ # 'nodesep': '0.5',
52+ 'layout' : 'dot' ,
53+ # 'pack': 'true',
54+ # 'clusterrank': 'local',
55+ # 'packMode': 'clust'
56+ }
57+
58+
59+ def make_diagram (name , yaml_dict ):
60+ add_opts = False # adding opts make the resulting scheme a bit messy
61+ opt_connections = []
62+
63+ with Diagram (name , show = False , outformat = 'png' , graph_attr = diagram_attr ):
64+ for src_name , spec in yaml_dict .get ('sources' , None ).items ():
65+ node = source_nodes [spec ['type' ]]
66+ src = node (src_name )
67+ sources [src_name ] = src
68+
69+ for trs_name , spec in yaml_dict .get ('transforms' , None ).items ():
70+ node = transform_nodes .get (spec ['type' ], TRANSFORM_DEFAULT )
71+ trs = node (trs_name )
72+ transforms [trs_name ] = trs
73+ if 'source' in spec :
74+ source = sources .get (spec ['source' ]) or transforms .get (spec ['source' ])
75+ source >> trs
76+
77+ # repeated code!
78+ for view_name , spec in yaml_dict .get ('views' , {}).items ():
79+ node = view_nodes .get (spec ['type' ], VIEW_DEFAULT )
80+ view = node (view_name )
81+ views [view_name ] = view
82+ if 'source' in spec :
83+ source = sources .get (spec ['source' ]) or transforms .get (spec ['source' ])
84+ source >> view
85+ elif 'sources' in spec :
86+ for src_id , src_name in spec ['sources' ].items ():
87+ source = sources .get (src_name ) or transforms .get (src_name )
88+ source >> view
89+ elif 'views' in spec :
90+ for component_view_name in spec ['views' ]:
91+ component_view = views .get (component_view_name )
92+ component_view >> view
93+ if add_opts and 'opts' in spec :
94+ for opt_name in spec ['opts' ]:
95+ if isinstance (opt_name , dict ):
96+ pass
97+ else :
98+ try :
99+ opt = opts [opt_name ]
100+ view << opt
101+ except KeyError :
102+ opt_connections .append ((opt_name , view ))
103+
104+ for module_name , module_spec in yaml_dict ['modules' ].items ():
105+ with Cluster (module_name , graph_attr = cluster_attr ):
106+ for src_name , spec in module_spec .get ('sources' , {}).items ():
107+ node = source_nodes [spec ['type' ]]
108+ src = node (src_name )
109+ sources [src_name ] = src
110+
111+ for trs_name , spec in module_spec .get ('transforms' , {}).items ():
112+ node = transform_nodes .get (spec ['type' ], TRANSFORM_DEFAULT )
113+ trs = node (trs_name )
114+ transforms [trs_name ] = trs
115+ if 'source' in spec :
116+ source = sources .get (spec ['source' ]) or transforms .get (spec ['source' ])
117+ source >> trs
118+
119+ if add_opts :
120+ for opt_name , spec in module_spec .get ('opts' , {}).items ():
121+ node = opts_nodes .get (spec ['type' ], OPTS_DEFAULT )
122+ opt = node (opt_name )
123+ opts [opt_name ] = opt
124+
125+ for view_name , spec in module_spec .get ('views' , {}).items ():
126+ node = view_nodes .get (spec ['type' ], VIEW_DEFAULT )
127+ view = node (view_name )
128+ views [view_name ] = view
129+ if 'source' in spec :
130+ source = sources .get (spec ['source' ]) or transforms .get (spec ['source' ])
131+ source >> view
132+ elif 'sources' in spec :
133+ for src_id , src_name in spec ['sources' ].items ():
134+ source = sources .get (src_name ) or transforms .get (src_name )
135+ source >> view
136+ elif 'views' in spec :
137+ for component_view_name in spec ['views' ]:
138+ component_view = views .get (component_view_name )
139+ component_view >> view
140+ if add_opts and 'opts' in spec :
141+ for opt_name in spec ['opts' ]:
142+ if isinstance (opt_name , dict ):
143+ pass
144+ else :
145+ try :
146+ opt = opts [opt_name ]
147+ view << opt
148+ except KeyError :
149+ opt_connections .append ((opt_name , view ))
150+
151+ if add_opts :
152+ with Cluster ('Opts' ):
153+ for opt_name , spec in yaml_dict ['opts' ].items ():
154+ node = opts_nodes .get (spec ['type' ], OPTS_DEFAULT )
155+ opt = node (opt_name )
156+ opts [opt_name ] = opt
157+
158+ for opt_name , view in opt_connections :
159+ view << opts [opt_name ]
160+
161+
162+ if __name__ == '__main__' :
163+ app_names = ['PyHDX_main_application' , 'PyHDX_rfu' ]
164+ app_files = ['pyhdx_app.yaml' , 'rfu_app.yaml' ]
165+
166+ d = {}
167+ for name , file in zip (app_names , app_files ):
168+ yaml_dir = root_dir / 'pyhdx' / 'web' / 'apps' / file
169+ yaml_str = yaml_dir .read_text (encoding = 'utf-8' )
170+ d [name ] = yaml .safe_load (yaml_str )
171+
172+ for name , yaml_dict in d .items ():
173+ make_diagram (name , yaml_dict )
0 commit comments