pyedb 0.57.0__py3-none-any.whl → 0.59.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyedb might be problematic. Click here for more details.

Files changed (46) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_pin_groups.py +2 -0
  3. pyedb/dotnet/database/cell/hierarchy/component.py +2 -8
  4. pyedb/dotnet/database/cell/layout.py +1 -1
  5. pyedb/dotnet/database/components.py +38 -42
  6. pyedb/dotnet/database/edb_data/control_file.py +13 -5
  7. pyedb/dotnet/database/edb_data/padstacks_data.py +34 -12
  8. pyedb/dotnet/database/edb_data/sources.py +21 -2
  9. pyedb/dotnet/database/general.py +4 -8
  10. pyedb/dotnet/database/layout_validation.py +8 -0
  11. pyedb/dotnet/database/sim_setup_data/data/settings.py +2 -2
  12. pyedb/dotnet/database/sim_setup_data/io/siwave.py +53 -0
  13. pyedb/dotnet/database/stackup.py +5 -32
  14. pyedb/dotnet/database/utilities/hfss_simulation_setup.py +81 -0
  15. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +259 -11
  16. pyedb/dotnet/edb.py +26 -13
  17. pyedb/extensions/create_cell_array.py +48 -44
  18. pyedb/generic/general_methods.py +24 -36
  19. pyedb/generic/plot.py +8 -23
  20. pyedb/generic/process.py +78 -10
  21. pyedb/grpc/database/components.py +7 -5
  22. pyedb/grpc/database/control_file.py +13 -5
  23. pyedb/grpc/database/definition/padstack_def.py +10 -5
  24. pyedb/grpc/database/hierarchy/component.py +2 -9
  25. pyedb/grpc/database/modeler.py +28 -8
  26. pyedb/grpc/database/padstacks.py +62 -103
  27. pyedb/grpc/database/primitive/padstack_instance.py +41 -12
  28. pyedb/grpc/database/primitive/path.py +13 -13
  29. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +79 -0
  30. pyedb/grpc/database/source_excitations.py +7 -7
  31. pyedb/grpc/database/stackup.py +5 -33
  32. pyedb/grpc/database/terminal/padstack_instance_terminal.py +9 -11
  33. pyedb/grpc/database/terminal/point_terminal.py +30 -0
  34. pyedb/grpc/database/terminal/terminal.py +16 -2
  35. pyedb/grpc/database/utility/xml_control_file.py +13 -5
  36. pyedb/grpc/edb.py +46 -20
  37. pyedb/grpc/edb_init.py +7 -19
  38. pyedb/misc/aedtlib_personalib_install.py +2 -2
  39. pyedb/misc/downloads.py +18 -3
  40. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +2 -1
  41. pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +0 -1
  42. pyedb/workflows/sipi/hfss_auto_configuration.py +711 -0
  43. {pyedb-0.57.0.dist-info → pyedb-0.59.0.dist-info}/METADATA +4 -5
  44. {pyedb-0.57.0.dist-info → pyedb-0.59.0.dist-info}/RECORD +46 -45
  45. {pyedb-0.57.0.dist-info → pyedb-0.59.0.dist-info}/WHEEL +0 -0
  46. {pyedb-0.57.0.dist-info → pyedb-0.59.0.dist-info}/licenses/LICENSE +0 -0
@@ -22,9 +22,20 @@
22
22
 
23
23
  from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
24
24
  from ansys.edb.core.terminal.point_terminal import PointTerminal as GrpcPointTerminal
25
+ from ansys.edb.core.terminal.terminal import BoundaryType as GrpcBoundaryType
25
26
 
26
27
  from pyedb.grpc.database.utility.value import Value
27
28
 
29
+ mapping_boundary_type = {
30
+ "port": GrpcBoundaryType.PORT,
31
+ "dc_terminal": GrpcBoundaryType.DC_TERMINAL,
32
+ "voltage_probe": GrpcBoundaryType.VOLTAGE_PROBE,
33
+ "voltage_source": GrpcBoundaryType.VOLTAGE_SOURCE,
34
+ "current_source": GrpcBoundaryType.CURRENT_SOURCE,
35
+ "rlc": GrpcBoundaryType.RLC,
36
+ "pec": GrpcBoundaryType.PEC,
37
+ }
38
+
28
39
 
