pyedb 0.44.0__py3-none-any.whl → 0.46.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 (39) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +1 -1
  3. pyedb/configuration/cfg_components.py +7 -7
  4. pyedb/configuration/cfg_data.py +1 -1
  5. pyedb/configuration/cfg_general.py +8 -2
  6. pyedb/configuration/cfg_modeler.py +7 -0
  7. pyedb/configuration/cfg_operations.py +48 -2
  8. pyedb/configuration/cfg_pin_groups.py +1 -1
  9. pyedb/configuration/cfg_ports_sources.py +159 -51
  10. pyedb/configuration/cfg_s_parameter_models.py +51 -1
  11. pyedb/configuration/cfg_setup.py +77 -16
  12. pyedb/configuration/configuration.py +13 -3
  13. pyedb/dotnet/database/cell/primitive/path.py +12 -0
  14. pyedb/dotnet/database/geometry/point_data.py +26 -0
  15. pyedb/dotnet/database/geometry/polygon_data.py +9 -0
  16. pyedb/dotnet/database/nets.py +13 -3
  17. pyedb/dotnet/edb.py +41 -18
  18. pyedb/generic/design_types.py +2 -0
  19. pyedb/grpc/database/components.py +1 -2
  20. pyedb/grpc/database/definition/component_def.py +1 -1
  21. pyedb/grpc/database/hfss.py +10 -1
  22. pyedb/grpc/database/layout_validation.py +2 -2
  23. pyedb/grpc/database/padstacks.py +15 -9
  24. pyedb/grpc/database/ports/ports.py +3 -3
  25. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +18 -13
  26. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +73 -30
  27. pyedb/grpc/database/simulation_setup/sweep_data.py +12 -1
  28. pyedb/grpc/database/siwave.py +10 -1
  29. pyedb/grpc/database/source_excitations.py +12 -2
  30. pyedb/grpc/database/stackup.py +12 -4
  31. pyedb/grpc/database/terminal/edge_terminal.py +93 -0
  32. pyedb/grpc/database/terminal/pingroup_terminal.py +14 -1
  33. pyedb/grpc/edb.py +13 -9
  34. pyedb/grpc/edb_init.py +19 -15
  35. pyedb/grpc/rpc_session.py +11 -8
  36. {pyedb-0.44.0.dist-info → pyedb-0.46.0.dist-info}/METADATA +6 -6
  37. {pyedb-0.44.0.dist-info → pyedb-0.46.0.dist-info}/RECORD +39 -39
  38. {pyedb-0.44.0.dist-info → pyedb-0.46.0.dist-info}/LICENSE +0 -0
  39. {pyedb-0.44.0.dist-info → pyedb-0.46.0.dist-info}/WHEEL +0 -0
@@ -57,7 +57,14 @@ class SiwaveSimulationSetup(GrpcSIWaveSimulationSetup):
57
57
  super(SiwaveSimulationSetup, self.__class__).type.__set__(self, GrpcSimulationSetupType.SI_WAVE_DCIR)
58
58
 
59
59
  def add_sweep(
60
- self, name=None, distribution="linear", start_freq="0GHz", stop_freq="20GHz", step="10MHz", discrete=False
60
+ self,
61
+ name=None,
62
+ distribution="linear",
63
+ start_freq="0GHz",
64
+ stop_freq="20GHz",
65
+ step="10MHz",
66
+ discrete=False,
67
+ frequency_set=None,
61
68
  ):
62
69
  """Add a HFSS frequency sweep.
63
70
 
@@ -81,39 +88,75 @@ class SiwaveSimulationSetup(GrpcSIWaveSimulationSetup):
81
88
  distribution. Must be integer in that case.
82
89
  discrete : bool, optional
83
90
  Whether the sweep is discrete. The default is ``False``.
91
+ frequency_set : List, optional
92
+ Frequency set is a list adding one or more frequency sweeps. If ``frequency_set`` is provided, the other
93
+ arguments are ignored except ``discrete``. Default value is ``None``.
94
+ example of frequency_set : [['linear_scale', '50MHz', '200MHz', '10MHz']].
84
95
 
85
96
  Returns
86
97
  -------
87
98
  bool
88
99
  """
