@@ -127,10 +127,18 @@ def __init__(
127127 self ._runpath = runpath
128128 self ._model_name = modelname
129129 self ._timeout = timeout
130+
131+ # dictionaries of command line arguments for the model executable
130132 self ._args : dict [str , str | None ] = {}
133+ # 'override' argument needs special handling, as it is a dict on its own saved as dict elements following the
134+ # structure: 'key' => 'key=value'
131135 self ._arg_override : dict [str , str ] = {}
132136
133- def arg_set (self , key : str , val : Optional [str | dict [str , Any ]] = None ) -> None :
137+ def arg_set (
138+ self ,
139+ key : str ,
140+ val : Optional [str | dict [str , Any ] | numbers .Number ] = None ,
141+ ) -> None :
134142 """
135143 Set one argument for the executable model.
136144
@@ -140,12 +148,24 @@ def arg_set(self, key: str, val: Optional[str | dict[str, Any]] = None) -> None:
140148 indicates variables to override
141149 """
142150
143- def override2str (okey : str , oval : Any ) -> str :
151+ def override2str (
152+ okey : str ,
153+ oval : str | bool | numbers .Number ,
154+ ) -> str :
144155 """
145156 Convert a value for 'override' to a string taking into account differences between Modelica and Python.
146157 """
158+ # check oval for any string representations of numbers (or bool) and convert these to Python representations
159+ if isinstance (oval , str ):
160+ try :
161+ oval_evaluated = ast .literal_eval (oval )
162+ if isinstance (oval_evaluated , (numbers .Number , bool )):
163+ oval = oval_evaluated
164+ except (ValueError , SyntaxError ):
165+ pass
166+
147167 if isinstance (oval , str ):
148- oval_str = f" \" { oval .strip ()} \" " # TODO: use shlex.quote()?
168+ oval_str = oval .strip ()
149169 elif isinstance (oval , bool ):
150170 oval_str = 'true' if oval else 'false'
151171 elif isinstance (oval , numbers .Number ):
@@ -159,14 +179,32 @@ def override2str(okey: str, oval: Any) -> str:
159179 raise ModelicaSystemError (f"Invalid argument key: { repr (key )} (type: { type (key )} )" )
160180 key = key .strip ()
161181
162- if key == 'override' and isinstance (val , dict ):
163- for okey in val :
164- if not isinstance (okey , str ) or not isinstance (val [okey ], (str , bool , numbers .Number )):
165- raise ModelicaSystemError ("Invalid argument for 'override': "
166- f"{ repr (okey )} = { repr (val [okey ])} " )
167- self ._arg_override [okey ] = val [okey ]
182+ if isinstance (val , dict ):
183+ if key != 'override' :
184+ raise ModelicaSystemError ("Dictionary input only possible for key 'override'!" )
185+
186+ for okey , oval in val .items ():
187+ if not isinstance (okey , str ):
188+ raise ModelicaSystemError ("Invalid key for argument 'override': "
189+ f"{ repr (okey )} (type: { type (okey )} )" )
190+
191+ if not isinstance (oval , (str , bool , numbers .Number , type (None ))):
192+ raise ModelicaSystemError (f"Invalid input for 'override'.{ repr (okey )} : "
193+ f"{ repr (oval )} (type: { type (oval )} )" )
168194
169- argval = ',' .join ([override2str (okey = okey , oval = oval ) for okey , oval in self ._arg_override .items ()])
195+ if okey in self ._arg_override :
196+ if oval is None :
197+ logger .info (f"Remove model executable override argument: { repr (self ._arg_override [okey ])} " )
198+ del self ._arg_override [okey ]
199+ continue
200+
201+ logger .info (f"Update model executable override argument: { repr (okey )} = { repr (oval )} "
202+ f"(was: { repr (self ._arg_override [okey ])} )" )
203+
204+ if oval is not None :
205+ self ._arg_override [okey ] = override2str (okey = okey , oval = oval )
206+
207+ argval = ',' .join (sorted (self ._arg_override .values ()))
170208 elif val is None :
171209 argval = None
172210 elif isinstance (val , str ):
@@ -181,7 +219,7 @@ def override2str(okey: str, oval: Any) -> str:
181219 f"(was: { repr (self ._args [key ])} )" )
182220 self ._args [key ] = argval
183221
184- def arg_get (self , key : str ) -> Optional [str | dict ]:
222+ def arg_get (self , key : str ) -> Optional [str | dict [ str , str | bool | numbers . Number ] ]:
185223 """
186224 Return the value for the given key
187225 """
@@ -190,7 +228,10 @@ def arg_get(self, key: str) -> Optional[str | dict]:
190228
191229 return None
192230
193- def args_set (self , args : dict [str , Optional [str | dict [str , Any ]]]) -> None :
231+ def args_set (
232+ self ,
233+ args : dict [str , Optional [str | dict [str , Any ] | numbers .Number ]],
234+ ) -> None :
194235 """
195236 Define arguments for the model executable.
196237 """
@@ -203,7 +244,7 @@ def get_cmd_args(self) -> list[str]:
203244 """
204245
205246 cmdl = []
206- for key in self ._args :
247+ for key in sorted ( self ._args ) :
207248 if self ._args [key ] is None :
208249 cmdl .append (f"-{ key } " )
209250 else :
@@ -233,7 +274,7 @@ def definition(self) -> OMCSessionRunData:
233274 return omc_run_data_updated
234275
235276 @staticmethod
236- def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , str ] ]]:
277+ def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]:
237278 """
238279 Parse a simflag definition; this is deprecated!
239280
@@ -242,7 +283,7 @@ def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, str]]]:
242283 warnings .warn ("The argument 'simflags' is depreciated and will be removed in future versions; "
243284 "please use 'simargs' instead" , DeprecationWarning , stacklevel = 2 )
244285
245- simargs : dict [str , Optional [str | dict [str , str ] ]] = {}
286+ simargs : dict [str , Optional [str | dict [str , Any ] | numbers . Number ]] = {}
246287
247288 args = [s for s in simflags .split (' ' ) if s ]
248289 for arg in args :
@@ -935,7 +976,7 @@ def simulate_cmd(
935976 self ,
936977 result_file : OMCPath ,
937978 simflags : Optional [str ] = None ,
938- simargs : Optional [dict [str , Optional [str | dict [str , str ] ]]] = None ,
979+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]] = None ,
939980 timeout : Optional [float ] = None ,
940981 ) -> ModelicaSystemCmd :
941982 """
@@ -1014,7 +1055,7 @@ def simulate(
10141055 self ,
10151056 resultfile : Optional [str ] = None ,
10161057 simflags : Optional [str ] = None ,
1017- simargs : Optional [dict [str , Optional [str | dict [str , str ] ]]] = None ,
1058+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]] = None ,
10181059 timeout : Optional [float ] = None ,
10191060 ) -> None :
10201061 """Simulate the model according to simulation options.
@@ -1547,9 +1588,13 @@ def optimize(self) -> dict[str, Any]:
15471588
15481589 return optimizeResult
15491590
1550- def linearize (self , lintime : Optional [float ] = None , simflags : Optional [str ] = None ,
1551- simargs : Optional [dict [str , Optional [str | dict [str , str ]]]] = None ,
1552- timeout : Optional [float ] = None ) -> LinearizationResult :
1591+ def linearize (
1592+ self ,
1593+ lintime : Optional [float ] = None ,
1594+ simflags : Optional [str ] = None ,
1595+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers .Number ]]] = None ,
1596+ timeout : Optional [float ] = None ,
1597+ ) -> LinearizationResult :
15531598 """Linearize the model according to linearization options.
15541599
15551600 See setLinearizationOptions.
@@ -1759,7 +1804,7 @@ def __init__(
17591804 omc_process : Optional [OMCProcess ] = None ,
17601805 # simulation specific input
17611806 # TODO: add more settings (simulation options, input options, ...)
1762- simargs : Optional [dict [str , Optional [str | dict [str , Any ]]]] = None ,
1807+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]] = None ,
17631808 timeout : Optional [int ] = None ,
17641809 # DoE specific inputs
17651810 resultpath : Optional [str | os .PathLike ] = None ,
0 commit comments