11# -*- coding: utf-8 -*-
22"""
33OMPython is a Python interface to OpenModelica.
4- To get started, create an OMCSession/OMCSessionZMQ object:
5- from OMPython import OMCSession/OMCSessionZMQ
6- omc = OMCSession()/OMCSessionZMQ()
7- omc.sendExpression(command)
8-
9- Note: Conversion from OMPython 1.0 to OMPython 2.0 is very simple
10- 1.0:
11- import OMPython
12- OMPython.execute(command)
13- 2.0:
14- from OMPython import OMCSession
15- OMPython = OMCSession()
16- OMPython.execute(command)
17-
18- OMPython 3.0 includes a new class OMCSessionZMQ uses PyZMQ to communicate
19- with OpenModelica. A new argument `useCorba=False` is added to ModelicaSystem
20- class which means it will use OMCSessionZMQ by default. If you want to use
21- OMCSession then create ModelicaSystem object like this,
22- obj = ModelicaSystem(useCorba=True)
23-
24- The difference between execute and sendExpression is the type of the
25- returned expression. sendExpression maps Modelica types to Python types,
26- while execute tries to map also output that is not valid Modelica.
27- That format is harder to use.
4+ To get started, create an OMCSessionZMQ object:
5+ from OMPython import OMCSessionZMQ
6+ omc = OMCSessionZMQ()
7+ omc.sendExpression("command")
288"""
299
3010from __future__ import absolute_import
@@ -56,7 +36,8 @@ class which means it will use OMCSessionZMQ by default. If you want to use
5636import numpy as np
5737import pyparsing
5838import importlib
59-
39+ import zmq
40+ import warnings
6041
6142if sys .platform == 'darwin' :
6243 # On Mac let's assume omc is installed here and there might be a broken omniORB installed in a bad place
@@ -552,154 +533,6 @@ def getClassNames(self, className=None, recursive=False, qualified=False, sort=F
552533 str (builtin ).lower (), str (showProtected ).lower ()))
553534 return value
554535
555-
556- class OMCSession (OMCSessionHelper , OMCSessionBase ):
557-
558- def __init__ (self , readonly = False , serverFlag = '--interactive=corba' , timeout = 10.0 ,
559- docker = None , dockerContainer = None , dockerExtraArgs = None , dockerOpenModelicaPath = "omc" ,
560- dockerNetwork = None , omhome : str = None ):
561- if dockerExtraArgs is None :
562- dockerExtraArgs = []
563-
564- OMCSessionHelper .__init__ (self , omhome = omhome )
565- OMCSessionBase .__init__ (self , readonly )
566- self ._create_omc_log_file ("objid" )
567- # Locating and using the IOR
568- if sys .platform != 'win32' or docker or dockerContainer :
569- self ._port_file = "openmodelica." + self ._currentUser + ".objid." + self ._random_string
570- else :
571- self ._port_file = "openmodelica.objid." + self ._random_string
572- self ._port_file = os .path .join ("/tmp" if (docker or dockerContainer ) else self ._temp_dir , self ._port_file ).replace ("\\ " , "/" )
573- # set omc executable path and args
574- self ._docker = docker
575- self ._dockerContainer = dockerContainer
576- self ._dockerExtraArgs = dockerExtraArgs
577- self ._dockerOpenModelicaPath = dockerOpenModelicaPath
578- self ._dockerNetwork = dockerNetwork
579- self ._timeout = timeout
580- self ._create_omc_log_file ("port" )
581-
582- self ._set_omc_command ([serverFlag , "+c={0}" .format (self ._random_string )])
583-
584- # start up omc executable, which is waiting for the CORBA connection
585- self ._start_omc_process (timeout )
586- # connect to the running omc instance using CORBA
587- self ._connect_to_omc (timeout )
588-
589- def __del__ (self ):
590- OMCSessionBase .__del__ (self )
591-
592- def _connect_to_omc (self , timeout ):
593- # add OPENMODELICAHOME\lib\python to PYTHONPATH so python can load omniORB imports
594- sys .path .append (os .path .join (self .omhome , 'lib' , 'python' ))
595- # import the skeletons for the global module
596- try :
597- from omniORB import CORBA
598- from OMPythonIDL import _OMCIDL
599- except ImportError :
600- self ._omc_process .kill ()
601- raise
602- self ._omc_corba_uri = "file:///" + self ._port_file
603- # See if the omc server is running
604- attempts = 0
605- while True :
606- if self ._dockerCid :
607- try :
608- self ._ior = subprocess .check_output (["docker" , "exec" , self ._dockerCid , "cat" , self ._port_file ], stderr = subprocess .DEVNULL if (sys .version_info > (3 , 0 )) else subprocess .STDOUT ).decode ().strip ()
609- break
610- except subprocess .CalledProcessError :
611- pass
612- if os .path .isfile (self ._port_file ):
613- # Read the IOR file
614- with open (self ._port_file , 'r' ) as f_p :
615- self ._ior = f_p .readline ()
616- break
617- attempts += 1
618- if attempts == 80 :
619- name = self ._omc_log_file .name
620- self ._omc_log_file .close ()
621- with open (name ) as fin :
622- contents = fin .read ()
623- self ._omc_process .kill ()
624- raise Exception ("OMC Server is down (timeout=%f). Please start it! If the OMC version is old, try OMCSession(..., serverFlag='-d=interactiveCorba') or +d=interactiveCorba. Log-file says:\n %s" % (timeout , contents ))
625- time .sleep (timeout / 80.0 )
626-
627- while True :
628- if self ._dockerCid :
629- try :
630- self ._port = subprocess .check_output (["docker" , "exec" , self ._dockerCid , "cat" , self ._port_file ]).decode ().strip ()
631- break
632- except :
633- pass
634- else :
635- if os .path .isfile (self ._port_file ):
636- # Read the port file
637- with open (self ._port_file , 'r' ) as f_p :
638- self ._port = f_p .readline ()
639- os .remove (self ._port_file )
640- break
641-
642- attempts += 1
643- if attempts == 80.0 :
644- name = self ._omc_log_file .name
645- self ._omc_log_file .close ()
646- logger .error ("OMC Server is down (timeout=%f). Please start it! Log-file says:\n %s" % open (name ).read ())
647- raise Exception ("OMC Server is down. Could not open file %s" % (timeout ,self ._port_file ))
648- time .sleep (timeout / 80.0 )
649-
650- logger .info ("OMC Server is up and running at {0}" .format (self ._omc_corba_uri ))
651- # initialize the ORB with maximum size for the ORB set
652- sys .argv .append ("-ORBgiopMaxMsgSize" )
653- sys .argv .append ("2147483647" )
654- self ._orb = CORBA .ORB_init (sys .argv , CORBA .ORB_ID )
655-
656- # Find the root POA
657- self ._poa = self ._orb .resolve_initial_references ("RootPOA" )
658- # Convert the IOR into an object reference
659- self ._obj_reference = self ._orb .string_to_object (self ._ior )
660- # Narrow the reference to the OmcCommunication object
661- self ._omc = self ._obj_reference ._narrow (_OMCIDL .OmcCommunication )
662- # Check if we are using the right object
663- if self ._omc is None :
664- logger .error ("Object reference is not valid" )
665- raise Exception
666-
667- def execute (self , command ):
668- ## check for process is running
669- p = self ._omc_process .poll ()
670- if (p == None ):
671- result = self ._omc .sendExpression (command )
672- if command == "quit()" :
673- self ._omc = None
674- return result
675- else :
676- answer = OMParser .check_for_values (result )
677- return answer
678- else :
679- raise Exception ("Process Exited, No connection with OMC. Create a new instance of OMCSession" )
680-
681- def sendExpression (self , command , parsed = True ):
682- ## check for process is running
683- p = self ._omc_process .poll ()
684- if (p == None ):
685- result = self ._omc .sendExpression (str (command ))
686- if command == "quit()" :
687- self ._omc = None
688- return result
689- else :
690- if parsed is True :
691- answer = OMTypedParser .parseString (result )
692- return answer
693- else :
694- return result
695- else :
696- raise Exception ("Process Exited, No connection with OMC. Create a new instance of OMCSession" )
697-
698- try :
699- import zmq
700- except ImportError :
701- pass
702-
703536class OMCSessionZMQ (OMCSessionHelper , OMCSessionBase ):
704537
705538 def __init__ (self , readonly = False , timeout = 10.00 ,
@@ -770,7 +603,6 @@ def _connect_to_omc(self, timeout):
770603 logger .info ("OMC Server is up and running at {0} pid={1} cid={2}" .format (self ._omc_zeromq_uri , self ._omc_process .pid , self ._dockerCid ))
771604
772605 # Create the ZeroMQ socket and connect to OMC server
773- import zmq
774606 context = zmq .Context .instance ()
775607 self ._omc = context .socket (zmq .REQ )
776608 self ._omc .setsockopt (zmq .LINGER , 0 ) # Dismisses pending messages if closed
@@ -810,16 +642,13 @@ def sendExpression(self, command, parsed=True):
810642 else :
811643 return result
812644 else :
813- raise Exception ("Process Exited, No connection with OMC. Create a new instance of OMCSession" )
814-
645+ raise Exception ("Process Exited, No connection with OMC. Create a new instance of OMCSessionZMQ" )
815646
816647class ModelicaSystemError (Exception ):
817648 pass
818649
819-
820650class ModelicaSystem (object ):
821- def __init__ (self , fileName = None , modelName = None , lmodel = None ,
822- useCorba = False , commandLineOptions = None ,
651+ def __init__ (self , fileName = None , modelName = None , lmodel = None , commandLineOptions = None ,
823652 variableFilter = None , customBuildDirectory = None , verbose = True , raiseerrors = False ,
824653 omhome : str = None , session : OMCSessionBase = None ): # 1
825654 """
@@ -831,14 +660,8 @@ def __init__(self, fileName=None, modelName=None, lmodel=None,
831660 Note: If the model file is not in the current working directory, then the path where file is located must be included together with file name. Besides, if the Modelica model contains several different models within the same package, then in order to build the specific model, in second argument, user must put the package name with dot(.) followed by specific model name.
832661 ex: myModel = ModelicaSystem("ModelicaModel.mo", "modelName")
833662 """
834- if session is not None :
835- self .getconn = session
836- elif useCorba :
837- self .getconn = OMCSession (omhome = omhome )
838- else :
839- self .getconn = OMCSessionZMQ (omhome = omhome )
840-
841663 if fileName is None and modelName is None and not lmodel : # all None
664+ raise Exception ("Cannot create ModelicaSystem object without any arguments" )
842665 return
843666
844667 self .tree = None
@@ -860,7 +683,12 @@ def __init__(self, fileName=None, modelName=None, lmodel=None,
860683
861684 self ._verbose = verbose
862685
863- ## needed for properly deleting the OMCSessionZMQ
686+ if session is not None :
687+ self .getconn = session
688+ else :
689+ self .getconn = OMCSessionZMQ (omhome = omhome )
690+
691+ ## needed for properly deleting the session
864692 self ._omc_log_file = self .getconn ._omc_log_file
865693 self ._omc_process = self .getconn ._omc_process
866694
@@ -1880,41 +1708,3 @@ def getLinearStates(self):
18801708 >>> getLinearStates()
18811709 """
18821710 return self .linearstates
1883-
1884-
1885- def FindBestOMCSession (* args , ** kwargs ):
1886- """
1887- Analyzes the OMC executable version string to find a suitable selection
1888- of CORBA or ZMQ, as well as older flags to launch the executable (such
1889- as +d=interactiveCorba for RML-based OMC).
1890-
1891- This is mainly useful if you are testing old OpenModelica versions using
1892- the latest OMPython.
1893- """
1894- base = OMCSessionHelper ()
1895- omc = base ._get_omc_path ()
1896- versionOK = False
1897- for cmd in ["--version" , "+version" ]:
1898- try :
1899- v = str (subprocess .check_output ([omc , cmd ], stderr = subprocess .STDOUT ))
1900- versionOK = True
1901- break
1902- except subprocess .CalledProcessError :
1903- pass
1904- if not versionOK :
1905- raise Exception ("Failed to use omc --version or omc +version. Is omc on the PATH?" )
1906- zmq = False
1907- v = v .strip ().split ("-" )[0 ].split ("~" )[0 ].strip ()
1908- a = re .search (r"v?([0-9]+)[.]([0-9]+)[.][0-9]+" , v )
1909- try :
1910- major = int (a .group (1 ))
1911- minor = int (a .group (2 ))
1912- if major > 1 or (major == 1 and minor >= 12 ):
1913- zmq = True
1914- except :
1915- pass
1916- if zmq :
1917- return OMCSessionZMQ (* args , ** kwargs )
1918- if cmd == "+version" :
1919- return OMCSession (* args , serverFlag = "+d=interactiveCorba" , ** kwargs )
1920- return OMCSession (* args , serverFlag = "-d=interactiveCorba" , ** kwargs )
0 commit comments