Skip to content

Commit

Permalink
FEAT: Desktop launch (#4980)
Browse files Browse the repository at this point in the history
Co-authored-by: maxcapodi78 <Shark78>
  • Loading branch information
maxcapodi78 authored Aug 2, 2024
1 parent b9429d0 commit 8467cd5
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 55 deletions.
2 changes: 1 addition & 1 deletion _unittest/test_14_AedtLogger.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def test_05_disable_stdout(self):
handler.close()
logger._global.removeHandler(handler)
assert stream_content[0] == "PyAEDT INFO: Info for Global\n"
assert stream_content[1] == "PyAEDT INFO: StdOut is enabled\n"
assert stream_content[1] == "PyAEDT INFO: Log on console is enabled.\n"
assert stream_content[2] == "PyAEDT INFO: Info after re-enabling the stdout handler.\n"


Expand Down
22 changes: 10 additions & 12 deletions _unittest/test_20_HFSS.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,32 +889,30 @@ def test_30_assign_initial_mesh(self):
assert self.aedtapp.mesh.assign_initial_mesh_from_slider(6)

def test_30a_add_mesh_link(self):
design_name = self.aedtapp.design_name
nominal_adaptive = self.aedtapp.nominal_adaptive
self.aedtapp.duplicate_design(self.aedtapp.design_name)
self.aedtapp.set_active_design(self.aedtapp.design_list[0])
assert self.aedtapp.setups[0].add_mesh_link(design=self.aedtapp.design_list[1])
self.aedtapp._setups = None
assert self.aedtapp.setups[0].add_mesh_link(design=design_name)
meshlink_props = self.aedtapp.setups[0].props["MeshLink"]
assert meshlink_props["Project"] == "This Project*"
assert meshlink_props["PathRelativeTo"] == "TargetProject"
assert meshlink_props["Design"] == self.aedtapp.design_list[1]
assert meshlink_props["Soln"] == "MySetup : LastAdaptive"
assert meshlink_props["Design"] == design_name
assert meshlink_props["Soln"] == nominal_adaptive
assert sorted(list(meshlink_props["Params"].keys())) == sorted(self.aedtapp.available_variations.variables)
assert sorted(list(meshlink_props["Params"].values())) == sorted(self.aedtapp.available_variations.variables)
assert not self.aedtapp.setups[0].add_mesh_link(design="")
assert self.aedtapp.setups[0].add_mesh_link(design=design_name, solution="MySetup : LastAdaptive")
assert not self.aedtapp.setups[0].add_mesh_link(design=design_name, solution="Setup_Test : LastAdaptive")
assert self.aedtapp.setups[0].add_mesh_link(
design=self.aedtapp.design_list[1], solution="MySetup : LastAdaptive"
)
assert not self.aedtapp.setups[0].add_mesh_link(
design=self.aedtapp.design_list[1], solution="Setup_Test : LastAdaptive"
)
assert self.aedtapp.setups[0].add_mesh_link(
design=self.aedtapp.design_list[1], parameters=self.aedtapp.available_variations.nominal_w_values_dict
design=design_name, parameters=self.aedtapp.available_variations.nominal_w_values_dict
)
example_project = os.path.join(
local_path, "../_unittest/example_models", test_subfolder, diff_proj_name + ".aedt"
)
example_project_copy = os.path.join(self.local_scratch.path, diff_proj_name + "_copy.aedt")
shutil.copyfile(example_project, example_project_copy)
assert self.aedtapp.setups[0].add_mesh_link(design=self.aedtapp.design_list[1], project=example_project_copy)
assert self.aedtapp.setups[0].add_mesh_link(design=design_name, project=example_project_copy)

def test_31_create_microstrip_port(self):
self.aedtapp.insert_design("Microstrip")
Expand Down
7 changes: 4 additions & 3 deletions _unittest/test_30_Q2D.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# SOFTWARE.

import os
import time

from _unittest.conftest import config
from _unittest.conftest import desktop_version
Expand Down Expand Up @@ -162,7 +163,9 @@ def test_14_export_matrix_data(self, add_app):
q2d.matrices[2].name == "Test2"
q2d.insert_reduced_matrix(q2d.MATRIXOPERATIONS.SetReferenceGround, "Circle2", "Test3")
q2d.matrices[3].name == "Test3"
q2d.analyze_setup(q2d.active_setup)
q2d.analyze_setup(q2d.active_setup, blocking=False)
while q2d.desktop_class.are_there_simulations_running:
time.sleep(1)
q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"))
assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), problem_type="CG")
assert q2d.export_matrix_data(
Expand Down Expand Up @@ -200,8 +203,6 @@ def test_14_export_matrix_data(self, add_app):
os.path.join(self.local_scratch.path, "test_2d.txt"), precision=16, field_width=22
)
assert not q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), precision=16.2)
assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), freq="1", freq_unit="GHz")
assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), freq="3", freq_unit="GHz")
assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), freq="3", freq_unit="Hz")
assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), use_sci_notation=True)
assert q2d.export_matrix_data(os.path.join(self.local_scratch.path, "test_2d.txt"), use_sci_notation=False)
Expand Down
13 changes: 7 additions & 6 deletions pyaedt/aedt_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,18 +800,18 @@ def add_logger(self, destination, level=logging.DEBUG):
def disable_desktop_log(self):
"""Disable the log in AEDT."""
self._log_on_desktop = False
self.info("Log on Desktop Message Manager is disabled")
self.info("Log on AEDT is disabled.")