29
40
  class PointTerminal(GrpcPointTerminal):
30
41
  """Manages point terminal properties."""
@@ -33,6 +44,25 @@ class PointTerminal(GrpcPointTerminal):
33
44
  super().__init__(edb_object.msg)
34
45
  self._pedb = pedb
35
46
 
47
+ @property
48
+ def boundary_type(self):
49
+ """Boundary type.
50
+
51
+ Returns
52
+ -------
53
+ str : boundary type.
54
+
55
+ """
56
+ return super().boundary_type.name.lower()
57
+
58
+ @boundary_type.setter
59
+ def boundary_type(self, value):
60
+ if isinstance(value, str):
61
+ value = mapping_boundary_type.get(value.lower(), None)
62
+ if not isinstance(value, GrpcBoundaryType):
63
+ raise ValueError("Value must be a string or BoundaryType enum.")
64
+ super(PointTerminal, self.__class__).boundary_type.__set__(self, value)
65
+
36
66
  @property
37
67
  def location(self) -> list[float]:
38
68
  """Terminal position.
@@ -38,6 +38,16 @@ from ansys.edb.core.terminal.terminal import (
38
38
  from pyedb.grpc.database.primitive.primitive import Primitive
39
39
  from pyedb.grpc.database.utility.value import Value
40
40
 
41
+ mapping_boundary_type = {
42
+ "port": GrpcBoundaryType.PORT,
43
+ "dc_terminal": GrpcBoundaryType.DC_TERMINAL,
44
+ "voltage_probe": GrpcBoundaryType.VOLTAGE_PROBE,
45
+ "voltage_source": GrpcBoundaryType.VOLTAGE_SOURCE,
46
+ "current_source": GrpcBoundaryType.CURRENT_SOURCE,
47
+ "rlc": GrpcBoundaryType.RLC,
48
+ "pec": GrpcBoundaryType.PEC,
49
+ }
50
+
41
51
 
42
52
  class Terminal(GrpcTerminal):
43
53
  def __init__(self, pedb, edb_object):
@@ -202,7 +212,11 @@ class Terminal(GrpcTerminal):
202
212
 
203
213
  @boundary_type.setter
204
214
  def boundary_type(self, value):
205
- super(Terminal, self.__class__).boundary_type.__set__(self, self._boundary_type_mapping[value])
215
+ if isinstance(value, str):
216
+ value = mapping_boundary_type.get(value.lower(), None)
217
+ if not isinstance(value, GrpcBoundaryType):
218
+ raise ValueError("Value must be a string or BoundaryType enum.")
219
+ super(Terminal, self.__class__).boundary_type.__set__(self, value)
206
220
 
207
221
  @property
208
222
  def is_port(self) -> bool:
@@ -250,7 +264,7 @@ class Terminal(GrpcTerminal):
250
264
 
251
265
  @impedance.setter
252
266
  def impedance(self, value):
253
- self.impedance = Value(value)
267
+ super(Terminal, self.__class__).impedance.__set__(self, self._pedb.value(value))
254
268
 
255
269
  @property
256
270
  def reference_object(self) -> any:
@@ -23,9 +23,11 @@
23
23
  import copy
24
24
  import os
25
25
  import re
26
- import subprocess
26
+ import subprocess # nosec B404
27
27
  import sys
28
28
 
29
+ from defusedxml.ElementTree import parse as defused_parse
30
+
29
31
  from pyedb.generic.general_methods import ET, env_path, env_value, is_linux
30
32
  from pyedb.generic.settings import settings
31
33
  from pyedb.misc.aedtlib_personalib_install import write_pretty_xml
@@ -35,6 +37,11 @@ from pyedb.misc.misc import list_installed_ansysem
35
37
  def convert_technology_file(tech_file, edbversion=None, control_file=None):
36
38
  """Convert a technology file to edb control file (xml).
37
39
 
