pyedb 0.50.1__py3-none-any.whl → 0.52.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 (37) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_ports_sources.py +79 -239
  3. pyedb/configuration/configuration.py +213 -340
  4. pyedb/dotnet/clr_module.py +9 -3
  5. pyedb/dotnet/database/cell/layout.py +10 -1
  6. pyedb/dotnet/database/dotnet/database.py +0 -2
  7. pyedb/dotnet/database/edb_data/padstacks_data.py +8 -2
  8. pyedb/dotnet/database/layout_validation.py +20 -26
  9. pyedb/dotnet/database/modeler.py +0 -1
  10. pyedb/dotnet/database/stackup.py +4 -3
  11. pyedb/dotnet/edb.py +42 -2
  12. pyedb/generic/design_types.py +183 -62
  13. pyedb/grpc/database/__init__.py +0 -1
  14. pyedb/grpc/database/components.py +110 -0
  15. pyedb/grpc/database/control_file.py +150 -17
  16. pyedb/grpc/database/definition/materials.py +7 -7
  17. pyedb/grpc/database/definitions.py +36 -2
  18. pyedb/grpc/database/hfss.py +15 -0
  19. pyedb/grpc/database/hierarchy/component.py +10 -2
  20. pyedb/grpc/database/hierarchy/pin_pair_model.py +1 -1
  21. pyedb/grpc/database/layout_validation.py +58 -7
  22. pyedb/grpc/database/net/differential_pair.py +2 -1
  23. pyedb/grpc/database/nets.py +233 -4
  24. pyedb/grpc/database/padstacks.py +97 -0
  25. pyedb/grpc/database/primitive/padstack_instance.py +1 -1
  26. pyedb/grpc/database/primitive/polygon.py +1 -1
  27. pyedb/grpc/database/siwave.py +63 -3
  28. pyedb/grpc/database/source_excitations.py +317 -50
  29. pyedb/grpc/database/stackup.py +107 -2
  30. pyedb/grpc/database/terminal/point_terminal.py +2 -2
  31. pyedb/grpc/database/terminal/terminal.py +1 -1
  32. pyedb/grpc/edb.py +190 -224
  33. pyedb/grpc/edb_init.py +54 -5
  34. {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/METADATA +4 -4
  35. {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/RECORD +37 -37
  36. {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/LICENSE +0 -0
  37. {pyedb-0.50.1.dist-info → pyedb-0.52.0.dist-info}/WHEEL +0 -0
@@ -35,23 +35,156 @@ from pyedb.misc.misc import list_installed_ansysem
35
35
  def convert_technology_file(tech_file, edbversion=None, control_file=None):
36
36
  """Convert a technology file to EDB control file (XML).
37
37
 
38
- Parameters
39
- ----------
40
- tech_file : str
41
- Full path to technology file.
42
- edbversion : str, optional
43
- EDB version to use. If ``None``, uses latest available version.
44
- control_file : str, optional
45
- Output control file path. If ``None``, uses same path and name as ``tech_file``.
46
-
47
- Returns
48
- -------
49
- str or bool
50
- Full path to created control file if successful, ``False`` otherwise.
51
-
52
- Notes
53
- -----
54
- This function is only supported on Linux systems.
38
+ Parameters
39
+ ----------
40
+ tech_file : str
41
+ Full path to technology file.
42
+ edbversion : str, optional
43
+ EDB version to use. If ``None``, uses latest available version.
44
+ control_file : str, optional
45
+ Output control file path. If ``None``, uses same path and name as ``tech_file``.
46
+
47
+ Returns
48
+ -------
49
+ str or bool
50
+ Full path to created control file if successful, ``False`` otherwise.
51
+
52
+ Notes
53
+ -----
54
+ This function is only supported on Linux systems.
55
+
56
+ Example
57
+ -------
58
+ # Example 1: Converting a technology file to control file
59
+ >>> converted_file = convert_technology_file(
60
+ >>> tech_file="/path/to/tech.t",
61
+ >>> edbversion="2025.2",
62
+ >>> control_file="/path/to/output.xml"
63
+ >>> )
64
+ >>> if converted_file:
65
+ >>> print(f"Converted to: {converted_file}")
66
+
67
+ # Example 2: Creating a material
68
+ >>> from pyedb import ControlFileMaterial
69
+ >>> material = ControlFileMaterial(
70
+ >>> "Copper",
71
+ >>> {"Permittivity": 1.0, "Conductivity": 5.8e7}
72
+ >>> )
73
+
74
+ # Example 3: Creating a dielectric layer
75
+ >>> from pyedb import ControlFileDielectric
76
+ >>> dielectric = ControlFileDielectric(
77
+ >>> "Core",
78
+ >>> {"Thickness": "0.2mm", "Material": "FR4"}
79
+ >>> )
80
+
81
+ # Example 4: Creating a signal layer
82
+ >>> from pyedb import ControlFileLayer
83
+ >>> signal_layer = ControlFileLayer(
84
+ >>> "TopLayer",
85
+ >>> {"Type": "signal", "Material": "Copper", "Thickness": "0.035mm"}
86
+ >>> )
87
+
88
+ # Example 5: Creating a via layer
89
+ >>> from pyedb import ControlFileVia
90
+ >>> via_layer = ControlFileVia(
91
+ >>> "Via1",
92
+ >>> {"StartLayer": "TopLayer", "StopLayer": "BottomLayer"}
93
+ >>> )
94
+ >>> via_layer.create_via_group = True
95
+ >>> via_layer.tolerance = "0.1mm"
96
+
97
+ # Example 6: Managing stackup
98
+ >>> from pyedb import ControlFileStackup
99
+ >>> stackup = ControlFileStackup(units="mm")
100
+ >>> stackup.add_material("FR4", permittivity=4.4, dielectric_loss_tg=0.02)
101
+ >>> stackup.add_layer("L1", elevation=0, material="Copper", thickness=0.035)
102
+ >>> stackup.add_dielectric("Diel1", material="FR4", thickness=0.2)
103
+ >>> stackup.add_via("Via1", start_layer="L1", stop_layer="L2")
104
+
105
+ # Example 7: Configuring import options
106
+ >>> from pyedb import ControlFileImportOptions
107
+ >>> import_ops = ControlFileImportOptions()
108
+ >>> import_ops.auto_close = True
109
+ >>> import_ops.defeature_tolerance = 0.001
110
+
111
+ # Example 8: Setting up simulation extents
112
+ >>> from pyedb import ControlExtent
113
+ >>> extent = ControlExtent(
114
+ >>> type="Conforming",
115
+ >>> diel_hactor=0.3,
116
+ >>> airbox_hfactor=0.5
117
+ >>> )
118
+
119
+ # Example 9: Creating circuit ports
120
+ >>> from pyedb import ControlCircuitPt
121
+ >>> port = ControlCircuitPt("Port1", 0, 0, "TopLayer", 1, 0, "TopLayer", 50)
122
+
123
+ # Example 10: Managing components
124
+ >>> from pyedb import ControlFileComponent
125
+ >>> comp = ControlFileComponent()
126
+ >>> comp.refdes = "U1"
127
+ >>> comp.add_pin("Pin1", 0.5, 0.5, "TopLayer")
128
+ >>> comp.add_port("Port1", 50, "Pin1", refpin="GND")
129
+
130
+ # Example 11: Component management
131
+ >>> from pyedb import ControlFileComponents
132
+ >>> components = ControlFileComponents()
133
+ >>> ic = components.add_component("U1", "BGA", "IC", die_type="Flip chip")
134
+ >>> ic.add_pin("A1", 1.0, 1.0, "TopLayer")
135
+
136
+ # Example 12: Boundary setup
137
+ >>> from pyedb import ControlFileBoundaries
138
+ >>> boundaries = ControlFileBoundaries()
139
+ >>> boundaries.add_port("Port1", 0, 0, "L1", 1, 0, "L1", 50)
140
+ >>> boundaries.add_extent(diel_hactor=0.3)
141
+
142
+ # Example 13: Frequency sweep configuration
143
+ >>> from pyedb import ControlFileSweep
144
+ >>> sweep = ControlFileSweep(
145
+ >>> "Sweep1", "1GHz", "10GHz", "0.1GHz",
146
+ >>> "Interpolating", "LinearStep", True
147
+ >>> )
148
+
149
+ # Example 14: Mesh operation setup
150
+ >>> from pyedb import ControlFileMeshOp
151
+ >>> mesh_op = ControlFileMeshOp(
152
+ >>> "FineMesh", "Region1", "MeshOperationSkinDepth",
153
+ >>> {"Net1": "TopLayer"}
154
+ >>> )
155
+ >>> mesh_op.skin_depth = "1um"
156
+
157
+ # Example 15: Simulation setup configuration
158
+ >>> from pyedb import ControlFileSetup
159
+ >>> setup = ControlFileSetup("SimSetup1")
160
+ >>> setup.frequency = "5GHz"
161
+ >>> setup.add_sweep("Sweep1", "1GHz", "10GHz", "0.5GHz")
162
+ >>> setup.add_mesh_operation("Mesh1", "Chip", "MeshOperationLength", {"PWR": "Top"})
163
+
164
+ # Example 16: Setup management
165
+ >>> from pyedb import ControlFileSetups
166
+ >>> setups = ControlFileSetups()
167
+ >>> sim_setup = setups.add_setup("MySetup", "10GHz")
168
+ >>> sim_setup.add_sweep("Swp1", "1GHz", "20GHz", 100, step_type="LinearCount")
169
+
170
+ # Example 17: Main control file creation
171
+ >>> from pyedb import ControlFile
172
+
173
+ # Create from scratch
174
+ >>> ctrl = ControlFile()
175
+ >>> ctrl.stackup.add_material("Copper", conductivity=5.8e7)
176
+ >>> ctrl.stackup.add_layer("Signal", thickness=0.035, material="Copper")
177
+ >>> ctrl.boundaries.add_port("Input", 0, 0, "Signal", 1, 0, "Signal", 50)
178
+ >>> ctrl.write_xml("/path/to/control.xml")
179
+
180
+ # Parse existing file
181
+ >>> ctrl = ControlFile(xml_input="/path/to/existing.xml")
182
+
183
+ # Convert technology file
184
+ >>> ctrl = ControlFile(tecnhology="/path/to/tech.t")
185
+
186
+ # Apply layer mapping
187
+ >>> ctrl.parse_layer_map("/path/to/layer_map.txt")
55
188
  """
56
189
  if is_linux: # pragma: no cover
57
190
  if not edbversion:
@@ -228,14 +228,14 @@ class Material(GrpcMaterialDef):
228
228
 
229
229
  """
230
230
  try:
231
- return self.dielectric_material_model.dc_relative_permitivity
231
+ return self.dielectric_material_model.dc_relative_permittivity
232
232
  except:
233
233
  return None
234
234
 
235
235
  @dc_permittivity.setter
236
236
  def dc_permittivity(self, value):
237
237
  if self.dielectric_material_model:
238
- self.dielectric_material_model.dc_relative_permitivity = float(value)
238
+ self.dielectric_material_model.dc_relative_permittivity = float(value)
239
239
 
240
240
  @property
241
241
  def loss_tangent_at_frequency(self) -> float:
@@ -289,14 +289,14 @@ class Material(GrpcMaterialDef):
289
289
 
290
290
  """
291
291
  try:
292
- return self.dielectric_material_model.relative_permitivity_at_frequency
292
+ return self.dielectric_material_model.relative_permittivity_at_frequency
293
293
  except:
294
294
  return None
295
295
 
296
296
  @permittivity_at_frequency.setter
297
297
  def permittivity_at_frequency(self, value):
298
298
  if self.dielectric_material_model:
299
- self.dielectric_material_model.relative_permitivity_at_frequency = float(value)
299
+ self.dielectric_material_model.relative_permittivity_at_frequency = float(value)
300
300
 
301
301
  @property
302
302
  def permittivity(self) -> float:
@@ -771,14 +771,14 @@ class Materials(object):
771
771
  raise ValueError(f"Material names are case-insensitive and {name.lower()} already exists.")
772
772
 
773
773
  material_model = GrpcDjordjecvicSarkarModel.create()
774
- material_model.relative_permitivity_at_frequency = permittivity_at_frequency
774
+ material_model.relative_permittivity_at_frequency = permittivity_at_frequency
775
775
  material_model.loss_tangent_at_frequency = loss_tangent_at_frequency
776
776
  material_model.frequency = dielectric_model_frequency
777
777
  if dc_conductivity is not None:
778
778
  material_model.dc_conductivity = dc_conductivity
779
779
  material_model.use_dc_relative_conductivity = True
780
780
  if dc_permittivity is not None:
781
- material_model.dc_relative_permitivity = dc_permittivity
781
+ material_model.dc_relative_permittivity = dc_permittivity
782
782
  try:
783
783
  material = self.__add_dielectric_material_model(name, material_model)
784
784
  for key, value in kwargs.items():
@@ -841,7 +841,7 @@ class Materials(object):
841
841
  material_model = GrpcDebyeModel.create()
842
842
  material_model.frequency_range = (lower_freqency, higher_frequency)
843
843
  material_model.loss_tangent_at_high_low_frequency = (loss_tangent_low, loss_tangent_high)
844
- material_model.relative_permitivity_at_high_low_frequency = (permittivity_low, permittivity_high)
844
+ material_model.relative_permittivity_at_high_low_frequency = (permittivity_low, permittivity_high)
845
845
  try:
846
846
  material = self.__add_dielectric_material_model(name, material_model)
847
847
  for key, value in kwargs.items():
@@ -34,12 +34,30 @@ class Definitions:
34
34
 
35
35
  @property
36
36
  def component(self) -> dict[str, ComponentDef]:
37
- """Component definitions"""
37
+ """Component definitions
38
+
39
+ Examples
40
+ --------
41
+ >>> from pyedb import Edb
42
+ >>> edb = Edb()
43
+ >>> component_defs = edb.definitions.component
44
+ >>> for name, comp_def in component_defs.items():
45
+ ... print(f"Component: {name}, Part: {comp_def.part}")
46
+ """
38
47
  return {l.name: ComponentDef(self._pedb, l) for l in self._pedb.active_db.component_defs}
39
48
 
40
49
  @property
41
50
  def package(self) -> dict[str, PackageDef]:
42
- """Package definitions."""
51
+ """Package definitions.
52
+
53
+ Examples
54
+ --------
55
+ >>> from pyedb import Edb
56
+ >>> edb = Edb()
57
+ >>> package_defs = edb.definitions.package
58
+ >>> for name, pkg_def in package_defs.items():
59
+ ... print(f"Package: {name}, Boundary: {pkg_def.exterior_boundary}")
60
+ """
43
61
  return {l.name: PackageDef(self._pedb, l) for l in self._pedb.active_db.package_defs}
44
62
 
45
63
  def add_package_def(self, name, component_part_name=None, boundary_points=None) -> Union[PackageDef, bool]:
@@ -57,6 +75,22 @@ class Definitions:
57
75
  Returns
58
76
  -------
59
77
  PackageDef object.
78
+
79
+ Examples
80
+ --------
81
+ >>> from pyedb import Edb
82
+ >>> edb = Edb()
83
+
84
+ Example 1: Create package using component's bounding box
85
+ >>> comp_def = edb.definitions.add_package_def("QFP64", "QFP64_COMPONENT")
86
+ >>> if comp_def: # Check if created successfully
87
+ ... print(f"Created package: {comp_def.name}")
88
+
89
+ Example 2: Create package with custom boundary
90
+ >>> boundary = [[0, 0], [10e-3, 0], [10e-3, 10e-3], [0, 10e-3]]
91
+ >>> custom_pkg = edb.definitions.add_package_def("CustomIC", boundary_points=boundary)
92
+ >>> if custom_pkg:
93
+ ... print(f"Custom package boundary: {custom_pkg.exterior_boundary}")
60
94
  """
61
95
  if not name in self.package:
62
96
  package_def = PackageDef.create(self._pedb.active_db, name=name)
@@ -200,6 +200,12 @@ class Hfss(object):
200
200
  -------
201
201
  dict
202
202
  Dictionary mapping net names to smallest trace widths.
203
+
204
+ Examples
205
+ --------
206
+ >>> widths = edb.hfss.get_trace_width_for_traces_with_ports()
207
+ >>> for net_name, width in widths.items():
208
+ ... print(f"Net '{net_name}': Smallest width = {width}")
203
209
  """
204
210
  nets = {}
205
211
  for net in self._pedb.excitations_nets:
@@ -925,6 +931,15 @@ class Hfss(object):
925
931
  -------
926
932
  list
927
933
  [min_x, min_y, max_x, max_y] coordinates.
934
+
935
+ Examples
936
+ --------
937
+ >>> bbox = edb.hfss.get_layout_bounding_box()
938
+ >>> print(f"Layout Bounding Box: {bbox}")
939
+ >>>
940
+ >>> # With custom parameters
941
+ >>> custom_layout = edb.layouts["MyLayout"]
942
+ >>> bbox = edb.hfss.get_layout_bounding_box(custom_layout, 5)
928
943
  """
929
944
  if not layout:
930
945
  layout = self._active_layout
@@ -132,7 +132,7 @@ class Component(GrpcComponentGroup):
132
132
  self.enabled = value
133
133
 
134
134
  @property
135
- def ic_die_properties(self) -> ICDieProperty:
135
+ def ic_die_properties(self) -> any:
136
136
  """IC Die property.
137
137
 
138
138
  returns
@@ -877,12 +877,20 @@ class Component(GrpcComponentGroup):
877
877
  def numpins(self) -> int:
878
878
  """Number of Pins of Component.
879
879
 
880
+ ..deprecated:: 0.51.0
881
+ Use: func:`num_pins` instead.
880
882
  Returns
881
883
  -------
882
884
  int
883
885
  Component pins number.
884
886
  """
885
- return self.num_pins
887
+
888
+ warnings.warn("Use num_pins instead.", DeprecationWarning)
889
+ try:
890
+ return self.num_pins
891
+ except Exception as e:
892
+ self._pedb.logger.error(f"{e}")
893
+ return 0
886
894
 
887
895
  @property
888
896
  def partname(self) -> str:
@@ -27,7 +27,7 @@ from ansys.edb.core.utility.value import Value as GrpcValue
27
27
 
28
28
 
29
29
  class PinPairModel(GrpcPinPairModel):
30
- """Manage pin pair model."""
30
+ """Manage pin-pair model."""
31
31
 
32
32
  def __init__(self, pedb, edb_object):
33
33
  self._pedb_comp = pedb
@@ -55,10 +55,12 @@ class LayoutValidation:
55
55
 
56
56
  Examples
57
57
  --------
58
-
59
58
  >>> edb = Edb("edb_file")
60
- >>> dc_shorts = edb.layout_validation.dc_shorts()
61
-
59
+ >>> # Find shorts without fixing
60
+ >>> shorts = edb.layout_validation.dc_shorts()
61
+ >>>
62
+ >>> # Find and fix shorts on specific nets
63
+ >>> fixed_shorts = edb.layout_validation.dc_shorts(net_list=["GND", "VCC"], fix=True)
62
64
  """
63
65
  if not net_list:
64
66
  net_list = list(self._pedb.nets.nets.keys())
@@ -154,8 +156,17 @@ class LayoutValidation:
154
156
 
155
157
  Examples
156
158
  --------
157
-
158
- >>> renamed_nets = edb.layout_validation.disjoint_nets(["GND","Net2"])
159
+ >>> edb = Edb("edb_file")
160
+ >>> # Find disjoint nets on all nets
161
+ >>> new_nets = edb.layout_validation.disjoint_nets()
162
+ >>>
163
+ >>> # Clean disjoints on specific nets with advanced options
164
+ >>> cleaned = edb.layout_validation.disjoint_nets(
165
+ ... net_list=["GND"],
166
+ ... keep_only_main_net=True,
167
+ ... clean_disjoints_less_than=1e-6,
168
+ ... order_by_area=True
169
+ ... ))
159
170
  """
160
171
  timer_start = self._pedb.logger.reset_timer()
161
172
 
@@ -274,6 +285,15 @@ class LayoutValidation:
274
285
  Returns
275
286
  -------
276
287
  bool
288
+
289
+ Examples
290
+ --------
291
+ >>> edb = Edb("edb_file")
292
+ >>> # Fix self-intersections on all nets
293
+ >>> edb.layout_validation.fix_self_intersections()
294
+ >>>
295
+ >>> # Fix self-intersections on specific nets
296
+ >>> edb.layout_validation.fix_self_intersections(net_list=["RF_line"])
277
297
  """
278
298
  if not net_list:
279
299
  net_list = list(self._pedb.nets.nets.keys())
@@ -290,7 +310,17 @@ class LayoutValidation:
290
310
  return True
291
311
 
292
312
  def illegal_net_names(self, fix=False):
293
- """Find and fix illegal net names."""
313
+ """Find and fix illegal net names.
314
+
315
+ Examples
316
+ --------
317
+ >>> edb = Edb("edb_file")
318
+ >>> # Identify illegal net names
319
+ >>> edb.layout_validation.illegal_net_names()
320
+ >>>
321
+ >>> # Find and automatically fix illegal names
322
+ >>> edb.layout_validation.illegal_net_names(fix=True)
323
+ """
294
324
  pattern = r"[\(\)\\\/:;*?<>\'\"|`~$]"
295
325
 
296
326
  nets = self._pedb.nets.nets
@@ -307,7 +337,17 @@ class LayoutValidation:
307
337
  return
308
338
 
309
339
  def illegal_rlc_values(self, fix=False) -> list[str]:
310
- """Find and fix RLC illegal values."""
340
+ """Find and fix RLC illegal values.
341
+
342
+ Examples
343
+ --------
344
+ >>> edb = Edb("edb_file")
345
+ >>> # Identify components with illegal RLC values
346
+ >>> bad_components = edb.layout_validation.illegal_rlc_values()
347
+ >>>
348
+ >>> # Automatically fix invalid inductor values
349
+ >>> edb.layout_validation.illegal_rlc_values(fix=True)
350
+ """
311
351
  inductors = self._pedb.components.inductors
312
352
 
313
353
  temp = []
@@ -321,6 +361,17 @@ class LayoutValidation:
321
361
  return temp
322
362
 
323
363
  def padstacks_no_name(self, fix=False):
364
+ """Identify and fix padstacks without names.
365
+
366
+ Examples
367
+ --------
368
+ >>> edb = Edb("edb_file")
369
+ >>> # Report unnamed padstacks
370
+ >>> edb.layout_validation.padstacks_no_name()
371
+ >>>
372
+ >>> # Automatically assign names to unnamed padstacks
373
+ >>> edb.layout_validation.padstacks_no_name(fix=True)
374
+ """
324
375
  pds = self._pedb.layout.padstack_instances
325
376
  counts = 0
326
377
  via_count = 1
@@ -85,10 +85,11 @@ class DifferentialPairs:
85
85
  -------
86
86
  list
87
87
  A list containing identified differential pair names.
88
+
88
89
  Examples
89
90
  --------
90
91
  >>> from pyedb import Edb
91
- >>> edbapp = Edb("myaedbfolder", edbversion="2023.1")
92
+ >>> edbapp = Edb("myaedbfolder", edbversion="2025.2")
92
93
  >>> edb_nets = edbapp.differential_pairs.auto_identify()
93
94
  """
94
95
  nets = self._pedb.nets.nets