89
100
  init_sweep_count = len(self.sweep_data)
90
- start_freq = self._pedb.number_with_units(start_freq, "Hz")
91
- stop_freq = self._pedb.number_with_units(stop_freq, "Hz")
92
- step = str(step)
93
- if distribution.lower() == "linear":
94
- distribution = "LIN"
95
- elif distribution.lower() == "linear_count":
96
- distribution = "LINC"
97
- elif distribution.lower() == "exponential":
98
- distribution = "ESTP"
99
- elif distribution.lower() == "decade_count":
100
- distribution = "DEC"
101
- elif distribution.lower() == "octave_count":
102
- distribution = "OCT"
101
+ if frequency_set:
102
+ for sweep in frequency_set:
103
+ if "linear_scale" in sweep:
104
+ distribution = "LIN"
105
+ elif "linear_count" in sweep:
106
+ distribution = "LINC"
107
+ elif "exponential" in sweep:
108
+ distribution = "ESTP"
109
+ elif "log_scale" in sweep:
110
+ distribution = "DEC"
111
+ elif "octave_count" in sweep:
112
+ distribution = "OCT"
113
+ else:
114
+ distribution = "LIN"
115
+ start_freq = self._pedb.number_with_units(sweep[1], "Hz")
116
+ stop_freq = self._pedb.number_with_units(sweep[2], "Hz")
117
+ step = str(sweep[3])
118
+ if not name:
119
+ name = f"sweep_{init_sweep_count + 1}"
120
+ sweep_data = [
121
+ SweepData(
122
+ self._pedb, name=name, distribution=distribution, start_f=start_freq, end_f=stop_freq, step=step
123
+ )
124
+ ]
125
+ if discrete:
126
+ sweep_data[0].type = sweep_data[0].type.DISCRETE_SWEEP
127
+ for sweep in self.sweep_data:
128
+ sweep_data.append(sweep)
129
+ self.sweep_data = sweep_data
103
130
  else:
104
- distribution = "LIN"
105
- if not name:
106
- name = f"sweep_{init_sweep_count + 1}"
107
- sweep_data = [
108
- SweepData(self._pedb, name=name, distribution=distribution, start_f=start_freq, end_f=stop_freq, step=step)
109
- ]
110
- if discrete:
111
- sweep_data[0].type = sweep_data[0].type.DISCRETE_SWEEP
112
- for sweep in self.sweep_data:
113
- sweep_data.append(sweep)
114
- self.sweep_data = sweep_data
115
- if len(self.sweep_data) == init_sweep_count + 1:
116
- return True
117
- else:
118
- self._pedb.logger.error("Failed to add frequency sweep data")
119
- return False
131
+ start_freq = self._pedb.number_with_units(start_freq, "Hz")
132
+ stop_freq = self._pedb.number_with_units(stop_freq, "Hz")
133
+ step = str(step)
134
+ if distribution.lower() == "linear":
135
+ distribution = "LIN"
136
+ elif distribution.lower() == "linear_count":
137
+ distribution = "LINC"
138
+ elif distribution.lower() == "exponential":
139
+ distribution = "ESTP"
140
+ elif distribution.lower() == "decade_count":
141
+ distribution = "DEC"
142
+ elif distribution.lower() == "octave_count":
143
+ distribution = "OCT"
144
+ else:
145
+ distribution = "LIN"
146
+ if not name:
147
+ name = f"sweep_{init_sweep_count + 1}"
148
+ sweep_data = [
149
+ SweepData(
150
+ self._pedb, name=name, distribution=distribution, start_f=start_freq, end_f=stop_freq, step=step
151
+ )
152
+ ]
153
+ if discrete:
154
+ sweep_data[0].type = sweep_data[0].type.DISCRETE_SWEEP
155
+ for sweep in self.sweep_data:
156
+ sweep_data.append(sweep)
157
+ self.sweep_data = sweep_data
158
+ if len(self.sweep_data) == init_sweep_count + 1:
159
+ return True
160
+ else:
161
+ self._pedb.logger.error("Failed to add frequency sweep data")
162
+ return False
@@ -20,6 +20,12 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ from ansys.edb.core.simulation_setup.simulation_setup import (
24
+ Distribution as GrpcDistribution,
25
+ )
26
+ from ansys.edb.core.simulation_setup.simulation_setup import (
27
+ FrequencyData as GrpcFrequencyData,
28
+ )
23
29
  from ansys.edb.core.simulation_setup.simulation_setup import SweepData as GrpcSweepData