def enable_desktop_log(self):
"""Enable the log in AEDT."""
self._log_on_desktop = True
self.info("Log on Desktop Message Manager is enabled")
self.info("Log on AEDT is enabled.")

def disable_stdout_log(self):
"""Disable printing log messages to stdout."""
self._log_on_screen = False
self._global.removeHandler(self._std_out_handler)
self.info("StdOut is disabled")
self.info("Log on console is disabled.")

def enable_stdout_log(self):
"""Enable printing log messages to stdout."""
Expand All @@ -824,7 +824,7 @@ def enable_stdout_log(self):
self._std_out_handler.setFormatter(_logger_stdout_formatter)
self._global.addHandler(self._std_out_handler)
self._global.addHandler(self._std_out_handler)
self.info("StdOut is enabled")
self.info("Log on console is enabled.")

def disable_log_on_file(self):
"""Disable writing log messages to an output file."""
Expand All @@ -843,14 +843,15 @@ def disable_log_on_file(self):
if isinstance(_file_handler, FileHandler):
_file_handler.close()
self.project_logger.removeHandler(_file_handler)
self.info("Log on file is disabled")
self.info("Log on file is disabled.")

def enable_log_on_file(self):
"""Enable writing log messages to an output file."""
self._log_on_file = True
for _file_handler in self._files_handlers:
self._global.addHandler(_file_handler)
self.info("Log on file is enabled")
if "baseFilename" in dir(_file_handler):
self.info("Log on file {} is enabled.".format(_file_handler.baseFilename))

