Skip to content

Commit c1a3d20

Browse files
authored
Merge branch 'master' into use_subprocess.run
2 parents 863d6b6 + 1ff0843 commit c1a3d20

3 files changed

Lines changed: 62 additions & 60 deletions

File tree

OMPython/OMCSession.py

Lines changed: 48 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
import warnings
5252

5353
# TODO: replace this with the new parser
54-
from OMPython import OMTypedParser
55-
from OMPython import OMParser
54+
from OMPython.OMTypedParser import parseString as om_parser_typed
55+
from OMPython.OMParser import om_parser_basic
5656

5757

5858
# define logger using the current module name as ID
@@ -75,15 +75,16 @@ def wait(self, timeout):
7575
return self.process.wait(timeout=timeout)
7676

7777

78+
class OMCSessionException(Exception):
79+
pass
80+
81+
7882
class OMCSessionBase(metaclass=abc.ABCMeta):
7983

8084
def __init__(self, readonly=False):
8185
self._readonly = readonly
8286
self._omc_cache = {}
8387

84-
def clearOMParserResult(self):
85-
OMParser.result = {}
86-
8788
def execute(self, command):
8889
warnings.warn("This function is depreciated and will be removed in future versions; "
8990
"please use sendExpression() instead", DeprecationWarning, stacklevel=1)
@@ -122,7 +123,7 @@ def ask(self, question, opt=None, parsed=True):
122123

123124
try:
124125
res = self.sendExpression(expression, parsed=parsed)
125-
except Exception:
126+
except OMCSessionException:
126127
logger.error("OMC failed: %s, %s, parsed=%s", question, opt, parsed)
127128
raise
128129

@@ -197,7 +198,7 @@ def getClassComment(self, className):
197198
return self.ask('getClassComment', className)
198199
except pyparsing.ParseException as ex:
199200
logger.warning("Method 'getClassComment' failed for %s", className)
200-
logger.warning('OMTypedParser error: %s', ex.message)
201+
logger.warning('OMTypedParser error: %s', ex.msg)
201202
return 'No description available'
202203

203204
def getNthComponent(self, className, comp_id):
@@ -232,44 +233,20 @@ def getParameterValue(self, className, parameterName):
232233
try:
233234
return self.ask('getParameterValue', f'{className}, {parameterName}')
234235
except pyparsing.ParseException as ex:
235-
logger.warning('OMTypedParser error: %s', ex.message)
236+
logger.warning('OMTypedParser error: %s', ex.msg)
236237
return ""
237238

238239
def getComponentModifierNames(self, className, componentName):
239240
return self.ask('getComponentModifierNames', f'{className}, {componentName}')
240241

241242
def getComponentModifierValue(self, className, componentName):
242-
try:
243-
# FIXME: OMPython exception UnboundLocalError exception for 'Modelica.Fluid.Machines.ControlledPump'
244-
return self.ask('getComponentModifierValue', f'{className}, {componentName}')
245-
except pyparsing.ParseException as ex:
246-
logger.warning('OMTypedParser error: %s', ex.message)
247-
result = self.ask('getComponentModifierValue', f'{className}, {componentName}', parsed=False)
248-
try:
249-
answer = OMParser.check_for_values(result)
250-
OMParser.result = {}
251-
return answer[2:]
252-
except (TypeError, UnboundLocalError) as ex:
253-
logger.warning('OMParser error: %s', ex)
254-
return result
243+
return self.ask(question='getComponentModifierValue', opt=f'{className}, {componentName}')
255244

256245
def getExtendsModifierNames(self, className, componentName):
257246
return self.ask('getExtendsModifierNames', f'{className}, {componentName}')
258247