24
30
 
25
31
 
@@ -27,6 +33,11 @@ class SweepData(GrpcSweepData):
27
33
  """Frequency sweep data class."""
28
34
 
29
35
  def __init__(self, pedb, name, distribution, start_f, end_f, step, edb_object=None):
30
- super().__init__(name=name, distribution=distribution, start_f=start_f, end_f=end_f, step=step)
36
+ super().__init__(
37
+ name=name,
38
+ frequency_data=GrpcFrequencyData(
39
+ distribution=GrpcDistribution[distribution], start_f=start_f, end_f=end_f, step=step
40
+ ),
41
+ )
31
42
  self._edb_object = edb_object
32
43
  self._pedb = pedb
@@ -28,6 +28,12 @@ import os
28
28
  import warnings
29
29
 
30
30
  from ansys.edb.core.database import ProductIdType as GrpcProductIdType
31
+ from ansys.edb.core.simulation_setup.simulation_setup import (
32
+ Distribution as GrpcDistribution,
33
+ )
34
+ from ansys.edb.core.simulation_setup.simulation_setup import (
35
+ FrequencyData as GrpcFrequencyData,
36
+ )
31
37
  from ansys.edb.core.simulation_setup.simulation_setup import SweepData as GrpcSweepData
32
38
 
33
39
  from pyedb.misc.siw_feature_config.xtalk_scan.scan_config import SiwaveScanConfig
@@ -592,7 +598,10 @@ class Siwave(object):
592
598
  sweep_name = f"sweep_{len(setup.sweep_data) + 1}"
593
599
  sweep_data = [
594
600
  GrpcSweepData(
595
- name=sweep_name, distribution=distribution, start_f=start_freq, end_f=stop_freq, step=step_freq
601
+ name=sweep_name,
602
+ frequency_data=GrpcFrequencyData(
603
+ distribution=GrpcDistribution[distribution], start_f=start_freq, end_f=stop_freq, step=step_freq
604
+ ),
596
605
  )
597
606
  ]
598
607
  if discrete_sweep:
@@ -225,7 +225,7 @@ class SourceExcitation:
225
225
  if refdes and any(refdes.rlc_values):
226
226
  return self._pedb.components.deactivate_rlc_component(component=refdes, create_circuit_port=True)
227
227
  if not port_name:
228
- port_name = f"Port_{pins[0].net_name}_{pins[0].name}"
228
+ port_name = f"Port_{pins[0].net_name}_{pins[0].component.name}_{pins[0].name}"
229
229
 
230
230
  if len(pins) > 1 or pingroup_on_single_pin:
231
231
  pec_boundary = False
@@ -713,9 +713,19 @@ class SourceExcitation:
713
713
  -------
714
714
  Edb pin group terminal.
715
715
  """
716
+ from ansys.edb.core.hierarchy.pin_group import PinGroup as GrpcPinGroup
717
+
718
+ from pyedb.grpc.database.hierarchy.pingroup import PinGroup
719
+
716
720
  if pingroup.is_null:
717
721
  self._logger.error(f"{pingroup} is null")
718
- pin = PadstackInstance(self._pedb, pingroup.pins[0])
722
+ if not pingroup.pins:
723
+ self._pedb.logger.error("No pins defined on pingroup.")
724
+ return False
725
+ if isinstance(pingroup, GrpcPinGroup):
726
+ pingroup = PinGroup(self._pedb, pingroup)
727
+ pin = list(pingroup.pins.values())[0]
728
+ pin = PadstackInstance(self._pedb, pin)
719
729
  if term_name is None:
720
730
  term_name = f"{pin.component.name}.{pin.name}.{pin.net_name}"
721
731
  for t in self._pedb.active_layout.terminals:
@@ -138,15 +138,23 @@ class LayerCollection(GrpcLayerCollection):
138
138
 
139
139
  """
