pyedb 0.54.0__py3-none-any.whl → 0.56.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 (105) hide show
  1. pyedb/__init__.py +1 -8
  2. pyedb/configuration/cfg_boundaries.py +69 -151
  3. pyedb/configuration/cfg_components.py +201 -460
  4. pyedb/configuration/cfg_data.py +4 -2
  5. pyedb/configuration/cfg_general.py +13 -36
  6. pyedb/configuration/cfg_modeler.py +2 -1
  7. pyedb/configuration/cfg_nets.py +21 -35
  8. pyedb/configuration/cfg_operations.py +22 -151
  9. pyedb/configuration/cfg_package_definition.py +56 -112
  10. pyedb/configuration/cfg_padstacks.py +292 -688
  11. pyedb/configuration/cfg_pin_groups.py +32 -79
  12. pyedb/configuration/cfg_ports_sources.py +19 -6
  13. pyedb/configuration/cfg_s_parameter_models.py +67 -172
  14. pyedb/configuration/cfg_setup.py +102 -295
  15. pyedb/configuration/configuration.py +64 -5
  16. pyedb/dotnet/database/Variables.py +26 -19
  17. pyedb/dotnet/database/cell/connectable.py +38 -9
  18. pyedb/dotnet/database/cell/hierarchy/component.py +28 -28
  19. pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
  20. pyedb/dotnet/database/cell/layout.py +63 -2
  21. pyedb/dotnet/database/cell/layout_obj.py +2 -2
  22. pyedb/dotnet/database/cell/primitive/path.py +6 -8
  23. pyedb/dotnet/database/cell/primitive/primitive.py +3 -24
  24. pyedb/dotnet/database/cell/terminal/edge_terminal.py +2 -2
  25. pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
  26. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  27. pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
  28. pyedb/dotnet/database/cell/terminal/terminal.py +24 -24
  29. pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
  30. pyedb/dotnet/database/components.py +137 -124
  31. pyedb/dotnet/database/definition/component_def.py +4 -4
  32. pyedb/dotnet/database/definition/component_model.py +1 -1
  33. pyedb/dotnet/database/definition/package_def.py +2 -3
  34. pyedb/dotnet/database/dotnet/database.py +3 -199
  35. pyedb/dotnet/database/dotnet/primitive.py +3 -3
  36. pyedb/dotnet/database/edb_data/control_file.py +5 -5
  37. pyedb/dotnet/database/edb_data/hfss_extent_info.py +6 -6
  38. pyedb/dotnet/database/edb_data/layer_data.py +23 -23
  39. pyedb/dotnet/database/edb_data/padstacks_data.py +63 -88
  40. pyedb/dotnet/database/edb_data/primitives_data.py +5 -5
  41. pyedb/dotnet/database/edb_data/sources.py +6 -6
  42. pyedb/dotnet/database/edb_data/variables.py +1 -1
  43. pyedb/dotnet/database/geometry/point_data.py +14 -10
  44. pyedb/dotnet/database/geometry/polygon_data.py +3 -3
  45. pyedb/dotnet/database/hfss.py +46 -48
  46. pyedb/dotnet/database/layout_validation.py +14 -11
  47. pyedb/dotnet/database/materials.py +10 -11
  48. pyedb/dotnet/database/modeler.py +97 -91
  49. pyedb/dotnet/database/nets.py +19 -22
  50. pyedb/dotnet/database/padstack.py +171 -83
  51. pyedb/dotnet/database/siwave.py +42 -42
  52. pyedb/dotnet/database/stackup.py +140 -72
  53. pyedb/dotnet/database/utilities/heatsink.py +4 -4
  54. pyedb/dotnet/database/utilities/obj_base.py +2 -2
  55. pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
  56. pyedb/dotnet/database/utilities/value.py +16 -16
  57. pyedb/dotnet/edb.py +230 -152
  58. pyedb/edb_logger.py +12 -27
  59. pyedb/extensions/create_cell_array.py +394 -0
  60. pyedb/extensions/via_design_backend.py +6 -3
  61. pyedb/generic/data_handlers.py +6 -7
  62. pyedb/generic/design_types.py +81 -30
  63. pyedb/generic/filesystem.py +5 -2
  64. pyedb/generic/general_methods.py +2 -122
  65. pyedb/generic/process.py +44 -108
  66. pyedb/generic/settings.py +79 -19
  67. pyedb/grpc/database/components.py +26 -4
  68. pyedb/grpc/database/control_file.py +5 -5
  69. pyedb/grpc/database/definition/materials.py +1 -1
  70. pyedb/grpc/database/definition/package_def.py +3 -3
  71. pyedb/grpc/database/definition/padstack_def.py +53 -0
  72. pyedb/grpc/database/geometry/polygon_data.py +1 -1
  73. pyedb/grpc/database/layout/layout.py +81 -5
  74. pyedb/grpc/database/layout_validation.py +5 -5
  75. pyedb/grpc/database/modeler.py +24 -16
  76. pyedb/grpc/database/net/net.py +15 -14
  77. pyedb/grpc/database/nets.py +70 -0
  78. pyedb/grpc/database/padstacks.py +122 -17
  79. pyedb/grpc/database/primitive/padstack_instance.py +175 -7
  80. pyedb/grpc/database/primitive/polygon.py +2 -2
  81. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +3 -2
  82. pyedb/grpc/database/siwave.py +1 -1
  83. pyedb/grpc/database/source_excitations.py +12 -5
  84. pyedb/grpc/database/stackup.py +1 -1
  85. pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
  86. pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
  87. pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
  88. pyedb/grpc/database/utility/value.py +1 -0
  89. pyedb/grpc/database/utility/xml_control_file.py +5 -5
  90. pyedb/grpc/edb.py +80 -30
  91. pyedb/grpc/edb_init.py +3 -3
  92. pyedb/grpc/rpc_session.py +14 -13
  93. pyedb/libraries/common.py +366 -0
  94. pyedb/libraries/rf_libraries/base_functions.py +1358 -0
  95. pyedb/libraries/rf_libraries/planar_antennas.py +628 -0
  96. pyedb/misc/decorators.py +61 -0
  97. pyedb/misc/misc.py +0 -13
  98. pyedb/modeler/geometry_operators.py +6 -6
  99. pyedb/siwave.py +6 -8
  100. pyedb/siwave_core/__init__.py +0 -0
  101. pyedb/siwave_core/cpa/__init__.py +0 -0
  102. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/METADATA +1 -2
  103. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/RECORD +105 -98
  104. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/WHEEL +0 -0
  105. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/licenses/LICENSE +0 -0