40
+ .. warning::
41
+ Do not execute this function with untrusted function argument, environment
42
+ variables or pyedb global settings.
43
+ See the :ref:`security guide<ref_security_consideration>` for details.
44
+
38
45
  Parameters
39
46
  ----------
40
47
  tech_file : str
@@ -98,10 +105,11 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
98
105
  ]
99
106
  commands.append(command)
100
107
  commands.append(["rm", "-r", vlc_file_name + ".aedb"])
101
- my_env = os.environ.copy()
102
108
  for command in commands:
103
- p = subprocess.Popen(command, env=my_env)
104
- p.wait()
109
+ try:
110
+ subprocess.run(command, check=True) # nosec
111
+ except subprocess.CalledProcessError as e: # nosec
112
+ raise RuntimeError("An error occurred while converting a technology file to edb control file") from e
105
113
  if os.path.exists(control_file):
106
114
  settings.logger.info("Xml file created.")
107
115
  return control_file
@@ -1188,7 +1196,7 @@ class ControlFile:
1188
1196
  -------
1189
1197
  bool
1190
1198
  """
1191
- tree = ET.parse(xml_input)
1199
+ tree = defused_parse(xml_input)
1192
1200
  root = tree.getroot()
1193
1201
  for el in root:
1194
1202
  if el.tag == "Stackup":
pyedb/grpc/edb.py CHANGED
@@ -60,7 +60,7 @@ from itertools import combinations
60
60
  import os
61
61
  import re
62
62
  import shutil
63
- import subprocess
63
+ import subprocess # nosec B404
64
64
  import sys
65
65
  import tempfile
66
66
  import time
@@ -217,8 +217,8 @@ class Edb(EdbInit):
217
217
  self.standalone = True
218
218
  self.oproject = oproject
219
219
  self._main = sys.modules["__main__"]
220
- self.edbversion = edbversion
221
- if not float(self.edbversion) >= 2025.2:
220
+ self.version = edbversion
221
+ if not float(self.version) >= 2025.2:
222
222
  raise "EDB gRPC is only supported with ANSYS release 2025R2 and higher."
223
223
  self.logger.info("Using PyEDB with gRPC as Beta until ANSYS 2025R2 official release.")
224
224
  self.isaedtowned = isaedtowned
@@ -620,7 +620,7 @@ class Edb(EdbInit):
620
620
  if self.db.is_null:
621
621
  self.logger.warning("Error Opening db")
622
622
  self._active_cell = None
623
- self.logger.info(f"Database {os.path.split(self.edbpath)[-1]} Opened in {self.edbversion}")
623
+ self.logger.info(f"Database {os.path.split(self.edbpath)[-1]} Opened in {self.version}")
624
624
  self._active_cell = None
625
625
  if self.cellname:
626
626
  for cell in self.active_db.circuit_cells:
@@ -761,6 +761,11 @@ class Edb(EdbInit):
761
761
 
762
762
  This function supports all AEDT formats, including DXF, GDS, SML (IPC2581), BRD, MCM, SIP, ZIP and TGZ.
763
763
 
764
+ .. warning::
765
+ Do not execute this function with untrusted function argument, environment
766
+ variables or pyedb global settings.
767
+ See the :ref:`security guide<ref_security_consideration>` for details.
768
+
764
769
  Parameters
765
770
  ----------
766
771
  input_file : str
@@ -803,16 +808,16 @@ class Edb(EdbInit):
803
808
  self._nets = None
804
809
  aedb_name = os.path.splitext(os.path.basename(input_file))[0] + ".aedb"
805
810
  if anstranslator_full_path and os.path.exists(anstranslator_full_path):
806
- command = anstranslator_full_path
811
+ executable_path = anstranslator_full_path
807
812
  else:
808
- command = os.path.join(self.base_path, "anstranslator")
813
+ executable_path = os.path.join(self.base_path, "anstranslator")
809
814
  if is_windows:
810
- command += ".exe"
815
+ executable_path += ".exe"
811
816
 
812
817
  if not working_dir:
813
818
  working_dir = os.path.dirname(input_file)
814
819
  cmd_translator = [
815
- command,
820
+ executable_path,
816
821
  input_file,
817
822
  os.path.join(working_dir, aedb_name),
818
823
  "-l={}".format(os.path.join(working_dir, "Translator.log")),
@@ -830,7 +835,10 @@ class Edb(EdbInit):
830
835
  cmd_translator.append('-t="{}"'.format(tech_file))
831
836
  if layer_filter:
832
837
  cmd_translator.append('-f="{}"'.format(layer_filter))
833
- subprocess.run(cmd_translator)
838
+ try:
839
+ subprocess.run(cmd_translator, check=True) # nosec
840
+ except subprocess.CalledProcessError as e: # nosec
841
+ raise RuntimeError("An error occurred while translating board file to ``edb.def`` file") from e
834
842
  if not os.path.exists(os.path.join(working_dir, aedb_name)):
835
843
  self.logger.error("Translator failed to translate.")
836
844
  return False
@@ -1340,6 +1348,11 @@ class Edb(EdbInit):
1340
1348
  ):
1341
1349
  """Import GDS file.