140
140
  thickness = GrpcValue(0.0)
141
+ layer_type_map = {"dielectric": GrpcLayerType.DIELECTRIC_LAYER, "signal": GrpcLayerType.SIGNAL_LAYER}
141
142
  if "thickness" in kwargs:
142
143
  thickness = GrpcValue(kwargs["thickness"])
143
144
  elevation = GrpcValue(0.0)
144
- _layer_type = GrpcLayerType.SIGNAL_LAYER
145
- if layer_type.lower() == "dielectric":
146
- _layer_type = GrpcLayerType.DIELECTRIC_LAYER
145
+ if "type" in kwargs:
146
+ _layer_type = layer_type_map[kwargs["type"]]
147
+ else:
148
+ _layer_type = layer_type_map[layer_type]
149
+ if "material" in kwargs:
150
+ _material = kwargs["material"]
151
+ else:
152
+ _material = "copper"
147
153
  layer = GrpcStackupLayer.create(
148
- name=name, layer_type=_layer_type, thickness=thickness, material="copper", elevation=elevation
154
+ name=name, layer_type=_layer_type, thickness=thickness, material=_material, elevation=elevation
149
155
  )
156
+ if "fill_material" in kwargs:
157
+ layer.set_fill_material(kwargs["fill_material"])
150
158
  return self._layer_collection.add_layer_bottom(layer)
151
159
 
152
160
  def add_layer_below(self, name, base_layer_name, layer_type="signal", **kwargs):
@@ -20,6 +20,8 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ import re
24
+
23
25
  from ansys.edb.core.terminal.bundle_terminal import BundleTerminal as GrpcBundleTerminal
24
26
  from ansys.edb.core.terminal.edge_terminal import EdgeTerminal as GrpcEdgeTerminal
25
27
 
@@ -29,6 +31,65 @@ class EdgeTerminal(GrpcEdgeTerminal):
29
31
  super().__init__(edb_object.msg)
30
32
  self._pedb = pedb
31
33
  self._edb_object = edb_object
34
+ self._hfss_type = "Gap"
35
+
36
+ @property
37
+ def _edb_properties(self):
38
+ from ansys.edb.core.database import ProductIdType as GrpcProductIdType
39
+
40
+ try:
41
+ p = self._edb_object.get_product_property(GrpcProductIdType.DESIGNER, 1)
42
+ except:
43
+ p = ""
44
+ return p
45
+
46
+ @_edb_properties.setter
47
+ def _edb_properties(self, value):
48
+ from ansys.edb.core.database import ProductIdType as GrpcProductIdType
49
+
50
+ self._edb_object.set_product_property(GrpcProductIdType.DESIGNER, 1, value)
51
+
52
+ @property
53
+ def is_wave_port(self):
54
+ if self._hfss_port_property:
55
+ return True
56
+ return False
57
+
58
+ @property
59
+ def _hfss_port_property(self):
60
+ """HFSS port property."""
61
+ hfss_prop = re.search(r"HFSS\(.*?\)", self._edb_properties)
62
+ p = {}
63
+ if hfss_prop:
64
+ hfss_type = re.search(r"'HFSS Type'='([^']+)'", hfss_prop.group())
65
+ orientation = re.search(r"'Orientation'='([^']+)'", hfss_prop.group())
66
+ horizontal_ef = re.search(r"'Horizontal Extent Factor'='([^']+)'", hfss_prop.group())
67
+ vertical_ef = re.search(r"'Vertical Extent Factor'='([^']+)'", hfss_prop.group())
68
+ radial_ef = re.search(r"'Radial Extent Factor'='([^']+)'", hfss_prop.group())
69
+ pec_w = re.search(r"'PEC Launch Width'='([^']+)'", hfss_prop.group())
70
+
71
+ p["HFSS Type"] = hfss_type.group(1) if hfss_type else ""
72
+ p["Orientation"] = orientation.group(1) if orientation else ""
73
+ p["Horizontal Extent Factor"] = float(horizontal_ef.group(1)) if horizontal_ef else ""
74
+ p["Vertical Extent Factor"] = float(vertical_ef.group(1)) if vertical_ef else ""
75
+ p["Radial Extent Factor"] = float(radial_ef.group(1)) if radial_ef else ""
76
+ p["PEC Launch Width"] = pec_w.group(1) if pec_w else ""
77
+ else:
78
+ p["HFSS Type"] = ""
79
+ p["Orientation"] = ""
80
+ p["Horizontal Extent Factor"] = ""
81
+ p["Vertical Extent Factor"] = ""
82
+ p["Radial Extent Factor"] = ""
83
+ p["PEC Launch Width"] = ""
84
+ return p
85
+
86
+ @_hfss_port_property.setter
87
+ def _hfss_port_property(self, value):
88
+ txt = []
89
+ for k, v in value.items():
90
+ txt.append("'{}'='{}'".format(k, v))
91
+ txt = ",".join(txt)
92
+ self._edb_properties = "HFSS({})".format(txt)
32
93
 