259248
def getExtendsModifierValue(self, className, extendsName, modifierName):
260-
try:
261-
# FIXME: OMPython exception UnboundLocalError exception for 'Modelica.Fluid.Machines.ControlledPump'
262-
return self.ask('getExtendsModifierValue', f'{className}, {extendsName}, {modifierName}')
263-
except pyparsing.ParseException as ex:
264-
logger.warning('OMTypedParser error: %s', ex.message)
265-
result = self.ask('getExtendsModifierValue', f'{className}, {extendsName}, {modifierName}', parsed=False)
266-
try:
267-
answer = OMParser.check_for_values(result)
268-
OMParser.result = {}
269-
return answer[2:]
270-
except (TypeError, UnboundLocalError) as ex:
271-
logger.warning('OMParser error: %s', ex)
272-
return result
249+
return self.ask(question='getExtendsModifierValue', opt=f'{className}, {extendsName}, {modifierName}')
273250

274251
def getNthComponentModification(self, className, comp_id):
275252
# FIXME: OMPython exception Results KeyError exception
@@ -323,7 +300,7 @@ def __init__(self, readonly=False, timeout=10.00,
323300
self._serverIPAddress = "127.0.0.1"
324301
self._interactivePort = None
325302
# FIXME: this code is not well written... need to be refactored
326-
self._temp_dir = tempfile.gettempdir()
303+
self._temp_dir = pathlib.Path(tempfile.gettempdir())
327304
# generate a random string for this session
328305
self._random_string = uuid.uuid4().hex
329306
# omc log file
@@ -348,7 +325,7 @@ def __init__(self, readonly=False, timeout=10.00,
348325
self._dockerNetwork = dockerNetwork
349326
self._create_omc_log_file("port")
350327
self._timeout = timeout
351-
self._port_file = os.path.join("/tmp" if docker else self._temp_dir, self._port_file).replace("\\", "/")
328+
self._port_file = ((pathlib.Path("/tmp") if docker else self._temp_dir) / self._port_file).as_posix()
352329
self._interactivePort = port
353330
# set omc executable path and args
354331
self._set_omc_command([
@@ -364,14 +341,15 @@ def __init__(self, readonly=False, timeout=10.00,
364341
def __del__(self):
365342
try:
366343
self.sendExpression("quit()")
367-
except Exception:
344+
except OMCSessionException:
368345
pass
369346
self._omc_log_file.close()
370347
try:
371348
self._omc_process.wait(timeout=2.0)
372-
except Exception:
349+
except subprocess.TimeoutExpired:
373350
if self._omc_process:
374-
logger.warning("OMC did not exit after being sent the quit() command; killing the process with pid=%s", self._omc_process.pid)
351+
logger.warning("OMC did not exit after being sent the quit() command; "
352+
"killing the process with pid=%s", self._omc_process.pid)
375353
self._omc_process.kill()
376354
self._omc_process.wait()
377355

@@ -381,7 +359,7 @@ def _create_omc_log_file(self, suffix):
381359
else:
382360
log_filename = f"openmodelica.{self._currentUser}.{suffix}.{self._random_string}.log"
383361
# this file must be closed in the destructor
384-
self._omc_log_file = open(pathlib.Path(self._temp_dir) / log_filename, "w+")
362+
self._omc_log_file = open(self._temp_dir / log_filename, "w+")
385363

386364
def _start_omc_process(self, timeout):
387365
if sys.platform == 'win32':
@@ -401,18 +379,19 @@ def _start_omc_process(self, timeout):
401379
try:
402380
with open(self._dockerCidFile, "r") as fin:
403381
self._dockerCid = fin.read().strip()
404-
except Exception:
382+
except IOError:
405383
pass
406384
if self._dockerCid:
407385
break
408386
time.sleep(timeout / 40.0)
409387
try:
410388
os.remove(self._dockerCidFile)
411-
except Exception:
389+
except FileNotFoundError:
412390
pass
413391
if self._dockerCid is None:
414392
logger.error("Docker did not start. Log-file says:\n%s" % (open(self._omc_log_file.name).read()))
415-
raise Exception("Docker did not start (timeout=%f might be too short especially if you did not docker pull the image before this command)." % timeout)
393+
raise OMCSessionException("Docker did not start (timeout=%f might be too short especially if you did "
394+
"not docker pull the image before this command)." % timeout)
416395

417396
dockerTop = None
418397
if self._docker or self._dockerContainer:
@@ -429,17 +408,16 @@ def _start_omc_process(self, timeout):
429408
try:
430409
self._omc_process = DummyPopen(int(columns[1]))
431410
except psutil.NoSuchProcess:
432-
raise Exception(
433-
f"Could not find PID {dockerTop} - is this a docker instance spawned without --pid=host?\n"
434-
f"Log-file says:\n{open(self._omc_log_file.name).read()}")
411+
raise OMCSessionException(
412+
f"Could not find PID {dockerTop} - is this a docker instance spawned "
413+
f"without --pid=host?\nLog-file says:\n{open(self._omc_log_file.name).read()}")
435414
break
436415
if self._omc_process is not None:
437416
break
438417
time.sleep(timeout / 40.0)
439418
if self._omc_process is None:
440-
441-
raise Exception("Docker top did not contain omc process %s:\n%s\nLog-file says:\n%s"
442-
% (self._random_string, dockerTop, open(self._omc_log_file.name).read()))
419+
raise OMCSessionException("Docker top did not contain omc process %s:\n%s\nLog-file says:\n%s"
420+
% (self._random_string, dockerTop, open(self._omc_log_file.name).read()))
443421
return self._omc_process
444422

445423
def _getuid(self):
@@ -460,7 +438,9 @@ def _set_omc_command(self, omc_path_and_args_list):
460438
if (self._docker or self._dockerContainer) and sys.platform == "win32":
461439
extraFlags = ["-d=zmqDangerousAcceptConnectionsFromAnywhere"]
462440
if not self._interactivePort:
463-
raise Exception("docker on Windows requires knowing which port to connect to. For dockerContainer=..., the container needs to have already manually exposed this port when it was started (-p 127.0.0.1:n:n) or you get an error later.")
441+
raise OMCSessionException("docker on Windows requires knowing which port to connect to. For "
442+
"dockerContainer=..., the container needs to have already manually exposed "
443+
"this port when it was started (-p 127.0.0.1:n:n) or you get an error later.")
464444
else:
465445
extraFlags = []
466446
if self._docker:
@@ -473,7 +453,7 @@ def _set_omc_command(self, omc_path_and_args_list):
473453
dockerNetworkStr = []
474454
extraFlags = ["-d=zmqDangerousAcceptConnectionsFromAnywhere"]
475455
else:
476-
raise Exception('dockerNetwork was set to %s, but only \"host\" or \"separate\" is allowed')
456+
raise OMCSessionException('dockerNetwork was set to %s, but only \"host\" or \"separate\" is allowed')
477457
self._dockerCidFile = self._omc_log_file.name + ".docker.cid"
478458
omcCommand = ["docker", "run", "--cidfile", self._dockerCidFile, "--rm", "--env", "USER=%s" % self._currentUser, "--user", str(self._getuid())] + self._dockerExtraArgs + dockerNetworkStr + [self._docker, self._dockerOpenModelicaPath]
479459
elif self._dockerContainer:
@@ -503,7 +483,7 @@ def _get_omhome(self, omhome: str = None):
503483
if path_to_omc is not None:
504484
return pathlib.Path(path_to_omc).parents[1]
505485

506-
raise ValueError("Cannot find OpenModelica executable, please install from openmodelica.org")
486+
raise OMCSessionException("Cannot find OpenModelica executable, please install from openmodelica.org")
507487

508488
def _get_omc_path(self) -> pathlib.Path:
509489
return self.omhome / "bin" / "omc"
@@ -516,9 +496,10 @@ def _connect_to_omc(self, timeout):
516496
while True:
517497
if self._dockerCid:
518498
try:
519-
self._port = subprocess.check_output(["docker", "exec", self._dockerCid, "cat", self._port_file], stderr=subprocess.DEVNULL).decode().strip()
499+
self._port = subprocess.check_output(["docker", "exec", self._dockerCid, "cat", self._port_file],
500+
stderr=subprocess.DEVNULL).decode().strip()
520501
break
521-
except Exception:
502+
except subprocess.CalledProcessError:
522503
pass
523504
else:
524505
if os.path.isfile(self._port_file):
@@ -533,7 +514,8 @@ def _connect_to_omc(self, timeout):
533514
name = self._omc_log_file.name
534515
self._omc_log_file.close()
535516
logger.error("OMC Server did not start. Please start it! Log-file says:\n%s" % open(name).read())
536-
raise Exception(f"OMC Server did not start (timeout={timeout}). Could not open file {self._port_file}")
517+
raise OMCSessionException(f"OMC Server did not start (timeout={timeout}). "
518+
"Could not open file {self._port_file}")
537519
time.sleep(timeout / 80.0)
538520

539521
self._port = self._port.replace("0.0.0.0", self._serverIPAddress)
@@ -549,7 +531,7 @@ def _connect_to_omc(self, timeout):
549531
def sendExpression(self, command, parsed=True):
550532
p = self._omc_process.poll() # check if process is running
551533
if p is not None:
552-
raise Exception("Process Exited, No connection with OMC. Create a new instance of OMCSessionZMQ")
534+
raise OMCSessionException("Process Exited, No connection with OMC. Create a new instance of OMCSessionZMQ!")
553535

554536
attempts = 0
555537
while True:
@@ -563,7 +545,7 @@ def sendExpression(self, command, parsed=True):
563545
self._omc_log_file.seek(0)
564546
log = self._omc_log_file.read()
565547
self._omc_log_file.close()
566-
raise Exception(f"No connection with OMC (timeout={self._timeout}). Log-file says: \n{log}")
548+
raise OMCSessionException(f"No connection with OMC (timeout={self._timeout}). Log-file says: \n{log}")
567549
time.sleep(self._timeout / 50.0)
568550
if command == "quit()":
569551
self._omc.close()
@@ -572,7 +554,14 @@ def sendExpression(self, command, parsed=True):
572554
else:
573555
result = self._omc.recv_string()
574556
if parsed is True:
575-
answer = OMTypedParser.parseString(result)
576-
return answer
557+
try:
558+
return om_parser_typed(result)
559+
except pyparsing.ParseException as ex:
560+
logger.warning('OMTypedParser error: %s. Returning the basic parser result.', ex.msg)
561+
try:
562+
return om_parser_basic(result)
563+
except (TypeError, UnboundLocalError) as ex:
564+
logger.warning('OMParser error: %s. Returning the unparsed result.', ex)
565+
return result
577566
else:
578567
return result

OMPython/OMParser.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,3 +892,15 @@ def check_for_values(string):
892892
check_for_values(next_set)
893893

894894
return result
895+
896+
897+
# TODO: hack to be able to use one entry point which also resets the (global) variable results
898+
# this should be checked such that the content of this file can be used as class with correct handling of
899+
# variable usage
900+
def om_parser_basic(string: str):
901+
result_return = check_for_values(string=string)
902+
903+
global result
904+
result = {}
905+
906+
return result_return

OMPython/__init__.py

Lines changed: 2 additions & 1 deletion
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
39+
from OMPython.OMCSession import OMCSessionBase, OMCSessionZMQ, OMCSessionException
4040
from OMPython.ModelicaSystem import ModelicaSystem, ModelicaSystemError, LinearizationResult
4141

4242
# global names imported if import 'from OMPython import *' is used
@@ -45,6 +45,7 @@
4545
'ModelicaSystemError',
4646
'LinearizationResult',
4747

48+
'OMCSessionException',
4849
'OMCSessionZMQ',
4950
'OMCSessionBase',
5051
]

0 commit comments

Comments
 (0)