1+ """
2+ This is the file that contains the code to compile a given command on a model.
3+
4+ There are a few ways to compile the commands for a model, firstly if there is a command object already initialized
5+ that has a valid compile key and a list of components the base method of `compile_command(command)` can be used to produce
6+ the desired output. If no command object has been initialized then the `dynamic_compile(*components, compile_key=None)`
7+ can be used to produce the desired output without the need to first go through a command object. The output of either
8+ compile method will be the same.
9+
10+ The output produced by compiling a command will be two objects.
11+
12+ The first object produced by compiling a command is the compiled method itself. This method requires at least one
13+ positional argument and then any number of additional arguments. The first argument that is provided to the compiled
14+ method is a python dictionary that contains the state for all compartments this method will need to access,
15+ as discerning this can be a challenge it is normal to just pass it all compartments present on your model. The
16+ remaining list of arguments are all the run time arguments that the various compiled methods need to run properly.
17+ The return value of this compiled method is the final state of all compartments after running through the compiled
18+ command. Note here that the value on the compartments are not automatically updated and that will need to be done after.
19+
20+ The second object produced by compiling a command is the list of arguments that the compile command is expecting to
21+ be passed in alongside the initial state of all the compartments. It is a good habit to get into printing this list
22+ out after compiling as it can help catch typos present in the compiled methods that will not cause the compiling to
23+ fail but will produce unknown behavior.
24+
25+ There is a wrapper method offered in this file we recommend using to assist with the design patterned required by the
26+ compiled command. This is done with `wrap_command(command)`. This method will return another method that removes the
27+ need for creating the initial state of the compartments and setting all the compartment values after running. Arguments
28+ are still required to be passed in at run time.
29+
30+ """
131from ngcsimlib .compilers .component_compiler import parse as parse_component , compile as compile_component
232from ngcsimlib .compilers .op_compiler import parse as parse_connection
333from ngcsimlib .utils import Get_Compartment_Batch , Set_Compartment_Batch
4-
34+ from ngcsimlib . logger import critical
535
636def _compile (compile_key , components ):
37+ """
38+ This is the top level compile method for commands. Note this does not actually require you to compile a
39+ specific command object as it works purely off the compile key provided to the method.
40+ The general process that this takes to compile down everything, is by producing an execution order that knows which
41+ methods that are going to be called and where the results of the method are supposed to be stored.
42+
43+ The execution order is as follows:
44+
45+ For each component in the provided array of components;
46+ | compile it with the provided key
47+ | resolve the outputs of the compiled function
48+
49+ Args:
50+ compile_key: The key that is being compiled (mapped to each function that has the @resolver decorator
51+ above it)
52+
53+ components: The list of components to compile for this function
54+
55+ Returns:
56+ Produces the two objects described at the top of this file
57+ """
758 assert compile_key is not None
859 ## for each component, get compartments, get output compartments
960 resolvers = {}
@@ -30,15 +81,20 @@ def _compile(compile_key, components):
3081 path = str (component .__dict__ [comp ].path )
3182 if path not in needed_comps :
3283 needed_comps .append (path )
33- arg_order = needed_args + needed_comps
84+
3485 exc_order = []
3586 for c_name , component in components .items ():
36- exc_order .extend (compile_component (component , resolvers [c_name ], arg_order ))
87+ exc_order .extend (compile_component (component , resolvers [c_name ]))
88+
89+ def compiled (compartment_values , ** kwargs ):
90+ for n in needed_args :
91+ if n not in kwargs :
92+ critical (f"Missing keyword argument \" { n } \" in compiled function."
93+ f"\t Expected keyword arguments { needed_args } " )
3794
38- def compiled (compartment_values , * cargs ):
3995 for exc , outs , name in exc_order :
40- _comps = [ compartment_values [key ] for key in needed_comps ]
41- vals = exc (* cargs , * _comps )
96+ _comps = { key : compartment_values [key ] for key in needed_comps }
97+ vals = exc (** kwargs , * *_comps )
4298 if len (outs ) == 1 :
4399 compartment_values [outs [0 ]] = vals
44100 elif len (outs ) > 1 :
@@ -49,16 +105,49 @@ def compiled(compartment_values, *cargs):
49105 return compiled , needed_args
50106
51107
52- def compile (command ):
108+ def compile_command (command ):
109+ """
110+ Compiles a given command object to the spec described at the top of this file
111+
112+ Args:
113+ command: the command object
114+
115+ Returns:
116+ compiled_command, needed_arguments
117+
118+ """
53119 return _compile (command .compile_key , command .components )
54120
55121
56122def dynamic_compile (* components , compile_key = None ):
123+ """
124+ Dynamically compiles a command without the need of a command object to produce
125+ the spec described at the top of this file.
126+
127+ Args:
128+ *components: a list of components to be compiled
129+
130+ compile_key: the compile key specifying what to compile
131+
132+ Returns:
133+ compiled_command, needed_arguments
134+ """
57135 assert compile_key is not None
58136 return _compile (compile_key , {c .name : c for c in components })
59137
60138
61139def wrap_command (command ):
140+ """
141+ Wraps the provided command to provide the state of all compartments as input
142+ and saves the returned state to all compartments after running. Designed to
143+ be used with compiled commands
144+
145+ Args:
146+ command: the command to wrap
147+
148+ Returns:
149+ the output of the command after it's been executed
150+ """
62151 def _wrapped (* args ):
63152 vals = command (Get_Compartment_Batch (), * args )
64153 Set_Compartment_Batch (vals )
0 commit comments