33
94
  def couple_ports(self, port):
34
95
  """Create a bundle wave port.
@@ -49,3 +110,35 @@ class EdgeTerminal(GrpcEdgeTerminal):
49
110
  temp.extend([i for i in port])
50
111
  bundle_terminal = GrpcBundleTerminal.create(temp)
51
112
  return self._pedb.ports[bundle_terminal.name]
113
+
114
+ @property
115
+ def is_port(self):
116
+ return True
117
+
118
+ @property
119
+ def ref_terminal(self):
120
+ """Return refeference terminal.
121
+
122
+ ..deprecated:: 0.44.0
123
+ Use: func:`reference_terminal` property instead.
124
+
125
+ """
126
+ self._pedb.logger.warning("ref_terminal is deprecated, use reference_terminal property instead.")
127
+ return self.reference_terminal
128
+
129
+ @ref_terminal.setter
130
+ def ref_terminal(self, value):
131
+ self._pedb.logger.warning("ref_terminal is deprecated, use reference_terminal property instead.")
132
+ self.reference_terminal = value
133
+
134
+ @property
135
+ def hfss_type(self):
136
+ return self._hfss_type
137
+
138
+ @hfss_type.setter
139
+ def hfss_type(self, value):
140
+ self._hfss_type = value
141
+
142
+ @property
143
+ def terminal_type(self):
144
+ return "EdgeTerminal"
@@ -184,12 +184,25 @@ class PinGroupTerminal(GrpcPinGroupTerminal):
184
184
 
185
185
  """
186
186
  self._pedb.logger.warning("ref_terminal property is deprecated, use reference_terminal property instead.")
187
- return self.reference_terminal
187
+ return PinGroupTerminal(self._pedb, self.reference_terminal)
188
188
 
189
189
  @ref_terminal.setter
190
190
  def ref_terminal(self, value):
191
+ self._pedb.logger.warning("ref_terminal is deprecated, use reference_terminal instead.")
191
192
  self.reference_terminal = value
192
193
 
193
194
  @property
194
195
  def hfss_type(self):
195
196
  return "circuit"
197
+
198
+ @property
199
+ def is_current_source(self):
200
+ if self.boundary_type == "current_source":
201
+ return True
202
+ return False
203
+
204
+ @property
205
+ def is_voltage_source(self):
206
+ if self.boundary_type == "voltage_source":
207
+ return True
208
+ return False
pyedb/grpc/edb.py CHANGED
@@ -198,7 +198,6 @@ class Edb(EdbInit):
198
198
  use_ppe=False,
199
199
  technology_file=None,
200
200
  restart_rpc_server=False,
201
- kill_all_instances=False,
202
201
  ):
203
202
  edbversion = get_string_version(edbversion)
204
203
  self._clean_variables()
@@ -273,9 +272,9 @@ class Edb(EdbInit):
273
272
  self.logger.info("EDB %s was created correctly from %s file.", self.edbpath, edbpath[-2:])
274
273
  elif edbpath.endswith("edb.def"):
275
274
  self.edbpath = os.path.dirname(edbpath)