1342
1350
 
1351
+ .. warning::
1352
+ Do not execute this function with untrusted function argument, environment
1353
+ variables or pyedb global settings.
1354
+ See the :ref:`security guide<ref_security_consideration>` for details.
1355
+
1343
1356
  Parameters
1344
1357
  ----------
1345
1358
  inputGDS : str
@@ -1358,7 +1371,7 @@ class Edb(EdbInit):
1358
1371
  Layer filter file.
1359
1372
  """
1360
1373
  control_file_temp = os.path.join(tempfile.gettempdir(), os.path.split(inputGDS)[-1][:-3] + "xml")
1361
- if float(self.edbversion) < 2024.1:
1374
+ if float(self.version) < 2024.1:
1362
1375
  if not is_linux and tech_file:
1363
1376
  self.logger.error("Technology files are supported only in Linux. Use control file instead.")
1364
1377
  return False
@@ -1403,9 +1416,12 @@ class Edb(EdbInit):
1403
1416
  f'-f="{layer_filter}"',
1404
1417
  ]
1405
1418
 
1406
- result = subprocess.run(command, capture_output=True, text=True, shell=True)
1407
- print(result.stdout)
1408
- print(command)
1419
+ try:
1420
+ result = subprocess.run(command, capture_output=True, text=True, check=True) # nosec
1421
+ print(result.stdout)
1422
+ print(command)
1423
+ except subprocess.CalledProcessError as e: # nosec
1424
+ raise RuntimeError("An error occurred while converting file") from e
1409
1425
  temp_inputGDS = inputGDS.split(".gds")[0]
1410
1426
  self.edbpath = temp_inputGDS + ".aedb"
1411
1427
  return self.open()
@@ -3046,7 +3062,7 @@ class Edb(EdbInit):
3046
3062
  if name in self.setups:
3047
3063
  self.logger.error("Setup name already used in the layout")
3048
3064
  return False
3049
- version = self.edbversion.split(".")
3065
+ version = self.version.split(".")
3050
3066
  if int(version[0]) >= 2024 and int(version[-1]) >= 2 or int(version[0]) > 2024:
3051
3067
  setup = GrpcRaptorXSimulationSetup.create(cell=self.active_cell, name=name)
3052
3068
  return RaptorXSimulationSetup(self, setup)
@@ -3237,7 +3253,7 @@ class Edb(EdbInit):
3237
3253
  defined_ports = {}
3238
3254
  project_connexions = None
3239
3255
  for edb_path, zone_info in zone_dict.items():
3240
- edb = Edb(edbversion=self.edbversion, edbpath=edb_path)
3256
+ edb = Edb(edbversion=self.version, edbpath=edb_path)
3241
3257
  edb.cutout(
3242
3258
  use_pyaedt_cutout=True,
3243
3259
  custom_extent=zone_info[1],
@@ -3779,7 +3795,7 @@ class Edb(EdbInit):
3779
3795
  "No padstack instances found inside evaluated voids during model creation for arbitrary waveports"
3780
3796
  )
3781
3797
  return False
3782
- cloned_edb = Edb(edbpath=output_edb, edbversion=self.edbversion, restart_rpc_server=True)
3798
+ cloned_edb = Edb(edbpath=output_edb, edbversion=self.version, restart_rpc_server=True)
3783
3799
 
3784
3800
  cloned_edb.stackup.add_layer(
3785
3801
  layer_name="ports",
@@ -3908,6 +3924,11 @@ class Edb(EdbInit):
3908
3924
  def compare(self, input_file, results=""):
3909
3925
  """Compares current open database with another one.
