33Definition of an OMC session.
44"""
55
6+ from __future__ import annotations
7+
68__license__ = """
79 This file is part of OpenModelica.
810
3335"""
3436
3537import shutil
36- import abc
3738import getpass
3839import logging
3940import json
4546import sys
4647import tempfile
4748import time
49+ from typing import Optional
4850import uuid
4951import pyparsing
5052import zmq
@@ -79,53 +81,40 @@ class OMCSessionException(Exception):
7981 pass
8082
8183
82- class OMCSessionBase ( metaclass = abc . ABCMeta ) :
84+ class OMCSessionCmd :
8385
84- def __init__ (self , readonly = False ):
86+ def __init__ (self , session : OMCSessionZMQ , readonly : Optional [bool ] = False ):
87+ if not isinstance (session , OMCSessionZMQ ):
88+ raise OMCSessionException ("Invalid session definition!" )
89+ self ._session = session
8590 self ._readonly = readonly
8691 self ._omc_cache = {}
8792
88- def execute (self , command ):
89- warnings .warn ("This function is depreciated and will be removed in future versions; "
90- "please use sendExpression() instead" , DeprecationWarning , stacklevel = 1 )
93+ def sendExpression (self , command , parsed = True ):
94+ return self ._session .sendExpression (command = command , parsed = parsed )
9195
92- return self . sendExpression ( command , parsed = False )
96+ def _ask ( self , question : str , opt : Optional [ list [ str ]] = None , parsed : Optional [ bool ] = True ):
9397
94- @abc .abstractmethod
95- def sendExpression (self , command , parsed = True ):
96- """
97- Sends an expression to the OpenModelica. The return type is parsed as if the
98- expression was part of the typed OpenModelica API (see ModelicaBuiltin.mo).
99- * Integer and Real are returned as Python numbers
100- * Strings, enumerations, and typenames are returned as Python strings
101- * Arrays, tuples, and MetaModelica lists are returned as tuples
102- * Records are returned as dicts (the name of the record is lost)
103- * Booleans are returned as True or False
104- * NONE() is returned as None
105- * SOME(value) is returned as value
106- """
107- pass
98+ if opt is None :
99+ expression = question
100+ elif isinstance (opt , list ):
101+ expression = f"{ question } ({ ',' .join (opt )} )"
102+ else :
103+ raise OMCSessionException (f"Invalid definition of options for { repr (question )} : { repr (opt )} " )
108104
109- def ask (self , question , opt = None , parsed = True ):
110- p = (question , opt , parsed )
105+ p = (expression , parsed )
111106
112107 if self ._readonly and question != 'getErrorString' :
113108 # can use cache if readonly
114109 if p in self ._omc_cache :
115110 return self ._omc_cache [p ]
116111
117- if opt :
118- expression = f'{ question } ({ opt } )'
119- else :
120- expression = question
121-
122- logger .debug ('OMC ask: %s - parsed: %s' , expression , parsed )
112+ logger .debug ('OMC ask: %s (parsed=%s)' , expression , parsed )
123113
124114 try :
125- res = self .sendExpression (expression , parsed = parsed )
126- except OMCSessionException :
127- logger .error ("OMC failed: %s, %s, parsed=%s" , question , opt , parsed )
128- raise
115+ res = self ._session .sendExpression (expression , parsed = parsed )
116+ except OMCSessionException as ex :
117+ raise OMCSessionException ("OMC _ask() failed: %s (parsed=%s)" , expression , parsed ) from ex
129118
130119 # save response
131120 self ._omc_cache [p ] = res
@@ -134,126 +123,133 @@ def ask(self, question, opt=None, parsed=True):
134123
135124 # TODO: Open Modelica Compiler API functions. Would be nice to generate these.
136125 def loadFile (self , filename ):
137- return self .ask ( 'loadFile' , f'"{ filename } "' )
126+ return self ._ask ( question = 'loadFile' , opt = [ f'"{ filename } "' ] )
138127
139128 def loadModel (self , className ):
140- return self .ask ( 'loadModel' , className )
129+ return self ._ask ( question = 'loadModel' , opt = [ className ] )
141130
142131 def isModel (self , className ):
143- return self .ask ( 'isModel' , className )
132+ return self ._ask ( question = 'isModel' , opt = [ className ] )
144133
145134 def isPackage (self , className ):
146- return self .ask ( 'isPackage' , className )
135+ return self ._ask ( question = 'isPackage' , opt = [ className ] )
147136
148137 def isPrimitive (self , className ):
149- return self .ask ( 'isPrimitive' , className )
138+ return self ._ask ( question = 'isPrimitive' , opt = [ className ] )
150139
151140 def isConnector (self , className ):
152- return self .ask ( 'isConnector' , className )
141+ return self ._ask ( question = 'isConnector' , opt = [ className ] )
153142
154143 def isRecord (self , className ):
155- return self .ask ( 'isRecord' , className )
144+ return self ._ask ( question = 'isRecord' , opt = [ className ] )
156145
157146 def isBlock (self , className ):
158- return self .ask ( 'isBlock' , className )
147+ return self ._ask ( question = 'isBlock' , opt = [ className ] )
159148
160149 def isType (self , className ):
161- return self .ask ( 'isType' , className )
150+ return self ._ask ( question = 'isType' , opt = [ className ] )
162151
163152 def isFunction (self , className ):
164- return self .ask ( 'isFunction' , className )
153+ return self ._ask ( question = 'isFunction' , opt = [ className ] )
165154
166155 def isClass (self , className ):
167- return self .ask ( 'isClass' , className )
156+ return self ._ask ( question = 'isClass' , opt = [ className ] )
168157
169158 def isParameter (self , className ):
170- return self .ask ( 'isParameter' , className )
159+ return self ._ask ( question = 'isParameter' , opt = [ className ] )
171160
172161 def isConstant (self , className ):
173- return self .ask ( 'isConstant' , className )
162+ return self ._ask ( question = 'isConstant' , opt = [ className ] )
174163
175164 def isProtected (self , className ):
176- return self .ask ( 'isProtected' , className )
165+ return self ._ask ( question = 'isProtected' , opt = [ className ] )
177166
178167 def getPackages (self , className = "AllLoadedClasses" ):
179- return self .ask ( 'getPackages' , className )
168+ return self ._ask ( question = 'getPackages' , opt = [ className ] )
180169
181170 def getClassRestriction (self , className ):
182- return self .ask ( 'getClassRestriction' , className )
171+ return self ._ask ( question = 'getClassRestriction' , opt = [ className ] )
183172
184173 def getDerivedClassModifierNames (self , className ):
185- return self .ask ( 'getDerivedClassModifierNames' , className )
174+ return self ._ask ( question = 'getDerivedClassModifierNames' , opt = [ className ] )
186175
187176 def getDerivedClassModifierValue (self , className , modifierName ):
188- return self .ask ( 'getDerivedClassModifierValue' , f' { className } , { modifierName } ' )
177+ return self ._ask ( question = 'getDerivedClassModifierValue' , opt = [ className , modifierName ] )
189178
190179 def typeNameStrings (self , className ):
191- return self .ask ( 'typeNameStrings' , className )
180+ return self ._ask ( question = 'typeNameStrings' , opt = [ className ] )
192181
193182 def getComponents (self , className ):
194- return self .ask ( 'getComponents' , className )
183+ return self ._ask ( question = 'getComponents' , opt = [ className ] )
195184
196185 def getClassComment (self , className ):
197186 try :
198- return self .ask ( 'getClassComment' , className )
187+ return self ._ask ( question = 'getClassComment' , opt = [ className ] )
199188 except pyparsing .ParseException as ex :
200- logger .warning ("Method 'getClassComment' failed for %s" , className )
201- logger . warning ( 'OMTypedParser error: %s' , ex .msg )
189+ logger .warning ("Method 'getClassComment(%s) ' failed; OMTypedParser error: %s" ,
190+ className , ex .msg )
202191 return 'No description available'
192+ except OMCSessionException :
193+ raise
203194
204195 def getNthComponent (self , className , comp_id ):
205196 """ returns with (type, name, description) """
206- return self .ask ( 'getNthComponent' , f' { className } , { comp_id } ' )
197+ return self ._ask ( question = 'getNthComponent' , opt = [ className , comp_id ] )
207198
208199 def getNthComponentAnnotation (self , className , comp_id ):
209- return self .ask ( 'getNthComponentAnnotation' , f' { className } , { comp_id } ' )
200+ return self ._ask ( question = 'getNthComponentAnnotation' , opt = [ className , comp_id ] )
210201
211202 def getImportCount (self , className ):
212- return self .ask ( 'getImportCount' , className )
203+ return self ._ask ( question = 'getImportCount' , opt = [ className ] )
213204
214205 def getNthImport (self , className , importNumber ):
215206 # [Path, id, kind]
216- return self .ask ( 'getNthImport' , f' { className } , { importNumber } ' )
207+ return self ._ask ( question = 'getNthImport' , opt = [ className , importNumber ] )
217208
218209 def getInheritanceCount (self , className ):
219- return self .ask ( 'getInheritanceCount' , className )
210+ return self ._ask ( question = 'getInheritanceCount' , opt = [ className ] )
220211
221212 def getNthInheritedClass (self , className , inheritanceDepth ):
222- return self .ask ( 'getNthInheritedClass' , f' { className } , { inheritanceDepth } ' )
213+ return self ._ask ( question = 'getNthInheritedClass' , opt = [ className , inheritanceDepth ] )
223214
224215 def getParameterNames (self , className ):
225216 try :
226- return self .ask ( 'getParameterNames' , className )
217+ return self ._ask ( question = 'getParameterNames' , opt = [ className ] )
227218 except KeyError as ex :
228219 logger .warning ('OMPython error: %s' , ex )
229220 # FIXME: OMC returns with a different structure for empty parameter set
230221 return []
222+ except OMCSessionException :
223+ raise
231224
232225 def getParameterValue (self , className , parameterName ):
233226 try :
234- return self .ask ( 'getParameterValue' , f' { className } , { parameterName } ' )
227+ return self ._ask ( question = 'getParameterValue' , opt = [ className , parameterName ] )
235228 except pyparsing .ParseException as ex :
236- logger .warning ('OMTypedParser error: %s' , ex .msg )
229+ logger .warning ("Method 'getParameterValue(%s, %s)' failed; OMTypedParser error: %s" ,
230+ className , parameterName , ex .msg )
237231 return ""
232+ except OMCSessionException :
233+ raise
238234
239235 def getComponentModifierNames (self , className , componentName ):
240- return self .ask ( 'getComponentModifierNames' , f' { className } , { componentName } ' )
236+ return self ._ask ( question = 'getComponentModifierNames' , opt = [ className , componentName ] )
241237
242238 def getComponentModifierValue (self , className , componentName ):
243- return self .ask (question = 'getComponentModifierValue' , opt = f' { className } , { componentName } ' )
239+ return self ._ask (question = 'getComponentModifierValue' , opt = [ className , componentName ] )
244240
245241 def getExtendsModifierNames (self , className , componentName ):
246- return self .ask ( 'getExtendsModifierNames' , f' { className } , { componentName } ' )
242+ return self ._ask ( question = 'getExtendsModifierNames' , opt = [ className , componentName ] )
247243
248244 def getExtendsModifierValue (self , className , extendsName , modifierName ):
249- return self .ask (question = 'getExtendsModifierValue' , opt = f' { className } , { extendsName } , { modifierName } ' )
245+ return self ._ask (question = 'getExtendsModifierValue' , opt = [ className , extendsName , modifierName ] )
250246
251247 def getNthComponentModification (self , className , comp_id ):
252248 # FIXME: OMPython exception Results KeyError exception
253249
254250 # get {$Code(....)} field
255251 # \{\$Code\((\S*\s*)*\)\}
256- value = self .ask ( 'getNthComponentModification' , f' { className } , { comp_id } ' , parsed = False )
252+ value = self ._ask ( question = 'getNthComponentModification' , opt = [ className , comp_id ] , parsed = False )
257253 value = value .replace ("{$Code(" , "" )
258254 return value [:- 3 ]
259255 # return self.re_Code.findall(value)
@@ -269,28 +265,22 @@ def getNthComponentModification(self, className, comp_id):
269265 # end getClassNames;
270266 def getClassNames (self , className = None , recursive = False , qualified = False , sort = False , builtin = False ,
271267 showProtected = False ):
272- value = self .ask (
273- 'getClassNames' ,
274- (f'{ className } , ' if className else '' ) +
275- f'recursive={ str (recursive ).lower ()} , '
276- f'qualified={ str (qualified ).lower ()} , '
277- f'sort={ str (sort ).lower ()} , '
278- f'builtin={ str (builtin ).lower ()} , '
279- f'showProtected={ str (showProtected ).lower ()} '
280- )
281- return value
268+ opt = [className ] if className else [] + [f'recursive={ str (recursive ).lower ()} ' ,
269+ f'qualified={ str (qualified ).lower ()} ' ,
270+ f'sort={ str (sort ).lower ()} ' ,
271+ f'builtin={ str (builtin ).lower ()} ' ,
272+ f'showProtected={ str (showProtected ).lower ()} ' ]
273+ return self ._ask (question = 'getClassNames' , opt = opt )
282274
283275
284- class OMCSessionZMQ ( OMCSessionBase ) :
276+ class OMCSessionZMQ :
285277
286- def __init__ (self , readonly = False , timeout = 10.00 ,
278+ def __init__ (self , timeout = 10.00 ,
287279 docker = None , dockerContainer = None , dockerExtraArgs = None , dockerOpenModelicaPath = "omc" ,
288280 dockerNetwork = None , port = None , omhome : str = None ):
289281 if dockerExtraArgs is None :
290282 dockerExtraArgs = []
291283
292- super ().__init__ (readonly = readonly )
293-
294284 self .omhome = self ._get_omhome (omhome = omhome )
295285
296286 self ._omc_process = None
@@ -528,6 +518,12 @@ def _connect_to_omc(self, timeout):
528518 self ._omc .setsockopt (zmq .IMMEDIATE , True ) # Queue messages only to completed connections
529519 self ._omc .connect (self ._port )
530520
521+ def execute (self , command ):
522+ warnings .warn ("This function is depreciated and will be removed in future versions; "
523+ "please use sendExpression() instead" , DeprecationWarning , stacklevel = 1 )
524+
525+ return self .sendExpression (command , parsed = False )
526+
531527 def sendExpression (self , command , parsed = True ):
532528 p = self ._omc_process .poll () # check if process is running
533529 if p is not None :
0 commit comments