@@ -57,6 +57,7 @@ from pyedb.grpc.database.hierarchy.pingroup import PinGroup
57
57
  from pyedb.grpc.database.padstacks import Padstacks
58
58
  from pyedb.grpc.database.utility.sources import SourceType
59
59
  from pyedb.grpc.database.utility.value import Value
60
+ from pyedb.misc.decorators import deprecate_argument_name
60
61
  from pyedb.modeler.geometry_operators import GeometryOperators
61
62
 
62
63
 
@@ -500,6 +501,7 @@ class Components(object):
500
501
  """
501
502
  return self.instances[name]
502
503
 
504
+ @deprecate_argument_name({"pinName": "pin_name"})
503
505
  def get_pin_from_component(
504
506
  self,
505
507
  component: Union[str, Component],
@@ -1063,6 +1065,9 @@ class Components(object):
1063
1065
  ComponentGroup as GrpcComponentGroup,
1064
1066
  )
1065
1067
 
1068
+ if not pins:
1069
+ raise ValueError("Pins must be a list of PadstackInstance objects.")
1070
+
1066
1071
  if not component_name:
1067
1072
  component_name = generate_unique_name("Comp_")
1068
1073
  if component_part_name:
@@ -1072,7 +1077,10 @@ class Components(object):
1072
1077
  if not compdef:
1073
1078
  return False
1074
1079
  new_cmp = GrpcComponentGroup.create(self._active_layout, component_name, compdef.name)
1075
- hosting_component_location = pins[0].component.transform
1080
+ if hasattr(pins[0], "component") and pins[0].component:
1081
+ hosting_component_location = pins[0].component.transform
1082
+ else:
1083
+ hosting_component_location = None
1076
1084
  if not len(pins) == len(compdef.component_pins):
1077
1085
  self._pedb.logger.error(
1078
1086
  f"Number on pins {len(pins)} does not match component definition number "
@@ -1090,7 +1098,18 @@ class Components(object):
1090
1098
  if new_cmp_layer_name in self._pedb.stackup.signal_layers:
1091
1099
  new_cmp_placement_layer = self._pedb.stackup.signal_layers[new_cmp_layer_name]
1092
1100
  new_cmp.placement_layer = new_cmp_placement_layer
1093
- new_cmp.component_type = GrpcComponentType.OTHER
1101
+ if r_value:
1102
+ new_cmp.component_type = GrpcComponentType.RESISTOR
1103
+ is_rlc = True
1104
+ elif c_value:
1105
+ new_cmp.component_type = GrpcComponentType.CAPACITOR
1106
+ is_rlc = True
1107
+ elif l_value:
1108
+ new_cmp.component_type = GrpcComponentType.INDUCTOR
1109
+ is_rlc = True
1110
+ else:
1111
+ new_cmp.component_type = GrpcComponentType.OTHER
1112
+ is_rlc = False
1094
1113
  if is_rlc and len(pins) == 2:
1095
1114
  rlc = GrpcRlc()
1096
1115
  rlc.is_parallel = is_parallel
@@ -1123,7 +1142,8 @@ class Components(object):
1123
1142
  component_property = new_cmp.component_property
1124
1143
  component_property.model = rlc_model
1125
1144
  new_cmp.component_property = component_property
1126
- new_cmp.transform = hosting_component_location
1145
+ if hosting_component_location:
1146
+ new_cmp.transform = hosting_component_location
1127
1147
  new_edb_comp = Component(self._pedb, new_cmp)
1128
1148
  self._cmp[new_cmp.name] = new_edb_comp
1129
1149
  return new_edb_comp
@@ -1664,7 +1684,9 @@ class Components(object):
1664
1684
  if comp.partname == part_name:
1665
1685
  pass
1666
1686
  else:
1667
- pinlist = self._pedb.padstacks.get_instances(refdes)
1687
+ pinlist = list(self.instances[refdes].pins.values())
1688
+ if not pinlist:
1689
+ continue
1668
1690
  if not part_name in self.definitions:
1669
1691
  comp_def = ComponentDef.create(self._db, part_name, None)
1670
1692
  # for pin in range(len(pinlist)):
@@ -27,8 +27,8 @@ import subprocess
27
27
  import sys
28
28
  from typing import Any, Dict, List, Optional, Union
29
29
 
30
- from pyedb.edb_logger import pyedb_logger
31
30
  from pyedb.generic.general_methods import ET, env_path, env_value, is_linux
31
+ from pyedb.generic.settings import settings
32
32
  from pyedb.misc.aedtlib_personalib_install import write_pretty_xml
33
33
  from pyedb.misc.misc import list_installed_ansysem
34
34
 
@@ -194,7 +194,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
194
194
  base_path = env_path(edbversion)
195
195
  sys.path.append(base_path)
196
196
  else:
197
- pyedb_logger.error("No EDB installation found. Check environment variables")
197
+ settings.logger.error("No EDB installation found. Check environment variables")
198
198
  return False
199
199
  os.environ["HELIC_ROOT"] = os.path.join(base_path, "helic")
200
200
  if os.getenv("ANSYSLMD_LICENCE_FILE", None) is None:
@@ -207,7 +207,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
207
207
  os.environ["ANSYSLMD_LICENSE_FILE"] = line.split("=")[1]
208
208
  break
209
209
  else:
210
- pyedb_logger.error("ANSYSLMD_LICENSE_FILE is not defined.")
210
+ settings.logger.error("ANSYSLMD_LICENSE_FILE is not defined.")
211
211
  vlc_file_name = os.path.splitext(tech_file)[0]
212
212
  if not control_file:
213
213
  control_file = vlc_file_name + ".xml"
@@ -241,9 +241,9 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
241
241
  p = subprocess.Popen(command, env=my_env)
242
242
  p.wait()
243
243
  if os.path.exists(control_file):
244
- pyedb_logger.info("XML file created.")
244
+ settings.logger.info("XML file created.")
245
245
  return control_file
246
- pyedb_logger.error("Technology files are supported only in Linux. Use control file instead.")
246
+ settings.logger.error("Technology files are supported only in Linux. Use control file instead.")
247
247
  return False
248
248
 
249
249
 
@@ -378,7 +378,7 @@ class Material(GrpcMaterialDef):
378
378
  "Use property dielectric_loss_tangent instead.",
379
379
  DeprecationWarning,
380
380
  )
381
- self.dielectric_loss_tangent(value)
381
+ self.dielectric_loss_tangent = value
382
382
 
383
383
  @dielectric_loss_tangent.setter
384
384
  def dielectric_loss_tangent(self, value):
@@ -23,10 +23,10 @@
23
23
  from ansys.edb.core.definition.package_def import PackageDef as GrpcPackageDef
24
24
  from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
25
25
 
26
- from pyedb.edb_logger import pyedb_logger
26
+ from pyedb.generic.settings import settings
27
27
  from pyedb.grpc.database.utility.heat_sink import HeatSink
28
28
  from pyedb.grpc.database.utility.value import Value
29
- from pyedb.misc.misc import deprecated_property
29
+ from pyedb.misc.decorators import deprecated_property
30
30
 
31
31
 
32
32
  class PackageDef(GrpcPackageDef):
@@ -82,7 +82,7 @@ class PackageDef(GrpcPackageDef):
82
82
  else:
83
83
  bbox = extent_bounding_box
84
84
  if bbox is None:
85
- pyedb_logger.warning(
85
+ settings.logger.warning(
86
86
  "Package creation uses bounding box but it cannot be inferred. "
87
87
  "Please set argument 'component_part_name' or 'extent_bounding_box'."
88
88
  )
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  import math
24
+ import warnings
24
25
 
25
26
  from ansys.edb.core.definition.padstack_def import PadstackDef as GrpcPadstackDef
26
27
  from ansys.edb.core.definition.padstack_def_data import (
@@ -109,6 +110,26 @@ class PadProperties:
109
110
  """