276
- self.open_edb(restart_rpc_server=restart_rpc_server, kill_all_instances=kill_all_instances)
275
+ self.open_edb(restart_rpc_server=restart_rpc_server)
277
276
  elif not os.path.exists(os.path.join(self.edbpath, "edb.def")):
278
- self.create_edb(restart_rpc_server=restart_rpc_server, kill_all_instances=kill_all_instances)
277
+ self.create_edb(restart_rpc_server=restart_rpc_server)
279
278
  self.logger.info("EDB %s created correctly.", self.edbpath)
280
279
  elif ".aedb" in edbpath:
281
280
  self.edbpath = edbpath
@@ -290,8 +289,7 @@ class Edb(EdbInit):
290
289
  return self
291
290
 
292
291
  def __exit__(self, ex_type, ex_value, ex_traceback):
293
- if ex_type:
294
- self.edb_exception(ex_value, ex_traceback)
292
+ self._signal_handler(ex_type, ex_value)
295
293
 
296
294
  def __getitem__(self, variable_name):
297
295
  """Get a variable to the Edb project. The variable can be project using ``$`` prefix or
@@ -493,7 +491,9 @@ class Edb(EdbInit):
493
491
  """
494
492
  terminals = [term for term in self.layout.terminals if not term.is_reference_terminal]
495
493
  ports = {}
494
+ from pyedb.grpc.database.ports.ports import WavePort
496
495
  from pyedb.grpc.database.terminal.bundle_terminal import BundleTerminal
496
+ from pyedb.grpc.database.terminal.edge_terminal import EdgeTerminal
497
497
  from pyedb.grpc.database.terminal.padstack_instance_terminal import (
498
498
  PadstackInstanceTerminal,
499
499
  )
@@ -504,6 +504,11 @@ class Edb(EdbInit):
504
504
  ports[bundle_ter.name] = bundle_ter
505
505
  elif isinstance(t, PadstackInstanceTerminal):
506
506
  ports[t.name] = CoaxPort(self, t)
507
+ elif isinstance(t, EdgeTerminal):
508
+ if t.is_wave_port:
509
+ ports[t.name] = WavePort(self, t)
510
+ else:
511
+ ports[t.name] = EdgeTerminal(self, t)
507
512
  else:
508
513
  ports[t.name] = GapPort(self, t)
509
514
  return ports
@@ -572,7 +577,6 @@ class Edb(EdbInit):
572
577
  self.edbpath,
573
578
  self.isreadonly,
574
579
  restart_rpc_server=restart_rpc_server,
575
- kill_all_instances=kill_all_instances,
576
580
  )
577
581
  n_try -= 1
578
582
  except Exception as e:
@@ -613,7 +617,7 @@ class Edb(EdbInit):
613
617
  n_try = 10
614
618
  while not self.db and n_try:
615
619
  try:
616
- self.create(self.edbpath, restart_rpc_server=restart_rpc_server, kill_all_instances=kill_all_instances)
620
+ self.create(self.edbpath, restart_rpc_server=restart_rpc_server)
617
621
  n_try -= 1
618
622
  except Exception as e:
619
623
  self.logger.error(e.args[0])
@@ -2015,8 +2019,8 @@ class Edb(EdbInit):
2015
2019
  nets_to_preserve.extend(el.nets)
2016
2020
  if include_pingroups:
2017
2021
  for pingroup in self.layout.pin_groups:
2018
- for pin in pingroup.pins:
2019
- if pin.net_name in reference_list:
2022
+ for pin_name, pin in pingroup.pins.items():
2023
+ if pin_name in reference_list:
2020
2024
  pins_to_preserve.append(pin.edb_uid)
2021
2025
  if check_terminals:
