From ec13a05643116f3a26d03b1c8bc4eb6be7d0fc8b Mon Sep 17 00:00:00 2001 From: syntron Date: Thu, 24 Apr 2025 21:20:35 +0200 Subject: [PATCH 01/12] [DummyPopen] remove redundant parentheses --- OMPython/OMCSession.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 04615b9ed..bafb545a6 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -62,7 +62,7 @@ logger = logging.getLogger(__name__) -class DummyPopen(): +class DummyPopen: def __init__(self, pid): self.pid = pid self.process = psutil.Process(pid) From 0d8eb54a7546c64b24debf896ec49c1c5c5df276 Mon Sep 17 00:00:00 2001 From: syntron Date: Tue, 29 Apr 2025 20:48:30 +0200 Subject: [PATCH 02/12] [OMCSession*] move logging into OMCSessionZMQ.sendExpression() --- OMPython/OMCSession.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index bafb545a6..073e5cbad 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -107,8 +107,6 @@ def _ask(self, question: str, opt: Optional[list[str]] = None, parsed: Optional[ if p in self._omc_cache: return self._omc_cache[p] - logger.debug('OMC ask: %s (parsed=%s)', expression, parsed) - try: res = self._session.sendExpression(expression, parsed=parsed) except OMCSessionException as ex: @@ -533,6 +531,8 @@ def sendExpression(self, command, parsed=True): if self._omc is None: raise OMCSessionException("No OMC running. Create a new instance of OMCSessionZMQ!") + logger.debug("sendExpression(%r, parsed=%r)", command, parsed) + attempts = 0 while True: try: From 49eb694003e2ec1dc2216f444016bc41027740d5 Mon Sep 17 00:00:00 2001 From: syntron Date: Tue, 6 May 2025 08:41:02 +0200 Subject: [PATCH 03/12] [OMCSessionZMQ] fix f-string --- OMPython/OMCSession.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 073e5cbad..180a63447 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -504,7 +504,7 @@ def _connect_to_omc(self, timeout): self._omc_log_file.close() logger.error("OMC Server did not start. Please start it! Log-file says:\n%s" % open(name).read()) raise OMCSessionException(f"OMC Server did not start (timeout={timeout}). " - "Could not open file {self._port_file}") + f"Could not open file {self._port_file}") time.sleep(timeout / 80.0) self._port = self._port.replace("0.0.0.0", self._serverIPAddress) From b60428c451f0aed6222dc90005ddf1d873920039 Mon Sep 17 00:00:00 2001 From: syntron Date: Thu, 8 May 2025 09:32:22 +0200 Subject: [PATCH 04/12] [OMCSessionZMQ] layout fix based on PyCharm warnings --- OMPython/OMCSession.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 180a63447..e368ede8b 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -57,7 +57,6 @@ from OMPython.OMTypedParser import parseString as om_parser_typed from OMPython.OMParser import om_parser_basic - # define logger using the current module name as ID logger = logging.getLogger(__name__) @@ -314,11 +313,9 @@ def __init__(self, timeout=10.00, self._port_file = ((pathlib.Path("/tmp") if docker else self._temp_dir) / self._port_file).as_posix() self._interactivePort = port # set omc executable path and args - self._set_omc_command([ - "--interactive=zmq", - "--locale=C", - f"-z={self._random_string}" - ]) + self._set_omc_command(omc_path_and_args_list=["--interactive=zmq", + "--locale=C", + f"-z={self._random_string}"]) # start up omc executable, which is waiting for the ZMQ connection self._start_omc_process(timeout) # connect to the running omc instance using ZMQ @@ -385,7 +382,8 @@ def _start_omc_process(self, timeout): dockerTop = None if self._docker or self._dockerContainer: if self._dockerNetwork == "separate": - self._serverIPAddress = json.loads(subprocess.check_output(["docker", "inspect", self._dockerCid]).decode().strip())[0]["NetworkSettings"]["IPAddress"] + output = subprocess.check_output(["docker", "inspect", self._dockerCid]).decode().strip() + self._serverIPAddress = json.loads(output)[0]["NetworkSettings"]["IPAddress"] for i in range(0, 40): if sys.platform == 'win32': break @@ -444,9 +442,20 @@ def _set_omc_command(self, omc_path_and_args_list): else: raise OMCSessionException('dockerNetwork was set to %s, but only \"host\" or \"separate\" is allowed') self._dockerCidFile = self._omc_log_file.name + ".docker.cid" - omcCommand = ["docker", "run", "--cidfile", self._dockerCidFile, "--rm", "--env", "USER=%s" % self._currentUser, "--user", str(self._getuid())] + self._dockerExtraArgs + dockerNetworkStr + [self._docker, self._dockerOpenModelicaPath] + omcCommand = (["docker", "run", + "--cidfile", self._dockerCidFile, + "--rm", + "--env", "USER=%s" % self._currentUser, + "--user", str(self._getuid())] + + self._dockerExtraArgs + + dockerNetworkStr + + [self._docker, self._dockerOpenModelicaPath]) elif self._dockerContainer: - omcCommand = ["docker", "exec", "--env", "USER=%s" % self._currentUser, "--user", str(self._getuid())] + self._dockerExtraArgs + [self._dockerContainer, self._dockerOpenModelicaPath] + omcCommand = (["docker", "exec", + "--env", "USER=%s" % self._currentUser, + "--user", str(self._getuid())] + + self._dockerExtraArgs + + [self._dockerContainer, self._dockerOpenModelicaPath]) self._dockerCid = self._dockerContainer else: omcCommand = [str(self._get_omc_path())] @@ -508,7 +517,8 @@ def _connect_to_omc(self, timeout): time.sleep(timeout / 80.0) self._port = self._port.replace("0.0.0.0", self._serverIPAddress) - logger.info(f"OMC Server is up and running at {self._omc_zeromq_uri} pid={self._omc_process.pid} cid={self._dockerCid}") + logger.info(f"OMC Server is up and running at {self._omc_zeromq_uri} " + f"pid={self._omc_process.pid} cid={self._dockerCid}") # Create the ZeroMQ socket and connect to OMC server context = zmq.Context.instance() From 7124ed739738ff8a68df566a16cd422aa868fd7e Mon Sep 17 00:00:00 2001 From: syntron Date: Tue, 6 May 2025 08:58:47 +0200 Subject: [PATCH 05/12] [OMCSessionZMQ] rename omhome => _omhome --- OMPython/OMCSession.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index e368ede8b..093fee6d0 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -276,7 +276,7 @@ def __init__(self, timeout=10.00, if dockerExtraArgs is None: dockerExtraArgs = [] - self.omhome = self._get_omhome(omhome=omhome) + self._omhome = self._get_omhome(omhome=omhome) self._omc_process = None self._omc_command = None @@ -349,7 +349,7 @@ def _create_omc_log_file(self, suffix): def _start_omc_process(self, timeout): if sys.platform == 'win32': - omhome_bin = (self.omhome / "bin").as_posix() + omhome_bin = (self._omhome / "bin").as_posix() my_env = os.environ.copy() my_env["PATH"] = omhome_bin + os.pathsep + my_env["PATH"] self._omc_process = subprocess.Popen(self._omc_command, stdout=self._omc_log_file, @@ -484,7 +484,7 @@ def _get_omhome(self, omhome: str = None): raise OMCSessionException("Cannot find OpenModelica executable, please install from openmodelica.org") def _get_omc_path(self) -> pathlib.Path: - return self.omhome / "bin" / "omc" + return self._omhome / "bin" / "omc" def _connect_to_omc(self, timeout): self._omc_zeromq_uri = "file:///" + self._port_file From 53dfbbfe4c478a0e147b1b5f2039c10bab208d6b Mon Sep 17 00:00:00 2001 From: syntron Date: Fri, 9 May 2025 10:22:35 +0200 Subject: [PATCH 06/12] [OMCSessionZMQ] update _create_omc_log_file() --- OMPython/OMCSession.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 093fee6d0..92cc78ab2 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -288,8 +288,6 @@ def __init__(self, timeout=10.00, self._temp_dir = pathlib.Path(tempfile.gettempdir()) # generate a random string for this session self._random_string = uuid.uuid4().hex - # omc log file - self._omc_log_file = None try: self._currentUser = getpass.getuser() if not self._currentUser: @@ -308,7 +306,7 @@ def __init__(self, timeout=10.00, self._dockerExtraArgs = dockerExtraArgs self._dockerOpenModelicaPath = dockerOpenModelicaPath self._dockerNetwork = dockerNetwork - self._create_omc_log_file("port") + self._omc_log_file = self._create_omc_log_file("port") self._timeout = timeout self._port_file = ((pathlib.Path("/tmp") if docker else self._temp_dir) / self._port_file).as_posix() self._interactivePort = port @@ -339,13 +337,15 @@ def __del__(self): self._omc_process.kill() self._omc_process.wait() - def _create_omc_log_file(self, suffix): + def _create_omc_log_file(self, suffix): # output? if sys.platform == 'win32': log_filename = f"openmodelica.{suffix}.{self._random_string}.log" else: log_filename = f"openmodelica.{self._currentUser}.{suffix}.{self._random_string}.log" # this file must be closed in the destructor - self._omc_log_file = open(self._temp_dir / log_filename, "w+") + omc_log_file = open(self._temp_dir / log_filename, "w+") + + return omc_log_file def _start_omc_process(self, timeout): if sys.platform == 'win32': From 7c08a02d38f74a2326dc6f45fad877c70019f6ad Mon Sep 17 00:00:00 2001 From: syntron Date: Fri, 9 May 2025 10:28:56 +0200 Subject: [PATCH 07/12] [OMCSessionZMQ] remove fixme - check source of this line --- OMPython/OMCSession.py | 1 - 1 file changed, 1 deletion(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 92cc78ab2..867e1d573 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -284,7 +284,6 @@ def __init__(self, timeout=10.00, self._dockerCid = None self._serverIPAddress = "127.0.0.1" self._interactivePort = None - # FIXME: this code is not well written... need to be refactored self._temp_dir = pathlib.Path(tempfile.gettempdir()) # generate a random string for this session self._random_string = uuid.uuid4().hex From d30bf9a833c5597e76723c725e2c663ec13b0ea1 Mon Sep 17 00:00:00 2001 From: syntron Date: Fri, 9 May 2025 10:34:20 +0200 Subject: [PATCH 08/12] [OMCSessionZMQ] simplify _port_file --- OMPython/OMCSession.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 867e1d573..dd433c266 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -295,11 +295,6 @@ def __init__(self, timeout=10.00, # We are running as a uid not existing in the password database... Pretend we are nobody self._currentUser = "nobody" - # Locating and using the IOR - if sys.platform != 'win32' or docker or dockerContainer: - self._port_file = "openmodelica." + self._currentUser + ".port." + self._random_string - else: - self._port_file = "openmodelica.port." + self._random_string self._docker = docker self._dockerContainer = dockerContainer self._dockerExtraArgs = dockerExtraArgs @@ -307,7 +302,12 @@ def __init__(self, timeout=10.00, self._dockerNetwork = dockerNetwork self._omc_log_file = self._create_omc_log_file("port") self._timeout = timeout - self._port_file = ((pathlib.Path("/tmp") if docker else self._temp_dir) / self._port_file).as_posix() + # Locating and using the IOR + if sys.platform != 'win32' or docker or dockerContainer: + port_file = "openmodelica." + self._currentUser + ".port." + self._random_string + else: + port_file = "openmodelica.port." + self._random_string + self._port_file = ((pathlib.Path("/tmp") if docker else self._temp_dir) / port_file).as_posix() self._interactivePort = port # set omc executable path and args self._set_omc_command(omc_path_and_args_list=["--interactive=zmq", From 15bc0ce0947ebad1ecaaedf5a070991cbcfc41a7 Mon Sep 17 00:00:00 2001 From: syntron Date: Fri, 9 May 2025 10:29:08 +0200 Subject: [PATCH 09/12] [OMCSessionZMQ] simplify _connect_to_omc() / _port --- OMPython/OMCSession.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index dd433c266..2eb1af3ed 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -316,7 +316,7 @@ def __init__(self, timeout=10.00, # start up omc executable, which is waiting for the ZMQ connection self._start_omc_process(timeout) # connect to the running omc instance using ZMQ - self._connect_to_omc(timeout) + self._omc_port = self._connect_to_omc(timeout) self._re_log_entries = None self._re_log_raw = None @@ -485,16 +485,16 @@ def _get_omhome(self, omhome: str = None): def _get_omc_path(self) -> pathlib.Path: return self._omhome / "bin" / "omc" - def _connect_to_omc(self, timeout): - self._omc_zeromq_uri = "file:///" + self._port_file + def _connect_to_omc(self, timeout) -> str: + omc_zeromq_uri = "file:///" + self._port_file # See if the omc server is running attempts = 0 - self._port = None + port = None while True: if self._dockerCid: try: - self._port = subprocess.check_output(["docker", "exec", self._dockerCid, "cat", self._port_file], - stderr=subprocess.DEVNULL).decode().strip() + port = subprocess.check_output(["docker", "exec", self._dockerCid, "cat", self._port_file], + stderr=subprocess.DEVNULL).decode().strip() break except subprocess.CalledProcessError: pass @@ -502,7 +502,7 @@ def _connect_to_omc(self, timeout): if os.path.isfile(self._port_file): # Read the port file with open(self._port_file, 'r') as f_p: - self._port = f_p.readline() + port = f_p.readline() os.remove(self._port_file) break @@ -515,8 +515,8 @@ def _connect_to_omc(self, timeout): f"Could not open file {self._port_file}") time.sleep(timeout / 80.0) - self._port = self._port.replace("0.0.0.0", self._serverIPAddress) - logger.info(f"OMC Server is up and running at {self._omc_zeromq_uri} " + port = port.replace("0.0.0.0", self._serverIPAddress) + logger.info(f"OMC Server is up and running at {omc_zeromq_uri} " f"pid={self._omc_process.pid} cid={self._dockerCid}") # Create the ZeroMQ socket and connect to OMC server @@ -524,7 +524,9 @@ def _connect_to_omc(self, timeout): self._omc = context.socket(zmq.REQ) self._omc.setsockopt(zmq.LINGER, 0) # Dismisses pending messages if closed self._omc.setsockopt(zmq.IMMEDIATE, True) # Queue messages only to completed connections - self._omc.connect(self._port) + self._omc.connect(port) + + return port def execute(self, command): warnings.warn("This function is depreciated and will be removed in future versions; " From eeccdfa23fc8081eac8e580816db4f3f3bdcd71a Mon Sep 17 00:00:00 2001 From: syntron Date: Fri, 9 May 2025 10:26:36 +0200 Subject: [PATCH 10/12] [OMCSessionZMQ] cleanup self._start_omc_process() --- OMPython/OMCSession.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 2eb1af3ed..58a4b87eb 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -314,7 +314,7 @@ def __init__(self, timeout=10.00, "--locale=C", f"-z={self._random_string}"]) # start up omc executable, which is waiting for the ZMQ connection - self._start_omc_process(timeout) + self._omc_process = self._start_omc_process(timeout) # connect to the running omc instance using ZMQ self._omc_port = self._connect_to_omc(timeout) @@ -346,19 +346,19 @@ def _create_omc_log_file(self, suffix): # output? return omc_log_file - def _start_omc_process(self, timeout): + def _start_omc_process(self, timeout): # output? if sys.platform == 'win32': omhome_bin = (self._omhome / "bin").as_posix() my_env = os.environ.copy() my_env["PATH"] = omhome_bin + os.pathsep + my_env["PATH"] - self._omc_process = subprocess.Popen(self._omc_command, stdout=self._omc_log_file, - stderr=self._omc_log_file, env=my_env) + omc_process = subprocess.Popen(self._omc_command, stdout=self._omc_log_file, + stderr=self._omc_log_file, env=my_env) else: # set the user environment variable so omc running from wsgi has the same user as OMPython my_env = os.environ.copy() my_env["USER"] = self._currentUser - self._omc_process = subprocess.Popen(self._omc_command, stdout=self._omc_log_file, - stderr=self._omc_log_file, env=my_env) + omc_process = subprocess.Popen(self._omc_command, stdout=self._omc_log_file, + stderr=self._omc_log_file, env=my_env) if self._docker: for i in range(0, 40): try: @@ -387,24 +387,24 @@ def _start_omc_process(self, timeout): if sys.platform == 'win32': break dockerTop = subprocess.check_output(["docker", "top", self._dockerCid]).decode().strip() - self._omc_process = None + omc_process = None for line in dockerTop.split("\n"): columns = line.split() if self._random_string in line: try: - self._omc_process = DummyPopen(int(columns[1])) + omc_process = DummyPopen(int(columns[1])) except psutil.NoSuchProcess: raise OMCSessionException( f"Could not find PID {dockerTop} - is this a docker instance spawned " f"without --pid=host?\nLog-file says:\n{open(self._omc_log_file.name).read()}") break - if self._omc_process is not None: + if omc_process is not None: break time.sleep(timeout / 40.0) - if self._omc_process is None: + if omc_process is None: raise OMCSessionException("Docker top did not contain omc process %s:\n%s\nLog-file says:\n%s" % (self._random_string, dockerTop, open(self._omc_log_file.name).read())) - return self._omc_process + return omc_process def _getuid(self): """ From 4ce10d5d9b5517e409ab4f8f3e56d505fb8ca015 Mon Sep 17 00:00:00 2001 From: syntron Date: Wed, 28 May 2025 20:25:33 +0200 Subject: [PATCH 11/12] [OMCSessionZMQ] cleanup self._set_omc_command() --- OMPython/OMCSession.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 58a4b87eb..cdf04b090 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -310,9 +310,9 @@ def __init__(self, timeout=10.00, self._port_file = ((pathlib.Path("/tmp") if docker else self._temp_dir) / port_file).as_posix() self._interactivePort = port # set omc executable path and args - self._set_omc_command(omc_path_and_args_list=["--interactive=zmq", - "--locale=C", - f"-z={self._random_string}"]) + self._omc_command = self._set_omc_command(omc_path_and_args_list=["--interactive=zmq", + "--locale=C", + f"-z={self._random_string}"]) # start up omc executable, which is waiting for the ZMQ connection self._omc_process = self._start_omc_process(timeout) # connect to the running omc instance using ZMQ @@ -414,7 +414,7 @@ def _getuid(self): """ return 1000 if sys.platform == 'win32' else os.getuid() - def _set_omc_command(self, omc_path_and_args_list): + def _set_omc_command(self, omc_path_and_args_list) -> list: """Define the command that will be called by the subprocess module. On Windows, use the list input style of the subprocess module to @@ -461,9 +461,9 @@ def _set_omc_command(self, omc_path_and_args_list): if self._interactivePort: extraFlags = extraFlags + ["--interactivePort=%d" % int(self._interactivePort)] - self._omc_command = omcCommand + omc_path_and_args_list + extraFlags + omc_command = omcCommand + omc_path_and_args_list + extraFlags - return self._omc_command + return omc_command def _get_omhome(self, omhome: str = None): # use the provided path From cf937cc1f614d234c898c6634b518eeca09e4788 Mon Sep 17 00:00:00 2001 From: syntron Date: Thu, 22 May 2025 20:42:19 +0200 Subject: [PATCH 12/12] [OMCSession*] fix mypy warnings --- OMPython/OMCSession.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index cdf04b090..ff1a6cca4 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -48,7 +48,7 @@ import sys import tempfile import time -from typing import Optional +from typing import Any, Optional import uuid import warnings import zmq @@ -83,14 +83,14 @@ class OMCSessionException(Exception): class OMCSessionCmd: - def __init__(self, session: OMCSessionZMQ, readonly: Optional[bool] = False): + def __init__(self, session: OMCSessionZMQ, readonly: bool = False): if not isinstance(session, OMCSessionZMQ): raise OMCSessionException("Invalid session definition!") self._session = session self._readonly = readonly - self._omc_cache = {} + self._omc_cache: dict[tuple[str, bool], Any] = {} - def _ask(self, question: str, opt: Optional[list[str]] = None, parsed: Optional[bool] = True): + def _ask(self, question: str, opt: Optional[list[str]] = None, parsed: bool = True): if opt is None: expression = question @@ -270,9 +270,15 @@ def getClassNames(self, className=None, recursive=False, qualified=False, sort=F class OMCSessionZMQ: - def __init__(self, timeout=10.00, - docker=None, dockerContainer=None, dockerExtraArgs=None, dockerOpenModelicaPath="omc", - dockerNetwork=None, port=None, omhome: str = None): + def __init__(self, + timeout: float = 10.00, + docker: Optional[str] = None, + dockerContainer: Optional[int] = None, + dockerExtraArgs: Optional[list] = None, + dockerOpenModelicaPath: str = "omc", + dockerNetwork: Optional[str] = None, + port: Optional[int] = None, + omhome: Optional[str] = None): if dockerExtraArgs is None: dockerExtraArgs = [] @@ -280,8 +286,8 @@ def __init__(self, timeout=10.00, self._omc_process = None self._omc_command = None - self._omc = None - self._dockerCid = None + self._omc: Optional[Any] = None + self._dockerCid: Optional[int] = None self._serverIPAddress = "127.0.0.1" self._interactivePort = None self._temp_dir = pathlib.Path(tempfile.gettempdir()) @@ -465,7 +471,7 @@ def _set_omc_command(self, omc_path_and_args_list) -> list: return omc_command - def _get_omhome(self, omhome: str = None): + def _get_omhome(self, omhome: Optional[str] = None): # use the provided path if omhome is not None: return pathlib.Path(omhome) @@ -493,7 +499,9 @@ def _connect_to_omc(self, timeout) -> str: while True: if self._dockerCid: try: - port = subprocess.check_output(["docker", "exec", self._dockerCid, "cat", self._port_file], + port = subprocess.check_output(args=["docker", + "exec", str(self._dockerCid), + "cat", str(self._port_file)], stderr=subprocess.DEVNULL).decode().strip() break except subprocess.CalledProcessError: @@ -517,7 +525,7 @@ def _connect_to_omc(self, timeout) -> str: port = port.replace("0.0.0.0", self._serverIPAddress) logger.info(f"OMC Server is up and running at {omc_zeromq_uri} " - f"pid={self._omc_process.pid} cid={self._dockerCid}") + f"pid={self._omc_process.pid if self._omc_process else '?'} cid={self._dockerCid}") # Create the ZeroMQ socket and connect to OMC server context = zmq.Context.instance()