4848import sys
4949import tempfile
5050import time
51- from typing import Optional
51+ from typing import Any , Optional
5252import uuid
5353import warnings
5454import zmq
5757from OMPython .OMTypedParser import parseString as om_parser_typed
5858from OMPython .OMParser import om_parser_basic
5959
60-
6160# define logger using the current module name as ID
6261logger = logging .getLogger (__name__ )
6362
6463
65- class DummyPopen () :
64+ class DummyPopen :
6665 def __init__ (self , pid ):
6766 self .pid = pid
6867 self .process = psutil .Process (pid )
@@ -84,14 +83,14 @@ class OMCSessionException(Exception):
8483
8584class OMCSessionCmd :
8685
87- def __init__ (self , session : OMCSessionZMQ , readonly : Optional [ bool ] = False ):
86+ def __init__ (self , session : OMCSessionZMQ , readonly : bool = False ):
8887 if not isinstance (session , OMCSessionZMQ ):
8988 raise OMCSessionException ("Invalid session definition!" )
9089 self ._session = session
9190 self ._readonly = readonly
92- self ._omc_cache = {}
91+ self ._omc_cache : dict [ tuple [ str , bool ], Any ] = {}
9392
94- def _ask (self , question : str , opt : Optional [list [str ]] = None , parsed : Optional [ bool ] = True ):
93+ def _ask (self , question : str , opt : Optional [list [str ]] = None , parsed : bool = True ):
9594
9695 if opt is None :
9796 expression = question
@@ -107,8 +106,6 @@ def _ask(self, question: str, opt: Optional[list[str]] = None, parsed: Optional[
107106 if p in self ._omc_cache :
108107 return self ._omc_cache [p ]
109108
110- logger .debug ('OMC ask: %s (parsed=%s)' , expression , parsed )
111-
112109 try :
113110 res = self ._session .sendExpression (expression , parsed = parsed )
114111 except OMCSessionException as ex :
@@ -273,26 +270,29 @@ def getClassNames(self, className=None, recursive=False, qualified=False, sort=F
273270
274271class OMCSessionZMQ :
275272
276- def __init__ (self , timeout = 10.00 ,
277- docker = None , dockerContainer = None , dockerExtraArgs = None , dockerOpenModelicaPath = "omc" ,
278- dockerNetwork = None , port = None , omhome : str = None ):
273+ def __init__ (self ,
274+ timeout : float = 10.00 ,
275+ docker : Optional [str ] = None ,
276+ dockerContainer : Optional [int ] = None ,
277+ dockerExtraArgs : Optional [list ] = None ,
278+ dockerOpenModelicaPath : str = "omc" ,
279+ dockerNetwork : Optional [str ] = None ,
280+ port : Optional [int ] = None ,
281+ omhome : Optional [str ] = None ):
279282 if dockerExtraArgs is None :
280283 dockerExtraArgs = []
281284
282- self .omhome = self ._get_omhome (omhome = omhome )
285+ self ._omhome = self ._get_omhome (omhome = omhome )
283286
284287 self ._omc_process = None
285288 self ._omc_command = None
286- self ._omc = None
287- self ._dockerCid = None
289+ self ._omc : Optional [ Any ] = None
290+ self ._dockerCid : Optional [ int ] = None
288291 self ._serverIPAddress = "127.0.0.1"
289292 self ._interactivePort = None
290- # FIXME: this code is not well written... need to be refactored
291293 self ._temp_dir = pathlib .Path (tempfile .gettempdir ())
292294 # generate a random string for this session
293295 self ._random_string = uuid .uuid4 ().hex
294- # omc log file
295- self ._omc_log_file = None
296296 try :
297297 self ._currentUser = getpass .getuser ()
298298 if not self ._currentUser :
@@ -301,30 +301,28 @@ def __init__(self, timeout=10.00,
301301 # We are running as a uid not existing in the password database... Pretend we are nobody
302302 self ._currentUser = "nobody"
303303
304- # Locating and using the IOR
305- if sys .platform != 'win32' or docker or dockerContainer :
306- self ._port_file = "openmodelica." + self ._currentUser + ".port." + self ._random_string
307- else :
308- self ._port_file = "openmodelica.port." + self ._random_string
309304 self ._docker = docker
310305 self ._dockerContainer = dockerContainer
311306 self ._dockerExtraArgs = dockerExtraArgs
312307 self ._dockerOpenModelicaPath = dockerOpenModelicaPath
313308 self ._dockerNetwork = dockerNetwork
314- self ._create_omc_log_file ("port" )
309+ self ._omc_log_file = self . _create_omc_log_file ("port" )
315310 self ._timeout = timeout
316- self ._port_file = ((pathlib .Path ("/tmp" ) if docker else self ._temp_dir ) / self ._port_file ).as_posix ()
311+ # Locating and using the IOR
312+ if sys .platform != 'win32' or docker or dockerContainer :
313+ port_file = "openmodelica." + self ._currentUser + ".port." + self ._random_string
314+ else :
315+ port_file = "openmodelica.port." + self ._random_string
316+ self ._port_file = ((pathlib .Path ("/tmp" ) if docker else self ._temp_dir ) / port_file ).as_posix ()
317317 self ._interactivePort = port
318318 # set omc executable path and args
319- self ._set_omc_command ([
320- "--interactive=zmq" ,
321- "--locale=C" ,
322- f"-z={ self ._random_string } "
323- ])
319+ self ._omc_command = self ._set_omc_command (omc_path_and_args_list = ["--interactive=zmq" ,
320+ "--locale=C" ,
321+ f"-z={ self ._random_string } " ])
324322 # start up omc executable, which is waiting for the ZMQ connection
325- self ._start_omc_process (timeout )
323+ self ._omc_process = self . _start_omc_process (timeout )
326324 # connect to the running omc instance using ZMQ
327- self ._connect_to_omc (timeout )
325+ self ._omc_port = self . _connect_to_omc (timeout )
328326
329327 self ._re_log_entries = None
330328 self ._re_log_raw = None
@@ -344,27 +342,29 @@ def __del__(self):
344342 self ._omc_process .kill ()
345343 self ._omc_process .wait ()
346344
347- def _create_omc_log_file (self , suffix ):
345+ def _create_omc_log_file (self , suffix ): # output?
348346 if sys .platform == 'win32' :
349347 log_filename = f"openmodelica.{ suffix } .{ self ._random_string } .log"
350348 else :
351349 log_filename = f"openmodelica.{ self ._currentUser } .{ suffix } .{ self ._random_string } .log"
352350 # this file must be closed in the destructor
353- self ._omc_log_file = open (self ._temp_dir / log_filename , "w+" )
351+ omc_log_file = open (self ._temp_dir / log_filename , "w+" )
352+
353+ return omc_log_file
354354
355- def _start_omc_process (self , timeout ):
355+ def _start_omc_process (self , timeout ): # output?
356356 if sys .platform == 'win32' :
357- omhome_bin = (self .omhome / "bin" ).as_posix ()
357+ omhome_bin = (self ._omhome / "bin" ).as_posix ()
358358 my_env = os .environ .copy ()
359359 my_env ["PATH" ] = omhome_bin + os .pathsep + my_env ["PATH" ]
360- self . _omc_process = subprocess .Popen (self ._omc_command , stdout = self ._omc_log_file ,
361- stderr = self ._omc_log_file , env = my_env )
360+ omc_process = subprocess .Popen (self ._omc_command , stdout = self ._omc_log_file ,
361+ stderr = self ._omc_log_file , env = my_env )
362362 else :
363363 # set the user environment variable so omc running from wsgi has the same user as OMPython
364364 my_env = os .environ .copy ()
365365 my_env ["USER" ] = self ._currentUser
366- self . _omc_process = subprocess .Popen (self ._omc_command , stdout = self ._omc_log_file ,
367- stderr = self ._omc_log_file , env = my_env )
366+ omc_process = subprocess .Popen (self ._omc_command , stdout = self ._omc_log_file ,
367+ stderr = self ._omc_log_file , env = my_env )
368368 if self ._docker :
369369 for i in range (0 , 40 ):
370370 try :
@@ -387,29 +387,30 @@ def _start_omc_process(self, timeout):
387387 dockerTop = None
388388 if self ._docker or self ._dockerContainer :
389389 if self ._dockerNetwork == "separate" :
390- self ._serverIPAddress = json .loads (subprocess .check_output (["docker" , "inspect" , self ._dockerCid ]).decode ().strip ())[0 ]["NetworkSettings" ]["IPAddress" ]
390+ output = subprocess .check_output (["docker" , "inspect" , self ._dockerCid ]).decode ().strip ()
391+ self ._serverIPAddress = json .loads (output )[0 ]["NetworkSettings" ]["IPAddress" ]
391392 for i in range (0 , 40 ):
392393 if sys .platform == 'win32' :
393394 break
394395 dockerTop = subprocess .check_output (["docker" , "top" , self ._dockerCid ]).decode ().strip ()
395- self . _omc_process = None
396+ omc_process = None
396397 for line in dockerTop .split ("\n " ):
397398 columns = line .split ()
398399 if self ._random_string in line :
399400 try :
400- self . _omc_process = DummyPopen (int (columns [1 ]))
401+ omc_process = DummyPopen (int (columns [1 ]))
401402 except psutil .NoSuchProcess :
402403 raise OMCSessionException (
403404 f"Could not find PID { dockerTop } - is this a docker instance spawned "
404405 f"without --pid=host?\n Log-file says:\n { open (self ._omc_log_file .name ).read ()} " )
405406 break
406- if self . _omc_process is not None :
407+ if omc_process is not None :
407408 break
408409 time .sleep (timeout / 40.0 )
409- if self . _omc_process is None :
410+ if omc_process is None :
410411 raise OMCSessionException ("Docker top did not contain omc process %s:\n %s\n Log-file says:\n %s"
411412 % (self ._random_string , dockerTop , open (self ._omc_log_file .name ).read ()))
412- return self . _omc_process
413+ return omc_process
413414
414415 def _getuid (self ):
415416 """
@@ -419,7 +420,7 @@ def _getuid(self):
419420 """
420421 return 1000 if sys .platform == 'win32' else os .getuid ()
421422
422- def _set_omc_command (self , omc_path_and_args_list ):
423+ def _set_omc_command (self , omc_path_and_args_list ) -> list :
423424 """Define the command that will be called by the subprocess module.
424425
425426 On Windows, use the list input style of the subprocess module to
@@ -446,20 +447,31 @@ def _set_omc_command(self, omc_path_and_args_list):
446447 else :
447448 raise OMCSessionException ('dockerNetwork was set to %s, but only \" host\" or \" separate\" is allowed' )
448449 self ._dockerCidFile = self ._omc_log_file .name + ".docker.cid"
449- omcCommand = ["docker" , "run" , "--cidfile" , self ._dockerCidFile , "--rm" , "--env" , "USER=%s" % self ._currentUser , "--user" , str (self ._getuid ())] + self ._dockerExtraArgs + dockerNetworkStr + [self ._docker , self ._dockerOpenModelicaPath ]
450+ omcCommand = (["docker" , "run" ,
451+ "--cidfile" , self ._dockerCidFile ,
452+ "--rm" ,
453+ "--env" , "USER=%s" % self ._currentUser ,
454+ "--user" , str (self ._getuid ())]
455+ + self ._dockerExtraArgs
456+ + dockerNetworkStr
457+ + [self ._docker , self ._dockerOpenModelicaPath ])
450458 elif self ._dockerContainer :
451- omcCommand = ["docker" , "exec" , "--env" , "USER=%s" % self ._currentUser , "--user" , str (self ._getuid ())] + self ._dockerExtraArgs + [self ._dockerContainer , self ._dockerOpenModelicaPath ]
459+ omcCommand = (["docker" , "exec" ,
460+ "--env" , "USER=%s" % self ._currentUser ,
461+ "--user" , str (self ._getuid ())]
462+ + self ._dockerExtraArgs
463+ + [self ._dockerContainer , self ._dockerOpenModelicaPath ])
452464 self ._dockerCid = self ._dockerContainer
453465 else :
454466 omcCommand = [str (self ._get_omc_path ())]
455467 if self ._interactivePort :
456468 extraFlags = extraFlags + ["--interactivePort=%d" % int (self ._interactivePort )]
457469
458- self . _omc_command = omcCommand + omc_path_and_args_list + extraFlags
470+ omc_command = omcCommand + omc_path_and_args_list + extraFlags
459471
460- return self . _omc_command
472+ return omc_command
461473
462- def _get_omhome (self , omhome : str = None ):
474+ def _get_omhome (self , omhome : Optional [ str ] = None ):
463475 # use the provided path
464476 if omhome is not None :
465477 return pathlib .Path (omhome )
@@ -477,26 +489,28 @@ def _get_omhome(self, omhome: str = None):
477489 raise OMCSessionException ("Cannot find OpenModelica executable, please install from openmodelica.org" )
478490
479491 def _get_omc_path (self ) -> pathlib .Path :
480- return self .omhome / "bin" / "omc"
492+ return self ._omhome / "bin" / "omc"
481493
482- def _connect_to_omc (self , timeout ):
483- self . _omc_zeromq_uri = "file:///" + self ._port_file
494+ def _connect_to_omc (self , timeout ) -> str :
495+ omc_zeromq_uri = "file:///" + self ._port_file
484496 # See if the omc server is running
485497 attempts = 0
486- self . _port = None
498+ port = None
487499 while True :
488500 if self ._dockerCid :
489501 try :
490- self ._port = subprocess .check_output (["docker" , "exec" , self ._dockerCid , "cat" , self ._port_file ],
491- stderr = subprocess .DEVNULL ).decode ().strip ()
502+ port = subprocess .check_output (args = ["docker" ,
503+ "exec" , str (self ._dockerCid ),
504+ "cat" , str (self ._port_file )],
505+ stderr = subprocess .DEVNULL ).decode ().strip ()
492506 break
493507 except subprocess .CalledProcessError :
494508 pass
495509 else :
496510 if os .path .isfile (self ._port_file ):
497511 # Read the port file
498512 with open (self ._port_file , 'r' ) as f_p :
499- self . _port = f_p .readline ()
513+ port = f_p .readline ()
500514 os .remove (self ._port_file )
501515 break
502516
@@ -506,18 +520,21 @@ def _connect_to_omc(self, timeout):
506520 self ._omc_log_file .close ()
507521 logger .error ("OMC Server did not start. Please start it! Log-file says:\n %s" % open (name ).read ())
508522 raise OMCSessionException (f"OMC Server did not start (timeout={ timeout } ). "
509- "Could not open file {self._port_file}" )
523+ f "Could not open file { self ._port_file } " )
510524 time .sleep (timeout / 80.0 )
511525
512- self ._port = self ._port .replace ("0.0.0.0" , self ._serverIPAddress )
513- logger .info (f"OMC Server is up and running at { self ._omc_zeromq_uri } pid={ self ._omc_process .pid } cid={ self ._dockerCid } " )
526+ port = port .replace ("0.0.0.0" , self ._serverIPAddress )
527+ logger .info (f"OMC Server is up and running at { omc_zeromq_uri } "
528+ f"pid={ self ._omc_process .pid if self ._omc_process else '?' } cid={ self ._dockerCid } " )
514529
515530 # Create the ZeroMQ socket and connect to OMC server
516531 context = zmq .Context .instance ()
517532 self ._omc = context .socket (zmq .REQ )
518533 self ._omc .setsockopt (zmq .LINGER , 0 ) # Dismisses pending messages if closed
519534 self ._omc .setsockopt (zmq .IMMEDIATE , True ) # Queue messages only to completed connections
520- self ._omc .connect (self ._port )
535+ self ._omc .connect (port )
536+
537+ return port
521538
522539 def execute (self , command ):
523540 warnings .warn ("This function is depreciated and will be removed in future versions; "
@@ -533,6 +550,8 @@ def sendExpression(self, command, parsed=True):
533550 if self ._omc is None :
534551 raise OMCSessionException ("No OMC running. Create a new instance of OMCSessionZMQ!" )
535552
553+ logger .debug ("sendExpression(%r, parsed=%r)" , command , parsed )
554+
536555 attempts = 0
537556 while True :
538557 try :
0 commit comments