def info(self, msg, *args, **kwargs):
"""Write an info message to the global logger."""
Expand Down
2 changes: 1 addition & 1 deletion pyaedt/application/Design.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ def odesktop(self):
>>> hfss.odesktop
<class 'win32com.client.CDispatch'>
"""
return self._desktop
return self.desktop_class.odesktop

@pyaedt_function_handler()
def __delitem__(self, key):
Expand Down
64 changes: 39 additions & 25 deletions pyaedt/desktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ def launch_aedt_in_lsf(non_graphical, port): # pragma: no cover


def _check_grpc_port(port, machine_name=""):
s = socket.socket()
if not port:
return False
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
if not machine_name:
machine_name = "127.0.0.1"
Expand All @@ -226,10 +228,16 @@ def _check_grpc_port(port, machine_name=""):
def _find_free_port():
from contextlib import closing

with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(("127.0.0.1", 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.getsockname()[1]
def _find():
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(("127.0.0.1", 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.getsockname()[1]

while True:
new_port = _find()
if new_port not in list(active_sessions().values()):
return new_port


def exception_to_desktop(ex_value, tb_data): # pragma: no cover
Expand Down Expand Up @@ -476,7 +484,7 @@ def __new__(cls, *args, **kwargs):
kwargs.get("specified_version") or kwargs.get("version") or None if (not args or len(args) < 1) else args[0]
)
new_desktop = (
kwargs.get("new_desktop_session") or kwargs.get("new_desktop") or False
kwargs.get("new_desktop_session") or kwargs.get("new_desktop") or True
if (not args or len(args) < 3)
else args[2]
)
Expand All @@ -485,6 +493,9 @@ def __new__(cls, *args, **kwargs):
specified_version = get_string_version(specified_version)
port = kwargs.get("port") or 0 if (not args or len(args) < 7) else args[6]
aedt_process_id = kwargs.get("aedt_process_id") or None if (not args or len(args) < 8) else args[7]
if not settings.remote_api:
pyaedt_logger.info("Python version %s", sys.version)
pyaedt_logger.info("PyAEDT version {}.".format(pyaedt_version))
if settings.use_multi_desktop and not inside_desktop and new_desktop:
pyaedt_logger.info("Initializing new Desktop session.")
return object.__new__(cls)
Expand Down Expand Up @@ -659,10 +670,10 @@ def __init__(
else:
settings.aedt_version = version_key
if starting_mode == "ironpython": # pragma no cover
self._logger.info("Launching PyAEDT outside AEDT with IronPython.")
self._logger.info("Launching PyAEDT with IronPython.")
self._init_ironpython(non_graphical, new_desktop, version)
elif starting_mode == "com": # pragma no cover
self._logger.info("Launching PyAEDT outside AEDT with CPython and PythonNET.")
self._logger.info("Launching PyAEDT with CPython and PythonNET.")
self._init_dotnet(
non_graphical,
new_desktop,
Expand All @@ -672,15 +683,12 @@ def __init__(
aedt_process_id,
)
elif starting_mode == "grpc":
self._logger.info("Launching PyAEDT outside AEDT with gRPC plugin.")
self._logger.info("Launching PyAEDT with gRPC plugin.")
self._init_grpc(non_graphical, new_desktop, version, student_version_flag, version_key)

self._set_logger_file()
settings.enable_desktop_logs = not self.non_graphical
self._init_desktop()
self._logger.info("pyaedt v%s", pyaedt_version)
if not settings.remote_api:
self._logger.info("Python version %s", sys.version)

current_pid = int(self.odesktop.GetProcessID())
if aedt_process_id and not new_desktop and aedt_process_id != current_pid: # pragma no cover
Expand All @@ -700,8 +708,6 @@ def __init__(

self.aedt_version_id = self.odesktop.GetVersion()[0:6]

self._logger.info("AEDT %s Build Date %s", self.odesktop.GetVersion(), self.odesktop.GetBuildDateTimeString())

if is_ironpython: # pragma no cover
sys.path.append(os.path.join(settings.aedt_install_dir, "common", "commonfiles", "IronPython", "DLLs"))
if "GetGrpcServerPort" in dir(self.odesktop):
Expand Down Expand Up @@ -982,12 +988,7 @@ def _init_dotnet(
if proc == processID2 and len(processID2) > 1:
self._dispatch_win32(version)
elif version_key >= "2021.2":
if student_version:
self.logger.info("AEDT {} Student version started with process ID {}.".format(version_key, proc[0]))
elif aedt_process_id:
self.logger.info("Connecting to AEDT session with process ID {}.".format(proc[0]))
else:
self.logger.info("AEDT {} Started with process ID {}.".format(version_key, proc[0]))

context = pythoncom.CreateBindCtx(0)
running_coms = pythoncom.GetRunningObjectTable()
monikiers = running_coms.EnumRunning()
Expand All @@ -999,6 +1000,12 @@ def _init_dotnet(
from pyaedt.generic.clr_module import win32_client

self.odesktop = win32_client.Dispatch(obj.QueryInterface(pythoncom.IID_IDispatch))
if student_version:
self.logger.info("New AEDT {} Student version process ID {}.".format(version_key, proc[0]))
elif aedt_process_id:
self.logger.info("Existing AEDT session process ID {}.".format(proc[0]))
else:
self.logger.info("New AEDT {} Started process ID {}.".format(version_key, proc[0]))
break
else:
self.logger.warning(
Expand Down Expand Up @@ -1030,6 +1037,8 @@ def _initialize(
else:
return StandalonePyScriptWrapper.CreateObject(version)
else:
settings.use_grpc_api = True
self.is_grpc_api = True
base_path = settings.aedt_install_dir
sys.path.insert(0, base_path)
sys.path.insert(0, os.path.join(base_path, "PythonFiles", "DesktopPlugin"))
Expand All @@ -1051,7 +1060,6 @@ def _initialize(

self.isoutsideDesktop = True
self.aedt_process_id = self.odesktop.GetProcessID()
self.is_grpc_api = True
return True

@property
Expand All @@ -1066,10 +1074,16 @@ def odesktop(self):
>>> d = Desktop()
>>> d.odesktop
"""
try:
return self.grpc_plugin.odesktop
except Exception:
return self._odesktop
if settings.use_grpc_api:
tries = 0
while tries < 5:
try:
self._odesktop = self.grpc_plugin.odesktop
return self._odesktop
except Exception: # pragma: no cover
tries += 1
time.sleep(1)
return self._odesktop # pragma: no cover

