pyedb 0.56.0__py3-none-any.whl → 0.58.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 (110) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_pin_groups.py +2 -0
  4. pyedb/configuration/cfg_terminals.py +232 -0
  5. pyedb/configuration/configuration.py +146 -3
  6. pyedb/dotnet/clr_module.py +1 -2
  7. pyedb/dotnet/database/Variables.py +30 -22
  8. pyedb/dotnet/database/cell/hierarchy/component.py +2 -8
  9. pyedb/dotnet/database/cell/layout.py +5 -1
  10. pyedb/dotnet/database/cell/primitive/primitive.py +2 -2
  11. pyedb/dotnet/database/cell/terminal/bundle_terminal.py +12 -0
  12. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  13. pyedb/dotnet/database/cell/terminal/terminal.py +38 -0
  14. pyedb/dotnet/database/components.py +15 -19
  15. pyedb/dotnet/database/dotnet/database.py +1 -0
  16. pyedb/dotnet/database/edb_data/control_file.py +19 -8
  17. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  18. pyedb/dotnet/database/edb_data/padstacks_data.py +39 -14
  19. pyedb/dotnet/database/edb_data/ports.py +0 -25
  20. pyedb/dotnet/database/edb_data/primitives_data.py +3 -3
  21. pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +18 -19
  22. pyedb/dotnet/database/edb_data/simulation_configuration.py +3 -3
  23. pyedb/dotnet/database/edb_data/sources.py +21 -2
  24. pyedb/dotnet/database/general.py +1 -6
  25. pyedb/dotnet/database/hfss.py +9 -8
  26. pyedb/dotnet/database/layout_validation.py +14 -3
  27. pyedb/dotnet/database/materials.py +1 -3
  28. pyedb/dotnet/database/modeler.py +7 -3
  29. pyedb/dotnet/database/nets.py +27 -19
  30. pyedb/dotnet/database/padstack.py +4 -2
  31. pyedb/dotnet/database/sim_setup_data/io/siwave.py +54 -1
  32. pyedb/dotnet/database/siwave.py +4 -3
  33. pyedb/dotnet/database/stackup.py +55 -58
  34. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  35. pyedb/dotnet/database/utilities/hfss_simulation_setup.py +81 -0
  36. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  37. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  38. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +264 -13
  39. pyedb/dotnet/edb.py +65 -47
  40. pyedb/exceptions.py +1 -2
  41. pyedb/extensions/create_cell_array.py +67 -49
  42. pyedb/generic/data_handlers.py +13 -23
  43. pyedb/generic/design_types.py +9 -35
  44. pyedb/generic/filesystem.py +4 -2
  45. pyedb/generic/general_methods.py +28 -41
  46. pyedb/generic/plot.py +8 -23
  47. pyedb/generic/process.py +78 -10
  48. pyedb/grpc/database/_typing.py +0 -0
  49. pyedb/grpc/database/components.py +14 -13
  50. pyedb/grpc/database/control_file.py +27 -40
  51. pyedb/grpc/database/definition/materials.py +1 -1
  52. pyedb/grpc/database/definition/package_def.py +6 -3
  53. pyedb/grpc/database/definition/padstack_def.py +14 -12
  54. pyedb/grpc/database/hfss.py +1 -4
  55. pyedb/grpc/database/hierarchy/component.py +5 -13
  56. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  57. pyedb/grpc/database/layers/layer.py +1 -2
  58. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  59. pyedb/grpc/database/layout/layout.py +43 -27
  60. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  61. pyedb/grpc/database/layout_validation.py +5 -2
  62. pyedb/grpc/database/modeler.py +254 -252
  63. pyedb/grpc/database/net/differential_pair.py +9 -2
  64. pyedb/grpc/database/net/extended_net.py +24 -9
  65. pyedb/grpc/database/net/net.py +14 -5
  66. pyedb/grpc/database/net/net_class.py +24 -7
  67. pyedb/grpc/database/nets.py +11 -43
  68. pyedb/grpc/database/padstacks.py +67 -119
  69. pyedb/grpc/database/primitive/bondwire.py +3 -67
  70. pyedb/grpc/database/primitive/circle.py +42 -3
  71. pyedb/grpc/database/primitive/padstack_instance.py +58 -31
  72. pyedb/grpc/database/primitive/path.py +160 -11
  73. pyedb/grpc/database/primitive/polygon.py +73 -7
  74. pyedb/grpc/database/primitive/primitive.py +2 -2
  75. pyedb/grpc/database/primitive/rectangle.py +105 -4
  76. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  77. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  78. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +79 -0
  79. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +1 -0
  80. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  81. pyedb/grpc/database/siwave.py +6 -13
  82. pyedb/grpc/database/source_excitations.py +46 -63
  83. pyedb/grpc/database/stackup.py +55 -60
  84. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  85. pyedb/grpc/database/terminal/padstack_instance_terminal.py +9 -11
  86. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  87. pyedb/grpc/database/terminal/point_terminal.py +30 -0
  88. pyedb/grpc/database/terminal/terminal.py +35 -10
  89. pyedb/grpc/database/utility/heat_sink.py +0 -1
  90. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  91. pyedb/grpc/database/utility/xml_control_file.py +19 -8
  92. pyedb/grpc/edb.py +63 -32
  93. pyedb/grpc/edb_init.py +1 -0
  94. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  95. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  96. pyedb/ipc2581/ipc2581.py +8 -7
  97. pyedb/libraries/common.py +3 -4
  98. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  99. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  100. pyedb/misc/aedtlib_personalib_install.py +2 -2
  101. pyedb/misc/downloads.py +19 -3
  102. pyedb/misc/misc.py +5 -2
  103. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +3 -2
  104. pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +0 -1
  105. pyedb/misc/utilities.py +0 -1
  106. pyedb/modeler/geometry_operators.py +3 -2
  107. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/METADATA +6 -7
  108. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/RECORD +110 -108
  109. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/WHEEL +0 -0
  110. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/licenses/LICENSE +0 -0