3910
3926
 
3927
+ .. warning::
3928
+ Do not execute this function with untrusted function argument, environment
3929
+ variables or pyedb global settings.
3930
+ See the :ref:`security guide<ref_security_consideration>` for details.
3931
+
3911
3932
  Parameters
3912
3933
  ----------
3913
3934
  input_file : str
@@ -3924,13 +3945,18 @@ class Edb(EdbInit):
3924
3945
  if not results:
3925
3946
  results = self.edbpath[:-5] + "_compare_results"
3926
3947
  os.mkdir(results)
3927
- command = os.path.join(self.base_path, "EDBDiff.exe")
3948
+ executable_path = os.path.join(self.base_path, "EDBDiff.exe")
3928
3949
  if is_linux:
3929
3950
  mono_path = os.path.join(self.base_path, "common/mono/Linux64/bin/mono")
3930
- cmd_input = [mono_path, command, input_file, self.edbpath, results]
3951
+ command = [mono_path, executable_path, input_file, self.edbpath, results]
3931
3952
  else:
3932
- cmd_input = [command, input_file, self.edbpath, results]
3933
- subprocess.run(cmd_input)
3953
+ command = [executable_path, input_file, self.edbpath, results]
3954
+ try:
3955
+ subprocess.run(command, check=True) # nosec
3956
+ except subprocess.CalledProcessError as e: # nosec
3957
+ raise RuntimeError(
3958
+ "EDBDiff.exe execution failed. Please check if the executable is present in the base path."
3959
+ )
3934
3960
 
3935
3961
  if not os.path.exists(os.path.join(results, "EDBDiff.csv")):
3936
3962
  self.logger.error("Comparison execution failed")
pyedb/grpc/edb_init.py CHANGED
@@ -43,23 +43,23 @@ class EdbInit(object):
43
43
  def __init__(self, edbversion):
44
44
  self.logger = settings.logger
45
45
  self._db = None
46
- self.edbversion = edbversion
46
+ self.version = edbversion
47
47
  self.logger.info("Logger is initialized in EDB.")
48
48
  self.logger.info("legacy v%s", __version__)
49
49
  self.logger.info("Python version %s", sys.version)
50
50
  self.session = None
51
51
  if is_linux:
52
- if env_value(self.edbversion) in os.environ:
53
- self.base_path = env_path(self.edbversion)
52
+ if env_value(self.version) in os.environ:
53
+ self.base_path = env_path(self.version)
54
54
  sys.path.append(self.base_path)
55
55
  else:
56
56
  edb_path = os.getenv("PYAEDT_SERVER_AEDT_PATH")
57
57
  if edb_path:
58
58
  self.base_path = edb_path
59
59
  sys.path.append(edb_path)
60
- os.environ[env_value(self.edbversion)] = self.base_path
60
+ os.environ[env_value(self.version)] = self.base_path
61
61
  else:
62
- self.base_path = env_path(self.edbversion)
62
+ self.base_path = env_path(self.version)
63
63
  sys.path.append(self.base_path)
64
64
  os.environ["ECAD_TRANSLATORS_INSTALL_DIR"] = self.base_path
65
65
  oa_directory = os.path.join(self.base_path, "common", "oa")