110
111
  return self._pad_parameter_value[0].name.split("_")[-1].lower()
111
112
 
113
+ @shape.setter
114
+ def shape(self, value: str):
115
+ """Set pad shape.
116
+
117
+ Parameters
118
+ ----------
119
+ value : str
120
+ Pad shape.
121
+ """
122
+ if value.lower() == "circle":
123
+ self._update_pad_parameters_parameters(geom_type=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE)
124
+ elif value.lower() == "rectangle":
125
+ self._update_pad_parameters_parameters(geom_type=GrpcPadGeometryType.PADGEOMTYPE_RECTANGLE)
126
+ elif value.lower() == "polygon":
127
+ self._update_pad_parameters_parameters(geom_type=GrpcPadGeometryType.PADGEOMTYPE_POLYGON)
128
+ else:
129
+ raise ValueError(
130
+ f"Unsupported pad shape: {value}. Supported shapes are 'circle', " f"'rectangle', and 'polygon'."
131
+ )
132
+
112
133
  @property
113
134
  def parameters_values(self):
114
135
  """Parameters.
@@ -300,6 +321,22 @@ class PadstackDef(GrpcPadstackDef):
300
321
  """
301
322
  return self.layers[0]
302
323
 
324
+ @property
325
+ def via_start_layer(self):
326
+ """Via starting layer.
327
+
328
+ .deprecated
329
+ Use: :method:`start_layer <pyedb.grpc.database.definition.padstack_def.PadstackDef.start_layer>`
330
+ instead.
331
+
332
+ Returns
333
+ -------
334
+ str
335
+ Name of the via starting layer.
336
+ """
337
+ warnings.warn("via_start_layer is deprecated. Use start_layer instead.", DeprecationWarning)
338
+ return self.start_layer
339
+
303
340
  @property