@@ -41,15 +41,18 @@ from ansys.edb.core.definition.solder_ball_property import (
41
41
  from ansys.edb.core.geometry.point3d_data import Point3DData as GrpcPoint3DData
42
42
  from ansys.edb.core.hierarchy.cell_instance import CellInstance as GrpcCellInstance
43
43
  from ansys.edb.core.hierarchy.component_group import ComponentType as GrpcComponentType
44
- from ansys.edb.core.layer.layer import LayerType as GrpcLayerType
45
- from ansys.edb.core.layer.layer import TopBottomAssociation as GrpcTopBottomAssociation
44
+ from ansys.edb.core.layer.layer import LayerType as GrpcLayerType, TopBottomAssociation as GrpcTopBottomAssociation
46
45
  from ansys.edb.core.layer.layer_collection import (
46
+ LayerCollection as GrpcLayerCollection,
47
47
  LayerCollectionMode as GrpcLayerCollectionMode,
48
+ LayerTypeSet as GrpcLayerTypeSet,
48
49
  )
49
- from ansys.edb.core.layer.layer_collection import LayerCollection as GrpcLayerCollection
50
- from ansys.edb.core.layer.layer_collection import LayerTypeSet as GrpcLayerTypeSet
51
50
  from ansys.edb.core.layer.stackup_layer import StackupLayer as GrpcStackupLayer
52
51
  from ansys.edb.core.layout.mcad_model import McadModel as GrpcMcadModel
52
+ from defusedxml.ElementTree import parse as defused_parse
53
+ import matplotlib.colors as colors
54
+ import numpy as np
55
+ import pandas as pd
53
56
 
54
57
  from pyedb.generic.general_methods import ET, generate_unique_name
55
58
  from pyedb.grpc.database.layers.layer import Layer
@@ -57,24 +60,6 @@ from pyedb.grpc.database.layers.stackup_layer import StackupLayer
57
60
  from pyedb.grpc.database.utility.value import Value
58
61
  from pyedb.misc.aedtlib_personalib_install import write_pretty_xml
59
62
 
60
- colors = None
61
- pd = None
62
- np = None
63
- try:
64
- import matplotlib.colors as colors
65
- except ImportError:
66
- colors = None
67
-
68
- try:
69
- import numpy as np
70
- except ImportError:
71
- np = None
72
-
73
- try:
74
- import pandas as pd
75
- except ImportError:
76
- pd = None
77
-
78
63
  logger = logging.getLogger(__name__)
79
64
 
80
65
 
@@ -128,8 +113,9 @@ class LayerCollection(GrpcLayerCollection):
128
113
  --------
129
114
  >>> from pyedb import Edb
130
115
  >>> edb = Edb()
131
- >>> top_layer = edb.stackup.add_layer_top("NewTopLayer", layer_type="signal", thickness="0.1mm",
132
- ... material="copper")
116
+ >>> top_layer = edb.stackup.add_layer_top(
117
+ ... "NewTopLayer", layer_type="signal", thickness="0.1mm", material="copper"
118
+ ... )
133
119
  """
134
120
  thickness = Value(0.0)
135
121
  if "thickness" in kwargs:
@@ -167,8 +153,9 @@ class LayerCollection(GrpcLayerCollection):
167
153
  --------
168
154
  >>> from pyedb import Edb
169
155
  >>> edb = Edb()
170
- >>> bot_layer = edb.stackup.add_layer_bottom("NewBottomLayer", layer_type="signal", thickness="0.1mm",
171
- ... material="copper")
156
+ >>> bot_layer = edb.stackup.add_layer_bottom(
157
+ ... "NewBottomLayer", layer_type="signal", thickness="0.1mm", material="copper"
158
+ ... )
172
159
  """
173
160
  thickness = Value(0.0)
174
161
  layer_type_map = {"dielectric": GrpcLayerType.DIELECTRIC_LAYER, "signal": GrpcLayerType.SIGNAL_LAYER}
@@ -564,9 +551,6 @@ class Stackup(LayerCollection):
564
551
  >>> edb = Edb()
565
552
  >>> edb.stackup.create_symmetric_stackup(layer_count=4)
566
553
  """
567
- if not np:
568
- self._pedb.logger.error("Numpy is needed. Please, install it first.")
569
- return False
570
554
  if not layer_count % 2 == 0:
571
555
  return False
572
556
 
@@ -1023,10 +1007,6 @@ class Stackup(LayerCollection):
1023
1007
  return self.export(fpath, file_format=file_format, include_material_with_layer=include_material_with_layer)
1024
1008
 
1025
1009
  def _export_layer_stackup_to_csv_xlsx(self, fpath: Optional[str] = None, file_format: Optional[str] = None) -> bool:
1026
- if not pd:
1027
- self._pedb.logger.error("Pandas is needed. Please, install it first.")
1028
- return False
1029
-
1030
1010
  data = {
1031
1011
  "Type": [],
1032
1012
  "Material": [],
@@ -1189,8 +1169,11 @@ class Stackup(LayerCollection):
1189
1169
  sball_prop = cmp_prop.solder_ball_property
1190
1170
  sball_prop.placement = GrpcSolderballPlacement.ABOVE_PADSTACK
1191
1171
  cmp_prop.solder_ball_property = sball_prop
1192
- except:
1193
- pass
1172
+ except Exception as e:
1173
+ self._logger.warning(
1174
+ f"A(n) {type(e).__name__} error occurred while attempting to update "
1175
+ f"solder_ball_property for component {cmp}: {str(e)}"
1176
+ )
1194
1177
  if cmp_type == GrpcComponentType.IC:
1195
1178
  die_prop = cmp_prop.die_property
1196
1179
  chip_orientation = die_prop.die_orientation
@@ -1236,8 +1219,11 @@ class Stackup(LayerCollection):
1236
1219
  try:
1237
1220
  if val.solder_ball_height and val.placement_layer == layer_name:
1238
1221
  height = val.solder_ball_height
1239
- except:
1240
- pass
1222
+ except Exception as e:
1223
+ self._logger.error(
1224
+ f"A(n) {type(e).__name__} error occurred while attempting to retrieve solder_height "
1225
+ f"for layer {layer_name} - Default value of 0.0 is returned: {str(e)}"
1226
+ )
1241
1227
  return height
1242
1228
 
1243
1229
  def _remove_solder_pec(self, layer_name):
@@ -1330,15 +1316,21 @@ class Stackup(LayerCollection):
1330
1316
  >>> mounted_cmp = edb2.components.get_component_by_name("BGA")
1331
1317
 
1332
1318
  >>> vector, rotation, solder_ball_height = edb1.components.get_component_placement_vector(
1333
- ... mounted_component=mounted_cmp,
1334
- ... hosting_component=hosting_cmp,
1335
- ... mounted_component_pin1="A12",
1336
- ... mounted_component_pin2="A14",
1337
- ... hosting_component_pin1="A12",
1338
- ... hosting_component_pin2="A14")
1339
- >>> edb2.stackup.place_in_layout(edb1.active_cell, angle=0.0, offset_x=vector[0],
1340
- ... offset_y=vector[1], flipped_stackup=False, place_on_top=True,
1341
- ... )
1319
+ ... mounted_component=mounted_cmp,
1320
+ ... hosting_component=hosting_cmp,
1321
+ ... mounted_component_pin1="A12",
1322
+ ... mounted_component_pin2="A14",
1323
+ ... hosting_component_pin1="A12",
1324
+ ... hosting_component_pin2="A14",
1325
+ ... )
1326
+ >>> edb2.stackup.place_in_layout(
1327
+ ... edb1.active_cell,
1328
+ ... angle=0.0,
1329
+ ... offset_x=vector[0],
1330
+ ... offset_y=vector[1],
1331
+ ... flipped_stackup=False,
1332
+ ... place_on_top=True,
1333
+ ... )
1342
1334
  """
1343
1335
  # if flipped_stackup and place_on_top or (not flipped_stackup and not place_on_top):
1344
1336
  self.adjust_solder_dielectrics()
@@ -1418,9 +1410,14 @@ class Stackup(LayerCollection):
1418
1410
  >>> edb2 = Edb(edbpath=targetfile2, edbversion="2021.2")
1419
1411
  >>> hosting_cmp = edb1.components.get_component_by_name("U100")
1420
1412
  >>> mounted_cmp = edb2.components.get_component_by_name("BGA")
1421
- >>> edb2.stackup.place_in_layout(edb1.active_cell, angle=0.0, offset_x="1mm",
1422
- ... offset_y="2mm", flipped_stackup=False, place_on_top=True,
1423
- ... )
1413
+ >>> edb2.stackup.place_in_layout(
1414
+ ... edb1.active_cell,
1415
+ ... angle=0.0,
1416
+ ... offset_x="1mm",
1417
+ ... offset_y="2mm",
1418
+ ... flipped_stackup=False,
1419
+ ... place_on_top=True,
1420
+ ... )
1424
1421
  """
1425
1422
  _angle = angle * math.pi / 180.0
1426
1423
 
@@ -1678,9 +1675,14 @@ class Stackup(LayerCollection):
1678
1675
  --------
1679
1676
  >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
1680
1677
  >>> a3dcomp_path = "connector.a3dcomp"
1681
- >>> edb1.stackup.place_a3dcomp_3d_placement(a3dcomp_path, angle=0.0, offset_x="1mm",
1682
- ... offset_y="2mm", flipped_stackup=False, place_on_top=True,
1683
- ... )
1678
+ >>> edb1.stackup.place_a3dcomp_3d_placement(
1679
+ ... a3dcomp_path,
1680
+ ... angle=0.0,
1681
+ ... offset_x="1mm",
1682
+ ... offset_y="2mm",
1683
+ ... flipped_stackup=False,
1684
+ ... place_on_top=True,
1685
+ ... )
1684
1686
  """
1685
1687
  rotation_axis_from = GrpcPoint3DData(1.0, 0.0, 0.0)
1686
1688
  _angle = angle * math.pi / 180.0
@@ -1932,10 +1934,6 @@ class Stackup(LayerCollection):
1932
1934
  bool
1933
1935
  ``True`` when successful.
1934
1936
  """
1935
- if not pd:
1936
- self._pedb.logger.error("Pandas is needed. You must install it first.")
1937
- return False
1938
-
1939
1937
  df = pd.read_csv(file_path, index_col=0)
1940
1938
 
1941
1939
  for name in self.layers.keys(): # pragma: no cover
@@ -2204,10 +2202,7 @@ class Stackup(LayerCollection):
2204
2202
  bool
2205
2203
  ``True`` when successful.
2206
2204
  """
2207
- if not colors:
2208
- self._pedb.logger.error("Matplotlib is needed. Please, install it first.")
2209
- return False
2210
- tree = ET.parse(file_path)
2205
+ tree = defused_parse(file_path)
2211
2206
  root = tree.getroot()
2212
2207
  stackup = root.find("Stackup")
2213
2208
  stackup_dict = {}
@@ -20,15 +20,20 @@
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 __future__ import annotations
24
+
25
+ from typing import TYPE_CHECKING
26
+
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.hierarchy.component import Component
29
+ from pyedb.grpc.database.net.net import Net
23
30
  from ansys.edb.core.terminal.bundle_terminal import BundleTerminal as GrpcBundleTerminal
24
31
  from ansys.edb.core.terminal.terminal import (
32
+ HfssPIType as GrpcHfssPIType,
25
33
  SourceTermToGroundType as GrpcSourceTermToGroundType,
26
34
  )
27
- from ansys.edb.core.terminal.terminal import HfssPIType as GrpcHfssPIType
28
35
 
29
- from pyedb.grpc.database.hierarchy.component import Component
30
36
  from pyedb.grpc.database.layers.layer import Layer
31
- from pyedb.grpc.database.net.net import Net
32
37
  from pyedb.grpc.database.terminal.terminal import Terminal
33
38
  from pyedb.grpc.database.utility.rlc import Rlc
34
39
  from pyedb.grpc.database.utility.value import Value
@@ -77,6 +82,7 @@ class BundleTerminal(GrpcBundleTerminal):
77
82
  -------
78
83
  :class:`Component <pyedb.grpc.database.hierarchy.component.Component`
79
84
  """
85
+
80
86
  return Component(self._pedb, self.component)
81
87
 
82
88
  @property
@@ -102,6 +108,7 @@ class BundleTerminal(GrpcBundleTerminal):
102
108
  -------
103
109
  :class:`Net <pyedb.grpc.database.net.net.Net>`
104
110
  """
111
+
105
112
  return Net(self._pedb, self.net)
106
113
 
107
114
  @property
@@ -37,16 +37,6 @@ class PadstackInstanceTerminal(GrpcPadstackInstanceTerminal):
37
37
  super().__init__(edb_object.msg)
38
38
  self._pedb = pedb
39
39
 
40
- @property
41
- def boundary_type(self) -> str:
42
- """Boundary type.
43
-
44
- Returns
45
- -------
46
- str : boundary type.
47
- """
48
- return super().boundary_type.name.lower()
49
-
50
40
  @property
51
41
  def position(self) -> list[float]:
52
42
  """Terminal position.
@@ -193,7 +183,15 @@ class PadstackInstanceTerminal(GrpcPadstackInstanceTerminal):
193
183
  "rlc": GrpcBoundaryType.RLC,
194
184
  "pec": GrpcBoundaryType.PEC,
195
185
  }
196
- super(PadstackInstanceTerminal, self.__class__).boundary_type.__set__(self, mapping[value.name.lower()])
186
+ if isinstance(value, str):
187
+ key = value.lower()
188
+ else:
189
+ key = value.name.lower()
190
+ new_boundary_type = mapping.get(key)
191
+ if new_boundary_type is None:
192
+ valid_types = ", ".join(mapping.keys())
193
+ raise ValueError(f"Invalid boundary type '{value}'. Valid types are: {valid_types}")
194
+ super(PadstackInstanceTerminal, self.__class__).boundary_type.__set__(self, new_boundary_type)
197
195
 
198
196
  @property
199
197
  def is_port(self) -> bool:
@@ -20,12 +20,17 @@
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 __future__ import annotations
24
+
25
+ from typing import TYPE_CHECKING
26
+
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.net.net import Net
23
29
  from ansys.edb.core.terminal.pin_group_terminal import (
24
30
  PinGroupTerminal as GrpcPinGroupTerminal,
25
31
  )
26
32
  from ansys.edb.core.terminal.terminal import BoundaryType as GrpcBoundaryType
27
33
 
28
- from pyedb.grpc.database.net.net import Net
29
34
  from pyedb.grpc.database.utility.value import Value
30
35
  from pyedb.misc.decorators import deprecated_property
31
36
 
@@ -151,6 +156,8 @@ class PinGroupTerminal(GrpcPinGroupTerminal):
151
156
  Terminal Net object.
152
157
 
153
158
  """
159
+ from pyedb.grpc.database.net.net import Net
160
+
154
161
  return Net(self._pedb, super().net)
155
162
 
156
163
  @net.setter
@@ -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.
@@ -20,17 +20,34 @@
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 __future__ import annotations
24
+
25
+ from typing import TYPE_CHECKING
26
+
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
23
29
  import re
24
30
 
25
31
  from ansys.edb.core.terminal.edge_terminal import EdgeType as GrpcEdgeType
26
- from ansys.edb.core.terminal.terminal import BoundaryType as GrpcBoundaryType
27
- from ansys.edb.core.terminal.terminal import Terminal as GrpcTerminal
28
- from ansys.edb.core.terminal.terminal import TerminalType as GrpcTerminalType
32
+ from ansys.edb.core.terminal.terminal import (
33
+ BoundaryType as GrpcBoundaryType,
34
+ Terminal as GrpcTerminal,
35
+ TerminalType as GrpcTerminalType,
36
+ )
29
37
 
30
- from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
31
38
  from pyedb.grpc.database.primitive.primitive import Primitive
32
39
  from pyedb.grpc.database.utility.value import Value
33
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
+
34
51
 
35
52
  class Terminal(GrpcTerminal):
36
53
  def __init__(self, pedb, edb_object):
@@ -195,7 +212,11 @@ class Terminal(GrpcTerminal):
195
212
 
196
213
  @boundary_type.setter
197
214
  def boundary_type(self, value):
198
- 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)
199
220
 