2022
2026
  terms = [
pyedb/grpc/edb_init.py CHANGED
@@ -22,7 +22,9 @@
22
22
 
23
23
 
24
24
  """Database."""
25
+ import atexit
25
26
  import os
27
+ import signal
26
28
  import sys
27
29
 
28
30
  import ansys.edb.core.database as database
@@ -68,13 +70,22 @@ class EdbInit(object):
68
70
  oa_directory = os.path.join(self.base_path, "common", "oa")
69
71
  os.environ["ANSYS_OADIR"] = oa_directory
70
72
  os.environ["PATH"] = "{};{}".format(os.environ["PATH"], self.base_path)
73
+ # register server kill
74
+ atexit.register(self._signal_handler)
75
+ # register signal handlers
76
+ signal.signal(signal.SIGTERM, self._signal_handler)
77
+ signal.signal(signal.SIGINT, self._signal_handler)
78
+
79
+ @staticmethod
80
+ def _signal_handler(signum=None, frame=None):
81
+ RpcSession.kill()
71
82
 
72
83
  @property
73
84
  def db(self):
74
85
  """Active database object."""
75
86
  return self._db
76
87
 
77
- def create(self, db_path, port=0, restart_rpc_server=False, kill_all_instances=False):
88
+ def create(self, db_path, port=0, restart_rpc_server=False):
78
89
  """Create a Database at the specified file location.
79
90
 
80
91
  Parameters
@@ -82,12 +93,12 @@ class EdbInit(object):
82
93
  db_path : str
83
94
  Path to top-level database folder
84
95
 
96
+ port : int
97
+ grpc port number.
98
+
85
99
  restart_rpc_server : optional, bool
86
100
  Force restarting RPC server when `True`.Default value is `False`
87
101
 
88
- kill_all_instances : optional, bool.
89
- Force killing all RPC server instances, must be used with caution. Default value is `False`.
90
-
91
102
  Returns
92
103
  -------
93
104
  Database
@@ -97,7 +108,6 @@ class EdbInit(object):
97
108
  edb_version=self.edbversion,
98
109
  port=port,
99
110
  restart_server=restart_rpc_server,
100
- kill_all_instances=kill_all_instances,
101
111
  )
102
112
  if not RpcSession.pid:
103
113
  self.logger.error("Failed to start RPC server.")
@@ -105,7 +115,7 @@ class EdbInit(object):
105
115
  self._db = database.Database.create(db_path)
106
116
  return self._db
107
117
 
108
- def open(self, db_path, read_only, port=0, restart_rpc_server=False, kill_all_instances=False):
118
+ def open(self, db_path, read_only, port=0, restart_rpc_server=False):
109
119
  """Open an existing Database at the specified file location.
110
120
 
111
121
  Parameters
@@ -115,11 +125,9 @@ class EdbInit(object):
115
125
  read_only : bool
116
126
  Obtain read-only access.
117
127
  port : optional, int.
118
- Specify the port number.If not provided a randon free one is selected. Default value is `0`.
128
+ Specify the port number. If not provided a randon free one is selected. Default value is `0`.
119
129
  restart_rpc_server : optional, bool
120
130
  Force restarting RPC server when `True`. Default value is `False`.
121
- kill_all_instances : optional, bool.
122
- Force killing all RPC server instances, must be used with caution. Default value is `False`.
123
131
 
124
132
  Returns
125
133
  -------
@@ -133,7 +141,6 @@ class EdbInit(object):
133
141
  edb_version=self.edbversion,
134
142
  port=port,
135
143
  restart_server=restart_rpc_server,
136
- kill_all_instances=kill_all_instances,
137
144
  )
138
145
  if not RpcSession.pid:
139
146
  self.logger.error("Failed to start RPC server.")
@@ -154,7 +161,7 @@ class EdbInit(object):
154
161
  """Save any changes into a file."""
155
162
  return self._db.save()
156
163
 
157
- def close(self, terminate_rpc_session=True, kill_all_instances=False):
164
+ def close(self, terminate_rpc_session=True):
158
165
  """Close the database.
159
166
 
160
167
  Parameters
@@ -167,10 +174,7 @@ class EdbInit(object):
167
174
  """
168
175
  self._db.close()
169
176
  self._db = None
170
- if kill_all_instances:
171
- RpcSession._kill_all_instances()
172
- RpcSession.pid = 0
173
- elif terminate_rpc_session:
177
+ if terminate_rpc_session:
174
178
  RpcSession.rpc_session.disconnect()
175
179
  RpcSession.pid = 0
176
180
  return True
pyedb/grpc/rpc_session.py CHANGED
@@ -50,7 +50,7 @@ class RpcSession:
50
50
  port = 10000