304
341
  def stop_layer(self):
305
342
  """Stopping layer.
@@ -311,6 +348,22 @@ class PadstackDef(GrpcPadstackDef):
311
348
  """
312
349
  return self.layers[-1]
313
350
 
351
+ @property
352
+ def via_stop_layer(self):
353
+ """Via stop layer.
354
+
355
+ .deprecated
356
+ Use :method:`stop_layer <pyedb.grpc.database.definition.padstack_def.PadstackDef.stop_layer>`
357
+ instead.
358
+
359
+ Returns
360
+ -------
361
+ str
362
+ Name of the via stop layer.
363
+ """
364
+ warnings.warn("via_stop_layer is deprecated. Use stop_layer instead.", DeprecationWarning)
365
+ return self.stop_layer
366
+
314
367
  @property
315
368
  def hole_diameter(self) -> float:
316
369
  """Hole diameter.
@@ -127,7 +127,7 @@ class PolygonData(GrpcPolygonData):
127
127
  bool
128
128
 
129
129
  """
130
- new_poly = self.expand(offset, tolerance, round_corners, maximum_corner_extension)
130
+ new_poly = super().expand(offset, tolerance, round_corners, maximum_corner_extension)
131
131
  if not new_poly[0].points:
132
132
  return False
133
133
  self._edb_object = new_poly[0]
