@@ -119,10 +119,18 @@ def __init__(self, runpath: pathlib.Path, modelname: str, timeout: Optional[floa
119119 self ._runpath = pathlib .Path (runpath ).resolve ().absolute ()
120120 self ._model_name = modelname
121121 self ._timeout = timeout
122+
123+ # dictionaries of command line arguments for the model executable
122124 self ._args : dict [str , str | None ] = {}
125+ # 'override' argument needs special handling, as it is a dict on its own saved as dict elements following the
126+ # structure: 'key' => 'key=value'
123127 self ._arg_override : dict [str , str ] = {}
124128
125- def arg_set (self , key : str , val : Optional [str | dict ] = None ) -> None :
129+ def arg_set (
130+ self ,
131+ key : str ,
132+ val : Optional [str | dict [str , Any ] | numbers .Number ] = None ,
133+ ) -> None :
126134 """
127135 Set one argument for the executable model.
128136
@@ -132,12 +140,24 @@ def arg_set(self, key: str, val: Optional[str | dict] = None) -> None:
132140 indicates variables to override
133141 """
134142
135- def override2str (okey : str , oval : Any ) -> str :
143+ def override2str (
144+ okey : str ,
145+ oval : str | bool | numbers .Number ,
146+ ) -> str :
136147 """
137148 Convert a value for 'override' to a string taking into account differences between Modelica and Python.
138149 """
150+ # check oval for any string representations of numbers (or bool) and convert these to Python representations
151+ if isinstance (oval , str ):
152+ try :
153+ oval_evaluated = ast .literal_eval (oval )
154+ if isinstance (oval_evaluated , (numbers .Number , bool )):
155+ oval = oval_evaluated
156+ except (ValueError , SyntaxError ):
157+ pass
158+
139159 if isinstance (oval , str ):
140- oval_str = f" \" { oval .strip ()} \" "
160+ oval_str = oval .strip ()
141161 elif isinstance (oval , bool ):
142162 oval_str = 'true' if oval else 'false'
143163 elif isinstance (oval , numbers .Number ):
@@ -151,14 +171,32 @@ def override2str(okey: str, oval: Any) -> str:
151171 raise ModelicaSystemError (f"Invalid argument key: { repr (key )} (type: { type (key )} )" )
152172 key = key .strip ()
153173
154- if key == 'override' and isinstance (val , dict ):
155- for okey in val :
156- if not isinstance (okey , str ) or not isinstance (val [okey ], (str , bool , numbers .Number )):
157- raise ModelicaSystemError ("Invalid argument for 'override': "
158- f"{ repr (okey )} = { repr (val [okey ])} " )
159- self ._arg_override [okey ] = val [okey ]
174+ if isinstance (val , dict ):
175+ if key != 'override' :
176+ raise ModelicaSystemError ("Dictionary input only possible for key 'override'!" )
177+
178+ for okey , oval in val .items ():
179+ if not isinstance (okey , str ):
180+ raise ModelicaSystemError ("Invalid key for argument 'override': "
181+ f"{ repr (okey )} (type: { type (okey )} )" )
182+
183+ if not isinstance (oval , (str , bool , numbers .Number , type (None ))):
184+ raise ModelicaSystemError (f"Invalid input for 'override'.{ repr (okey )} : "
185+ f"{ repr (oval )} (type: { type (oval )} )" )
186+
187+ if okey in self ._arg_override :
188+ if oval is None :
189+ logger .info (f"Remove model executable override argument: { repr (self ._arg_override [okey ])} " )
190+ del self ._arg_override [okey ]
191+ continue
160192
161- argval = ',' .join ([override2str (okey = okey , oval = oval ) for okey , oval in self ._arg_override .items ()])
193+ logger .info (f"Update model executable override argument: { repr (okey )} = { repr (oval )} "
194+ f"(was: { repr (self ._arg_override [okey ])} )" )
195+
196+ if oval is not None :
197+ self ._arg_override [okey ] = override2str (okey = okey , oval = oval )
198+
199+ argval = ',' .join (sorted (self ._arg_override .values ()))
162200 elif val is None :
163201 argval = None
164202 elif isinstance (val , str ):
@@ -173,7 +211,7 @@ def override2str(okey: str, oval: Any) -> str:
173211 f"(was: { repr (self ._args [key ])} )" )
174212 self ._args [key ] = argval
175213
176- def arg_get (self , key : str ) -> Optional [str | dict ]:
214+ def arg_get (self , key : str ) -> Optional [str | dict [ str , str | bool | numbers . Number ] ]:
177215 """
178216 Return the value for the given key
179217 """
@@ -182,7 +220,10 @@ def arg_get(self, key: str) -> Optional[str | dict]:
182220
183221 return None
184222
185- def args_set (self , args : dict [str , Optional [str | dict [str , str ]]]) -> None :
223+ def args_set (
224+ self ,
225+ args : dict [str , Optional [str | dict [str , Any ] | numbers .Number ]],
226+ ) -> None :
186227 """
187228 Define arguments for the model executable.
188229 """
@@ -210,7 +251,7 @@ def get_cmd(self) -> list:
210251 path_exe = self .get_exe ()
211252
212253 cmdl = [path_exe .as_posix ()]
213- for key in self ._args :
254+ for key in sorted ( self ._args ) :
214255 if self ._args [key ] is None :
215256 cmdl .append (f"-{ key } " )
216257 else :
@@ -268,7 +309,7 @@ def run(self) -> int:
268309 return returncode
269310
270311 @staticmethod
271- def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , str ] ]]:
312+ def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]:
272313 """
273314 Parse a simflag definition; this is deprecated!
274315
@@ -277,7 +318,7 @@ def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, str]]]:
277318 warnings .warn ("The argument 'simflags' is depreciated and will be removed in future versions; "
278319 "please use 'simargs' instead" , DeprecationWarning , stacklevel = 2 )
279320
280- simargs : dict [str , Optional [str | dict [str , str ] ]] = {}
321+ simargs : dict [str , Optional [str | dict [str , Any ] | numbers . Number ]] = {}
281322
282323 args = [s for s in simflags .split (' ' ) if s ]
283324 for arg in args :
@@ -930,7 +971,7 @@ def simulate_cmd(
930971 self ,
931972 result_file : pathlib .Path ,
932973 simflags : Optional [str ] = None ,
933- simargs : Optional [dict [str , Optional [str | dict [str , str ] ]]] = None ,
974+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]] = None ,
934975 timeout : Optional [float ] = None ,
935976 ) -> ModelicaSystemCmd :
936977 """
@@ -1003,7 +1044,7 @@ def simulate(
10031044 self ,
10041045 resultfile : Optional [str ] = None ,
10051046 simflags : Optional [str ] = None ,
1006- simargs : Optional [dict [str , Optional [str | dict [str , str ] ]]] = None ,
1047+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers . Number ]]] = None ,
10071048 timeout : Optional [float ] = None ,
10081049 ) -> None :
10091050 """Simulate the model according to simulation options.
@@ -1524,9 +1565,13 @@ def optimize(self) -> dict[str, Any]:
15241565
15251566 return optimizeResult
15261567
1527- def linearize (self , lintime : Optional [float ] = None , simflags : Optional [str ] = None ,
1528- simargs : Optional [dict [str , Optional [str | dict [str , str ]]]] = None ,
1529- timeout : Optional [float ] = None ) -> LinearizationResult :
1568+ def linearize (
1569+ self ,
1570+ lintime : Optional [float ] = None ,
1571+ simflags : Optional [str ] = None ,
1572+ simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers .Number ]]] = None ,
1573+ timeout : Optional [float ] = None ,
1574+ ) -> LinearizationResult :
15301575 """Linearize the model according to linearization options.
15311576
15321577 See setLinearizationOptions.
0 commit comments