-
Notifications
You must be signed in to change notification settings - Fork 61
Finish error handling #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
81bcc74
f67f740
b7fc5b2
b2e4cb3
efc1d60
eae47bb
94ec48b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,7 @@ | |
import os | ||
import pathlib | ||
import psutil | ||
import re | ||
import signal | ||
import subprocess | ||
import sys | ||
|
@@ -325,6 +326,9 @@ def __init__(self, timeout=10.00, | |
# connect to the running omc instance using ZMQ | ||
self._connect_to_omc(timeout) | ||
|
||
self._re_log_entries = None | ||
self._re_log_raw = None | ||
|
||
def __del__(self): | ||
try: | ||
self.sendExpression("quit()") | ||
|
@@ -549,6 +553,62 @@ def sendExpression(self, command, parsed=True): | |
return None | ||
else: | ||
result = self._omc.recv_string() | ||
|
||
if command == "getErrorString()": | ||
# no error handling if 'getErrorString()' is called | ||
pass | ||
elif command == "getMessagesStringInternal()": | ||
# no error handling if 'getMessagesStringInternal()' is called; parsing NOT possible! | ||
if parsed: | ||
logger.warning("Result of 'getMessagesStringInternal()' cannot be parsed - set parsed to False!") | ||
parsed = False | ||
else: | ||
# allways check for error | ||
self._omc.send_string('getMessagesStringInternal()', flags=zmq.NOBLOCK) | ||
error_raw = self._omc.recv_string() | ||
# run error handling only if there is something to check | ||
if error_raw != "{}\n": | ||
if not self._re_log_entries: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I defined them as class variables to do the initialisation once (if needed at all). Later, the compiled re struture is just reused ... However, if the expected numbers of calls to this part is low, it makes sense to run this each time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The actual re compilation is run each time, its just they are initialized to none only once. I don't think initializing them to none locally is expensive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in OMCSession.py line 584ff (definition of sendExpression()):
Compilation is done only once (on first call; self._re* class variables are None); after that, the variables are set (not None) and, thus, the compiled version is used ... |
||
self._re_log_entries = re.compile(pattern=r'record OpenModelica\.Scripting\.ErrorMessage' | ||
'(.*?)' | ||
r'end OpenModelica\.Scripting\.ErrorMessage;', | ||
flags=re.MULTILINE | re.DOTALL) | ||
if not self._re_log_raw: | ||
self._re_log_raw = re.compile( | ||
pattern=r"\s+message = \"(.*?)\",\n" # message | ||
r"\s+kind = .OpenModelica.Scripting.ErrorKind.(.*?),\n" # kind | ||
r"\s+level = .OpenModelica.Scripting.ErrorLevel.(.*?),\n" # level | ||
r"\s+id = (.*?)" # id | ||
"(,\n|\n)", # end marker | ||
flags=re.MULTILINE | re.DOTALL) | ||
|
||
# extract all ErrorMessage records | ||
log_entries = self._re_log_entries.findall(string=error_raw) | ||
for log_entry in reversed(log_entries): | ||
log_raw = self._re_log_raw.findall(string=log_entry) | ||
if len(log_raw) != 1 or len(log_raw[0]) != 5: | ||
logger.warning("Invalid ErrorMessage record returned by 'getMessagesStringInternal()':" | ||
f" {repr(log_entry)}!") | ||
|
||
log_message = log_raw[0][0].encode().decode('unicode_escape') | ||
log_kind = log_raw[0][1] | ||
log_level = log_raw[0][2] | ||
log_id = log_raw[0][3] | ||
|
||
msg = (f"[OMC log for 'sendExpression({command}, {parsed})']: " | ||
f"[{log_kind}:{log_level}:{log_id}] {log_message}") | ||
|
||
# response according to the used log level | ||
# see: https://build.openmodelica.org/Documentation/OpenModelica.Scripting.ErrorLevel.html | ||
if log_level == 'error': | ||
raise OMCSessionException(msg) | ||
elif log_level == 'warning': | ||
logger.warning(msg) | ||
elif log_level == 'notification': | ||
logger.info(msg) | ||
else: # internal | ||
logger.debug(msg) | ||
|
||
if parsed is True: | ||
try: | ||
return om_parser_typed(result) | ||
|
@@ -557,7 +617,6 @@ def sendExpression(self, command, parsed=True): | |
try: | ||
return om_parser_basic(result) | ||
except (TypeError, UnboundLocalError) as ex: | ||
logger.warning('OMParser error: %s. Returning the unparsed result.', ex) | ||
return result | ||
raise OMCSessionException("Cannot parse OMC result") from ex | ||
else: | ||
return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to make them class members?