pyedb 0.51.2__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.

pyedb/__init__.py CHANGED
@@ -44,7 +44,7 @@ deprecation_warning()
44
44
  #
45
45
 
46
46
  pyedb_path = os.path.dirname(__file__)
47
- __version__ = "0.51.2"
47
+ __version__ = "0.52.0"
48
48
  version = __version__
49
49
 
50
50
  #
@@ -19,11 +19,11 @@
19
19
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
-
23
22
  from datetime import datetime
24
23
  import json
25
24
  import os
26
25
  from pathlib import Path
26
+ import warnings
27
27
 
28
28
  import toml
29
29
 
@@ -34,341 +34,9 @@ from pyedb.dotnet.database.definition.package_def import PackageDef
34
34
  class Configuration:
35
35
  """Enables export and import of a JSON configuration file that can be applied to a new or existing design."""
36
36
 
37
- class Grpc:
38
- def __init__(self, parent):
39
- self.parent = parent
40
- self._pedb = parent._pedb
41
-
42
- def configuration_stackup(self, kwargs):
43
- if kwargs.get("fix_padstack_def"):
44
- from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
45
-
46
- pedb_defs = self._pedb.padstacks.definitions
47
- temp = []
48
- for _, pdef in pedb_defs.items():
49
- cfg_def = CfgPadstackDefinition(self._pedb, pdef)
50
- cfg_def.api.retrieve_parameters_from_edb()
51
- temp.append(cfg_def)
52
- self.parent.cfg_data.stackup.apply()
53
- for cfg_pdef in temp:
54
- cfg_pdef.api.set_parameters_to_edb()
55
- else:
56
- temp_pdef_data = {}
57
- from ansys.edb.core.definition.padstack_def_data import (
58
- PadType as GrpcPadType,
59
- )
60
-
61
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
62
- for layer in pdef.data.layer_names:
63
- result = pdef.data.get_pad_parameters(layer, GrpcPadType.REGULAR_PAD)
64
- if len(result) == 4:
65
- # polygon based
66
- temp_pdef_data[pdef_name] = pdef.data
67
- break
68
- self.parent.cfg_data.stackup.apply()
69
- for pdef_name, pdef_data in temp_pdef_data.items():
70
- pdef = self._pedb.padstacks.definitions[pdef_name]
71
- pdef._padstack_def_data = pdef_data
72
-
73
- def _load_stackup(self):
74
- """Imports stackup information from json."""
75
- data = self.data["stackup"]
76
- materials = data.get("materials")
77
-
78
- if materials:
79
- edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
80
- for mat in materials:
81
- name = mat["name"].lower()
82
- if name in edb_materials:
83
- self._pedb.materials.delete_material(edb_materials[name])
84
- for mat in materials:
85
- self._pedb.materials.add_material(**mat)
86
-
87
- layers = data.get("layers")
88
-
89
- if layers:
90
- input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
91
- if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
92
- self._pedb.logger.error("Input signal layer count do not match.")
93
- return False
94
-
95
- removal_list = []
96
- lc_signal_layers = []
97
- for name, obj in self._pedb.stackup.all_layers.items():
98
- if obj.type == "dielectric":
99
- removal_list.append(name)
100
- elif obj.type == "signal":
101
- lc_signal_layers.append(obj.id)
102
- for l in removal_list:
103
- self._pedb.stackup.remove_layer(l)
104
-
105
- # update all signal layers
106
- id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
107
- signal_idx = 0
108
- for l in layers:
109
- if l["type"] == "signal":
110
- layer_id = lc_signal_layers[signal_idx]
111
- layer_name = id_name[layer_id]
112
- self._pedb.stackup.layers[layer_name].update(**l)
113
- signal_idx = signal_idx + 1
114
-
115
- # add all dielectric layers. Dielectric layers must be added last. Otherwise,
116
- # dielectric layer will occupy signal and document layer id.
117
- prev_layer_clone = None
118
- l = layers.pop(0)
119
- if l["type"] == "signal":
120
- prev_layer_clone = self._pedb.stackup.layers[l["name"]]
121
- else:
122
- prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
123
- for idx, l in enumerate(layers):
124
- if l["type"] == "dielectric":
125
- prev_layer_clone = self._pedb.stackup.add_layer_below(
126
- base_layer_name=prev_layer_clone.name, **l
127
- )
128
- elif l["type"] == "signal":
129
- prev_layer_clone = self._pedb.stackup.layers[l["name"]]
130
-
131
- def _load_package_def(self):
132
- """Imports package definition information from JSON."""
133
- comps = self._pedb.components.instances
134
- for pkgd in self.parent.data["package_definitions"]:
135
- name = pkgd["name"]
136
- if name in self._pedb.definitions.package:
137
- self._pedb.definitions.package[name].delete()
138
- extent_bounding_box = pkgd.get("extent_bounding_box", None)
139
- if extent_bounding_box:
140
- package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
141
- else:
142
- package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
143
- package_def.maximum_power = pkgd["maximum_power"]
144
- package_def.therm_cond = pkgd["therm_cond"]
145
- package_def.theta_jb = pkgd["theta_jb"]
146
- package_def.theta_jc = pkgd["theta_jc"]
147
- package_def.height = pkgd["height"]
148
-
149
- heatsink = pkgd.get("heatsink", None)
150
- if heatsink:
151
- package_def.set_heatsink(
152
- heatsink["fin_base_height"],
153
- heatsink["fin_height"],
154
- heatsink["fin_orientation"],
155
- heatsink["fin_spacing"],
156
- heatsink["fin_thickness"],
157
- )
158
-
159
- comp_def_name = pkgd["component_definition"]
160
- comp_def = self._pedb.definitions.component[comp_def_name]
161
-
162
- comp_list = dict()
163
- if pkgd["apply_to_all"]:
164
- comp_list.update(
165
- {
166
- refdes: comp
167
- for refdes, comp in comp_def.components.items()
168
- if refdes not in pkgd["components"]
169
- }
170
- )
171
- else:
172
- comp_list.update(
173
- {refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
174
- )
175
- for _, i in comp_list.items():
176
- i.package_def = name
177
-
178
- def get_data_from_db(self, **kwargs):
179
- """Get configuration data from layout.
180
-
181
- Parameters
182
- ----------
183
- stackup
184
-
185
- Returns
186
- -------
187
-
188
- """
189
- self._pedb.logger.info("Getting data from layout database.")
190
- data = {}
191
- if kwargs.get("general", False):
192
- data["general"] = self.parent.cfg_data.general.get_data_from_db()
193
- if kwargs.get("stackup", False):
194
- data["stackup"] = self.parent.cfg_data.stackup.get_data_from_db()
195
- if kwargs.get("package_definitions", False):
196
- data["package_definitions"] = self.parent.cfg_data.package_definitions.get_data_from_db()
197
- if kwargs.get("setups", False):
198
- setups = self.parent.cfg_data.setups
199
- setups.retrieve_parameters_from_edb()
200
- data["setups"] = setups.to_dict()
201
- if kwargs.get("sources", False):
202
- data["sources"] = self.parent.cfg_data.sources.get_data_from_db()
203
- if kwargs.get("ports", False):
204
- data["ports"] = self.parent.cfg_data.ports.get_data_from_db()
205
- if kwargs.get("components", False) or kwargs.get("s_parameters", False):
206
- self.parent.cfg_data.components.retrieve_parameters_from_edb()
207
- components = []
208
- for i in self.parent.cfg_data.components.components:
209
- if i.type == "io":
210
- components.append(i.get_attributes())
211
- components.append(i.get_attributes())
212
-
213
- if kwargs.get("components", False):
214
- data["components"] = components
215
- elif kwargs.get("s_parameters", False):
216
- data["s_parameters"] = self.parent.cfg_data.s_parameters.get_data_from_db(components)
217
- if kwargs.get("nets", False):
218
- data["nets"] = self.parent.cfg_data.nets.get_data_from_db()
219
- if kwargs.get("pin_groups", False):
220
- data["pin_groups"] = self.parent.cfg_data.pin_groups.get_data_from_db()
221
- if kwargs.get("operations", False):
222
- data["operations"] = self.parent.cfg_data.operations.get_data_from_db()
223
- if kwargs.get("padstacks", False):
224
- self.parent.cfg_data.padstacks.retrieve_parameters_from_edb()
225
- definitions = []
226
- for i in self.parent.cfg_data.padstacks.definitions:
227
- definitions.append(i.get_attributes())
228
- instances = []
229
- for i in self.parent.cfg_data.padstacks.instances:
230
- instances.append(i.get_attributes())
231
- data["padstacks"] = dict()
232
- data["padstacks"]["definitions"] = definitions
233
- data["padstacks"]["instances"] = instances
234
-
235
- if kwargs.get("boundaries", False):
236
- data["boundaries"] = self.parent.cfg_data.boundaries.get_data_from_db()
237
-
238
- return data
239
-
240
- def export(
241
- self,
242
- file_path,
243
- stackup=True,
244
- package_definitions=False,
245
- setups=True,
246
- sources=True,
247
- ports=True,
248
- nets=True,
249
- pin_groups=True,
250
- operations=True,
251
- components=True,
252
- boundaries=True,
253
- s_parameters=True,
254
- padstacks=True,
255
- general=True,
256
- ):
257
- """Export the configuration data from layout to a file.
258
-
259
- Parameters
260
- ----------
261
- file_path : str, Path
262
- File path to export the configuration data.
263
- stackup : bool
264
- Whether to export stackup or not.
265
- package_definitions : bool
266
- Whether to export package definitions or not.
267
- setups : bool
268
- Whether to export setups or not.
269
- sources : bool
270
- Whether to export sources or not.
271
- ports : bool
272
- Whether to export ports or not.
273
- nets : bool
274
- Whether to export nets.
275
- pin_groups : bool
276
- Whether to export pin groups.
277
- operations : bool
278
- Whether to export operations.
279
- components : bool
280
- Whether to export component.
281
- boundaries : bool
282
- Whether to export boundaries.
283
- s_parameters : bool
284
- Whether to export s_parameters.
285
- padstacks : bool
286
- Whether to export padstacks.
287
- general : bool
288
- Whether to export general information.
289
- Returns
290
- -------
291
- bool
292
- """
293
- data = self.get_data_from_db(
294
- stackup=stackup,
295
- package_definitions=package_definitions,
296
- setups=setups,
297
- sources=sources,
298
- ports=ports,
299
- nets=nets,
300
- pin_groups=pin_groups,
301
- operations=operations,
302
- components=components,
303
- boundaries=boundaries,
304
- s_parameters=s_parameters,
305
- padstacks=padstacks,
306
- general=general,
307
- )
308
-
309
- file_path = file_path if isinstance(file_path, Path) else Path(file_path)
310
- file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
311
-
312
- for comp in data["components"]:
313
- for key, value in comp.items():
314
- try:
315
- json.dumps(value)
316
- print(f"Key '{key}' is serializable.")
317
- except TypeError as e:
318
- print(f"Key '{key}' failed: {e}")
319
-
320
- with open(file_path, "w") as f:
321
- if file_path.suffix == ".json":
322
- json.dump(data, f, ensure_ascii=False, indent=4)
323
- else:
324
- toml.dump(data, f)
325
- return True if os.path.isfile(file_path) else False
326
-
327
- class DotNet(Grpc):
328
- def __init__(self, parent):
329
- super().__init__(parent)
330
-
331
- def configuration_stackup(self, kwargs):
332
- if kwargs.get("fix_padstack_def"):
333
- from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
334
-
335
- pedb_defs = self._pedb.padstacks.definitions
336
- temp = []
337
- for _, pdef in pedb_defs.items():
338
- cfg_def = CfgPadstackDefinition(self._pedb, pdef)
339
- cfg_def.api.retrieve_parameters_from_edb()
340
- temp.append(cfg_def)
341
- self.parent.cfg_data.stackup.apply()
342
- for cfg_pdef in temp:
343
- cfg_pdef.api.set_parameters_to_edb()
344
- else:
345
- temp_pdef_data = {}
346
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
347
- pdef_data = pdef._padstack_def_data
348
- for lyr_name in list(pdef_data.GetLayerNames()):
349
- result = pdef_data.GetPadParametersValue(
350
- lyr_name, self._pedb._edb.Definition.PadType.RegularPad
351
- )
352
- flag, pad_shape, params, offset_x, offset_y, rotation = result
353
- if flag is False:
354
- result = pdef_data.GetPolygonalPadParameters(
355
- lyr_name, self._pedb._edb.Definition.PadType.RegularPad
356
- )
357
- flag, polygon_data, offset_x, offset_y, rotation = result
358
- if flag:
359
- temp_pdef_data[pdef_name] = pdef_data
360
- break
361
- self.parent.cfg_data.stackup.apply()
362
- for pdef_name, pdef_data in temp_pdef_data.items():
363
- pdef = self._pedb.padstacks.definitions[pdef_name]
364
- pdef._padstack_def_data = pdef_data
365
-
366
37
  def __init__(self, pedb):
367
38
  self._pedb = pedb
368
- if self._pedb.grpc:
369
- self.api = self.Grpc(self)
370
- else:
371
- self.api = self.DotNet(self)
39
+
372
40
  self._components = self._pedb.components.instances
373
41
  self.data = {}
374
42
  self._s_parameter_library = ""
@@ -439,6 +107,8 @@ class Configuration:
439
107
 
440
108
  def run(self, **kwargs):
441
109
  """Apply configuration settings to the current design"""
110
+ if kwargs.get("fix_padstack_def"):
111
+ warnings.warn("fix_padstack_def is deprecated.", DeprecationWarning)
442
112
 
443
113
  if self.cfg_data.variables:
444
114
  self.cfg_data.variables.apply()
@@ -480,7 +150,7 @@ class Configuration:
480
150
  now = datetime.now()
481
151
 
482
152
  # Configure stackup
483
- self.api.configuration_stackup(kwargs)
153
+ self.configuration_stackup()
484
154
  self._pedb.logger.info(f"Updating stackup finished. Time lapse {datetime.now() - now}")
485
155
  now = datetime.now()
486
156
 
@@ -523,13 +193,123 @@ class Configuration:
523
193
 
524
194
  return True
525
195
 
196
+ def configuration_stackup(self):
197
+ temp_pdef_data = {}
198
+ for pdef_name, pdef in self._pedb.padstacks.definitions.items():
199
+ pdef_edb_object = pdef._padstack_def_data
200
+ temp_pdef_data[pdef_name] = pdef_edb_object
201
+
202
+ temp_p_inst_layer_map = {}
203
+ for p_inst in self._pedb.layout.padstack_instances:
204
+ temp_p_inst_layer_map[p_inst.id] = p_inst._edb_object.GetLayerMap()
205
+
206
+ self.cfg_data.stackup.apply()
207
+
208
+ for pdef_name, pdef_data in temp_pdef_data.items():
209
+ pdef = self._pedb.padstacks.definitions[pdef_name]
210
+ pdef._padstack_def_data = pdef_data
211
+
212
+ for p_inst in self._pedb.layout.padstack_instances:
213
+ p_inst._edb_object.SetLayerMap(temp_p_inst_layer_map[p_inst.id])
214
+
526
215
  def _load_stackup(self):
527
216
  """Imports stackup information from json."""
528
- self.api._load_stackup()
217
+ data = self.data["stackup"]
218
+ materials = data.get("materials")
219
+
220
+ if materials:
221
+ edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
222
+ for mat in materials:
223
+ name = mat["name"].lower()
224
+ if name in edb_materials:
225
+ self._pedb.materials.delete_material(edb_materials[name])
226
+ for mat in materials:
227
+ self._pedb.materials.add_material(**mat)
228
+
229
+ layers = data.get("layers")
230
+
231
+ if layers:
232
+ input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
233
+ if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
234
+ self._pedb.logger.error("Input signal layer count do not match.")
235
+ return False
236
+
237
+ removal_list = []
238
+ lc_signal_layers = []
239
+ for name, obj in self._pedb.stackup.all_layers.items():
240
+ if obj.type == "dielectric":
241
+ removal_list.append(name)
242
+ elif obj.type == "signal":
243
+ lc_signal_layers.append(obj.id)
244
+ for l in removal_list:
245
+ self._pedb.stackup.remove_layer(l)
246
+
247
+ # update all signal layers
248
+ id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
249
+ signal_idx = 0
250
+ for l in layers:
251
+ if l["type"] == "signal":
252
+ layer_id = lc_signal_layers[signal_idx]
253
+ layer_name = id_name[layer_id]
254
+ self._pedb.stackup.layers[layer_name].update(**l)
255
+ signal_idx = signal_idx + 1
256
+
257
+ # add all dielectric layers. Dielectric layers must be added last. Otherwise,
258
+ # dielectric layer will occupy signal and document layer id.
259
+ prev_layer_clone = None
260
+ l = layers.pop(0)
261
+ if l["type"] == "signal":
262
+ prev_layer_clone = self._pedb.stackup.layers[l["name"]]
263
+ else:
264
+ prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
265
+ for idx, l in enumerate(layers):
266
+ if l["type"] == "dielectric":
267
+ prev_layer_clone = self._pedb.stackup.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
268
+ elif l["type"] == "signal":
269
+ prev_layer_clone = self._pedb.stackup.layers[l["name"]]
529
270
 
530
271
  def _load_package_def(self):
531
272
  """Imports package definition information from JSON."""
532
- self.api._load_package_def()
273
+ comps = self._pedb.components.instances
274
+ for pkgd in self.data["package_definitions"]:
275
+ name = pkgd["name"]
276
+ if name in self._pedb.definitions.package:
277
+ self._pedb.definitions.package[name].delete()
278
+ extent_bounding_box = pkgd.get("extent_bounding_box", None)
279
+ if extent_bounding_box:
280
+ package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
281
+ else:
282
+ package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
283
+ package_def.maximum_power = pkgd["maximum_power"]
284
+ package_def.therm_cond = pkgd["therm_cond"]
285
+ package_def.theta_jb = pkgd["theta_jb"]
286
+ package_def.theta_jc = pkgd["theta_jc"]
287
+ package_def.height = pkgd["height"]
288
+
289
+ heatsink = pkgd.get("heatsink", None)
290
+ if heatsink:
291
+ package_def.set_heatsink(
292
+ heatsink["fin_base_height"],
293
+ heatsink["fin_height"],
294
+ heatsink["fin_orientation"],
295
+ heatsink["fin_spacing"],
296
+ heatsink["fin_thickness"],
297
+ )
298
+
299
+ comp_def_name = pkgd["component_definition"]
300
+ comp_def = self._pedb.definitions.component[comp_def_name]
301
+
302
+ comp_list = dict()
303
+ if pkgd["apply_to_all"]:
304
+ comp_list.update(
305
+ {refdes: comp for refdes, comp in comp_def.components.items() if refdes not in pkgd["components"]}
306
+ )
307
+ else:
308
+ comp_list.update(
309
+ {refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
310
+ )
311
+ for _, i in comp_list.items():
312
+ i.package_def = name
533
313
 
534
314
  def get_data_from_db(self, **kwargs):
535
315
  """Get configuration data from layout.
@@ -542,7 +322,56 @@ class Configuration:
542
322
  -------
543
323
 
544
324
  """
545
- return self.api.get_data_from_db(**kwargs)
325
+ self._pedb.logger.info("Getting data from layout database.")
326
+ data = {}
327
+ if kwargs.get("general", False):
328
+ data["general"] = self.cfg_data.general.get_data_from_db()
329
+ if kwargs.get("stackup", False):
330
+ data["stackup"] = self.cfg_data.stackup.get_data_from_db()
331
+ if kwargs.get("package_definitions", False):
332
+ data["package_definitions"] = self.cfg_data.package_definitions.get_data_from_db()
333
+ if kwargs.get("setups", False):
334
+ setups = self.cfg_data.setups
335
+ setups.retrieve_parameters_from_edb()
336
+ data["setups"] = setups.to_dict()
337
+ if kwargs.get("sources", False):
338
+ data["sources"] = self.cfg_data.sources.get_data_from_db()
339
+ if kwargs.get("ports", False):
340
+ data["ports"] = self.cfg_data.ports.get_data_from_db()
341
+ if kwargs.get("components", False) or kwargs.get("s_parameters", False):
342
+ self.cfg_data.components.retrieve_parameters_from_edb()
343
+ components = []
344
+ for i in self.cfg_data.components.components:
345
+ if i.type == "io":
346
+ components.append(i.get_attributes())
347
+ components.append(i.get_attributes())
348
+
349
+ if kwargs.get("components", False):
350
+ data["components"] = components
351
+ elif kwargs.get("s_parameters", False):
352
+ data["s_parameters"] = self.cfg_data.s_parameters.get_data_from_db(components)
353
+ if kwargs.get("nets", False):
354
+ data["nets"] = self.cfg_data.nets.get_data_from_db()
355
+ if kwargs.get("pin_groups", False):
356
+ data["pin_groups"] = self.cfg_data.pin_groups.get_data_from_db()
357
+ if kwargs.get("operations", False):
358
+ data["operations"] = self.cfg_data.operations.get_data_from_db()
359
+ if kwargs.get("padstacks", False):
360
+ self.cfg_data.padstacks.retrieve_parameters_from_edb()
361
+ definitions = []
362
+ for i in self.cfg_data.padstacks.definitions:
363
+ definitions.append(i.get_attributes())
364
+ instances = []
365
+ for i in self.cfg_data.padstacks.instances:
366
+ instances.append(i.get_attributes())
367
+ data["padstacks"] = dict()
368
+ data["padstacks"]["definitions"] = definitions
369
+ data["padstacks"]["instances"] = instances
370
+
371
+ if kwargs.get("boundaries", False):
372
+ data["boundaries"] = self.cfg_data.boundaries.get_data_from_db()
373
+
374
+ return data
546
375
 
547
376
  def export(
548
377
  self,
@@ -597,8 +426,7 @@ class Configuration:
597
426
  -------
598
427
  bool
599
428
  """
600
- return self.api.export(
601
- file_path,
429
+ data = self.get_data_from_db(
602
430
  stackup=stackup,
603
431
  package_definitions=package_definitions,
604
432
  setups=setups,
@@ -613,3 +441,21 @@ class Configuration:
613
441
  padstacks=padstacks,
614
442
  general=general,
615
443
  )
444
+
445
+ file_path = file_path if isinstance(file_path, Path) else Path(file_path)
446
+ file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
447
+
448
+ for comp in data["components"]:
449
+ for key, value in comp.items():
450
+ try:
451
+ json.dumps(value)
452
+ print(f"Key '{key}' is serializable.")
453
+ except TypeError as e:
454
+ print(f"Key '{key}' failed: {e}")
455
+
456
+ with open(file_path, "w") as f:
457
+ if file_path.suffix == ".json":
458
+ json.dump(data, f, ensure_ascii=False, indent=4)
459
+ else:
460
+ toml.dump(data, f)
461
+ return True if os.path.isfile(file_path) else False
@@ -1807,8 +1807,14 @@ class EDBPadstackInstance(Primitive):
1807
1807
 
1808
1808
  val = String("")
1809
1809
  _, name = self._edb_padstackinstance.GetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, val)
1810
- name = str(name).strip("'")
1811
- return name
1810
+ aedt_name = str(name).strip("'")
1811
+ if aedt_name == "":
1812
+ if self.is_pin and self.component:
1813
+ aedt_name = f"{self.component.name}-{self.component_pin}"
1814
+ elif self.component_pin:
1815
+ aedt_name = self.component_pin
1816
+ self.aedt_name = aedt_name
1817
+ return aedt_name
1812
1818
 
1813
1819
  @aedt_name.setter
1814
1820
  def aedt_name(self, value):
@@ -22,7 +22,6 @@
22
22
 
23
23
  import re
24
24
 
25
- from pyedb.dotnet.clr_module import String
26
25
  from pyedb.dotnet.database.edb_data.padstacks_data import EDBPadstackInstance
27
26
  from pyedb.dotnet.database.edb_data.primitives_data import Primitive
28
27
  from pyedb.generic.general_methods import generate_unique_name
@@ -325,21 +324,12 @@ class LayoutValidation:
325
324
  return
326
325
 
327
326
  def padstacks_no_name(self, fix=False):
327
+ """Find and fix padstacks without aedt_name."""
328
328
  pds = self._pedb.layout.padstack_instances
329
329
  counts = 0
330
- via_count = 1
331
330
  for obj in pds:
332
- val = String("")
333
- _, name = obj._edb_object.GetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, val)
334
- name = str(name).strip("'")
335
- if name == "":
331
+ if obj.aedt_name == "":
336
332
  counts += 1
337
333
  if fix:
338
- if not obj.component:
339
- obj._edb_object.SetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, f"Via{via_count}")
340
- via_count = via_count + 1
341
- else:
342
- obj._edb_object.SetProductProperty(
343
- self._pedb.edb_api.ProductId.Designer, 11, f"{obj.component.name}-{obj.component_pin}"
344
- )
334
+ obj.aedt_name = f"via_{obj.id}"
345
335
  self._pedb._logger.info(f"Found {counts}/{len(pds)} padstacks have no name.")
@@ -2234,7 +2234,7 @@ class Stackup(LayerCollection):
2234
2234
  material.loss_tanget = material_properties["DielectricLossTangent"]
2235
2235
  return True
2236
2236
 
2237
- def _import_xml(self, file_path, rename=False):
2237
+ def _import_xml(self, file_path):
2238
2238
  """Read external xml file and convert into json file.
2239
2239
  You can use xml file to import layer stackup but using json file is recommended.
2240
2240
  see :class:`pyedb.dotnet.database.edb_data.simulation_configuration.SimulationConfiguration´ class to
@@ -2304,7 +2304,8 @@ class Stackup(LayerCollection):
2304
2304
  layers.append(layer)
2305
2305
  stackup_dict["layers"] = layers
2306
2306
  cfg = {"stackup": stackup_dict}
2307
- return self._pedb.configuration.load(cfg, apply_file=True)
2307
+ self._pedb.configuration.load(cfg)
2308
+ return self._pedb.configuration.run()
2308
2309
 
2309
2310
  def _export_xml(self, file_path):
2310
2311
  """Export stackup information to an external XMLfile.
@@ -2391,7 +2392,7 @@ class Stackup(LayerCollection):
2391
2392
  elif file_path.endswith(".json"):
2392
2393
  return self._import_json(file_path, rename=rename)
2393
2394
  elif file_path.endswith(".xml"):
2394
- return self._import_xml(file_path, rename=rename)
2395
+ return self._import_xml(file_path)
2395
2396
  else:
2396
2397
  return False
2397
2398