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
@@ -19,10 +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
-
22
+ from datetime import datetime
23
23
  import json
24
24
  import os
25
25
  from pathlib import Path
26
+ import warnings
26
27
 
27
28
  import toml
28
29
 
@@ -33,341 +34,9 @@ from pyedb.dotnet.database.definition.package_def import PackageDef
33
34
  class Configuration:
34
35
  """Enables export and import of a JSON configuration file that can be applied to a new or existing design."""
35
36
 
36
- class Grpc:
37
- def __init__(self, parent):
38
- self.parent = parent
39
- self._pedb = parent._pedb
40
-
41
- def configuration_stackup(self, kwargs):
42
- if kwargs.get("fix_padstack_def"):
43
- from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
44
-
45
- pedb_defs = self._pedb.padstacks.definitions
46
- temp = []
47
- for _, pdef in pedb_defs.items():
48
- cfg_def = CfgPadstackDefinition(self._pedb, pdef)
49
- cfg_def.api.retrieve_parameters_from_edb()
50
- temp.append(cfg_def)
51
- self.parent.cfg_data.stackup.apply()
52
- for cfg_pdef in temp:
53
- cfg_pdef.api.set_parameters_to_edb()
54
- else:
55
- temp_pdef_data = {}
56
- from ansys.edb.core.definition.padstack_def_data import (
57
- PadType as GrpcPadType,
58
- )
59
-
60
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
61
- for layer in pdef.data.layer_names:
62
- result = pdef.data.get_pad_parameters(layer, GrpcPadType.REGULAR_PAD)
63
- if len(result) == 4:
64
- # polygon based
65
- temp_pdef_data[pdef_name] = pdef.data
66
- break
67
- self.parent.cfg_data.stackup.apply()
68
- for pdef_name, pdef_data in temp_pdef_data.items():
69
- pdef = self._pedb.padstacks.definitions[pdef_name]
70
- pdef._padstack_def_data = pdef_data
71
-
72
- def _load_stackup(self):
73
- """Imports stackup information from json."""
74
- data = self.data["stackup"]
75
- materials = data.get("materials")
76
-
77
- if materials:
78
- edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
79
- for mat in materials:
80
- name = mat["name"].lower()
81
- if name in edb_materials:
82
- self._pedb.materials.delete_material(edb_materials[name])
83
- for mat in materials:
84
- self._pedb.materials.add_material(**mat)
85
-
86
- layers = data.get("layers")
87
-
88
- if layers:
89
- input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
90
- if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
91
- self._pedb.logger.error("Input signal layer count do not match.")
92
- return False
93
-
94
- removal_list = []
95
- lc_signal_layers = []
96
- for name, obj in self._pedb.stackup.all_layers.items():
97
- if obj.type == "dielectric":
98
- removal_list.append(name)
99
- elif obj.type == "signal":
100
- lc_signal_layers.append(obj.id)
101
- for l in removal_list:
102
- self._pedb.stackup.remove_layer(l)
103
-
104
- # update all signal layers
105
- id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
106
- signal_idx = 0
107
- for l in layers:
108
- if l["type"] == "signal":
109
- layer_id = lc_signal_layers[signal_idx]
110
- layer_name = id_name[layer_id]
111
- self._pedb.stackup.layers[layer_name].update(**l)
112
- signal_idx = signal_idx + 1
113
-
114
- # add all dielectric layers. Dielectric layers must be added last. Otherwise,
115
- # dielectric layer will occupy signal and document layer id.
116
- prev_layer_clone = None
117
- l = layers.pop(0)
118
- if l["type"] == "signal":
119
- prev_layer_clone = self._pedb.stackup.layers[l["name"]]
120
- else:
121
- prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
122
- for idx, l in enumerate(layers):
123
- if l["type"] == "dielectric":
124
- prev_layer_clone = self._pedb.stackup.add_layer_below(
125
- base_layer_name=prev_layer_clone.name, **l
126
- )
127
- elif l["type"] == "signal":
128
- prev_layer_clone = self._pedb.stackup.layers[l["name"]]
129
-
130
- def _load_package_def(self):
131
- """Imports package definition information from JSON."""
132
- comps = self._pedb.components.instances
133
- for pkgd in self.parent.data["package_definitions"]:
134
- name = pkgd["name"]
135
- if name in self._pedb.definitions.package:
136
- self._pedb.definitions.package[name].delete()
137
- extent_bounding_box = pkgd.get("extent_bounding_box", None)
138
- if extent_bounding_box:
139
- package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
140
- else:
141
- package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
142
- package_def.maximum_power = pkgd["maximum_power"]
143
- package_def.therm_cond = pkgd["therm_cond"]
144
- package_def.theta_jb = pkgd["theta_jb"]
145
- package_def.theta_jc = pkgd["theta_jc"]
146
- package_def.height = pkgd["height"]
147
-
148
- heatsink = pkgd.get("heatsink", None)
149
- if heatsink:
150
- package_def.set_heatsink(
151
- heatsink["fin_base_height"],
152
- heatsink["fin_height"],
153
- heatsink["fin_orientation"],
154
- heatsink["fin_spacing"],
155
- heatsink["fin_thickness"],
156
- )
157
-
158
- comp_def_name = pkgd["component_definition"]
159
- comp_def = self._pedb.definitions.component[comp_def_name]
160
-
161
- comp_list = dict()
162
- if pkgd["apply_to_all"]:
163
- comp_list.update(
164
- {
165
- refdes: comp
166
- for refdes, comp in comp_def.components.items()
167
- if refdes not in pkgd["components"]
168
- }
169
- )
170
- else:
171
- comp_list.update(
172
- {refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
173
- )
174
- for _, i in comp_list.items():
175
- i.package_def = name
176
-
177
- def get_data_from_db(self, **kwargs):
178
- """Get configuration data from layout.
179
-
180
- Parameters
181
- ----------
182
- stackup
183
-
184
- Returns
185
- -------
186
-
187
- """
188
- self._pedb.logger.info("Getting data from layout database.")
189
- data = {}
190
- if kwargs.get("general", False):
191
- data["general"] = self.parent.cfg_data.general.get_data_from_db()
192
- if kwargs.get("stackup", False):
193
- data["stackup"] = self.parent.cfg_data.stackup.get_data_from_db()
194
- if kwargs.get("package_definitions", False):
195
- data["package_definitions"] = self.parent.cfg_data.package_definitions.get_data_from_db()
196
- if kwargs.get("setups", False):
197
- setups = self.parent.cfg_data.setups
198
- setups.retrieve_parameters_from_edb()
199
- data["setups"] = setups.to_dict()
200
- if kwargs.get("sources", False):
201
- data["sources"] = self.parent.cfg_data.sources.get_data_from_db()
202
- if kwargs.get("ports", False):
203
- data["ports"] = self.parent.cfg_data.ports.get_data_from_db()
204
- if kwargs.get("components", False) or kwargs.get("s_parameters", False):
205
- self.parent.cfg_data.components.retrieve_parameters_from_edb()
206
- components = []
207
- for i in self.parent.cfg_data.components.components:
208
- if i.type == "io":
209
- components.append(i.get_attributes())
210
- components.append(i.get_attributes())
211
-
212
- if kwargs.get("components", False):
213
- data["components"] = components
214
- elif kwargs.get("s_parameters", False):
215
- data["s_parameters"] = self.parent.cfg_data.s_parameters.get_data_from_db(components)
216
- if kwargs.get("nets", False):
217
- data["nets"] = self.parent.cfg_data.nets.get_data_from_db()
218
- if kwargs.get("pin_groups", False):
219
- data["pin_groups"] = self.parent.cfg_data.pin_groups.get_data_from_db()
220
- if kwargs.get("operations", False):
221
- data["operations"] = self.parent.cfg_data.operations.get_data_from_db()
222
- if kwargs.get("padstacks", False):
223
- self.parent.cfg_data.padstacks.retrieve_parameters_from_edb()
224
- definitions = []
225
- for i in self.parent.cfg_data.padstacks.definitions:
226
- definitions.append(i.get_attributes())
227
- instances = []
228
- for i in self.parent.cfg_data.padstacks.instances:
229
- instances.append(i.get_attributes())
230
- data["padstacks"] = dict()
231
- data["padstacks"]["definitions"] = definitions
232
- data["padstacks"]["instances"] = instances
233
-
234
- if kwargs.get("boundaries", False):
235
- data["boundaries"] = self.parent.cfg_data.boundaries.get_data_from_db()
236
-
237
- return data
238
-
239
- def export(
240
- self,
241
- file_path,
242
- stackup=True,
243
- package_definitions=False,
244
- setups=True,
245
- sources=True,
246
- ports=True,
247
- nets=True,
248
- pin_groups=True,
249
- operations=True,
250
- components=True,
251
- boundaries=True,
252
- s_parameters=True,
253
- padstacks=True,
254
- general=True,
255
- ):
256
- """Export the configuration data from layout to a file.
257
-
258
- Parameters
259
- ----------
260
- file_path : str, Path
261
- File path to export the configuration data.
262
- stackup : bool
263
- Whether to export stackup or not.
264
- package_definitions : bool
265
- Whether to export package definitions or not.
266
- setups : bool
267
- Whether to export setups or not.
268
- sources : bool
269
- Whether to export sources or not.
270
- ports : bool
271
- Whether to export ports or not.
272
- nets : bool
273
- Whether to export nets.
274
- pin_groups : bool
275
- Whether to export pin groups.
276
- operations : bool
277
- Whether to export operations.
278
- components : bool
279
- Whether to export component.
280
- boundaries : bool
281
- Whether to export boundaries.
282
- s_parameters : bool
283
- Whether to export s_parameters.
284
- padstacks : bool
285
- Whether to export padstacks.
286
- general : bool
287
- Whether to export general information.
288
- Returns
289
- -------
290
- bool
291
- """
292
- data = self.get_data_from_db(
293
- stackup=stackup,
294
- package_definitions=package_definitions,
295
- setups=setups,
296
- sources=sources,
297
- ports=ports,
298
- nets=nets,
299
- pin_groups=pin_groups,
300
- operations=operations,
301
- components=components,
302
- boundaries=boundaries,
303
- s_parameters=s_parameters,
304
- padstacks=padstacks,
305
- general=general,
306
- )
307
-
308
- file_path = file_path if isinstance(file_path, Path) else Path(file_path)
309
- file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
310
-
311
- for comp in data["components"]:
312
- for key, value in comp.items():
313
- try:
314
- json.dumps(value)
315
- print(f"Key '{key}' is serializable.")
316
- except TypeError as e:
317
- print(f"Key '{key}' failed: {e}")
318
-
319
- with open(file_path, "w") as f:
320
- if file_path.suffix == ".json":
321
- json.dump(data, f, ensure_ascii=False, indent=4)
322
- else:
323
- toml.dump(data, f)
324
- return True if os.path.isfile(file_path) else False
325
-
326
- class DotNet(Grpc):
327
- def __init__(self, parent):
328
- super().__init__(parent)
329
-
330
- def configuration_stackup(self, kwargs):
331
- if kwargs.get("fix_padstack_def"):
332
- from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
333
-
334
- pedb_defs = self._pedb.padstacks.definitions
335
- temp = []
336
- for _, pdef in pedb_defs.items():
337
- cfg_def = CfgPadstackDefinition(self._pedb, pdef)
338
- cfg_def.api.retrieve_parameters_from_edb()
339
- temp.append(cfg_def)
340
- self.parent.cfg_data.stackup.apply()
341
- for cfg_pdef in temp:
342
- cfg_pdef.api.set_parameters_to_edb()
343
- else:
344
- temp_pdef_data = {}
345
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
346
- pdef_data = pdef._padstack_def_data
347
- for lyr_name in list(pdef_data.GetLayerNames()):
348
- result = pdef_data.GetPadParametersValue(
349
- lyr_name, self._pedb._edb.Definition.PadType.RegularPad
350
- )
351
- flag, pad_shape, params, offset_x, offset_y, rotation = result
352
- if flag is False:
353
- result = pdef_data.GetPolygonalPadParameters(
354
- lyr_name, self._pedb._edb.Definition.PadType.RegularPad
355
- )
356
- flag, polygon_data, offset_x, offset_y, rotation = result
357
- if flag:
358
- temp_pdef_data[pdef_name] = pdef_data
359
- break
360
- self.parent.cfg_data.stackup.apply()
361
- for pdef_name, pdef_data in temp_pdef_data.items():
362
- pdef = self._pedb.padstacks.definitions[pdef_name]
363
- pdef._padstack_def_data = pdef_data
364
-
365
37
  def __init__(self, pedb):
366
38
  self._pedb = pedb
367
- if self._pedb.grpc:
368
- self.api = self.Grpc(self)
369
- else:
370
- self.api = self.DotNet(self)
39
+
371
40
  self._components = self._pedb.components.instances
372
41
  self.data = {}
373
42
  self._s_parameter_library = ""
@@ -438,6 +107,8 @@ class Configuration:
438
107
 
439
108
  def run(self, **kwargs):
440
109
  """Apply configuration settings to the current design"""
110
+ if kwargs.get("fix_padstack_def"):
111
+ warnings.warn("fix_padstack_def is deprecated.", DeprecationWarning)
441
112
 
442
113
  if self.cfg_data.variables:
443
114
  self.cfg_data.variables.apply()
@@ -446,63 +117,199 @@ class Configuration:
446
117
  self.cfg_data.general.apply()
447
118
 
448
119
  # Configure boundary settings
120
+ now = datetime.now()
449
121
  if self.cfg_data.boundaries:
450
122
  self.cfg_data.boundaries.apply()
123
+ self._pedb.logger.info(f"Updating boundaries finished. Time lapse {datetime.now() - now}")
124
+ now = datetime.now()
451
125
 
452
126
  # Configure nets
453
127
  if self.cfg_data.nets:
454
128
  self.cfg_data.nets.apply()
129
+ self._pedb.logger.info(f"Updating nets finished. Time lapse {datetime.now() - now}")
130
+ now = datetime.now()
455
131
 
456
132
  # Configure components
457
133
  self.cfg_data.components.apply()
134
+ self._pedb.logger.info(f"Updating components finished. Time lapse {datetime.now() - now}")
135
+ now = datetime.now()
458
136
 
459
137
  # Configure pin groups
460
138
  self.cfg_data.pin_groups.apply()
139
+ self._pedb.logger.info(f"Creating pin groups finished. Time lapse {datetime.now() - now}")
140
+ now = datetime.now()
461
141
 
462
142
  # Configure sources
463
143
  self.cfg_data.sources.apply()
144
+ self._pedb.logger.info(f"Placing sources finished. Time lapse {datetime.now() - now}")
145
+ now = datetime.now()
464
146
 
465
147
  # Configure setup
466
148
  self.cfg_data.setups.apply()
149
+ self._pedb.logger.info(f"Creating setups finished. Time lapse {datetime.now() - now}")
150
+ now = datetime.now()
467
151
 
468
152
  # Configure stackup
469
- self.api.configuration_stackup(kwargs)
153
+ self.configuration_stackup()
154
+ self._pedb.logger.info(f"Updating stackup finished. Time lapse {datetime.now() - now}")
155
+ now = datetime.now()
470
156
 
471
157
  # Configure padstacks
472
158
  if self.cfg_data.padstacks:
473
159
  self.cfg_data.padstacks.apply()
160
+ self._pedb.logger.info(f"Applying padstacks finished. Time lapse {datetime.now() - now}")
161
+ now = datetime.now()
474
162
 
475
163
  # Configure S-parameter
476
164
  self.cfg_data.s_parameters.apply()
165
+ self._pedb.logger.info(f"Applying S-parameters finished. Time lapse {datetime.now() - now}")
166
+ now = datetime.now()
477
167
 
478
168
  # Configure SPICE models
479
169
  for spice_model in self.cfg_data.spice_models:
480
170
  spice_model.apply()
171
+ self._pedb.logger.info(f"Assigning Spice models finished. Time lapse {datetime.now() - now}")
172
+ now = datetime.now()
481
173
 
482
174
  # Configure package definitions
483
175
  self.cfg_data.package_definitions.apply()
176
+ self._pedb.logger.info(f"Applying package definitions finished. Time lapse {datetime.now() - now}")
177
+ now = datetime.now()
484
178
 
485
179
  # Modeler
486
180
  self.cfg_data.modeler.apply()
487
181
 
488
182
  # Configure ports
489
183
  self.cfg_data.ports.apply()
184
+ self._pedb.logger.info(f"Placing ports finished. Time lapse {datetime.now() - now}")
185
+ now = datetime.now()
490
186
 
491
187
  # Configure probes
492
188
  self.cfg_data.probes.apply()
189
+ self._pedb.logger.info(f"Placing probes finished. Time lapse {datetime.now() - now}")
493
190
 
494
191
  # Configure operations
495
192
  self.cfg_data.operations.apply()
496
193
 
497
194
  return True
498
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
+
499
215
  def _load_stackup(self):
500
216
  """Imports stackup information from json."""
501
- 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"]]
502
270
 
503
271
  def _load_package_def(self):
504
272
  """Imports package definition information from JSON."""
505
- 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
506
313
 
507
314
  def get_data_from_db(self, **kwargs):
508
315
  """Get configuration data from layout.
@@ -515,7 +322,56 @@ class Configuration:
515
322
  -------
516
323
 
517
324
  """
518
- 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
519
375
 
520
376
  def export(
521
377
  self,
@@ -570,8 +426,7 @@ class Configuration:
570
426
  -------
571
427
  bool
572
428
  """
573
- return self.api.export(
574
- file_path,
429
+ data = self.get_data_from_db(
575
430
  stackup=stackup,
576
431
  package_definitions=package_definitions,
577
432
  setups=setups,
@@ -586,3 +441,21 @@ class Configuration:
586
441
  padstacks=padstacks,
587
442
  general=general,
588
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
@@ -38,6 +38,7 @@ if is_linux: # pragma: no cover
38
38
 
39
39
  dotnet_root = None
40
40
  runtime_config = None
41
+ runtime_spec = None
41
42
  # Use system .NET core runtime or fall back to dotnetcore2
42
43
  if os.environ.get("DOTNET_ROOT") is None:
43
44
  try:
@@ -78,11 +79,16 @@ if is_linux: # pragma: no cover
78
79
  "Please ensure that .NET SDK is correctly installed or "
79
80
  "that DOTNET_ROOT is correctly set."
80
81
  )
81
- runtime_config = candidates[0]
82
+ runtime_spec = candidates[0]
82
83
  # Use specific .NET core runtime
83
- if dotnet_root is not None and runtime_config is not None:
84
+ if dotnet_root is not None and (runtime_config is not None or runtime_spec is not None):
84
85
  try:
85
- load("coreclr", runtime_config=str(runtime_config), dotnet_root=str(dotnet_root))
86
+ load(
87
+ "coreclr",
88
+ runtime_config=str(runtime_config) if runtime_config else None,
89
+ runtime_spec=runtime_spec,
90
+ dotnet_root=str(dotnet_root),
91
+ )
86
92
  os.environ["DOTNET_ROOT"] = dotnet_root.as_posix()
87
93
  if "mono" not in os.getenv("LD_LIBRARY_PATH", ""):
88
94
  warnings.warn("LD_LIBRARY_PATH needs to be setup to use pyedb.")