51
51
 
52
52
  @staticmethod
53
- def start(edb_version, port=0, restart_server=False, kill_all_instances=False):
53
+ def start(edb_version, port=0, restart_server=False):
54
54
  """Start RPC-server, the server must be started before opening EDB.
55
55
 
56
56
  Parameters
@@ -107,10 +107,7 @@ class RpcSession:
107
107
  if RpcSession.pid:
108
108
  if restart_server:
109
109
  pyedb_logger.logger.info("Restarting RPC server")
110
- if kill_all_instances:
111
- RpcSession.__kill_all_instances()
112
- else:
113
- RpcSession.__kill()
110
+ RpcSession.kill()
114
111
  RpcSession.__start_rpc_server()
115
112
  else:
116
113
  pyedb_logger.info(f"Server already running on port {RpcSession.port}")
@@ -141,13 +138,18 @@ class RpcSession:
141
138
  pyedb_logger.logger.info("Grpc session started")
142
139
 
143
140
  @staticmethod
144
- def __kill():
141
+ def kill():
145
142
  p = psutil.Process(RpcSession.pid)
146
143
  time.sleep(latency_delay)
147
- p.terminate()
144
+ try:
145
+ p.terminate()
146
+ print(f"RPC session pid: {RpcSession.pid} killed due to execution failure.")
147
+ RpcSession.pid = 0
148
+ except:
149
+ print("RPC session closed.")
148
150
 
149
151
  @staticmethod
150
- def _kill_all_instances():
152
+ def kill_all_instances():
151
153
  proc = [p.pid for p in list(psutil.process_iter()) if "edb_rpc" in p.name().lower()]
152
154
  time.sleep(latency_delay)
153
155
  for pid in proc:
@@ -163,6 +165,7 @@ class RpcSession:
163
165
  end_managing()
164
166
  RpcSession.rpc_session.disconnect()
165
167
  time.sleep(latency_delay)
168
+ RpcSession.__get_process_id()
166
169
 
167
170
  @staticmethod
168
171
  def __get_random_free_port():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyedb
3
- Version: 0.44.0
3
+ Version: 0.46.0
4
4
  Summary: Higher-Level Pythonic Ansys Electronics Data Base
5
5
  Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
6
6
  Maintainer-email: PyEDB developers <simon.vandenbrouck@ansys.com>
@@ -127,15 +127,15 @@ Documentation for the latest stable release of PyEDB is hosted at
127
127
  [PyEDB documentation](https://edb.docs.pyansys.com/version/stable/index.html).
128
128
  The documentation has five sections:
129
129
 
130
- - [Getting started](https://edb.docs.pyansys.com/version/version/stable/getting_started/index.html): Describes
130
+ - [Getting started](https://edb.docs.pyansys.com/version/stable/getting_started/index.html): Describes
131
131
  how to install PyEDB in user mode.
132
- - [User guide](https://edb.docs.pyansys.com/version/version/stable/user_guide/index.html): Describes how to
132
+ - [User guide](https://edb.docs.pyansys.com/version/stable/user_guide/index.html#user-guide): Describes how to
133
133
  use PyEDB.
134
- - [API reference](https://edb.docs.pyansys.com/version/version/stable/api/index.html): Provides API member descriptions
134
+ - [API reference](https://edb.docs.pyansys.com/version/stable/api/index.html): Provides API member descriptions
135
135
  and usage examples.
136
- - [Examples](https://edb.docs.pyansys.com/version/version/stable/examples/index.html): Provides examples showing
136
+ - [Examples](https://examples.aedt.docs.pyansys.com/version/dev/examples/high_frequency/layout/index.html): Provides examples showing
137
137
  end-to-end workflows for using PyEDB.
138
- - [Contribute](https://edb.docs.pyansys.com/version/version/stable/contribute.html): Describes how to install
138
+ - [Contribute](https://edb.docs.pyansys.com/version/stable/contributing.html): Describes how to install
139
139
  PyEDB in developer mode and how to contribute to this PyAnsys library.
140
140
 
141
141
  In the upper right corner of the documentation's title bar, there is an option