200
221
  @property
201
222
  def is_port(self) -> bool:
@@ -243,7 +264,7 @@ class Terminal(GrpcTerminal):
243
264
 
244
265
  @impedance.setter
245
266
  def impedance(self, value):
246
- self.impedance = Value(value)
267
+ super(Terminal, self.__class__).impedance.__set__(self, self._pedb.value(value))
247
268
 
248
269
  @property
249
270
  def reference_object(self) -> any:
@@ -364,13 +385,17 @@ class Terminal(GrpcTerminal):
364
385
  return (primitive, self._pedb)
365
386
  return None # pragma: no cover
366
387
 
367
- def get_point_terminal_reference_primitive(self) -> Primitive: # pragma : no cover
368
- """Find and return the primitive reference for the point terminal or the padstack instance.
388
+ def get_point_terminal_reference_primitive(self) -> Primitive:
389
+ """
390
+ Find and return the primitive reference for the point terminal or the padstack instance.
369
391
 
370
392
  Returns
371
393
  -------
372
- :class:`PadstackInstance <pyedb.grpc.database.primitive.padstack_instance.PadstackInstance>` or
373
- :class:`Primitive <pyedb.grpc.database.primitive.primitive.Primitive>`
394
+ Primitive or PadstackInstance
395
+ The primitive reference for the point terminal or the padstack instance.
396
+ Returns an instance of :class:`PadstackInstance
397
+ <pyedb.grpc.database.primitive.padstack_instance.PadstackInstance>`
398
+ or :class:`Primitive <pyedb.grpc.database.primitive.primitive.Primitive>`.
374
399
  """
375
400
 
376
401
  ref_term = self.reference_terminal # return value is type terminal
@@ -27,7 +27,6 @@ from ansys.edb.core.utility.value import Value as GrpcValue
27
27
 
28
28
 
29
29
  class HeatSink:
30
-
31
30
  """Heatsink model description.