@@ -23,7 +23,7 @@
23
23
  """
24
24
  This module contains these classes: `EdbLayout` and `Shape`.
25
25
  """
26
- from typing import Union
26
+ from typing import Dict, List, Union
27
27
 
28
28
  from ansys.edb.core.layout.layout import Layout as GrpcLayout
29
29
  import ansys.edb.core.primitive.bondwire
@@ -63,6 +63,7 @@ class Layout(GrpcLayout):
63
63
  super().__init__(pedb.active_cell._Cell__stub.GetLayout(pedb.active_cell.msg))
64
64
  self._pedb = pedb
65
65
  self.__primitives = []
66
+ self.__padstack_instances = {}
66
67
 
67
68
  @property
68
69
  def cell(self):
@@ -74,8 +75,9 @@ class Layout(GrpcLayout):
74
75
 
75
76
  @property
76
77
  def primitives(self) -> list[any]:
78
+ primitives = super().primitives
77
79
  self.__primitives = []
78
- for prim in super().primitives:
80
+ for prim in primitives:
79
81
  if isinstance(prim, ansys.edb.core.primitive.path.Path):
80
82
  self.__primitives.append(Path(self._pedb, prim))
81
83
  elif isinstance(prim, ansys.edb.core.primitive.polygon.Polygon):
@@ -196,11 +198,12 @@ class Layout(GrpcLayout):
196
198
  return [DifferentialPair(self._pedb, i) for i in self._pedb.active_cell.layout.differential_pairs]
197
199
 
198
200
  @property
199
- def padstack_instances(self) -> list[PadstackInstance]:
201
+ def padstack_instances(self) -> Dict[int, PadstackInstance]:
200
202
  """Get all padstack instances in a list."""
201
- return [PadstackInstance(self._pedb, i) for i in self._pedb.active_cell.layout.padstack_instances]
203
+ pad_stack_inst = super().padstack_instances
204
+ self.__padstack_instances = {i.edb_uid: PadstackInstance(self._pedb, i) for i in pad_stack_inst}
205
+ return self.__padstack_instances
202
206
 
203
- #
204
207
  @property
205
208
  def voltage_regulators(self) -> list[VoltageRegulator]:
206
209
  """Voltage regulators.
@@ -240,3 +243,76 @@ class Layout(GrpcLayout):
240
243
  prims = [i for i in prims if i.layer_name in layer_name] if layer_name is not None else prims
241
244
  prims = [i for i in prims if i.net_name in net_name] if net_name is not None else prims
242
245
  return prims
246
+
247
+ def find_padstack_instances(
248
+ self,
249
+ aedt_name: Union[str, List[str]] = None,
250
+ component_name: Union[str, List[str]] = None,
251
+ component_pin_name: Union[str, List[str]] = None,
252
+ net_name: Union[str, List[str]] = None,
253
+ instance_id: Union[int, List[int]] = None,
254
+ ) -> List:
255
+ """
256
+ Finds padstack instances matching the specified criteria.
257
+
258
+ This method filters the available padstack instances based on specified attributes such as
259
+ `aedt_name`, `component_name`, `component_pin_name`, `net_name`, or `instance_id`. Criteria
260
+ can be passed as individual values or as a list of values. If no padstack instances match
261
+ the criteria, an error is raised.
262
+
263
+ Parameters
264
+ ----------
265
+ aedt_name : Union[str, List[str]], optional
266
+ Name(s) of the AEDT padstack instance(s) to filter.
267
+ component_name : Union[str, List[str]], optional
268
+ Name(s) of the component(s) to filter padstack instances by.
269
+ component_pin_name : Union[str, List[str]], optional
270
+ Name(s) of the component pin(s) to filter padstack instances by.
271
+ net_name : Union[str, List[str]], optional
272
+ Name(s) of the net(s) to filter padstack instances by.
273
+ instance_id : Union[int, List[int]], optional
274
+ ID(s) of the padstack instance(s) to filter.
275
+
276
+ Returns
277
+ -------
278
+ List
279
+ A list of padstack instances matching the specified criteria.
280
+ """
281
+ padstacks = self.padstack_instances
282
+ instances_found = []
283
+ if instance_id is not None:
284
+ instance_ids = instance_id if isinstance(instance_id, list) else [instance_id]
285
+ if instance_id in instance_ids:
286
+ instances_found.append(padstacks[instance_id])
287
+
288
+ if aedt_name is not None:
289
+ name = aedt_name if isinstance(aedt_name, list) else [aedt_name]
290
+ [instances_found.append(i) for i in list(padstacks.values()) if i.aedt_name in name]
291
+
292
+ if component_name is not None:
293
+ value = component_name if isinstance(component_name, list) else [component_name]
294
+ for inst in padstacks.values():
295
+ if inst.component:
296
+ if inst.component.name in value:
297
+ instances_found.append(inst)
298
+
299
+ if net_name is not None:
300
+ value = net_name if isinstance(net_name, list) else [net_name]
301
+ for inst in padstacks.values():
302
+ if inst.net:
303
+ if inst.net.name in value:
304
+ instances_found.append(inst)
305
+
306
+ if component_pin_name is not None:
307
+ value = component_pin_name if isinstance(component_name, list) else [component_pin_name]
308
+ for inst in padstacks.values():
309
+ if inst.component:
310
+ if hasattr(inst, "name"):
311
+ if inst.name in value:
312
+ instances_found.append(inst)
313
+ if not instances_found: # pragma: no cover
314
+ raise ValueError(
315
+ f"Failed to find padstack instances with aedt_name={aedt_name}, component_name={component_name}, "
316
+ f"net_name={net_name}, component_pin_name={component_pin_name}"
317
+ )
318
+ return instances_found
@@ -334,7 +334,7 @@ class LayoutValidation:
334
334
  new_name = re.sub(pattern, "_", net)
335
335
  val.name = new_name
336
336
 
337
- self._pedb._logger.info("Found {} illegal net names.".format(len(renamed_nets)))
337
+ self._pedb.logger.info("Found {} illegal net names.".format(len(renamed_nets)))
338
338
  return
339
339
 
340
340
  def illegal_rlc_values(self, fix: bool = False) -> List[str]:
@@ -354,11 +354,11 @@ class LayoutValidation:
354
354
  temp = []
355
355
  for k, v in inductors.items():
356
356
  model = v.component_property.model
357
- if not len(model.pin_pairs): # pragma: no cover
357
+ if not len(model.pin_pairs()): # pragma: no cover
358
358
  temp.append(k)
359
359
  if fix:
360
360
  v.rlc_values = [0, 1, 0]
361
- self._pedb._logger.info(f"Found {len(temp)} inductors have no value.")
361
+ self._pedb.logger.info(f"Found {len(temp)} inductors have no value.")
362
362
  return temp
363
363
 
364
364
  def padstacks_no_name(self, fix: bool = False) -> None:
@@ -373,7 +373,7 @@ class LayoutValidation:
373
373
  >>> # Automatically assign names to unnamed padstacks
374
374
  >>> edb.layout_validation.padstacks_no_name(fix=True)
375
375
  """
376
- pds = self._pedb.layout.padstack_instances
376
+ pds = list(self._pedb.layout.padstack_instances.values())
377
377
  counts = 0
378
378
  via_count = 1
379
379
  for obj in pds:
@@ -389,4 +389,4 @@ class LayoutValidation:
389
389
  obj.set_product_property(
390
390
  GrpcProductIdType.DESIGNER, 11, f"{obj.component.name}-{obj.component_pin}"
391
391
  )
392
- self._pedb._logger.info(f"Found {counts}/{len(pds)} padstacks have no name.")
392
+ self._pedb.logger.info(f"Found {counts}/{len(pds)} padstacks have no name.")
@@ -92,7 +92,8 @@ class Modeler(object):
92
92
  def __init__(self, p_edb) -> None:
93
93
  """Initialize Modeler instance."""
94
94
  self._pedb = p_edb
95
- self._primitives = []
95
+ self.__primitives = []
96
+ self.__primitives_by_layer = {}
96
97
 
97
98
  @property
98
99
  def _edb(self) -> Any:
@@ -267,7 +268,7 @@ class Modeler(object):
267
268
  try:
268
269
  lay = i.layer.name
269
270
  if lay in _primitives_by_layer:
270
- _primitives_by_layer[lay].append(Primitive(self._pedb, i))
271
+ _primitives_by_layer[lay].append(i)
271
272
  except (InvalidArgumentException, AttributeError):
272
273
  pass
273
274
  return _primitives_by_layer
@@ -602,17 +603,20 @@ class Modeler(object):
602
603
  else:
603
604
  corner_style = GrpcPathCornerType.MITER
604
605
  _points = []
605
- for pt in points:
606
- _pt = []
607
- for coord in pt:
608
- coord = Value(coord, self._pedb.active_cell)
609
- _pt.append(coord)
610
- _points.append(_pt)
611
- points = _points
612
-
613
- width = Value(width, self._pedb.active_cell)
614
-
615
- polygon_data = GrpcPolygonData(points=[GrpcPointData(i) for i in points])
606
+ if isinstance(points, list):
607
+ for pt in points:
608
+ _pt = []
609
+ for coord in pt:
610
+ coord = Value(coord, self._pedb.active_cell)
611
+ _pt.append(coord)
612
+ _points.append(_pt)
613
+ points = _points
614
+ width = Value(width, self._pedb.active_cell)
615
+ polygon_data = GrpcPolygonData(points)
616
+ elif isinstance(points, GrpcPolygonData):
617
+ polygon_data = points
618
+ else:
619
+ raise TypeError("Points must be a list of points or a PolygonData object.")
616
620
  path = Path.create(
617
621
  layout=self._active_layout,
618
622
  layer=layer_name,
@@ -630,7 +634,7 @@ class Modeler(object):
630
634
 
631
635
  def create_trace(
632
636
  self,
633
- path_list: List[List[float]],
637
+ path_list: Union[List[List[float]], GrpcPolygonData],
634
638
  layer_name: str,
635
639
  width: float = 1,
636
640
  net_name: str = "",
@@ -1114,7 +1118,7 @@ class Modeler(object):
1114
1118
  # return None
1115
1119
  # pointA = GrpcPointData(pointA[0]), self._get_edb_value(shape.pointA[1])
1116
1120
  # )
1117
- # pointB = self._edb.geometry.point_data(
1121
+ # pointB = self._edb.Geometry.PointData(
1118
1122
  # self._get_edb_value(shape.pointB[0]), self._get_edb_value(shape.pointB[1])
1119
1123
  # )
1120
1124
  # return self._edb.geometry.polygon_data.create_from_bbox((pointA, pointB))
@@ -1475,7 +1479,11 @@ class Modeler(object):
1475
1479
  if isinstance(pins_by_name, str):
1476
1480
  pins_by_name = [pins_by_name]
1477
1481
  p_inst = self._pedb.layout.padstack_instances
1478
- _pins = {pin.id: pin for pin in p_inst if pin.aedt_name in pins_by_aedt_name or pin.name in pins_by_name}
1482
+ _pins = {
1483
+ pin_id: pin
1484
+ for pin_id, pin in p_inst.items()
1485
+ if pin.aedt_name in pins_by_aedt_name or pin.name in pins_by_name
1486
+ }
1479
1487
  if not pins:
1480
1488
  pins = _pins
1481
1489
  else:
@@ -60,7 +60,7 @@ class Net(GrpcNet):
60
60
  self._pedb = pedb
61
61
  self._core_components = pedb.components
62
62
  self._core_primitive = pedb.modeler
63
- self._edb_object = raw_net
63
+ self.__primitives = []
64
64
 
65
65
  @property
66
66
  def primitives(self) -> list[Union[Path, Polygon, Circle, Rectangle, Bondwire]]:
@@ -76,19 +76,20 @@ class Net(GrpcNet):
76
76
  - :class:`Rectangle <pyedb.grpc.database.primitive.rectangle.Rectangle>`
77
77
  - :class:`Bondwire <pyedb.grpc.database.primitive.bondwire.Bondwire>`
78
78
  """
79
- primitives = []
80
- for primitive in super().primitives:
81
- if primitive.primitive_type == GrpcPrimitiveType.PATH:
82
- primitives.append(Path(self._pedb, primitive))
83
- elif primitive.primitive_type == GrpcPrimitiveType.POLYGON:
84
- primitives.append(Polygon(self._pedb, primitive))
85
- elif primitive.primitive_type == GrpcPrimitiveType.CIRCLE:
86
- primitives.append(Circle(self._pedb, primitive))
87
- elif primitive.primitive_type == GrpcPrimitiveType.RECTANGLE:
88
- primitives.append(Rectangle(self._pedb, primitive))
89
- elif primitive.primitive_type == GrpcPrimitiveType.BONDWIRE:
90
- primitives.append(Bondwire(self._pedb, primitive))
91
- return primitives
79
+ primitives = super().primitives
80
+ if not len(self.__primitives) == len(primitives):
81
+ for primitive in primitives:
82
+ if primitive.primitive_type == GrpcPrimitiveType.PATH:
83
+ self.__primitives.append(Path(self._pedb, primitive))
84
+ elif primitive.primitive_type == GrpcPrimitiveType.POLYGON:
85
+ self.__primitives.append(Polygon(self._pedb, primitive))
86
+ elif primitive.primitive_type == GrpcPrimitiveType.CIRCLE:
87
+ self.__primitives.append(Circle(self._pedb, primitive))
88
+ elif primitive.primitive_type == GrpcPrimitiveType.RECTANGLE:
89
+ self.__primitives.append(Rectangle(self._pedb, primitive))
90
+ elif primitive.primitive_type == GrpcPrimitiveType.BONDWIRE:
91
+ self.__primitives.append(Bondwire(self._pedb, primitive))
92
+ return self.__primitives
92
93
 
93
94
  @property
94
95
  def padstack_instances(self) -> list[PadstackInstance]:
@@ -25,9 +25,12 @@ from __future__ import absolute_import # noreorder
25
25
  from typing import Any, Dict, List, Optional, Set, Tuple, Union
26
26
  import warnings
27
27
 
28
+ from ansys.edb.core.net.net_class import NetClass as GrpcNetClass
29
+
28
30
  from pyedb.common.nets import CommonNets
29
31
  from pyedb.generic.general_methods import generate_unique_name
30
32
  from pyedb.grpc.database.net.net import Net
33
+ from pyedb.grpc.database.net.net_class import NetClass
31
34
  from pyedb.grpc.database.primitive.bondwire import Bondwire
32
35
  from pyedb.grpc.database.primitive.path import Path
33
36
  from pyedb.grpc.database.primitive.polygon import Polygon
@@ -888,3 +891,70 @@ class Nets(CommonNets):
888
891
  if isinstance(net_names_list, str):
889
892
  net_names_list = [net_names_list]
890
893
  return self._pedb.modeler.unite_polygons_on_layer(net_names_list=net_names_list)
894
+
895
+
896
+ class NetClasses:
897
+ """Net classes management.
898
+
899
+ This class provides access to net classes in the EDB layout.
900
+ It allows for operations like retrieving nets, adding/removing nets,
901
+ and checking if a net is part of a net class.
902
+
903
+ Examples
904
+ --------
905
+ >>> from pyedb import Edb
906
+ >>> edb = Edb(myedb, edbversion="2025.1")
907
+ >>> net_classes = edb.net_classes
908
+ """
909
+
910
+ def __init__(self, pedb):
911
+ self._pedb = pedb
912
+ self._net_classes = pedb.active_layout.net_classes
913
+
914
+ def __getitem__(self, name: str) -> NetClass:
915
+ """Get a net by name.
916
+
917
+ Parameters
918
+ ----------
919
+ name : str
920
+ Name of the net to retrieve.
921
+
922
+ """
923
+ return self.items[name]
924
+
925
+ @property
926
+ def items(self) -> Dict[str, NetClass]:
927
+ """Extended nets.
928
+
929
+ Returns
930
+ -------
931
+ Dict[str, :class:`pyedb.grpc.database.nets.nets_class.NetClass`]
932
+ Dictionary of extended nets.
933
+ """
934
+ return {i.name: i for i in self._pedb.layout.net_classes}
935
+
936
+ def create(self, name, net) -> Union[bool, NetClass]:
937
+ """Create a new net class.
938
+
939
+ Parameters
940
+ ----------
941
+ name : str
942
+ Name of the net class.
943
+ net : str, list
944
+ Name of the nets to be added into this net class.
945
+
946
+ Returns
947
+ -------
948
+ :class:`pyedb.dotnet.database.edb_data.nets_data.EDBNetClassData` `False` if net name already exists.
949
+ """
950
+ if name in self.items:
951
+ self._pedb.logger.error("{} already exists.".format(name))
952
+ return False
953
+ grpc_net_class = GrpcNetClass.create(self._pedb.active_layout, name)
954
+ if isinstance(net, str):
955
+ net = [net]
956
+ for i in net:
957
+ grpc_net_class.add_net(self._pedb.nets[i])
958
+ net_class = NetClass(self._pedb, grpc_net_class)
959
+ self.items[name] = net_class
960
+ return net_class