Skip to content

Commit 1fa4cfd

Browse files
authored
Define omc session cmd (#282)
* [OMCSessionBase] fix exception handling * rename [OMCSessionBase] => [OMCSessionCmd]; remove dependencies * [OMCSessionZMQ] remove unused argument readonly * [OMCSessionCmd] restore test_ZMQ - move execute() back into OMCSessionZMQ * [OMCSessionCmd] make sendExpression() available * [tests] new test for OMCSessionCmd * [OMCSessionCmd] fix all try ... except ... usages - check for OMCSessionException * [OMCSessionCmd] improve code for getClassNames() * [ModelicaSystem] fix rebase - OMCSessionBase] => OMCSessionZMQ * [OMCSessionCmd] cleanup / remove sendExpression() as it is just a wrapper for _session.sendExpression() * [OMCSessionZMQ] verify that _omc is not None in sendExpression()
1 parent a6d877d commit 1fa4cfd

File tree

4 files changed

+66
-48
lines changed

4 files changed

+66
-48
lines changed

OMPython/ModelicaSystem.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
from dataclasses import dataclass
4747
from typing import Optional
4848

49-
from OMPython.OMCSession import OMCSessionBase, OMCSessionZMQ
49+
from OMPython.OMCSession import OMCSessionZMQ
5050

5151
# define logger using the current module name as ID
5252
logger = logging.getLogger(__name__)
@@ -117,7 +117,7 @@ def __init__(
117117
variableFilter: Optional[str] = None,
118118
customBuildDirectory: Optional[str | os.PathLike] = None,
119119
omhome: Optional[str] = None,
120-
session: Optional[OMCSessionBase] = None,
120+
session: Optional[OMCSessionZMQ] = None,
121121
build: Optional[bool] = True
122122
):
123123
"""Initialize, load and build a model.

OMPython/OMCSession.py

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
Definition of an OMC session.
44
"""
55

6+
from __future__ import annotations
7+
68
__license__ = """
79
This file is part of OpenModelica.
810
@@ -33,7 +35,6 @@
3335
"""
3436

3537
import shutil
36-
import abc
3738
import getpass
3839
import logging
3940
import json
@@ -80,41 +81,23 @@ class OMCSessionException(Exception):
8081
pass
8182

8283

83-
class OMCSessionBase(metaclass=abc.ABCMeta):
84+
class OMCSessionCmd:
8485

85-
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
8690
self._readonly = readonly
8791
self._omc_cache = {}
8892

89-
def execute(self, command):
90-
warnings.warn("This function is depreciated and will be removed in future versions; "
91-
"please use sendExpression() instead", DeprecationWarning, stacklevel=1)
92-
93-
return self.sendExpression(command, parsed=False)
94-
95-
@abc.abstractmethod
96-
def sendExpression(self, command, parsed=True):
97-
"""
98-
Sends an expression to the OpenModelica. The return type is parsed as if the
99-
expression was part of the typed OpenModelica API (see ModelicaBuiltin.mo).
100-
* Integer and Real are returned as Python numbers
101-
* Strings, enumerations, and typenames are returned as Python strings
102-
* Arrays, tuples, and MetaModelica lists are returned as tuples
103-
* Records are returned as dicts (the name of the record is lost)
104-
* Booleans are returned as True or False
105-
* NONE() is returned as None
106-
* SOME(value) is returned as value
107-
"""
108-
pass
109-
11093
def _ask(self, question: str, opt: Optional[list[str]] = None, parsed: Optional[bool] = True):
11194

11295
if opt is None:
11396
expression = question
11497
elif isinstance(opt, list):
11598
expression = f"{question}({','.join([str(x) for x in opt])})"
11699
else:
117-
raise Exception(f"Invalid definition of options for {repr(question)}: {repr(opt)}")
100+
raise OMCSessionException(f"Invalid definition of options for {repr(question)}: {repr(opt)}")
118101

119102
p = (expression, parsed)
120103