@odesktop.setter
def odesktop(self, val): # pragma: no cover
Expand Down
14 changes: 13 additions & 1 deletion pyaedt/generic/configurations.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,18 @@ def __init__(self, app):
self._app = app
self.options = ConfigurationsOptions()
self.results = ImportResults()
self._schema = None

@property
def schema(self):
"""Schema dictionary.
Returns
-------
dict
"""
if self._schema:
return self._schema
pyaedt_installed_path = os.path.dirname(pyaedt.__file__)

schema_bytes = None
Expand All @@ -732,6 +743,7 @@ def __init__(self, app):
else: # pragma: no cover
self._app.logger.error("Failed to load configuration schema.")
self._schema = None
return self._schema

@staticmethod
@pyaedt_function_handler()
Expand Down Expand Up @@ -1069,7 +1081,7 @@ def validate(self, config):
self._app.logger.warning("Iron Python: Unable to validate json Schema.")
else:
try:
validate(instance=config_data, schema=self._schema)
validate(instance=config_data, schema=self.schema)
return True
except exceptions.ValidationError as e:
self._app.logger.warning("Configuration is invalid.")
Expand Down
1 change: 1 addition & 0 deletions pyaedt/generic/general_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"Rename",
"RestoreProjectArchive",
"ImportGerber",
"EditSources",
]


Expand Down
11 changes: 5 additions & 6 deletions pyaedt/generic/grpc_plugin_dll_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,7 @@ def CreateAedtApplication(self, machine="", port=0, NGmode=False, alwaysNew=True

@property
def odesktop(self):
if settings.use_multi_desktop:
self.aedt = self.recreate_application()
return self.aedt.GetAppDesktop()
return self.recreate_application()

def recreate_application(self, force=False):
def run():
Expand All @@ -379,14 +377,15 @@ def run():
self.port = port
self.machine = machine
self.aedt = self.AedtAPI.CreateAedtApplication(self.machine, self.port, self.non_graphical, False)
return self.aedt
return self.aedt.GetAppDesktop()

if force:
return run()
else:
try:
self.aedt.GetAppDesktop()
return self.aedt
odesktop = self.aedt.GetAppDesktop()
if odesktop:
return odesktop
except Exception:
return run()

Expand Down

0 comments on commit 8467cd5

Please sign in to comment.