11from ngcsimlib .utils import make_unique_path , check_attributes , check_serializable , load_from_path
22from ngcsimlib .logger import warn , info
33from ngcsimlib .utils import get_compartment_by_name , \
4- get_context , add_context , get_current_path , get_current_context , set_new_context
4+ get_context , add_context , get_current_path , get_current_context , set_new_context , load_module , is_pre_loaded
5+ from ngcsimlib import preload_modules
56from ngcsimlib .compilers .command_compiler import dynamic_compile , wrap_command
67import json , os
78
@@ -75,13 +76,15 @@ def __exit__(self, exc_type, exc_val, exc_tb):
7576 """
7677 set_new_context (self ._last_context )
7778
78- def get_components (self , * component_names ):
79+ def get_components (self , * component_names , unwrap = True ):
7980 """
8081 Gets all the components by name in a context
8182
8283 Args:
8384 component_names: an arbitrary list of component names to get
8485
86+ unwrap: return just the component not a list of length 1 if only a single component is retrieved
87+
8588 Returns:
8689 either a list of components or a single component depending on the number of components being retrieved
8790 """
@@ -93,7 +96,7 @@ def get_components(self, *component_names):
9396 _components .append (self .components [a ])
9497 else :
9598 warn (f"Could not fine a component with the name \" { a } \" in the context" )
96- return _components if len (component_names ) > 1 else _components [0 ]
99+ return _components if len (component_names ) > 1 or not unwrap else _components [0 ]
97100
98101 def register_op (self , op ):
99102 """
@@ -119,7 +122,7 @@ def register_command(self, klass, *args, components=None, command_name=None, **k
119122
120123 kwargs: the keyword arguments passed into the command
121124 """
122- _components = [components .name for components in components ]
125+ _components = [component .name for component in components ]
123126 self ._json_objects ['commands' ][command_name ] = {"class" : klass , "components" : _components , "args" : args ,
124127 "kwargs" : kwargs }
125128
@@ -208,6 +211,9 @@ def save_to_json(self, directory, model_name=None, custom_save=True):
208211 """
209212 path = make_unique_path (directory , model_name )
210213
214+ with open (path + "/modules.json" , "w" ) as fp :
215+ json .dump (self .make_modules (), fp , indent = 4 )
216+
211217 with open (path + "/ops.json" , 'w' ) as fp :
212218 json .dump (self ._json_objects ['ops' ], fp , indent = 4 )
213219
@@ -278,6 +284,11 @@ def load_from_dir(self, directory, custom_folder="/custom"):
278284 custom_folder: The name of the custom data folder for building
279285 components. (Default: `/custom`)
280286 """
287+
288+ if os .path .isfile (directory + "/modules.json" ) and not is_pre_loaded ():
289+ info ("No modules file loaded, loading from model directory" )
290+ preload_modules (path = directory + "/modules.json" )
291+
281292 self .make_components (directory + "/components.json" , directory + custom_folder )
282293 self .make_ops (directory + "/ops.json" )
283294 self .make_commands (directory + "/commands.json" )
@@ -345,14 +356,15 @@ def make_commands(self, path_to_commands_file):
345356 if command ['class' ] == "dynamic_compiled" :
346357 if len (command ['components' ]) > 1 :
347358 self .compile_by_key (
348- * self .get_components (* command ['components' ]), compile_key = command ['compile_key' ], name = c_name )
359+ * self .get_components (* command ['components' ], unwrap = False ), compile_key = command ['compile_key' ],
360+ name = c_name )
349361 else :
350362 self .compile_by_key (
351- self .get_components (* command ['components' ]), compile_key = command ['compile_key' ],
363+ self .get_components (* command ['components' ], unwrap = False ), compile_key = command ['compile_key' ],
352364 name = c_name )
353365 else :
354366 klass = load_from_path (command ['class' ])
355- klass (* command ['args' ], ** command ['kwargs' ], components = self .get_components (* command ['components' ]),
367+ klass (* command ['args' ], ** command ['kwargs' ], components = self .get_components (* command ['components' ], unwrap = False ),
356368 command_name = c_name )
357369
358370 def _make_op (self , op_spec ):
@@ -425,3 +437,54 @@ def wrap_and_add_command(self, command, name=None):
425437 name: The name of the command (default: None)
426438 """
427439 self .add_command (wrap_command (command ), name = name )
440+
441+ def make_modules (self ):
442+ modules = {}
443+ jComponents = self ._json_objects ['components' ]
444+ for c_path , c in jComponents .items ():
445+ mod = load_module (c ["class" ]).__name__
446+
447+ module = "." .join (mod .split ("." )[:- 1 ])
448+ klass = c ["class" ]
449+
450+ if module not in modules .keys ():
451+ modules [module ] = {"attributes" : []}
452+
453+ if klass not in map (lambda x : x ["name" ], modules [module ]["attributes" ]):
454+ modules [module ]["attributes" ].append ({"name" : klass })
455+
456+ jOperators = self ._json_objects ['ops' ]
457+ for o in jOperators :
458+ mod = load_module (o ["class" ]).__name__
459+
460+ module = "." .join (mod .split ("." )[:- 1 ])
461+ klass = o ["class" ]
462+
463+ if module not in modules .keys ():
464+ modules [module ] = {"attributes" : []}
465+
466+ if klass not in map (lambda x : x ["name" ], modules [module ]["attributes" ]):
467+ modules [module ]["attributes" ].append ({"name" : klass })
468+
469+
470+ jCommands = self ._json_objects ['commands' ]
471+ for c_name , c in jCommands .items ():
472+ if c ["class" ] == "dynamic_compiled" :
473+ continue
474+
475+ mod = load_module (c ["class" ]).__name__
476+
477+ module = "." .join (mod .split ("." )[:- 1 ])
478+ klass = c ["class" ]
479+
480+ if module not in modules .keys ():
481+ modules [module ] = {"attributes" : []}
482+
483+ if klass not in map (lambda x : x ["name" ], modules [module ]["attributes" ]):
484+ modules [module ]["attributes" ].append ({"name" : klass })
485+
486+ _modules = []
487+ for key , value in modules .items ():
488+ _modules .append ({"absolute_path" : key , "attributes" : value ["attributes" ]})
489+
490+ return _modules
0 commit comments