Skip to content

Commit c25dda9

Browse files
SMoraisAnsyspyansys-ci-botMaxJPRey
authored
REFACTOR: Improve code quality and handling of subprocess calls (#5995)
Co-authored-by: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Co-authored-by: Maxime Rey <87315832+MaxJPRey@users.noreply.github.com>
1 parent 8a677ce commit c25dda9

7 files changed

Lines changed: 74 additions & 77 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve code quality and handling of subprocess calls

src/ansys/aedt/core/application/analysis.py

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
from ansys.aedt.core.generic.numbers import decompose_variable_value
6161
from ansys.aedt.core.generic.numbers import is_number
6262
from ansys.aedt.core.generic.settings import settings
63+
from ansys.aedt.core.internal.errors import AEDTRuntimeError
6364
from ansys.aedt.core.modules.boundary.layout_boundary import NativeComponentObject
6465
from ansys.aedt.core.modules.boundary.layout_boundary import NativeComponentPCB
6566
from ansys.aedt.core.modules.design_xploration import OptimizationSetups
@@ -1903,6 +1904,7 @@ def stop_simulations(self, clean_stop=True):
19031904
"""
19041905
return self.desktop_class.stop_simulations(clean_stop=clean_stop)
19051906

1907+
# flake8: noqa: E501
19061908
@pyaedt_function_handler(filename="file_name", numcores="cores", num_tasks="tasks", setup_name="setup")
19071909
def solve_in_batch(
19081910
self,
@@ -1919,6 +1921,11 @@ def solve_in_batch(
19191921
.. note::
19201922
To use this function, the project must be closed.
19211923
1924+
.. warning::
1925+
Do not execute this function with untrusted input parameters.
1926+
See the :ref:`security guide<https://aedt.docs.pyansys.com/version/stable/User_guide/security_consideration.html>`
1927+
for details.
1928+
19221929
Parameters
19231930
----------
19241931
file_name : str, optional
@@ -1945,6 +1952,15 @@ def solve_in_batch(
19451952
bool
19461953
``True`` when successful, ``False`` when failed.
19471954
"""
1955+
try:
1956+
cores = int(cores)
1957+
except ValueError:
1958+
raise ValueError(f"The number of cores is not a valid integer.")
1959+
try:
1960+
tasks = int(tasks)
1961+
except ValueError:
1962+
raise ValueError(f"The number of tasks is not a valid integer.")
1963+
19481964
inst_dir = self.desktop_install_dir
19491965
self.last_run_log = ""
19501966
self.last_run_job = ""
@@ -1979,46 +1995,37 @@ def solve_in_batch(
19791995
if setup and design_name:
19801996
options.append(f'{design_name}:{"Nominal" if setup in self.setup_names else "Optimetrics"}:{setup}')
19811997
if is_linux and not settings.use_lsf_scheduler:
1982-
batch_run = [inst_dir + "/ansysedt"]
1998+
command = [inst_dir + "/ansysedt"]
19831999
elif is_linux and settings.use_lsf_scheduler: # pragma: no cover
2000+
if not isinstance(settings.lsf_ram, int) or settings.lsf_ram <= 0:
2001+
raise AEDTRuntimeError("Invalid memory value.")
2002+
if not settings.lsf_aedt_command:
2003+
raise AEDTRuntimeError("Invalid LSF AEDT command.")
2004+
command = [
2005+
"bsub",
2006+
"-n",
2007+
str(cores),
2008+
"-R",
2009+
f"span[ptile={cores}]",
2010+
"-R",
2011+
f"rusage[mem={settings.lsf_ram}]",
2012+
settings.lsf_aedt_command,
2013+
]
19842014
if settings.lsf_queue:
1985-
batch_run = [
1986-
"bsub",
1987-
"-n",
1988-
str(cores),
1989-
"-R",
1990-
f"span[ptile={cores}]",
1991-
"-R",
1992-
f"rusage[mem={settings.lsf_ram}]",
1993-
f"-queue {settings.lsf_queue}",
1994-
settings.lsf_aedt_command,
1995-
]
1996-
else:
1997-
batch_run = [
1998-
"bsub",
1999-
"-n",
2000-
str(cores),
2001-
"-R",
2002-
f"span[ptile={cores}]",
2003-
"-R",
2004-
f"rusage[mem={settings.lsf_ram}]",
2005-
settings.lsf_aedt_command,
2006-
]
2015+
command.extend(["-queue", settings.lsf_queue])
20072016
else:
2008-
batch_run = [inst_dir + "/ansysedt.exe"]
2009-
batch_run.extend(options)
2010-
batch_run.append(file_name)
2017+
command = [inst_dir + "/ansysedt.exe"]
2018+
command.extend(options)
2019+
command.append(file_name)
20112020

20122021
# check for existing solution directory and delete it if it exists so we
20132022
# don't have old .asol files etc
2014-
20152023
self.logger.info("Solving model in batch mode on " + machine)
20162024
if run_in_thread and is_windows:
2017-
DETACHED_PROCESS = 0x00000008
2018-
subprocess.Popen(batch_run, creationflags=DETACHED_PROCESS)
2025+
subprocess.Popen(command, creationflags=subprocess.DETACHED_PROCESS) # nosec
20192026
self.logger.info("Batch job launched.")
20202027
else:
2021-
subprocess.Popen(batch_run)
2028+
subprocess.Popen(command) # nosec
20222029
self.logger.info("Batch job finished.")
20232030

20242031
if machine == "localhost":

src/ansys/aedt/core/common_rpc.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import os
2626
from pathlib import Path
2727
import signal
28+
import socket
2829
import sys
2930
import tempfile
3031
import time
@@ -187,7 +188,11 @@ def pyaedt_service_manager(port=17878, aedt_version=None, student_version=False)
187188
os.environ["PYAEDT_SERVER_AEDT_NG"] = "True"
188189
os.environ["ANS_NODEPCHECK"] = str(1)
189190

190-
hostname = "0.0.0.0"
191+
default_host = socket.gethostname()
192+
hostname = os.getenv("AEDT_HOST", default_host)
193+
if hostname == "0.0.0.0": # nosec
194+
logger.warning("The service is exposed on all network interfaces. This is a security risk.")
195+
191196
t = ThreadedServer(
192197
ServiceManager,
193198
hostname=hostname,
@@ -248,7 +253,11 @@ def launch_server(port=18000, ansysem_path=None, non_graphical=False, threaded=T
248253
os.environ["ANS_NO_MONO_CLEANUP"] = str(1)
249254
os.environ["ANS_NODEPCHECK"] = str(1)
250255

251-
hostname = "0.0.0.0"
256+
default_host = socket.gethostname()
257+
hostname = os.getenv("AEDT_HOST", default_host)
258+
if hostname == "0.0.0.0": # nosec
259+
logger.warning("The service is exposed on all network interfaces. This is a security risk.")
260+
252261
if threaded:
253262
service = ThreadedServer
254263
else:

src/ansys/aedt/core/generic/data_handlers.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -294,24 +294,13 @@ def unique_string_list(element_list, only_string=True):
294294
-------
295295
296296
"""
297-
if element_list:
298-
if isinstance(element_list, list):
299-
element_list = set(element_list)
300-
elif isinstance(element_list, str):
301-
element_list = [element_list]
302-
else:
303-
error_message = "Invalid list data"
304-
try:
305-
error_message += f" {element_list}"
306-
except Exception:
307-
pass
308-
raise Exception(error_message)
297+
if isinstance(element_list, str):
298+
element_list = [element_list]
309299

310-
if only_string:
311-
non_string_entries = [x for x in element_list if not isinstance(x, str)]
312-
assert not non_string_entries, f"Invalid list entries {non_string_entries} are not a string!"
300+
if only_string and any(not isinstance(x, str) for x in element_list):
301+
raise TypeError("Invalid list entries, some elements are not of type string.")
313302

314-
return element_list
303+
return list(set(element_list))
315304

316305

317306
@pyaedt_function_handler()
@@ -330,10 +319,10 @@ def string_list(element_list):
330319
list
331320
332321
"""
322+
if not isinstance(element_list, (str, list)):
323+
raise TypeError("Input must be a list or a string")
333324
if isinstance(element_list, str):
334325
element_list = [element_list]
335-
else:
336-
assert isinstance(element_list, str), "Input must be a list or a string"
337326
return element_list
338327

339328

src/ansys/aedt/core/internal/aedt_versions.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import os
3232
import warnings
3333

34+
from ansys.aedt.core.generic import settings
35+
3436
CURRENT_STABLE_AEDT_VERSION = 2025.1
3537

3638

@@ -106,7 +108,8 @@ def installed_versions(self):
106108
v_key = f"20{version}.{release}"
107109
return_dict[v_key] = os.environ[version_env_var]
108110
except Exception: # pragma: no cover
109-
pass
111+
if settings.logger:
112+
settings.logger.debug(f"Failed to parse version and release from {current_version_id}")
110113
self._installed_versions = return_dict
111114
return self._installed_versions
112115

src/ansys/aedt/core/internal/grpc_plugin_dll_class.py

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
from ctypes import py_object
3131
import os
3232
import re
33-
import socket
3433
import types
3534

3635
from ansys.aedt.core.generic.general_methods import _retry_ntimes
@@ -219,18 +218,18 @@ def __getattr__(self, attrName):
219218
return self.GetPropValue(propMap[attrName])
220219
raise GrpcApiError(f"Failed to retrieve attribute {attrName} from gRPC API")
221220

222-
def __setattr__(self, attrName, val):
223-
if attrName in self.__dict__:
224-
self.__dict__[attrName] = val
221+
def __setattr__(self, attr, val):
222+
if attr in self.__dict__:
223+
self.__dict__[attr] = val
225224
return
226225
propMap = self.__GetPropAttributes()
227226
try:
228-
if attrName in propMap:
229-
self.SetPropValue(propMap[attrName], val)
227+
if attr in propMap:
228+
self.SetPropValue(propMap[attr], val)
230229
return
231230
except Exception:
232-
pass
233-
super().__setattr__(attrName, val)
231+
settings.logger.debug(f"Failed to update attribute {attr} of AedtPropServer instance.")
232+
super().__setattr__(attr, val)
234233

235234
def GetName(self):
236235
return self.__Invoke__("GetName", ())
@@ -331,21 +330,6 @@ def SetPyObjCalbacks(self):
331330
self.callbackGetObjID = RetObj_InObj_Func_type(self.GetAedtObjId)
332331
self.AedtAPI.SetPyObjCalbacks(self.callbackToCreateObj, self.callbackCreateBlock, self.callbackGetObjID)
333332

334-
@staticmethod
335-
def _is_port_occupied(port, machine_name=""):
336-
s = socket.socket()
337-
try:
338-
if not machine_name:
339-
machine_name = "127.0.0.1"
340-
s.connect((machine_name, port))
341-
except socket.error:
342-
success = False
343-
else:
344-
success = True
345-
finally:
346-
s.close()
347-
return success
348-
349333
def CreateAedtApplication(self, machine="", port=0, NGmode=False, alwaysNew=True):
350334
if not alwaysNew and port:
351335
grpc_channel = grpc.insecure_channel(f"{machine}:{port}")

src/ansys/aedt/core/workflows/hfss/move_it.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import ansys.aedt.core
3030
from ansys.aedt.core import get_pyaedt_app
31+
from ansys.aedt.core.internal.errors import AEDTRuntimeError
3132
from ansys.aedt.core.workflows.misc import get_aedt_version
3233
from ansys.aedt.core.workflows.misc import get_arguments
3334
from ansys.aedt.core.workflows.misc import get_port
@@ -369,7 +370,9 @@ def main(extension_args):
369370
cs.props["YAxisXvec"] = "0mm"
370371
cs.props["YAxisYvec"] = "0mm"
371372
cs.props["YAxisZvec"] = "1mm"
372-
assert cs.update()
373+
res = cs.update()
374+
if not res:
375+
raise AEDTRuntimeError("Failed to update the coordinate system.")
373376

374377
else:
375378
cs = hfss.modeler.create_coordinate_system(
@@ -389,8 +392,9 @@ def main(extension_args):
389392
cs_rotated.props["YAxisYvec"] = "0"
390393
cs_rotated.props["YAxisZvec"] = "-1"
391394
cs_rotated.props["Reference CS"] = cs.name
392-
assert cs_rotated.update()
393-
395+
res = cs_rotated.update()
396+
if not res:
397+
raise AEDTRuntimeError("Failed to update the coordinate system.")
394398
else:
395399
_ = hfss.modeler.create_coordinate_system(name=cs_name_rotated, reference_cs=cs.name, y_pointing=[0, 0, -1])
396400

0 commit comments

Comments
 (0)