@@ -126,10 +109,9 @@ def _ask(self, question: str, opt: Optional[list[str]] = None, parsed: Optional[
126109
logger.debug('OMC ask: %s (parsed=%s)', expression, parsed)
127110

128111
try:
129-
res = self.sendExpression(expression, parsed=parsed)
130-
except OMCSessionException:
131-
logger.error("OMC failed: %s, %s, parsed=%s", question, opt, parsed)
132-
raise
112+
res = self._session.sendExpression(expression, parsed=parsed)
113+
except OMCSessionException as ex:
114+
raise OMCSessionException("OMC _ask() failed: %s (parsed=%s)", expression, parsed) from ex
133115

134116
# save response
135117
self._omc_cache[p] = res
@@ -201,9 +183,11 @@ def getClassComment(self, className):
201183
try:
202184
return self._ask(question='getClassComment', opt=[className])
203185
except pyparsing.ParseException as ex:
204-
logger.warning("Method 'getClassComment' failed for %s", className)
205-
logger.warning('OMTypedParser error: %s', ex.msg)
186+
logger.warning("Method 'getClassComment(%s)' failed; OMTypedParser error: %s",
187+
className, ex.msg)
206188
return 'No description available'
189+
except OMCSessionException:
190+
raise
207191

208192
def getNthComponent(self, className, comp_id):
209193
""" returns with (type, name, description) """
@@ -232,13 +216,18 @@ def getParameterNames(self, className):
232216
logger.warning('OMPython error: %s', ex)
233217
# FIXME: OMC returns with a different structure for empty parameter set
234218
return []
219+
except OMCSessionException:
220+
raise
235221

236222
def getParameterValue(self, className, parameterName):
237223
try:
238224
return self._ask(question='getParameterValue', opt=[className, parameterName])
239225
except pyparsing.ParseException as ex:
240-
logger.warning('OMTypedParser error: %s', ex.msg)
226+
logger.warning("Method 'getParameterValue(%s, %s)' failed; OMTypedParser error: %s",
227+
className, parameterName, ex.msg)
241228
return ""
229+
except OMCSessionException:
230+
raise
242231

243232
def getComponentModifierNames(self, className, componentName):
244233
return self._ask(question='getComponentModifierNames', opt=[className, componentName])
@@ -273,26 +262,22 @@ def getNthComponentModification(self, className, comp_id):
273262
# end getClassNames;
274263
def getClassNames(self, className=None, recursive=False, qualified=False, sort=False, builtin=False,
275264
showProtected=False):
276-
value = self._ask(question='getClassNames',
277-
opt=[className] if className else [] + [f'recursive={str(recursive).lower()}',
278-
f'qualified={str(qualified).lower()}',
279-
f'sort={str(sort).lower()}',
280-
f'builtin={str(builtin).lower()}',
281-
f'showProtected={str(showProtected).lower()}']
282-
)
283-
return value
265+
opt = [className] if className else [] + [f'recursive={str(recursive).lower()}',
266+
f'qualified={str(qualified).lower()}',
267+
f'sort={str(sort).lower()}',
268+
f'builtin={str(builtin).lower()}',
269+
f'showProtected={str(showProtected).lower()}']
270+
return self._ask(question='getClassNames', opt=opt)
284271

285272

286-
class OMCSessionZMQ(OMCSessionBase):
273+
class OMCSessionZMQ:
287274

288-
def __init__(self, readonly=False, timeout=10.00,
275+
def __init__(self, timeout=10.00,
289276
docker=None, dockerContainer=None, dockerExtraArgs=None, dockerOpenModelicaPath="omc",
290277
dockerNetwork=None, port=None, omhome: str = None):
291278
if dockerExtraArgs is None:
292279
dockerExtraArgs = []
293280

294-
super().__init__(readonly=readonly)
295-
296281
self.omhome = self._get_omhome(omhome=omhome)
297282

298283
self._omc_process = None
@@ -530,11 +515,20 @@ def _connect_to_omc(self, timeout):
530515
self._omc.setsockopt(zmq.IMMEDIATE, True) # Queue messages only to completed connections
531516
self._omc.connect(self._port)
532517

518+
def execute(self, command):
519+
warnings.warn("This function is depreciated and will be removed in future versions; "
520+
"please use sendExpression() instead", DeprecationWarning, stacklevel=1)
521+
522+
return self.sendExpression(command, parsed=False)
523+
533524
def sendExpression(self, command, parsed=True):
534525
p = self._omc_process.poll() # check if process is running
535526
if p is not None:
536527
raise OMCSessionException("Process Exited, No connection with OMC. Create a new instance of OMCSessionZMQ!")
537528

529+
if self._omc is None:
530+
raise OMCSessionException("No OMC running. Create a new instance of OMCSessionZMQ!")
531+
538532
attempts = 0
539533
while True:
540534
try:

OMPython/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
CONDITIONS OF OSMC-PL.
3737
"""
3838

39-
from OMPython.OMCSession import OMCSessionBase, OMCSessionZMQ, OMCSessionException
39+
from OMPython.OMCSession import OMCSessionCmd, OMCSessionZMQ, OMCSessionException
4040
from OMPython.ModelicaSystem import ModelicaSystem, ModelicaSystemError, LinearizationResult
4141

4242
# global names imported if import 'from OMPython import *' is used
@@ -47,5 +47,5 @@
4747

4848
'OMCSessionException',
4949
'OMCSessionZMQ',
50-
'OMCSessionBase',
50+
'OMCSessionCmd',
5151
]

tests/test_OMSessionCmd.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import OMPython
2+
import unittest
3+
4+
5+
class OMCSessionCmdTester(unittest.TestCase):
6+
def __init__(self, *args, **kwargs):
7+
super(OMCSessionCmdTester, self).__init__(*args, **kwargs)
8+
9+
def test_isPackage(self):
10+
omczmq = OMPython.OMCSessionZMQ()
11+
omccmd = OMPython.OMCSessionCmd(session=omczmq)
12+
assert not omccmd.isPackage('Modelica')
13+
14+
def test_isPackage2(self):
15+
mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog",
16+
lmodel=["Modelica"])
17+
omccmd = OMPython.OMCSessionCmd(session=mod.getconn)
18+
assert omccmd.isPackage('Modelica')
19+
20+
# TODO: add more checks ...
21+
22+
23+
if __name__ == '__main__':
24+
unittest.main()

0 commit comments

Comments
 (0)