32
31
 
33
32
  Parameters
@@ -21,10 +21,10 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  from ansys.edb.core.utility.hfss_extent_info import (
24
+ HfssExtentInfo as GrpcHfssExtentInfo,
24
25
  HFSSExtentInfoType as GrpcHfssExtentInfoType,
26
+ OpenRegionType as GrpcOpenRegionType,
25
27
  )
26
- from ansys.edb.core.utility.hfss_extent_info import HfssExtentInfo as GrpcHfssExtentInfo
27
- from ansys.edb.core.utility.hfss_extent_info import OpenRegionType as GrpcOpenRegionType
28
28
  from ansys.edb.core.utility.value import Value as GrpcValue
29
29
 
30
30
 
@@ -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
@@ -122,7 +130,7 @@ class ControlProperty:
122
130
  float(value)
123
131
  self.type = 0
124
132
  except TypeError:
125
- pass
133
+ self.type = -1
126
134
 
127
135
  def _write_xml(self, root):
128
136
  try:
@@ -132,8 +140,11 @@ class ControlProperty:
132
140
  double.text = str(self.value)
133
141
  else:
134
142
  pass
135
- except:
136
- pass
143
+ except Exception as e:
144
+ settings.logger.error(
145
+ f"A(n) {type(e).__name__} error occurred while attempting to create a new sub-element {self.name} "
146
+ f"for element {root}: {str(e)}"
147
+ )
137
148
 
138
149
 
139
150
  class ControlFileMaterial:
@@ -1185,7 +1196,7 @@ class ControlFile:
1185
1196
  -------
1186
1197
  bool
1187
1198
  """
1188
- tree = ET.parse(xml_input)
1199
+ tree = defused_parse(xml_input)
1189
1200
  root = tree.getroot()
1190
1201
  for el in root:
1191
1202
  if el.tag == "Stackup":