@@ -100,7 +100,7 @@ class EdbInit(object):
100
100
  """
101
101
  if not RpcSession.pid:
102
102
  RpcSession.start(
103
- edb_version=self.edbversion,
103
+ edb_version=self.version,
104
104
  port=port,
105
105
  restart_server=restart_rpc_server,
106
106
  )
@@ -133,7 +133,7 @@ class EdbInit(object):
133
133
  RpcSession.pid = 0
134
134
  if not RpcSession.pid:
135
135
  RpcSession.start(
136
- edb_version=self.edbversion,
136
+ edb_version=self.version,
137
137
  port=port,
138
138
  restart_server=restart_rpc_server,
139
139
  )
@@ -372,18 +372,6 @@ class EdbInit(object):
372
372
  """
373
373
  self._db.import_material_from_control_file(control_file, schema_dir, append)
374
374
 
375
- @property
376
- def version(self):
377
- """Get version of the Database.
378
-
379
- Returns
380
- -------
381
- tuple(int, int)
382
- A tuple of the version numbers [major, minor]
383
- """
384
- major, minor = self._db.version
385
- return major, minor
386
-
387
375
  def scale(self, scale_factor):
388
376
  """Uniformly scale all geometry and their locations by a positive factor.
389
377
 
@@ -20,8 +20,8 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- from xml.dom.minidom import parseString
24
- import xml.etree.ElementTree as ET
23
+ import defusedxml.ElementTree as ET
24
+ from defusedxml.minidom import parseString
25
25
 
26
26
 
27
27
  def write_pretty_xml(root, file_path):
pyedb/misc/downloads.py CHANGED
@@ -24,6 +24,7 @@
24
24
 
25
25
  import os
26
26
  import shutil
27
+ import subprocess # nosec B404
27
28
  import tempfile
28
29
  import urllib.request
29
30
  import zipfile
@@ -48,7 +49,18 @@ def _get_file_url(directory, filename=None):
48
49
 
49
50
 
50
51
  def _retrieve_file(url, filename, directory, destination=None, local_paths=[]): # pragma: no cover
51
- """Download a file from a url"""
52
+ """Download a file from a url
53
+
54
+ .. warning::
55
+ Do not execute this function with untrusted function argument, environment
56
+ variables or pyedb global settings.
57
+ See the :ref:`security guide<ref_security_consideration>` for details.
58
+
59
+ """
60
+ # Check that provided url is pointing to pyaedt-example repo
61
+ if not url.startswith(EXAMPLE_REPO):
62
+ raise ValueError(f"Attempting to download file(s) from url {url} not pointing the to example-data repo.")
63
+
52
64
  # First check if file has already been downloaded
53
65
  if not destination:
54
66
  destination = EXAMPLES_PATH
@@ -64,8 +76,11 @@ def _retrieve_file(url, filename, directory, destination=None, local_paths=[]):
64
76
  os.makedirs(destination_dir)
65
77
  # Perform download
66
78
  if is_linux:
67
- command = "wget {} -O {}".format(url, local_path)
68
- os.system(command)
79
+ command = ["wget", url, "-O", local_path]
80
+ try:
81
+ subprocess.run(command, check=True) # nosec
82
+ except subprocess.CalledProcessError as e: # nosec
83
+ raise RuntimeError("An error occurred while downloading wget") from e
69
84
  else:
70
85
  _, resp = urlretrieve(url, local_path)
71
86
  local_paths.append(local_path)
@@ -23,6 +23,7 @@
23
23
  from copy import deepcopy as copy
24
24
  import json
25
25
 
26
+ from defusedxml.ElementTree import parse as defused_parse
26
27
  import numpy as np
27
28
 
28
29
  from pyedb.generic.general_methods import ET
@@ -78,7 +79,7 @@ class EMCRuleCheckerSettings:
78
79
  fpath: str
79
80
  Path to file.
80
81
  """
81
- tree = ET.parse(fpath)
82
+ tree = defused_parse(fpath)
82
83
  root = tree.getroot()
83
84
 
84
85
  self.tag_library = TagLibrary(root.find("TagLibrary"))
@@ -22,7 +22,6 @@
22
22
 
23
23
  from enum import Enum
24
24
  import os
25
- import xml.etree as ET
26
25
 
27
26
  from pyedb.generic.general_methods import ET
28
27
  from pyedb.misc.siw_feature_config.xtalk_scan.fd_xtalk_scan_config import (