From 030889a5b0095fa16ce13641ad0e08084d8ee5cf Mon Sep 17 00:00:00 2001 From: jsalant Date: Tue, 14 Oct 2025 15:34:10 -0400 Subject: [PATCH 01/28] EMIT Pyaedt fixes Fix data rate conversion: B1347519 Fix some issues with creating components: B1347443 Make sure Emitters and Waveforms are cast correctly before returning: B1347518 Remove some unused node types (CategoriesViewNode and TopLevelSimulation): B1345240 Make sure _set_table_data() and _get_table_data() can handle both NodeProp and ColumnData tables (and both for BB EmissionsNodes); also fix some table_data() docstrings: B1342786 Exclude parameters used to orient components from the node classes: B1343826 Fix conversion from yards to meters and add conversion from mile to meters: B1347453 Add some unit tests Allow users to specify parameters as unitless strings (in addition to unitless floats and strings with units): B1347439 --- .../aedt/core/emit_core/emit_constants.py | 12 +- .../aedt/core/emit_core/emit_schematic.py | 38 +++++- .../aedt/core/emit_core/nodes/emit_node.py | 128 +++++++++++++++--- .../emit_core/nodes/generated/__init__.py | 8 +- .../emit_core/nodes/generated/amplifier.py | 30 ++-- .../core/emit_core/nodes/generated/band.py | 10 -- .../nodes/generated/categories_view_node.py | 37 ----- .../emit_core/nodes/generated/circulator.py | 16 +-- .../nodes/generated/custom_coupling_node.py | 2 +- .../indoor_propagation_coupling_node.py | 2 +- .../emit_core/nodes/generated/isolator.py | 16 +-- .../emit_core/nodes/generated/multiplexer.py | 29 +--- .../nodes/generated/power_divider.py | 16 +-- .../nodes/generated/rx_mixer_product_node.py | 17 +++ .../nodes/generated/rx_saturation_node.py | 16 +++ .../nodes/generated/rx_selectivity_node.py | 15 ++ .../emit_core/nodes/generated/rx_spur_node.py | 2 +- .../nodes/generated/sampling_node.py | 7 +- .../emit_core/nodes/generated/terminator.py | 33 +++-- .../nodes/generated/top_level_simulation.py | 37 ----- .../emit_core/nodes/generated/tr_switch.py | 30 ---- .../nodes/generated/tx_bb_emission_node.py | 8 +- .../nodes/generated/tx_harmonic_node.py | 15 ++ .../nodes/generated/tx_nb_emission_node.py | 15 ++ .../emit_core/nodes/generated/tx_spur_node.py | 2 +- .../emit_core/nodes/generated/waveform.py | 11 +- .../aedt/core/emit_core/results/revision.py | 9 +- src/ansys/aedt/core/generic/constants.py | 3 +- tests/system/emit/test_emit.py | 126 ++++++++++++++++- 29 files changed, 413 insertions(+), 277 deletions(-) delete mode 100644 src/ansys/aedt/core/emit_core/nodes/generated/categories_view_node.py delete mode 100644 src/ansys/aedt/core/emit_core/nodes/generated/top_level_simulation.py diff --git a/src/ansys/aedt/core/emit_core/emit_constants.py b/src/ansys/aedt/core/emit_core/emit_constants.py index 5cfa5f62561..9d3a15098f2 100644 --- a/src/ansys/aedt/core/emit_core/emit_constants.py +++ b/src/ansys/aedt/core/emit_core/emit_constants.py @@ -168,20 +168,20 @@ def data_rate_conv(value: float, units: str, to_internal: bool = True): if units == "bps": mult = 1.0 elif units == "kbps": - mult = 1e-3 + mult = 1e3 elif units == "Mbps": - mult = 1e-6 + mult = 1e6 elif units == "Gbps": - mult = 1e-9 + mult = 1e9 else: if units == "bps": mult = 1.0 elif units == "kbps": - mult = 1e3 + mult = 1e-3 elif units == "Mbps": - mult = 1e6 + mult = 1e-6 elif units == "Gbps": - mult = 1e9 + mult = 1e-9 return value * mult diff --git a/src/ansys/aedt/core/emit_core/emit_schematic.py b/src/ansys/aedt/core/emit_core/emit_schematic.py index 2eb83555604..7f3ed62160d 100644 --- a/src/ansys/aedt/core/emit_core/emit_schematic.py +++ b/src/ansys/aedt/core/emit_core/emit_schematic.py @@ -94,11 +94,19 @@ def create_component(self, component_type: str, name: str = None, library: str = try: # Retrieve matching components from the catalog + matching_components = [] matching_components = self.emit_instance.modeler.components.components_catalog[component_type] if not matching_components: - self.emit_instance.logger.error(f"No component found for type '{component_type}'.") - raise ValueError(f"No component found for type '{component_type}'.") + # couldn't find a component match, try looking at all component names + catalog_comps = self.emit_instance.modeler.components.components_catalog.components + for value in catalog_comps.values(): + if value.name == component_type: + matching_components.append(value) + + if not matching_components: + self.emit_instance.logger.error(f"No component found for type '{component_type}'.") + raise ValueError(f"No component found for type '{component_type}'.") if len(matching_components) == 1: # Use the single matching component @@ -123,6 +131,7 @@ def create_component(self, component_type: str, name: str = None, library: str = revision = self.emit_instance.results.get_revision() # Create the component using the EmitCom module + component.name = component.name.strip("'") new_component_id = self._emit_com_module.CreateEmitComponent( name, component.name, component.component_library ) @@ -203,3 +212,28 @@ def connect_components(self, component_name_1: str, component_name_2: str) -> No f"Failed to connect components '{component_name_1}' and '{component_name_2}': {e}" ) raise RuntimeError(f"Failed to connect components '{component_name_1}' and '{component_name_2}': {e}") + + @pyaedt_function_handler + def delete_component(self, name: str): + """Delete a component from the schematic. + + Parameters + ---------- + name : str + Name of the component. + + Raises + ------ + RuntimeError + If the deletion fails. + """ + try: + self._emit_com_module.DeleteEmitComponent(name) + self.emit_instance.logger.info( + f"Successfully deleted component '{name}'." + ) + except Exception as e: + self.emit_instance.logger.error( + f"Failed to delete component '{name}': {e}" + ) + raise RuntimeError(f"Failed to delete component '{name}': {e}") diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index b9dc35146de..56e95b2087d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -31,7 +31,6 @@ from ansys.aedt.core.emit_core.emit_constants import data_rate_conv import ansys.aedt.core.generic.constants as consts - class EmitNode: """Emit node class for managing and interacting with EMIT nodes.""" @@ -174,6 +173,7 @@ def _get_node(self, node_id: int): >>> new_node = node._get_node(node_id) """ from ansys.aedt.core.emit_core.nodes import generated + from ansys.aedt.core.emit_core.nodes.emitter_node import EmitterNode props = self._oRevisionData.GetEmitNodeProperties(self._result_id, node_id, True) props = self.props_to_dict(props) @@ -183,8 +183,18 @@ def _get_node(self, node_id: int): node = None try: - type_class = getattr(generated, f"{prefix}{node_type}") - node = type_class(self._emit_obj, self._result_id, node_id) + if node_type == "RadioNode" and props["IsEmitter"] == "true": + if prefix == "": + type_class = EmitterNode + # else: + # type_class = ReadOnlyEmitterNode + node = type_class(self._emit_obj, self._result_id, node_id) + elif node_type == 'Band' and props["IsEmitterBand"] == "true": + type_class = getattr(generated, f"{prefix}Waveform") + node = type_class(self._emit_obj, self._result_id, node_id) + else: + type_class = getattr(generated, f"{prefix}{node_type}") + node = type_class(self._emit_obj, self._result_id, node_id) except AttributeError: node = EmitNode(self._emit_obj, self._result_id, node_id) return node @@ -203,7 +213,7 @@ def children(self): child_nodes = [self._get_node(child_id) for child_id in child_ids] return child_nodes - def _get_property(self, prop, skipChecks=False) -> Union[str, List[str]]: + def _get_property(self, prop, skipChecks=False, isTable=False) -> Union[str, List[str]]: """Fetch the value of a given property. Parameters @@ -226,7 +236,14 @@ def _get_property(self, prop, skipChecks=False) -> Union[str, List[str]]: selected_kv_pair = selected_kv_pairs[0] val = selected_kv_pair[1] - if val.find("|") != -1: + if isTable: + # Node Prop tables + # Data formatted using compact string serialization + # with ';' separating rows and '|' separating columns + rows = val.split(";") + table = [tuple(row.split("|")) for row in rows if row] + return table + elif val.find("|") != -1: return val.split("|") else: return val @@ -271,6 +288,7 @@ def _string_to_value_units(value) -> tuple[float, str]: # see if we can split it based on a space between number # and units vals = value.split(" ") + units = "" if len(vals) == 2: dec_val = float(vals[0]) units = vals[1].strip() @@ -281,7 +299,11 @@ def _string_to_value_units(value) -> tuple[float, str]: dec_val = float(value[:i]) units = value[i:] return dec_val, units - raise ValueError(f"{value} is not valid for this property.") + # maybe it's a string but with no units + try: + return float(value), units + except ValueError: + raise ValueError(f"{value} is not valid for this property.") def _convert_to_internal_units(self, value: float | str, unit_system: str) -> float: """Takes a value and converts to internal EMIT units used for storing values. @@ -304,6 +326,8 @@ def _convert_to_internal_units(self, value: float | str, unit_system: str) -> fl units = consts.SI_UNITS[unit_system] else: value, units = self._string_to_value_units(value) + if units == "": + units = consts.SI_UNITS[unit_system] # verify the units are valid for the specified type if units not in EMIT_VALID_UNITS[unit_system]: raise ValueError(f"{units} are not valid units for this property.") @@ -331,10 +355,11 @@ def _convert_from_internal_units(value: float, unit_system: str) -> float: Value in SI units. """ # get the SI units - units = consts.SI_UNITS[unit_system] if unit_system == "Data Rate": + units = "bps" converted_value = data_rate_conv(value, units, False) else: + units = consts.SI_UNITS[unit_system] converted_value = consts.unit_converter(value, unit_system, EMIT_INTERNAL_UNITS[unit_system], units) return converted_value @@ -424,28 +449,88 @@ def _get_child_node_id(self, child_name: str) -> int: """ return self._oRevisionData.GetChildNodeID(self._result_id, self._node_id, child_name) + def _is_column_data_table(self): + """Returns true if the node uses column data tables. + + Returns + ------- + bool + True if the table is ColumnData, False otherwise. + """ + # BB Emission Nodes can have ColumnData or NodeProp tables + # so handle them first + if self._node_type == "TxBbEmissionNode": + if self._get_property("Noise Behavior") == "BroadbandEquation": + return False + return True + + table_title = self._get_property("CDTableTitle", True) + if table_title == "": + # No ColumnData Table Title, so it's a NodePropTable + return False + return True + def _get_table_data(self): """Returns the node's table data. Returns ------- - list - The node's table data. + list of tuples + The node's table data as a list of tuples. + [(x1, y1, z1), (x2, y2, z2)] """ - rows = self._oRevisionData.GetTableData(self._result_id, self._node_id) - nested_list = [col.split(" ") for col in rows] - return nested_list + try: + if self._is_column_data_table(): + # Column Data tables + # Data formatted using compact string serialization + # with '|' separating rows and ';' separating columns + data = self._oRevisionData.GetTableData(self._result_id, self._node_id) + rows = data.split("|") + string_table = [tuple(row.split(";")) for row in rows if row] + table = [tuple(float(x) for x in t) for t in string_table] + else: + # Node Prop tables + # Data formatted using compact string serialization + # with ';' separating rows and '|' separating columns + table_key = self._get_property('TableKey', True) + string_table = self._get_property(table_key, True, True) + + def try_float(val): + try: + return float(val) + except ValueError: + return val # keep as string for non-numeric (e.g. equations) + + table = [tuple(try_float(x) for x in t) for t in string_table] + except Exception as e: + print(f"Failed to get table data for node {self.name}. Error: {e}") + return table - def _set_table_data(self, nested_list): + def _set_table_data(self, table): """Sets the table data for the node. Parameters ---------- - nested_list : list + list of tuples Data to populate the table with. + [(x1, y1, z1), (x2, y2, z2)] """ - rows = [col.join(" ") for col in nested_list] - self._oRevisionData.SetTableData(self._result_id, self._node_id, rows) + try: + if self._is_column_data_table(): + # Column Data tables + # Data formatted using compact string serialization + # with '|' separating rows and ';' separating columns + data = "|".join(";".join(map(str, row)) for row in table) + self._oRevisionData.SetTableData(self._result_id, self._node_id, data) + else: + # Node Prop tables + # Data formatted using compact string serialization + # with ';' separating rows and '|' separating columns + table_key = self._get_property('TableKey', True) + data = ";".join("|".join(map(str, row)) for row in table) + self._set_property(table_key, data) + except Exception as e: + print(f"Failed to set table data for node {self.name}. Error: {e}") def _add_child_node(self, child_type, child_name=None): """Creates a child node of the given type and name. @@ -459,8 +544,8 @@ def _add_child_node(self, child_type, child_name=None): Returns ------- - int - Unique node ID assigned to the created child node. + node: EmitNode + The node. Raises ------ @@ -468,15 +553,16 @@ def _add_child_node(self, child_type, child_name=None): If the specified child type is not allowed. """ if not child_name: - child_name = f"New {child_type}" + child_name = f"{child_type}" - new_id = None + new_node = None if child_type not in self.allowed_child_types: raise ValueError( f"Child type {child_type} is not allowed for this node. Allowed types are: {self.allowed_child_types}" ) try: new_id = self._oRevisionData.CreateEmitNode(self._result_id, self._node_id, child_name, child_type) + new_node = self._get_node(new_id) except Exception as e: print(f"Failed to add child node of type {child_type} to node {self.name}. Error: {e}") - return new_id + return new_node diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py b/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py index 2820de648f5..33672f9677d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py @@ -28,9 +28,8 @@ from .antenna_passband import AntennaPassband from .band import Band from .band_folder import BandFolder -from .cable import Cable from .cad_node import CADNode -from .categories_view_node import CategoriesViewNode +from .cable import Cable from .circulator import Circulator from .coupling_link_node import CouplingLinkNode from .couplings_node import CouplingsNode @@ -60,10 +59,9 @@ from .scene_group_node import SceneGroupNode from .solution_coupling_node import SolutionCouplingNode from .solutions_node import SolutionsNode +from .tr_switch import TR_Switch from .terminator import Terminator -from .top_level_simulation import TopLevelSimulation from .touchstone_coupling_node import TouchstoneCouplingNode -from .tr_switch import TR_Switch from .two_ray_path_loss_coupling_node import TwoRayPathLossCouplingNode from .tx_bb_emission_node import TxBbEmissionNode from .tx_harmonic_node import TxHarmonicNode @@ -83,7 +81,6 @@ "BandFolder", "CADNode", "Cable", - "CategoriesViewNode", "Circulator", "CouplingLinkNode", "CouplingsNode", @@ -115,7 +112,6 @@ "SolutionsNode", "TR_Switch", "Terminator", - "TopLevelSimulation", "TouchstoneCouplingNode", "TwoRayPathLossCouplingNode", "TxBbEmissionNode", diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py b/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py index c556de6ea93..c9a4957de68 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py @@ -50,6 +50,21 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Harmonic Intercept Points, Ref. Input Table. + Table consists of 2 columns. + Harmonic: + Value should be between 2 and 20. + Intercept Point: + Value should be between -1000 and 1000. + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def filename(self) -> str: """Name of file defining the outboard component. @@ -86,21 +101,6 @@ def notes(self) -> str: def notes(self, value: str): self._set_property("Notes", f"{value}") - class AmplifierTypeOption(Enum): - TRANSMIT_AMPLIFIER = "Transmit Amplifier" - RECEIVE_AMPLIFIER = "Receive Amplifier" - - @property - def amplifier_type(self) -> AmplifierTypeOption: - """Configures the amplifier as a Tx or Rx amplifier.""" - val = self._get_property("Amplifier Type") - val = self.AmplifierTypeOption[val.upper()] - return val - - @amplifier_type.setter - def amplifier_type(self, value: AmplifierTypeOption): - self._set_property("Amplifier Type", f"{value.value}") - @property def gain(self) -> float: """Amplifier in-band gain. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/band.py b/src/ansys/aedt/core/emit_core/nodes/generated/band.py index 057ea7d77cb..ffa5753959f 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/band.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/band.py @@ -52,16 +52,6 @@ def enabled(self) -> bool: def enabled(self, value: bool): self._set_property("Enabled", f"{str(value).lower()}") - @property - def port(self): - """Radio Port associated with this Band.""" - val = self._get_property("Port") - return val - - @port.setter - def port(self, value): - self._set_property("Port", f"{value}") - @property def use_dd_1494_mode(self) -> bool: """Uses DD-1494 parameters to define the Tx/Rx spectrum. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/categories_view_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/categories_view_node.py deleted file mode 100644 index 07e43c5a2a7..00000000000 --- a/src/ansys/aedt/core/emit_core/nodes/generated/categories_view_node.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-FileCopyrightText: 2021 - 2025 ANSYS, Inc. and /or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode - - -class CategoriesViewNode(EmitNode): - def __init__(self, emit_obj, result_id, node_id): - self._is_component = False - EmitNode.__init__(self, emit_obj, result_id, node_id) - - @property - def node_type(self) -> str: - """The type of this emit node.""" - return self._node_type diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py b/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py index 3475dd5b427..42c3c28b2ce 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py @@ -105,21 +105,6 @@ def type(self) -> TypeOption: def type(self, value: TypeOption): self._set_property("Type", f"{value.value}") - class Port1LocationOption(Enum): - RADIO_SIDE = "Radio Side" - ANTENNA_SIDE = "Antenna Side" - - @property - def port_1_location(self) -> Port1LocationOption: - """Defines the orientation of the circulator.""" - val = self._get_property("Port 1 Location") - val = self.Port1LocationOption[val.upper()] - return val - - @port_1_location.setter - def port_1_location(self, value: Port1LocationOption): - self._set_property("Port 1 Location", f"{value.value}") - @property def insertion_loss(self) -> float: """Circulator in-band loss in forward direction. @@ -256,3 +241,4 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/custom_coupling_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/custom_coupling_node.py index 3d6e5b12b0e..ece0968a02d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/custom_coupling_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/custom_coupling_node.py @@ -59,7 +59,7 @@ def delete(self): @property def table_data(self): - """Table. + """Custom Coupling Values Table. Table consists of 2 columns. Frequency: Value should be between 1.0 and 100.0e9. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/indoor_propagation_coupling_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/indoor_propagation_coupling_node.py index f6c7fd0230f..2075210b97a 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/indoor_propagation_coupling_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/indoor_propagation_coupling_node.py @@ -57,7 +57,7 @@ def delete(self): @property def table_data(self): - """Table. + """Custom Building Values Table. Table consists of 3 columns. Frequency: Value should be between 1.0 and 100.0e9. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py b/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py index 4e3ee8d286b..d1a5da3d438 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py @@ -105,21 +105,6 @@ def type(self) -> TypeOption: def type(self, value: TypeOption): self._set_property("Type", f"{value.value}") - class Port1LocationOption(Enum): - RADIO_SIDE = "Radio Side" - ANTENNA_SIDE = "Antenna Side" - - @property - def port_1_location(self) -> Port1LocationOption: - """Defines the orientation of the isolator.""" - val = self._get_property("Port 1 Location") - val = self.Port1LocationOption[val.upper()] - return val - - @port_1_location.setter - def port_1_location(self, value: Port1LocationOption): - self._set_property("Port 1 Location", f"{value.value}") - @property def insertion_loss(self) -> float: """Isolator in-band loss in forward direction. @@ -256,3 +241,4 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py b/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py index c1b9a6fa535..6dd8d45dd80 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py @@ -110,34 +110,6 @@ def type(self) -> TypeOption: def type(self, value: TypeOption): self._set_property("Type", f"{value.value}") - class Port1LocationOption(Enum): - RADIO_SIDE = "Radio Side" - ANTENNA_SIDE = "Antenna Side" - - @property - def port_1_location(self) -> Port1LocationOption: - """Defines the orientation of the multiplexer.""" - val = self._get_property("Port 1 Location") - val = self.Port1LocationOption[val.upper()] - return val - - @port_1_location.setter - def port_1_location(self, value: Port1LocationOption): - self._set_property("Port 1 Location", f"{value.value}") - - @property - def flip_ports_vertically(self) -> bool: - """Reverses the port order on the multi-port side of the multiplexer. - - Value should be 'true' or 'false'. - """ - val = self._get_property("Flip Ports Vertically") - return val == "true" - - @flip_ports_vertically.setter - def flip_ports_vertically(self, value: bool): - self._set_property("Flip Ports Vertically", f"{str(value).lower()}") - @property def ports(self): """Assigns the child port nodes to the multiplexers ports.""" @@ -153,3 +125,4 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py b/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py index 57b5c8ca6df..724b563db4d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py @@ -106,21 +106,6 @@ def type(self) -> TypeOption: def type(self, value: TypeOption): self._set_property("Type", f"{value.value}") - class OrientationOption(Enum): - DIVIDER = "Divider" - COMBINER = "Combiner" - - @property - def orientation(self) -> OrientationOption: - """Defines the orientation of the Power Divider.""" - val = self._get_property("Orientation") - val = self.OrientationOption[val.upper()] - return val - - @orientation.setter - def orientation(self, value: OrientationOption): - self._set_property("Orientation", f"{value.value}") - @property def insertion_loss_above_ideal(self) -> float: """Insertion Loss Above Ideal. @@ -260,3 +245,4 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/rx_mixer_product_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/rx_mixer_product_node.py index c897e0b496f..73ac87b3bd7 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/rx_mixer_product_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/rx_mixer_product_node.py @@ -51,6 +51,23 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Edit Mixer Products Table. + Table consists of 3 columns. + RF Harmonic Order: + Value should be between -100 and 100. + LO Harmonic Order: + Value should be between 1 and 100. + Power (Relative or Absolute): + Value should be between -1000 and 1000. + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def enabled(self) -> bool: """Enabled state for this node.""" diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py index 03d65ecb7d7..86d0bc47f2c 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py @@ -49,6 +49,21 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Rx Saturation Profile Table. + Table consists of 2 columns. + Frequency: + Value should be between 1 and 100e9. + Amplitude: + Value should be between -1000 and 1000. + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def enabled(self) -> bool: """Enabled state for this node.""" @@ -57,3 +72,4 @@ def enabled(self) -> bool: @enabled.setter def enabled(self, value: bool): self._set_property("Enabled", f"{str(value).lower()}") + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/rx_selectivity_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/rx_selectivity_node.py index 9eb7a00f97b..9c8ea1d3380 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/rx_selectivity_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/rx_selectivity_node.py @@ -49,6 +49,21 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Rx Selectivity Table. + Table consists of 2 columns. + Bandwidth: + Value should be between 0 and 100e9. + Attenuation: + Value should be between -200 and 1000. + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def enabled(self) -> bool: """Enabled state for this node.""" diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/rx_spur_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/rx_spur_node.py index ab69c821415..2c14267787d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/rx_spur_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/rx_spur_node.py @@ -53,7 +53,7 @@ def delete(self): @property def table_data(self): - """Table. + """Spurs Table. Table consists of 3 columns. Frequency (MHz): Value should be a mathematical expression. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py index 5b10df45486..160e4099a7a 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py @@ -45,12 +45,12 @@ def node_type(self) -> str: @property def table_data(self): - """Table. + """Frequency Ranges Table. Table consists of 2 columns. Min: - Value should be greater than 1.0. + Value should be between 1.0 and 100e9. Max: - Value should be greater than 1.0. + Value should be between 1.0 and 100e9. """ return self._get_table_data() @@ -154,3 +154,4 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py b/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py index c7e7a51fce6..cd68bd97e65 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py @@ -50,6 +50,23 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Parametric VSWR Table. + Table consists of 3 columns. + Min: + Value should be between 1 and 100e9. + Max: + Value should be between 1 and 100e9. + VSWR: + + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def filename(self) -> str: """Name of file defining the Terminator. @@ -105,21 +122,6 @@ def type(self) -> TypeOption: def type(self, value: TypeOption): self._set_property("Type", f"{value.value}") - class PortLocationOption(Enum): - RADIO_SIDE = "Radio Side" - ANTENNA_SIDE = "Antenna Side" - - @property - def port_location(self) -> PortLocationOption: - """Defines the orientation of the terminator.""" - val = self._get_property("Port Location") - val = self.PortLocationOption[val.upper()] - return val - - @port_location.setter - def port_location(self, value: PortLocationOption): - self._set_property("Port Location", f"{value.value}") - @property def vswr(self) -> float: """VSWR. @@ -142,3 +144,4 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val + diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/top_level_simulation.py b/src/ansys/aedt/core/emit_core/nodes/generated/top_level_simulation.py deleted file mode 100644 index 9f64dfaa93e..00000000000 --- a/src/ansys/aedt/core/emit_core/nodes/generated/top_level_simulation.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-FileCopyrightText: 2021 - 2025 ANSYS, Inc. and /or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode - - -class TopLevelSimulation(EmitNode): - def __init__(self, emit_obj, result_id, node_id): - self._is_component = False - EmitNode.__init__(self, emit_obj, result_id, node_id) - - @property - def node_type(self) -> str: - """The type of this emit node.""" - return self._node_type diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py b/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py index c73d860719b..821d76c638b 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py @@ -86,36 +86,6 @@ def notes(self) -> str: def notes(self, value: str): self._set_property("Notes", f"{value}") - class TxPortOption(Enum): - PORT_1 = "Port 1" - PORT_2 = "Port 2" - - @property - def tx_port(self) -> TxPortOption: - """Specifies which port on the TR Switch is part of the Tx path.""" - val = self._get_property("Tx Port") - val = self.TxPortOption[val.upper()] - return val - - @tx_port.setter - def tx_port(self, value: TxPortOption): - self._set_property("Tx Port", f"{value.value}") - - class CommonPortLocationOption(Enum): - RADIO_SIDE = "Radio Side" - ANTENNA_SIDE = "Antenna Side" - - @property - def common_port_location(self) -> CommonPortLocationOption: - """Defines the orientation of the tr switch.""" - val = self._get_property("Common Port Location") - val = self.CommonPortLocationOption[val.upper()] - return val - - @common_port_location.setter - def common_port_location(self, value: CommonPortLocationOption): - self._set_property("Common Port Location", f"{value.value}") - @property def insertion_loss(self) -> float: """TR Switch in-band loss in forward direction. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/tx_bb_emission_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/tx_bb_emission_node.py index a0144b4e998..3db2f83ed5c 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/tx_bb_emission_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/tx_bb_emission_node.py @@ -55,10 +55,10 @@ def delete(self): def table_data(self): """Tx Broadband Noise Profile Table. Table consists of 2 columns. - Frequency (MHz): - Value should be a mathematical expression. - Amplitude (dBm/Hz): - Value should be between -200.0 and 150.0. + Frequency, Bandwidth, or Offset: + Value should be between -100e9 and 100e9. + Amplitude: + Value should be between -1000 and 200. """ return self._get_table_data() diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/tx_harmonic_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/tx_harmonic_node.py index 8fb5754bc61..d5b24df5a79 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/tx_harmonic_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/tx_harmonic_node.py @@ -51,6 +51,21 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Edit Harmonics Table. + Table consists of 2 columns. + Harmonic: + Value should be between 2 and 1000. + Power (Relative or Absolute): + Value should be between -1000 and 1000. + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def enabled(self) -> bool: """Enabled state for this node.""" diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/tx_nb_emission_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/tx_nb_emission_node.py index 3f0a9c551f9..3888c2f9ec6 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/tx_nb_emission_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/tx_nb_emission_node.py @@ -51,6 +51,21 @@ def delete(self): """Delete this node""" self._delete() + @property + def table_data(self): + """Tx Emissions Profile Table. + Table consists of 2 columns. + Bandwidth or Frequency: + Value should be between 1 and 100e9. + Attenuation or Power: + Value should be between -1000 and 1000. + """ + return self._get_table_data() + + @table_data.setter + def table_data(self, value): + self._set_table_data(value) + @property def enabled(self) -> bool: """Enabled state for this node.""" diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/tx_spur_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/tx_spur_node.py index 23857e1e35e..a40a55ea351 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/tx_spur_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/tx_spur_node.py @@ -53,7 +53,7 @@ def delete(self): @property def table_data(self): - """Table. + """Spurs Table. Table consists of 3 columns. Frequency (MHz): Value should be a mathematical expression. diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py b/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py index 38e8a392881..8df1cbcb85c 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py @@ -52,16 +52,6 @@ def enabled(self) -> bool: def enabled(self, value: bool): self._set_property("Enabled", f"{str(value).lower()}") - @property - def port(self): - """Radio Port associated with this Band.""" - val = self._get_property("Port") - return val - - @port.setter - def port(self, value): - self._set_property("Port", f"{value}") - class WaveformOption(Enum): PERIODIC_CLOCK = "Periodic Clock" SPREAD_SPECTRUM_CLOCK = "Spread Spectrum Clock" @@ -443,3 +433,4 @@ def delay_skew(self) -> float: def delay_skew(self, value: float | str): value = self._convert_to_internal_units(value, "Time") self._set_property("Delay Skew", f"{value}") + diff --git a/src/ansys/aedt/core/emit_core/results/revision.py b/src/ansys/aedt/core/emit_core/results/revision.py index 2d0830caf57..a1ec28cc841 100644 --- a/src/ansys/aedt/core/emit_core/results/revision.py +++ b/src/ansys/aedt/core/emit_core/results/revision.py @@ -29,6 +29,7 @@ from ansys.aedt.core.emit_core.emit_constants import ResultType from ansys.aedt.core.emit_core.emit_constants import TxRxMode from ansys.aedt.core.emit_core.nodes import generated +from ansys.aedt.core.emit_core.nodes.emitter_node import EmitterNode from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode from ansys.aedt.core.emit_core.nodes.generated import CouplingsNode from ansys.aedt.core.emit_core.nodes.generated import EmitSceneNode @@ -1014,7 +1015,13 @@ def _get_node(self, node_id: int) -> EmitNode: node = None try: if node_type == "RadioNode" and props["IsEmitter"] == "true": - type_class = getattr(generated, f"{prefix}EmitterNode") + if prefix == "": + type_class = EmitterNode + #else: + # type_class = ReadOnlyEmitterNode + node = type_class(self.emit_project, self.results_index, node_id) + elif node_type == 'Band' and props["IsEmitterBand"] == "true": + type_class = getattr(generated, f"{prefix}Waveform") node = type_class(self.emit_project, self.results_index, node_id) else: type_class = getattr(generated, f"{prefix}{node_type}") diff --git a/src/ansys/aedt/core/generic/constants.py b/src/ansys/aedt/core/generic/constants.py index b0bbcf55787..72f0cba0942 100644 --- a/src/ansys/aedt/core/generic/constants.py +++ b/src/ansys/aedt/core/generic/constants.py @@ -351,7 +351,8 @@ def validate_enum_class_value(cls, value): "mil": METER2IN * 1e-3, "in": METER2IN, "ft": METER2IN * 12, - "yd": METER2IN * 144, + "yd": METER2IN * 36, + "mile": METER2IN * 63360, }, "Mass": {"ug": 1e-9, "mg": 1e-6, "g": 1e-3, "kg": 1.0, "ton": 1000, "oz": 0.0283495, "lb": 0.453592}, "None": { diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 69e09d40a76..562fdd48d5d 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -52,10 +52,13 @@ from ansys.aedt.core.emit_core.emit_constants import TxRxMode from ansys.aedt.core.emit_core.nodes import generated from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode + from ansys.aedt.core.emit_core.nodes.generated import Amplifier from ansys.aedt.core.emit_core.nodes.generated import Band from ansys.aedt.core.emit_core.nodes.generated import Filter from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import SamplingNode + from ansys.aedt.core.emit_core.nodes.generated import TxBbEmissionNode + from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfNode from ansys.aedt.core.modeler.circuits.primitives_emit import EmitAntennaComponent from ansys.aedt.core.modeler.circuits.primitives_emit import EmitComponent from ansys.aedt.core.modeler.circuits.primitives_emit import EmitComponents @@ -1804,10 +1807,129 @@ def test_fm_fsk_freq_deviation(self, emit_app): band_node.freq_deviation = 1e4 assert band_node.freq_deviation == 1e4 - @pytest.mark.skipif(config["desktopVersion"] < "2025.1", reason="Skipped on versions earlier than 2024 R2.") - @pytest.mark.skipif(config["desktopVersion"] <= "2026.1", reason="Not stable test") + @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") + def test_tables(self, emit_app): + # Emit has 2 different types of tables: Node Prop Tables and ColumnData Tables + # this test confirms that the table_data properties work for both + radio = emit_app.schematic.create_component('New Radio') + radio = cast(RadioNode, radio) + + children = radio.children + for child in children: + if child.node_type == 'SamplingNode': + sampling = cast(SamplingNode, child) + + # Sampling node's use NodeProp tables + # Verify the table is empty by default + assert sampling.table_data == [] + + # Set the sampling table + sampling_data = [(100000000.0, 100000000.0), (200000000.0, 200000000.0)] + sampling.table_data = sampling_data + + # Get the sampling table and verify the data was set properly + assert sampling.table_data == sampling_data + + # Now add an amplifier and set its table to test ColumnData Tables + amp = emit_app.schematic.create_component("Amplifier") + amp = cast(Amplifier, amp) + + # Verify the table is empty by default + assert amp.table_data == [] + + # Set the amplifier table + amp_data = [(2, -50.0), (3, -60.0)] + amp.table_data = amp_data + + # Get the amplifier table and verify the data was set properly + assert amp.table_data == amp_data + + # Test BB Emissions Node since it can be either a NodeProp or + # ColumnData Table + radio2 = emit_app.schematic.create_component('New Radio') + radio2 = cast(RadioNode, radio2) + + children = radio2.children + tx_spec = None + for child in children: + if child.node_type == 'Band': + band_children = child.children + for band_child in band_children: + if band_child.node_type == 'TxSpectralProfNode': + tx_spec = cast(TxSpectralProfNode, band_child) + + bb_noise = tx_spec.add_tx_broadband_noise_profile() + bb_noise = cast(TxBbEmissionNode, bb_noise) + + # verify the table is empty by default + assert bb_noise.table_data == [] + + # Set the ColumnData Table + bb_data = [(100000.0, -170.0), (100000000.0, -160.0), (200000000.0, -170.0)] + bb_noise.table_data = bb_data + + # Verify the ColumnData Table was set + assert bb_noise.table_data == bb_data + + # Change it to a NodeProp Table (Equation based) + bb_data = [("RF+10", -160), ("RF+100", -166)] + bb_noise.noise_behavior = TxBbEmissionNode.NoiseBehaviorOption.EQUATION + bb_noise.table_data = bb_data + + # Verify the NodeProp Table was set + assert bb_noise.table_data == bb_data + + @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") + def test_units(self, emit_app): + new_radio = emit_app.schematic.create_component("New Radio") + band_node = [band for band in new_radio.children if "Band" == band.node_type][0] + band_node = cast(Band, band_node) + band_node.modulation = Band.ModulationOption.MSK + band_node.bit_rate = "600 bps" + assert band_node.bit_rate == 600.0 + + band_node.bit_rate = "600 Mbps" + assert band_node.bit_rate == 600000000.0 + + band_node.stop_frequency = 2000000000 + assert band_node.stop_frequency == 2000000000.0 + + band_node.stop_frequency = "1000000000" + assert band_node.stop_frequency == 1000000000.0 + + cable = emit_app.schematic.create_component("Cable") + cable.length = "5.4681 yd" + assert round(cable.length, 4) == 5.0000 + + cable.length = "0.0031 mile" + assert round(cable.length, 4) == 4.9890 + + @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") def test_27_components_catalog(self, emit_app): comp_list = emit_app.modeler.components.components_catalog["LTE"] assert len(comp_list) == 14 assert comp_list[12].name == "LTE BTS" assert comp_list[13].name == "LTE Mobile Station" + + # test that every EMIT component can be added to the schematic + # Components_catalog returns a list in the form Library:CompName + comp_list = emit_app.modeler.components.components_catalog + + for comp in comp_list.components: + comp_to_add = comp.split(":")[1] + # try to add just based on the CompName + comp_added = emit_app.schematic.create_component(comp_to_add) + if not comp_added: + # if CompName has multiple matches, then we need to + # also specify the library + library_name = comp.split(":")[0] + comp_added = emit_app.schematic.create_component(component_type=comp_to_add, library=library_name) + + assert comp_added + + # Delete the component + emit_app.schematic.delete_component(comp_added.name) + + rev = emit_app.results.analyze() + comps_in_schematic = rev.get_all_component_nodes() + assert comps_in_schematic == 0 From 66c53a54f6e2343a0d26bde1c7ce19f953919c6f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 19:35:49 +0000 Subject: [PATCH 02/28] CHORE: Auto fixes from pre-commit hooks --- .../aedt/core/emit_core/emit_schematic.py | 28 ++++++++----------- .../aedt/core/emit_core/nodes/emit_node.py | 7 +++-- .../emit_core/nodes/generated/__init__.py | 4 +-- .../emit_core/nodes/generated/amplifier.py | 1 - .../emit_core/nodes/generated/circulator.py | 1 - .../emit_core/nodes/generated/isolator.py | 1 - .../emit_core/nodes/generated/multiplexer.py | 1 - .../nodes/generated/power_divider.py | 1 - .../nodes/generated/rx_saturation_node.py | 1 - .../nodes/generated/sampling_node.py | 1 - .../emit_core/nodes/generated/terminator.py | 3 +- .../emit_core/nodes/generated/tr_switch.py | 1 - .../emit_core/nodes/generated/waveform.py | 1 - .../aedt/core/emit_core/results/revision.py | 6 ++-- tests/system/emit/test_emit.py | 10 +++---- 15 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/emit_schematic.py b/src/ansys/aedt/core/emit_core/emit_schematic.py index 7f3ed62160d..64ee5fa1cd1 100644 --- a/src/ansys/aedt/core/emit_core/emit_schematic.py +++ b/src/ansys/aedt/core/emit_core/emit_schematic.py @@ -217,23 +217,19 @@ def connect_components(self, component_name_1: str, component_name_2: str) -> No def delete_component(self, name: str): """Delete a component from the schematic. - Parameters - ---------- - name : str - Name of the component. - - Raises - ------ - RuntimeError - If the deletion fails. - """ + Parameters + ---------- + name : str + Name of the component. + + Raises + ------ + RuntimeError + If the deletion fails. + """ try: self._emit_com_module.DeleteEmitComponent(name) - self.emit_instance.logger.info( - f"Successfully deleted component '{name}'." - ) + self.emit_instance.logger.info(f"Successfully deleted component '{name}'.") except Exception as e: - self.emit_instance.logger.error( - f"Failed to delete component '{name}': {e}" - ) + self.emit_instance.logger.error(f"Failed to delete component '{name}': {e}") raise RuntimeError(f"Failed to delete component '{name}': {e}") diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 56e95b2087d..d4ebc5714c9 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -31,6 +31,7 @@ from ansys.aedt.core.emit_core.emit_constants import data_rate_conv import ansys.aedt.core.generic.constants as consts + class EmitNode: """Emit node class for managing and interacting with EMIT nodes.""" @@ -189,7 +190,7 @@ def _get_node(self, node_id: int): # else: # type_class = ReadOnlyEmitterNode node = type_class(self._emit_obj, self._result_id, node_id) - elif node_type == 'Band' and props["IsEmitterBand"] == "true": + elif node_type == "Band" and props["IsEmitterBand"] == "true": type_class = getattr(generated, f"{prefix}Waveform") node = type_class(self._emit_obj, self._result_id, node_id) else: @@ -492,7 +493,7 @@ def _get_table_data(self): # Node Prop tables # Data formatted using compact string serialization # with ';' separating rows and '|' separating columns - table_key = self._get_property('TableKey', True) + table_key = self._get_property("TableKey", True) string_table = self._get_property(table_key, True, True) def try_float(val): @@ -526,7 +527,7 @@ def _set_table_data(self, table): # Node Prop tables # Data formatted using compact string serialization # with ';' separating rows and '|' separating columns - table_key = self._get_property('TableKey', True) + table_key = self._get_property("TableKey", True) data = ";".join("|".join(map(str, row)) for row in table) self._set_property(table_key, data) except Exception as e: diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py b/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py index 33672f9677d..190fd9de11c 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/__init__.py @@ -28,8 +28,8 @@ from .antenna_passband import AntennaPassband from .band import Band from .band_folder import BandFolder -from .cad_node import CADNode from .cable import Cable +from .cad_node import CADNode from .circulator import Circulator from .coupling_link_node import CouplingLinkNode from .couplings_node import CouplingsNode @@ -59,9 +59,9 @@ from .scene_group_node import SceneGroupNode from .solution_coupling_node import SolutionCouplingNode from .solutions_node import SolutionsNode -from .tr_switch import TR_Switch from .terminator import Terminator from .touchstone_coupling_node import TouchstoneCouplingNode +from .tr_switch import TR_Switch from .two_ray_path_loss_coupling_node import TwoRayPathLossCouplingNode from .tx_bb_emission_node import TxBbEmissionNode from .tx_harmonic_node import TxHarmonicNode diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py b/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py index c9a4957de68..8ce07129130 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/amplifier.py @@ -23,7 +23,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from enum import Enum from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py b/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py index 42c3c28b2ce..551ef188e5c 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/circulator.py @@ -241,4 +241,3 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py b/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py index d1a5da3d438..8bebfe07784 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/isolator.py @@ -241,4 +241,3 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py b/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py index 6dd8d45dd80..6225e44da75 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/multiplexer.py @@ -125,4 +125,3 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py b/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py index 724b563db4d..db5d90afb57 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/power_divider.py @@ -245,4 +245,3 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py index 86d0bc47f2c..a84a5965a7d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/rx_saturation_node.py @@ -72,4 +72,3 @@ def enabled(self) -> bool: @enabled.setter def enabled(self, value: bool): self._set_property("Enabled", f"{str(value).lower()}") - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py b/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py index 160e4099a7a..701de81f7bd 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/sampling_node.py @@ -154,4 +154,3 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py b/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py index cd68bd97e65..2e37e3f2ae8 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/terminator.py @@ -59,7 +59,7 @@ def table_data(self): Max: Value should be between 1 and 100e9. VSWR: - + """ return self._get_table_data() @@ -144,4 +144,3 @@ def warnings(self) -> str: """Warning(s) for this node.""" val = self._get_property("Warnings") return val - diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py b/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py index 821d76c638b..70fed7d32cc 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/tr_switch.py @@ -23,7 +23,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from enum import Enum from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode diff --git a/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py b/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py index 8df1cbcb85c..b9e3354c6a5 100644 --- a/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py +++ b/src/ansys/aedt/core/emit_core/nodes/generated/waveform.py @@ -433,4 +433,3 @@ def delay_skew(self) -> float: def delay_skew(self, value: float | str): value = self._convert_to_internal_units(value, "Time") self._set_property("Delay Skew", f"{value}") - diff --git a/src/ansys/aedt/core/emit_core/results/revision.py b/src/ansys/aedt/core/emit_core/results/revision.py index a1ec28cc841..2583b820a6e 100644 --- a/src/ansys/aedt/core/emit_core/results/revision.py +++ b/src/ansys/aedt/core/emit_core/results/revision.py @@ -29,8 +29,8 @@ from ansys.aedt.core.emit_core.emit_constants import ResultType from ansys.aedt.core.emit_core.emit_constants import TxRxMode from ansys.aedt.core.emit_core.nodes import generated -from ansys.aedt.core.emit_core.nodes.emitter_node import EmitterNode from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode +from ansys.aedt.core.emit_core.nodes.emitter_node import EmitterNode from ansys.aedt.core.emit_core.nodes.generated import CouplingsNode from ansys.aedt.core.emit_core.nodes.generated import EmitSceneNode from ansys.aedt.core.emit_core.nodes.generated import ResultPlotNode @@ -1017,10 +1017,10 @@ def _get_node(self, node_id: int) -> EmitNode: if node_type == "RadioNode" and props["IsEmitter"] == "true": if prefix == "": type_class = EmitterNode - #else: + # else: # type_class = ReadOnlyEmitterNode node = type_class(self.emit_project, self.results_index, node_id) - elif node_type == 'Band' and props["IsEmitterBand"] == "true": + elif node_type == "Band" and props["IsEmitterBand"] == "true": type_class = getattr(generated, f"{prefix}Waveform") node = type_class(self.emit_project, self.results_index, node_id) else: diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 562fdd48d5d..541a40ac8d3 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1811,12 +1811,12 @@ def test_fm_fsk_freq_deviation(self, emit_app): def test_tables(self, emit_app): # Emit has 2 different types of tables: Node Prop Tables and ColumnData Tables # this test confirms that the table_data properties work for both - radio = emit_app.schematic.create_component('New Radio') + radio = emit_app.schematic.create_component("New Radio") radio = cast(RadioNode, radio) children = radio.children for child in children: - if child.node_type == 'SamplingNode': + if child.node_type == "SamplingNode": sampling = cast(SamplingNode, child) # Sampling node's use NodeProp tables @@ -1846,16 +1846,16 @@ def test_tables(self, emit_app): # Test BB Emissions Node since it can be either a NodeProp or # ColumnData Table - radio2 = emit_app.schematic.create_component('New Radio') + radio2 = emit_app.schematic.create_component("New Radio") radio2 = cast(RadioNode, radio2) children = radio2.children tx_spec = None for child in children: - if child.node_type == 'Band': + if child.node_type == "Band": band_children = child.children for band_child in band_children: - if band_child.node_type == 'TxSpectralProfNode': + if band_child.node_type == "TxSpectralProfNode": tx_spec = cast(TxSpectralProfNode, band_child) bb_noise = tx_spec.add_tx_broadband_noise_profile() From a44496ed075a55c0b6a00d61fc1379eccbdb8832 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Tue, 14 Oct 2025 19:38:51 +0000 Subject: [PATCH 03/28] chore: adding changelog file 6768.fixed.md [dependabot-skip] --- doc/changelog.d/6768.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/6768.fixed.md diff --git a/doc/changelog.d/6768.fixed.md b/doc/changelog.d/6768.fixed.md new file mode 100644 index 00000000000..60ddb2585aa --- /dev/null +++ b/doc/changelog.d/6768.fixed.md @@ -0,0 +1 @@ +EMIT Pyaedt fixes From f4dbd17b1be2608fb910a980ad9d418a8e958036 Mon Sep 17 00:00:00 2001 From: jsalant Date: Wed, 15 Oct 2025 09:16:00 -0400 Subject: [PATCH 04/28] Fix codacy issues expand unit test --- .github/workflows/ci_cd.yml | 2 +- .../aedt/core/emit_core/nodes/emit_node.py | 6 +++-- .../aedt/core/emit_core/results/revision.py | 6 +++-- tests/system/emit/test_emit.py | 25 ++++++++++++++----- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 31dde9f47b5..f53c57ecb43 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -928,7 +928,7 @@ jobs: with: max_attempts: 2 retry_on: error - timeout_minutes: 20 + timeout_minutes: 30 command: | .venv\Scripts\Activate.ps1 pytest ${{ env.PYTEST_ARGUMENTS }} --timeout=600 -v -rA --color=yes -m emit diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 56e95b2087d..4e991a11e90 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -184,8 +184,10 @@ def _get_node(self, node_id: int): node = None try: if node_type == "RadioNode" and props["IsEmitter"] == "true": - if prefix == "": - type_class = EmitterNode + type_class = EmitterNode + # TODO: enable when we add ReadOnlyNodes + # if prefix == "": + # type_class = EmitterNode # else: # type_class = ReadOnlyEmitterNode node = type_class(self._emit_obj, self._result_id, node_id) diff --git a/src/ansys/aedt/core/emit_core/results/revision.py b/src/ansys/aedt/core/emit_core/results/revision.py index a1ec28cc841..7b821a481bb 100644 --- a/src/ansys/aedt/core/emit_core/results/revision.py +++ b/src/ansys/aedt/core/emit_core/results/revision.py @@ -1015,8 +1015,10 @@ def _get_node(self, node_id: int) -> EmitNode: node = None try: if node_type == "RadioNode" and props["IsEmitter"] == "true": - if prefix == "": - type_class = EmitterNode + type_class = EmitterNode + # TODO: enable when we add ReadOnlyNodes + #if prefix == "": + #type_class = EmitterNode #else: # type_class = ReadOnlyEmitterNode node = type_class(self.emit_project, self.results_index, node_id) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 562fdd48d5d..20eea3cb128 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1807,7 +1807,7 @@ def test_fm_fsk_freq_deviation(self, emit_app): band_node.freq_deviation = 1e4 assert band_node.freq_deviation == 1e4 - @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") + @pytest.mark.skipif(config["desktopVersion"] <= "2025.2", reason="Skipped on versions earlier than 2025 R2.") def test_tables(self, emit_app): # Emit has 2 different types of tables: Node Prop Tables and ColumnData Tables # this test confirms that the table_data properties work for both @@ -1915,6 +1915,10 @@ def test_27_components_catalog(self, emit_app): # Components_catalog returns a list in the form Library:CompName comp_list = emit_app.modeler.components.components_catalog + # create a default radio and antenna to use for testing connections + default_radio = emit_app.schematic.create_component("New Radio") + default_antenna = emit_app.schematic.create_component("Antenna") + for comp in comp_list.components: comp_to_add = comp.split(":")[1] # try to add just based on the CompName @@ -1923,13 +1927,22 @@ def test_27_components_catalog(self, emit_app): # if CompName has multiple matches, then we need to # also specify the library library_name = comp.split(":")[0] - comp_added = emit_app.schematic.create_component(component_type=comp_to_add, library=library_name) + try: + comp_added = emit_app.schematic.create_component(component_type=comp_to_add, library=library_name) + assert comp_added + + # connect the component + if comp_added._node_type == "AntennaNode" or comp_added._node_type == "Terminator": + emit_app.schematic.connect_components(default_radio.name, comp_added.name) + else: + emit_app.schematic.connect_components(comp_added.name, default_antenna.name) - assert comp_added + # Delete the component + emit_app.schematic.delete_component(comp_added.name) - # Delete the component - emit_app.schematic.delete_component(comp_added.name) + except Exception as e: + print(f"Failed to create component: {comp_to_add} from library {library_name}. Error: {e}") rev = emit_app.results.analyze() comps_in_schematic = rev.get_all_component_nodes() - assert comps_in_schematic == 0 + assert comps_in_schematic == 2 # default antenna/radio should remain From 6841dace2f3a3c26f1c70235f28064dd27573156 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:21:27 +0000 Subject: [PATCH 05/28] CHORE: Auto fixes from pre-commit hooks --- src/ansys/aedt/core/emit_core/results/revision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/results/revision.py b/src/ansys/aedt/core/emit_core/results/revision.py index 1d982bb62e5..51e63846388 100644 --- a/src/ansys/aedt/core/emit_core/results/revision.py +++ b/src/ansys/aedt/core/emit_core/results/revision.py @@ -1017,9 +1017,9 @@ def _get_node(self, node_id: int) -> EmitNode: if node_type == "RadioNode" and props["IsEmitter"] == "true": type_class = EmitterNode # TODO: enable when we add ReadOnlyNodes - #if prefix == "": - #type_class = EmitterNode - #else: + # if prefix == "": + # type_class = EmitterNode + # else: # type_class = ReadOnlyEmitterNode node = type_class(self.emit_project, self.results_index, node_id) elif node_type == "Band" and props["IsEmitterBand"] == "true": From 4f0d8d41688da759367d8f9407a05a83bad7744f Mon Sep 17 00:00:00 2001 From: jsalant Date: Wed, 15 Oct 2025 11:23:51 -0400 Subject: [PATCH 06/28] Update test_emit.py skip test until https://github.com/ansys/pyaedt/issues/6767 is fixed --- tests/system/emit/test_emit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 4ae744ee2af..e81fe7bd39c 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1904,7 +1904,7 @@ def test_units(self, emit_app): cable.length = "0.0031 mile" assert round(cable.length, 4) == 4.9890 - @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") + @pytest.mark.skipif(config["desktopVersion"] <= "2025.2", reason="Skipped on versions earlier than 2026 R1.") def test_27_components_catalog(self, emit_app): comp_list = emit_app.modeler.components.components_catalog["LTE"] assert len(comp_list) == 14 From 63ad4e7f6a2f5da33bfb1c7645f7ead759956cd5 Mon Sep 17 00:00:00 2001 From: jsalant Date: Thu, 16 Oct 2025 16:30:50 -0400 Subject: [PATCH 07/28] fix some unit conversions make sure data rate conversions handled correctly --- src/ansys/aedt/core/emit_core/nodes/emit_node.py | 13 +++++++++++-- tests/system/emit/test_emit.py | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 8723eeaaeea..391b0bf919a 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -326,11 +326,20 @@ def _convert_to_internal_units(self, value: float | str, unit_system: str) -> fl """ if isinstance(value, float) or isinstance(value, int): # unitless, so assume SI Units - units = consts.SI_UNITS[unit_system] + if unit_system == "Data Rate": + # Data rate isn't included as part of PyAedt's unit class + units = 'bps' + else: + units = consts.SI_UNITS[unit_system] else: value, units = self._string_to_value_units(value) + # make sure units were specified, if not use SI Units if units == "": - units = consts.SI_UNITS[unit_system] + if unit_system == "Data Rate": + # Data rate isn't included as part of PyAedt unit class + units = 'bps' + else: + units = consts.SI_UNITS[unit_system] # verify the units are valid for the specified type if units not in EMIT_VALID_UNITS[unit_system]: raise ValueError(f"{units} are not valid units for this property.") diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index e81fe7bd39c..05509902b8d 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1891,12 +1891,21 @@ def test_units(self, emit_app): band_node.bit_rate = "600 Mbps" assert band_node.bit_rate == 600000000.0 + band_node.bit_rate = 500 + assert band_node.bit_rate == 500.0 + + band_node.bit_rate = "750" + assert band_node.bit_rate == 750.0 + band_node.stop_frequency = 2000000000 assert band_node.stop_frequency == 2000000000.0 band_node.stop_frequency = "1000000000" assert band_node.stop_frequency == 1000000000.0 + band_node.start_frequency = "100 MHz" + assert band_node.start_frequency == 100000000.0 + cable = emit_app.schematic.create_component("Cable") cable.length = "5.4681 yd" assert round(cable.length, 4) == 5.0000 From fb087ea0c757ebe2f61dce6a9d3a72d5a0ae7502 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 20:32:22 +0000 Subject: [PATCH 08/28] CHORE: Auto fixes from pre-commit hooks --- src/ansys/aedt/core/emit_core/nodes/emit_node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 391b0bf919a..48b11caf47c 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -328,7 +328,7 @@ def _convert_to_internal_units(self, value: float | str, unit_system: str) -> fl # unitless, so assume SI Units if unit_system == "Data Rate": # Data rate isn't included as part of PyAedt's unit class - units = 'bps' + units = "bps" else: units = consts.SI_UNITS[unit_system] else: @@ -337,7 +337,7 @@ def _convert_to_internal_units(self, value: float | str, unit_system: str) -> fl if units == "": if unit_system == "Data Rate": # Data rate isn't included as part of PyAedt unit class - units = 'bps' + units = "bps" else: units = consts.SI_UNITS[unit_system] # verify the units are valid for the specified type From 1673c4e5a4e99e57ac28aa9a85fb35e6a66fc423 Mon Sep 17 00:00:00 2001 From: jsalant Date: Fri, 24 Oct 2025 10:01:01 -0400 Subject: [PATCH 09/28] add testing B1342786: add some more unit testing --- .../aedt/core/emit_core/nodes/emit_node.py | 18 ++- .../aedt/core/emit_core/nodes/emitter_node.py | 35 ++++- .../aedt/core/emit_core/results/revision.py | 12 +- tests/system/emit/test_emit.py | 133 +++++++++++------- 4 files changed, 137 insertions(+), 61 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 48b11caf47c..4c3792672dd 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -109,9 +109,12 @@ def _parent(self): Returns ------- EmitNode - Parent node name. + Parent node. """ - return self._get_property("Parent", True) + parent_name = self._get_property("Parent", True) + parent_name = parent_name.replace("NODE-*-", "") + node_id = self._oRevisionData.GetTopLevelNodeID(0, parent_name) + return self._get_node(node_id) @property def properties(self) -> dict: @@ -127,7 +130,7 @@ def properties(self) -> dict: return props @property - def node_warnings(self) -> str: + def warnings(self) -> str: """Warnings for the node, if any. Returns @@ -191,13 +194,16 @@ def _get_node(self, node_id: int): # type_class = EmitterNode # else: # type_class = ReadOnlyEmitterNode - node = type_class(self._emit_obj, self._result_id, node_id) elif node_type == "Band" and props["IsEmitterBand"] == "true": type_class = getattr(generated, f"{prefix}Waveform") - node = type_class(self._emit_obj, self._result_id, node_id) + elif node_type == "TxSpectralProfNode": + if self.properties['IsEmitterBand'] == 'true': + type_class = getattr(generated, f"{prefix}TxSpectralProfEmitterNode") + else: + type_class = getattr(generated, f"{prefix}TxSpectralProfNode") else: type_class = getattr(generated, f"{prefix}{node_type}") - node = type_class(self._emit_obj, self._result_id, node_id) + node = type_class(self._emit_obj, self._result_id, node_id) except AttributeError: node = EmitNode(self._emit_obj, self._result_id, node_id) return node diff --git a/src/ansys/aedt/core/emit_core/nodes/emitter_node.py b/src/ansys/aedt/core/emit_core/nodes/emitter_node.py index 28807963674..9438d45212d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emitter_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emitter_node.py @@ -26,10 +26,13 @@ from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode from ansys.aedt.core.emit_core.nodes.generated import AntennaNode +from ansys.aedt.core.emit_core.nodes.generated import Band +from ansys.aedt.core.emit_core.nodes.generated import BandFolder from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import Waveform + class EmitterNode(EmitNode): """ Provides the EmitterNode object. @@ -65,6 +68,18 @@ def __init__(self, emit_obj, result_id, node_id): ant_id = self._oRevisionData.GetChildNodeID(result_id, scene_node_id, ant) self._antenna_node = AntennaNode(emit_obj, result_id, ant_id) + def node_type(self) -> str: + """The type of this emit node""" + return "EmitterNode" + + def duplicate(self, new_name: str): + """Duplicate this node""" + return self._duplicate(new_name) + + def delete(self): + """Delete this node""" + self._delete() + def get_radio(self) -> RadioNode: """Get the radio associated with this Emitter. @@ -93,6 +108,20 @@ def get_antenna(self) -> AntennaNode: """ return self._antenna_node + def children(self): + """Overridden to return the Waveforms + + Returns + ------- + waveforms: list[Waveform] + list of waveform nodes defined for the Emitter. + + Examples + -------- + >>> waveforms = emitter.get_waveforms() + """ + return self.get_waveforms() + def get_waveforms(self) -> list[Waveform]: """Get the waveform nodes for the Emitter. @@ -110,12 +139,12 @@ def get_waveforms(self) -> list[Waveform]: waveforms = [] # check for folders and recurse them if needed for child in radio_children: - if child.type == "BandFolder": + if isinstance(child, BandFolder): grandchildren = child.children for grandchild in grandchildren: - # don't allow nested folders, so can add these + # we don't allow nested folders, so can add these # directly to the waveform list waveforms.append(cast(Waveform, grandchild)) - elif child.type == "Band": + elif isinstance(child, Waveform): waveforms.append(cast(Waveform, child)) return waveforms diff --git a/src/ansys/aedt/core/emit_core/results/revision.py b/src/ansys/aedt/core/emit_core/results/revision.py index 51e63846388..5cb278efd0b 100644 --- a/src/ansys/aedt/core/emit_core/results/revision.py +++ b/src/ansys/aedt/core/emit_core/results/revision.py @@ -34,6 +34,7 @@ from ansys.aedt.core.emit_core.nodes.generated import CouplingsNode from ansys.aedt.core.emit_core.nodes.generated import EmitSceneNode from ansys.aedt.core.emit_core.nodes.generated import ResultPlotNode +from ansys.aedt.core.emit_core.nodes.generated import Waveform from ansys.aedt.core.generic.general_methods import pyaedt_function_handler from ansys.aedt.core.internal.checks import min_aedt_version @@ -1021,13 +1022,18 @@ def _get_node(self, node_id: int) -> EmitNode: # type_class = EmitterNode # else: # type_class = ReadOnlyEmitterNode - node = type_class(self.emit_project, self.results_index, node_id) elif node_type == "Band" and props["IsEmitterBand"] == "true": type_class = getattr(generated, f"{prefix}Waveform") - node = type_class(self.emit_project, self.results_index, node_id) + elif node_type == "TxSpectralProfNode": + parent_name = props["Parent"] + parent_name = parent_name.replace("NODE-*-", "") + node_id = self._emit_com.GetTopLevelNodeID(0, parent_name) + parent_node = self._get_node(node_id) + if isinstance(parent_node, Waveform): + type_class = getattr(generated, f"{prefix}TxSpectralProfEmitterNode") else: type_class = getattr(generated, f"{prefix}{node_type}") - node = type_class(self.emit_project, self.results_index, node_id) + node = type_class(self.emit_project, self.results_index, node_id) except AttributeError: node = EmitNode(self.emit_project, self.results_index, node_id) return node diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 05509902b8d..1c96b1ee8aa 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -52,13 +52,17 @@ from ansys.aedt.core.emit_core.emit_constants import TxRxMode from ansys.aedt.core.emit_core.nodes import generated from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode + from ansys.aedt.core.emit_core.nodes.emitter_node import EmitterNode from ansys.aedt.core.emit_core.nodes.generated import Amplifier + from ansys.aedt.core.emit_core.nodes.generated import AntennaNode from ansys.aedt.core.emit_core.nodes.generated import Band from ansys.aedt.core.emit_core.nodes.generated import Filter from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import SamplingNode from ansys.aedt.core.emit_core.nodes.generated import TxBbEmissionNode from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfNode + from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfEmitterNode + from ansys.aedt.core.emit_core.nodes.generated import Waveform from ansys.aedt.core.modeler.circuits.primitives_emit import EmitAntennaComponent from ansys.aedt.core.modeler.circuits.primitives_emit import EmitComponent from ansys.aedt.core.modeler.circuits.primitives_emit import EmitComponents @@ -1807,7 +1811,7 @@ def test_fm_fsk_freq_deviation(self, emit_app): band_node.freq_deviation = 1e4 assert band_node.freq_deviation == 1e4 - @pytest.mark.skipif(config["desktopVersion"] <= "2025.2", reason="Skipped on versions earlier than 2025 R2.") + @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") def test_tables(self, emit_app): # Emit has 2 different types of tables: Node Prop Tables and ColumnData Tables # this test confirms that the table_data properties work for both @@ -1844,40 +1848,71 @@ def test_tables(self, emit_app): # Get the amplifier table and verify the data was set properly assert amp.table_data == amp_data - # Test BB Emissions Node since it can be either a NodeProp or - # ColumnData Table - radio2 = emit_app.schematic.create_component("New Radio") - radio2 = cast(RadioNode, radio2) + if config["desktopVersion"] < "2026.1": + # Test BB Emissions Node since it can be either a NodeProp or + # ColumnData Table + radio2 = emit_app.schematic.create_component("New Radio") + radio2 = cast(RadioNode, radio2) - children = radio2.children - tx_spec = None - for child in children: - if child.node_type == "Band": - band_children = child.children - for band_child in band_children: - if band_child.node_type == "TxSpectralProfNode": - tx_spec = cast(TxSpectralProfNode, band_child) + children = radio2.children + tx_spec = None + for child in children: + if child.node_type == "Band": + band_children = child.children + for band_child in band_children: + if band_child.node_type == "TxSpectralProfNode": + tx_spec = cast(TxSpectralProfNode, band_child) + + bb_noise = tx_spec.add_tx_broadband_noise_profile() + bb_noise = cast(TxBbEmissionNode, bb_noise) + + # verify the table is empty by default + assert bb_noise.table_data == [] + + # Set the ColumnData Table + bb_data = [(100000.0, -170.0), (100000000.0, -160.0), (200000000.0, -170.0)] + bb_noise.table_data = bb_data + + # Verify the ColumnData Table was set + assert bb_noise.table_data == bb_data + + # Change it to a NodeProp Table (Equation based) + bb_data = [("RF+10", -160), ("RF+100", -166)] + bb_noise.noise_behavior = TxBbEmissionNode.NoiseBehaviorOption.EQUATION + bb_noise.table_data = bb_data + + # Verify the NodeProp Table was set + assert bb_noise.table_data == bb_data - bb_noise = tx_spec.add_tx_broadband_noise_profile() - bb_noise = cast(TxBbEmissionNode, bb_noise) + @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") + def test_emitters_radios(self, emit_app): + emitter_node: EmitterNode = emit_app.schematic.create_component("New Emitter", "Emitters") + + # Test that you can get the emitter's radio and antenna nodes + emitter_radio: RadioNode = emitter_node.get_radio() + assert isinstance(emitter_radio, RadioNode) + + emitter_ant: AntennaNode = emitter_node.get_antenna() + assert isinstance(emitter_ant, AntennaNode) + + emitter_band: Waveform = emitter_node.get_waveforms()[0] + assert emitter_band.warnings == "" + + assert emitter_node.children() == emitter_node.get_waveforms() - # verify the table is empty by default - assert bb_noise.table_data == [] + emitter_band.waveform = Waveform.WaveformOption.PRBS + assert emitter_band.waveform == Waveform.WaveformOption.PRBS - # Set the ColumnData Table - bb_data = [(100000.0, -170.0), (100000000.0, -160.0), (200000000.0, -170.0)] - bb_noise.table_data = bb_data + tx_spec: TxSpectralProfEmitterNode = emitter_band.children[0] + assert isinstance(tx_spec, TxSpectralProfEmitterNode) - # Verify the ColumnData Table was set - assert bb_noise.table_data == bb_data + radio_node: RadioNode = emit_app.schematic.create_component("New Radio", "Radios") - # Change it to a NodeProp Table (Equation based) - bb_data = [("RF+10", -160), ("RF+100", -166)] - bb_noise.noise_behavior = TxBbEmissionNode.NoiseBehaviorOption.EQUATION - bb_noise.table_data = bb_data + band: Band = radio_node.children[0] + assert isinstance(band, Band) - # Verify the NodeProp Table was set - assert bb_noise.table_data == bb_data + radio_tx_spec: TxSpectralProfNode = band.children[0] + assert isinstance(radio_tx_spec, TxSpectralProfNode) @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") def test_units(self, emit_app): @@ -1913,7 +1948,7 @@ def test_units(self, emit_app): cable.length = "0.0031 mile" assert round(cable.length, 4) == 4.9890 - @pytest.mark.skipif(config["desktopVersion"] <= "2025.2", reason="Skipped on versions earlier than 2026 R1.") + @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2026 R1.") def test_27_components_catalog(self, emit_app): comp_list = emit_app.modeler.components.components_catalog["LTE"] assert len(comp_list) == 14 @@ -1929,28 +1964,28 @@ def test_27_components_catalog(self, emit_app): default_antenna = emit_app.schematic.create_component("Antenna") for comp in comp_list.components: + library_name = comp.split(":")[0] comp_to_add = comp.split(":")[1] # try to add just based on the CompName - comp_added = emit_app.schematic.create_component(comp_to_add) - if not comp_added: - # if CompName has multiple matches, then we need to - # also specify the library - library_name = comp.split(":")[0] - try: - comp_added = emit_app.schematic.create_component(component_type=comp_to_add, library=library_name) - assert comp_added - - # connect the component - if comp_added._node_type == "AntennaNode" or comp_added._node_type == "Terminator": - emit_app.schematic.connect_components(default_radio.name, comp_added.name) - else: - emit_app.schematic.connect_components(comp_added.name, default_antenna.name) - - # Delete the component - emit_app.schematic.delete_component(comp_added.name) - - except Exception as e: - print(f"Failed to create component: {comp_to_add} from library {library_name}. Error: {e}") + try: + comp_added = emit_app.schematic.create_component(component_type=comp_to_add, library=library_name) + assert comp_added + + # connect the component + if comp_added.node_type == "EmitterNode": + # can't connect Emitters since they have no ports + continue + elif comp_added._node_type == "AntennaNode" or comp_added._node_type == "Terminator": + emit_app.schematic.connect_components(default_radio.name, comp_added.name) + else: + emit_app.schematic.connect_components(comp_added.name, default_antenna.name) + + # Delete the component + print(comp_added.name) + emit_app.schematic.delete_component(comp_added.name) + + except Exception as e: + print(f"Failed to create component: {comp_to_add} from library {library_name}. Error: {e}") rev = emit_app.results.analyze() comps_in_schematic = rev.get_all_component_nodes() From 65c09c271d1583a531255240ed522fa8340f2a6b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:02:14 +0000 Subject: [PATCH 10/28] CHORE: Auto fixes from pre-commit hooks --- src/ansys/aedt/core/emit_core/nodes/emit_node.py | 2 +- src/ansys/aedt/core/emit_core/nodes/emitter_node.py | 2 -- tests/system/emit/test_emit.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 4c3792672dd..d5441f56240 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -197,7 +197,7 @@ def _get_node(self, node_id: int): elif node_type == "Band" and props["IsEmitterBand"] == "true": type_class = getattr(generated, f"{prefix}Waveform") elif node_type == "TxSpectralProfNode": - if self.properties['IsEmitterBand'] == 'true': + if self.properties["IsEmitterBand"] == "true": type_class = getattr(generated, f"{prefix}TxSpectralProfEmitterNode") else: type_class = getattr(generated, f"{prefix}TxSpectralProfNode") diff --git a/src/ansys/aedt/core/emit_core/nodes/emitter_node.py b/src/ansys/aedt/core/emit_core/nodes/emitter_node.py index 9438d45212d..f6d8c6cd80d 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emitter_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emitter_node.py @@ -26,13 +26,11 @@ from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode from ansys.aedt.core.emit_core.nodes.generated import AntennaNode -from ansys.aedt.core.emit_core.nodes.generated import Band from ansys.aedt.core.emit_core.nodes.generated import BandFolder from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import Waveform - class EmitterNode(EmitNode): """ Provides the EmitterNode object. diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 1c96b1ee8aa..ea1a3d635a9 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -60,8 +60,8 @@ from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import SamplingNode from ansys.aedt.core.emit_core.nodes.generated import TxBbEmissionNode - from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfNode from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfEmitterNode + from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfNode from ansys.aedt.core.emit_core.nodes.generated import Waveform from ansys.aedt.core.modeler.circuits.primitives_emit import EmitAntennaComponent from ansys.aedt.core.modeler.circuits.primitives_emit import EmitComponent From 5cff9b114358ca9793332cb929d468cc46576c8b Mon Sep 17 00:00:00 2001 From: jsalant Date: Fri, 24 Oct 2025 10:06:21 -0400 Subject: [PATCH 11/28] fix test --- tests/system/emit/test_emit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 1c96b1ee8aa..bd10a74fa32 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1848,7 +1848,7 @@ def test_tables(self, emit_app): # Get the amplifier table and verify the data was set properly assert amp.table_data == amp_data - if config["desktopVersion"] < "2026.1": + if config["desktopVersion"] >= "2026.1": # Test BB Emissions Node since it can be either a NodeProp or # ColumnData Table radio2 = emit_app.schematic.create_component("New Radio") From 867077136ae3c7fc2f027ee97220d9a99613bf58 Mon Sep 17 00:00:00 2001 From: jsalant Date: Fri, 24 Oct 2025 14:53:22 -0400 Subject: [PATCH 12/28] fix test --- src/ansys/aedt/core/emit_core/nodes/emit_node.py | 1 + src/ansys/aedt/core/emit_core/results/revision.py | 1 + tests/system/emit/test_emit.py | 8 +++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index d5441f56240..06b9c6c8b20 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -187,6 +187,7 @@ def _get_node(self, node_id: int): node = None try: + type_class = EmitNode if node_type == "RadioNode" and props["IsEmitter"] == "true": type_class = EmitterNode # TODO: enable when we add ReadOnlyNodes diff --git a/src/ansys/aedt/core/emit_core/results/revision.py b/src/ansys/aedt/core/emit_core/results/revision.py index 5cb278efd0b..9f59b5c8a55 100644 --- a/src/ansys/aedt/core/emit_core/results/revision.py +++ b/src/ansys/aedt/core/emit_core/results/revision.py @@ -1015,6 +1015,7 @@ def _get_node(self, node_id: int) -> EmitNode: node = None try: + type_class = EmitNode if node_type == "RadioNode" and props["IsEmitter"] == "true": type_class = EmitterNode # TODO: enable when we add ReadOnlyNodes diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 3bc63bfd162..671483413ff 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -59,6 +59,7 @@ from ansys.aedt.core.emit_core.nodes.generated import Filter from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import SamplingNode + from ansys.aedt.core.emit_core.nodes.generated import Terminator from ansys.aedt.core.emit_core.nodes.generated import TxBbEmissionNode from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfEmitterNode from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfNode @@ -1948,7 +1949,7 @@ def test_units(self, emit_app): cable.length = "0.0031 mile" assert round(cable.length, 4) == 4.9890 - @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2026 R1.") + @pytest.mark.skipif(config["desktopVersion"] < "2026.1", reason="Skipped on versions earlier than 2026 R1.") def test_27_components_catalog(self, emit_app): comp_list = emit_app.modeler.components.components_catalog["LTE"] assert len(comp_list) == 14 @@ -1972,10 +1973,11 @@ def test_27_components_catalog(self, emit_app): assert comp_added # connect the component - if comp_added.node_type == "EmitterNode": + if isinstance(comp_added, EmitterNode): # can't connect Emitters since they have no ports + emit_app.schematic.delete_component(comp_added.name) continue - elif comp_added._node_type == "AntennaNode" or comp_added._node_type == "Terminator": + elif isinstance(comp_added, AntennaNode) or isinstance(comp_added, Terminator): emit_app.schematic.connect_components(default_radio.name, comp_added.name) else: emit_app.schematic.connect_components(comp_added.name, default_antenna.name) From a1fc145cfbb3877ac232b58e38e02139e8232ed7 Mon Sep 17 00:00:00 2001 From: jsalant Date: Fri, 24 Oct 2025 15:41:30 -0400 Subject: [PATCH 13/28] fix test --- tests/system/emit/test_emit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 671483413ff..b35036464c2 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1949,7 +1949,7 @@ def test_units(self, emit_app): cable.length = "0.0031 mile" assert round(cable.length, 4) == 4.9890 - @pytest.mark.skipif(config["desktopVersion"] < "2026.1", reason="Skipped on versions earlier than 2026 R1.") + @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2026 R1.") def test_27_components_catalog(self, emit_app): comp_list = emit_app.modeler.components.components_catalog["LTE"] assert len(comp_list) == 14 @@ -1991,4 +1991,4 @@ def test_27_components_catalog(self, emit_app): rev = emit_app.results.analyze() comps_in_schematic = rev.get_all_component_nodes() - assert comps_in_schematic == 2 # default antenna/radio should remain + assert len(comps_in_schematic) == 2 # default antenna/radio should remain From a6aee83a0b2fbfc548badec99978c536fda9407c Mon Sep 17 00:00:00 2001 From: jsalant Date: Fri, 24 Oct 2025 17:40:52 -0400 Subject: [PATCH 14/28] test fix --- tests/system/emit/test_emit.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index b35036464c2..a3717e183f3 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -598,10 +598,8 @@ def get_sampling_node(rad_name): sampling = get_sampling_node(rad3.name) mode_rx = TxRxMode.RX - assert ( - sampling.parent + "-*-" + sampling.name - == "NODE-*-RF Systems-*-Bluetooth 2-*-Radios-*-Bluetooth 2-*-Sampling" - ) + assert sampling.parent.name + "-*-" + sampling.name == "Bluetooth 2-*-Sampling" + sampling.specify_percentage = True sampling.percentage_of_channels = 25 rev = emit_app.results.analyze() @@ -1949,7 +1947,7 @@ def test_units(self, emit_app): cable.length = "0.0031 mile" assert round(cable.length, 4) == 4.9890 - @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2026 R1.") + @pytest.mark.skipif(config["desktopVersion"] < "2026.1", reason="Skipped on versions earlier than 2026 R1.") def test_27_components_catalog(self, emit_app): comp_list = emit_app.modeler.components.components_catalog["LTE"] assert len(comp_list) == 14 From c800dcf46243495d954c865b7f1766037fcaaff6 Mon Sep 17 00:00:00 2001 From: jsalant Date: Sat, 25 Oct 2025 12:21:35 -0400 Subject: [PATCH 15/28] add some more test coverage --- tests/system/emit/test_emit.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index a3717e183f3..9c52c2bc0d0 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1913,6 +1913,16 @@ def test_emitters_radios(self, emit_app): radio_tx_spec: TxSpectralProfNode = band.children[0] assert isinstance(radio_tx_spec, TxSpectralProfNode) + emit_app.schematic.delete_component(radio_node.name) + emit_app.schematic.delete_component(emitter_node.name) + + try: + emit_app.schematic.delete_component("Dummy Comp") + except Exception as e: + rev = emit_app.results.analyze() + comps_in_schematic = rev.get_all_component_nodes() + assert len(comps_in_schematic) == 0 + @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") def test_units(self, emit_app): new_radio = emit_app.schematic.create_component("New Radio") @@ -1940,6 +1950,9 @@ def test_units(self, emit_app): band_node.start_frequency = "100 MHz" assert band_node.start_frequency == 100000000.0 + band_node.start_frequency = "200MHz" + assert band_node.start_frequency == 200000000.0 + cable = emit_app.schematic.create_component("Cable") cable.length = "5.4681 yd" assert round(cable.length, 4) == 5.0000 From c548bd6fc7948c2b078cc440ab2407e204ff092b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 17:20:44 +0000 Subject: [PATCH 16/28] CHORE: Auto fixes from pre-commit hooks --- tests/system/emit/test_emit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 9c52c2bc0d0..9013588ecb5 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1918,7 +1918,7 @@ def test_emitters_radios(self, emit_app): try: emit_app.schematic.delete_component("Dummy Comp") - except Exception as e: + except Exception: rev = emit_app.results.analyze() comps_in_schematic = rev.get_all_component_nodes() assert len(comps_in_schematic) == 0 From cbae46eaa3568cab74d2164798b3fe2822709b86 Mon Sep 17 00:00:00 2001 From: jsalant Date: Sat, 25 Oct 2025 13:22:19 -0400 Subject: [PATCH 17/28] data rate test --- tests/system/emit/test_emit.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 9c52c2bc0d0..0823b0636b7 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1932,9 +1932,15 @@ def test_units(self, emit_app): band_node.bit_rate = "600 bps" assert band_node.bit_rate == 600.0 + band_node.bit_rate = "600 kbps" + assert band_node.bit_rate == 600000.0 + band_node.bit_rate = "600 Mbps" assert band_node.bit_rate == 600000000.0 + band_node.bit_rate = "600 Gbps" + assert band_node.bit_rate == 600000000000.0 + band_node.bit_rate = 500 assert band_node.bit_rate == 500.0 From 9fcd3c019c58e868de8138dcd0514fb1c967b375 Mon Sep 17 00:00:00 2001 From: jsalant Date: Sat, 25 Oct 2025 17:01:52 -0400 Subject: [PATCH 18/28] switch error to AEDTRuntimeError --- src/ansys/aedt/core/emit_core/emit_schematic.py | 4 ++-- tests/system/emit/test_emit.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/emit_schematic.py b/src/ansys/aedt/core/emit_core/emit_schematic.py index 64ee5fa1cd1..6eace68423d 100644 --- a/src/ansys/aedt/core/emit_core/emit_schematic.py +++ b/src/ansys/aedt/core/emit_core/emit_schematic.py @@ -25,7 +25,7 @@ from ansys.aedt.core.emit_core.nodes.emit_node import EmitNode from ansys.aedt.core.generic.general_methods import pyaedt_function_handler - +from ansys.aedt.core.internal.errors import AEDTRuntimeError class EmitSchematic: """Represents the EMIT schematic and provides methods to interact with it.""" @@ -232,4 +232,4 @@ def delete_component(self, name: str): self.emit_instance.logger.info(f"Successfully deleted component '{name}'.") except Exception as e: self.emit_instance.logger.error(f"Failed to delete component '{name}': {e}") - raise RuntimeError(f"Failed to delete component '{name}': {e}") + raise AEDTRuntimeError(f"Failed to delete component '{name}': {e}") diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index d123074d9b8..a043029f977 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1918,7 +1918,7 @@ def test_emitters_radios(self, emit_app): try: emit_app.schematic.delete_component("Dummy Comp") - except Exception: + except RuntimeError: rev = emit_app.results.analyze() comps_in_schematic = rev.get_all_component_nodes() assert len(comps_in_schematic) == 0 From 4f8524756a1f34a313dd619a57bf7550fddec37c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 21:02:43 +0000 Subject: [PATCH 19/28] CHORE: Auto fixes from pre-commit hooks --- src/ansys/aedt/core/emit_core/emit_schematic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/aedt/core/emit_core/emit_schematic.py b/src/ansys/aedt/core/emit_core/emit_schematic.py index 6eace68423d..bb4b4b3a057 100644 --- a/src/ansys/aedt/core/emit_core/emit_schematic.py +++ b/src/ansys/aedt/core/emit_core/emit_schematic.py @@ -27,6 +27,7 @@ from ansys.aedt.core.generic.general_methods import pyaedt_function_handler from ansys.aedt.core.internal.errors import AEDTRuntimeError + class EmitSchematic: """Represents the EMIT schematic and provides methods to interact with it.""" From 81f42a2b4a8533bea82994f3dd24bc12f0278052 Mon Sep 17 00:00:00 2001 From: jsalant Date: Sun, 26 Oct 2025 07:39:52 -0400 Subject: [PATCH 20/28] fix test --- tests/system/emit/test_emit.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index a043029f977..c2210fea3c9 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1886,6 +1886,7 @@ def test_tables(self, emit_app): @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") def test_emitters_radios(self, emit_app): emitter_node: EmitterNode = emit_app.schematic.create_component("New Emitter", "Emitters") + emitter_id = emitter_node._node_id # Test that you can get the emitter's radio and antenna nodes emitter_radio: RadioNode = emitter_node.get_radio() @@ -1914,12 +1915,15 @@ def test_emitters_radios(self, emit_app): assert isinstance(radio_tx_spec, TxSpectralProfNode) emit_app.schematic.delete_component(radio_node.name) + # the next two lines are only needed for 25.2, which had + # some instability in maintaining the node_ids + rev = emit_app.results.analyze() + emitter_node = rev._get_node(emitter_id) emit_app.schematic.delete_component(emitter_node.name) try: emit_app.schematic.delete_component("Dummy Comp") except RuntimeError: - rev = emit_app.results.analyze() comps_in_schematic = rev.get_all_component_nodes() assert len(comps_in_schematic) == 0 From 7fb7589d6d333388d4cb15ae06d1d4b93658df60 Mon Sep 17 00:00:00 2001 From: jsalant Date: Sun, 26 Oct 2025 12:32:24 -0400 Subject: [PATCH 21/28] fix test --- tests/system/emit/test_emit.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index c2210fea3c9..f1f0ac0c35d 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1885,8 +1885,10 @@ def test_tables(self, emit_app): @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") def test_emitters_radios(self, emit_app): - emitter_node: EmitterNode = emit_app.schematic.create_component("New Emitter", "Emitters") - emitter_id = emitter_node._node_id + emitter_name = "Test Emitter" + emitter_node: EmitterNode = emit_app.schematic.create_component(name=emitter_name, + component_type="New Emitter", + library="Emitters") # Test that you can get the emitter's radio and antenna nodes emitter_radio: RadioNode = emitter_node.get_radio() @@ -1918,7 +1920,7 @@ def test_emitters_radios(self, emit_app): # the next two lines are only needed for 25.2, which had # some instability in maintaining the node_ids rev = emit_app.results.analyze() - emitter_node = rev._get_node(emitter_id) + emitter_node = rev.get_component_node(emitter_name) emit_app.schematic.delete_component(emitter_node.name) try: From 008386ce11e9381c7850b6ab53024e2b21aedd9a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 26 Oct 2025 16:33:21 +0000 Subject: [PATCH 22/28] CHORE: Auto fixes from pre-commit hooks --- tests/system/emit/test_emit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index f1f0ac0c35d..cb5f1f65d7d 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1886,9 +1886,9 @@ def test_tables(self, emit_app): @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") def test_emitters_radios(self, emit_app): emitter_name = "Test Emitter" - emitter_node: EmitterNode = emit_app.schematic.create_component(name=emitter_name, - component_type="New Emitter", - library="Emitters") + emitter_node: EmitterNode = emit_app.schematic.create_component( + name=emitter_name, component_type="New Emitter", library="Emitters" + ) # Test that you can get the emitter's radio and antenna nodes emitter_radio: RadioNode = emitter_node.get_radio() From 415f70b26347f567f2f2c98cf8b45342e9518c24 Mon Sep 17 00:00:00 2001 From: jsalant Date: Sun, 26 Oct 2025 16:12:38 -0400 Subject: [PATCH 23/28] fix test --- tests/system/emit/test_emit.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index f1f0ac0c35d..7c239d410a5 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1926,8 +1926,7 @@ def test_emitters_radios(self, emit_app): try: emit_app.schematic.delete_component("Dummy Comp") except RuntimeError: - comps_in_schematic = rev.get_all_component_nodes() - assert len(comps_in_schematic) == 0 + print("Invalid component can't be deleted.") @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") def test_units(self, emit_app): From ee89ba6831759541654c28b9f7bc9968fae8fe2d Mon Sep 17 00:00:00 2001 From: jsalant Date: Mon, 27 Oct 2025 08:30:08 -0400 Subject: [PATCH 24/28] cleanup a comment and add some more test coverage --- .../aedt/core/emit_core/nodes/emit_node.py | 2 +- tests/system/emit/test_emit.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 06b9c6c8b20..0e8ddb7ed70 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -559,7 +559,7 @@ def _add_child_node(self, child_type, child_name=None): child_type : EmitNode Type of child node to create. child_name : str, optional - Optional name to use for the child node. If None, a default name is used. + Name to use for the child node. If None, a default name is used. Returns ------- diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 588c2bec6a3..2a04d123993 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -60,9 +60,17 @@ from ansys.aedt.core.emit_core.nodes.generated import RadioNode from ansys.aedt.core.emit_core.nodes.generated import SamplingNode from ansys.aedt.core.emit_core.nodes.generated import Terminator + from ansys.aedt.core.emit_core.nodes.generated import RxMixerProductNode + from ansys.aedt.core.emit_core.nodes.generated import RxSaturationNode + from ansys.aedt.core.emit_core.nodes.generated import RxSelectivityNode + from ansys.aedt.core.emit_core.nodes.generated import RxSusceptibilityProfNode + from ansys.aedt.core.emit_core.nodes.generated import RxSpurNode from ansys.aedt.core.emit_core.nodes.generated import TxBbEmissionNode + from ansys.aedt.core.emit_core.nodes.generated import TxHarmonicNode + from ansys.aedt.core.emit_core.nodes.generated import TxNbEmissionNode from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfEmitterNode from ansys.aedt.core.emit_core.nodes.generated import TxSpectralProfNode + from ansys.aedt.core.emit_core.nodes.generated import TxSpurNode from ansys.aedt.core.emit_core.nodes.generated import Waveform from ansys.aedt.core.modeler.circuits.primitives_emit import EmitAntennaComponent from ansys.aedt.core.modeler.circuits.primitives_emit import EmitComponent @@ -1916,6 +1924,44 @@ def test_emitters_radios(self, emit_app): radio_tx_spec: TxSpectralProfNode = band.children[0] assert isinstance(radio_tx_spec, TxSpectralProfNode) + radio_rx_spec: RxSusceptibilityProfNode = band.children[1] + assert isinstance(radio_rx_spec, RxSusceptibilityProfNode) + + # test the Tx Spectral Profile child nodes + radio_harmonics: TxHarmonicNode = radio_tx_spec.add_custom_tx_harmonics() + assert isinstance(radio_harmonics, TxHarmonicNode) + assert len(radio_harmonics.table_data) == 0 + + radio_bb_noise: TxBbEmissionNode = radio_tx_spec.add_tx_broadband_noise_profile() + assert isinstance(radio_bb_noise, TxBbEmissionNode) + assert len(radio_bb_noise.table_data) == 0 + + radio_nb_emissions: TxNbEmissionNode = radio_tx_spec.add_narrowband_emissions_mask() + assert isinstance(radio_nb_emissions, TxNbEmissionNode) + assert len(radio_nb_emissions.table_data) == 0 + + radio_tx_spur: TxSpurNode = radio_tx_spec.add_spurious_emissions() + assert isinstance(radio_tx_spur, TxSpurNode) + assert len(radio_tx_spur.table_data) == 0 + + # test the Rx Spectral Profile child nodes + radio_saturation: RxSaturationNode = radio_rx_spec.add_rx_saturation() + assert isinstance(radio_saturation, RxSaturationNode) + assert len(radio_saturation.table_data) == 0 + + radio_selectivity: RxSelectivityNode = radio_rx_spec.add_rx_selectivity() + assert isinstance(radio_selectivity, RxSelectivityNode) + assert len(radio_selectivity.table_data) == 0 + + radio_mixer_products: RxMixerProductNode = radio_rx_spec.add_mixer_products() + assert isinstance(radio_mixer_products, RxMixerProductNode) + assert len(radio_mixer_products.table_data) == 0 + + radio_rx_spurs: RxSpurNode = radio_rx_spec.add_spurious_responses() + assert isinstance(radio_rx_spurs, RxSpurNode) + assert len(radio_rx_spurs.table_data) == 0 + + # Test deleting components emit_app.schematic.delete_component(radio_node.name) # the next two lines are only needed for 25.2, which had # some instability in maintaining the node_ids From 1a250630bd4fb2b5d70a04723d94c698a8a3c3d4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:31:13 +0000 Subject: [PATCH 25/28] CHORE: Auto fixes from pre-commit hooks --- tests/system/emit/test_emit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 2a04d123993..500feb3fb62 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -58,13 +58,13 @@ from ansys.aedt.core.emit_core.nodes.generated import Band from ansys.aedt.core.emit_core.nodes.generated import Filter from ansys.aedt.core.emit_core.nodes.generated import RadioNode - from ansys.aedt.core.emit_core.nodes.generated import SamplingNode - from ansys.aedt.core.emit_core.nodes.generated import Terminator from ansys.aedt.core.emit_core.nodes.generated import RxMixerProductNode from ansys.aedt.core.emit_core.nodes.generated import RxSaturationNode from ansys.aedt.core.emit_core.nodes.generated import RxSelectivityNode - from ansys.aedt.core.emit_core.nodes.generated import RxSusceptibilityProfNode from ansys.aedt.core.emit_core.nodes.generated import RxSpurNode + from ansys.aedt.core.emit_core.nodes.generated import RxSusceptibilityProfNode + from ansys.aedt.core.emit_core.nodes.generated import SamplingNode + from ansys.aedt.core.emit_core.nodes.generated import Terminator from ansys.aedt.core.emit_core.nodes.generated import TxBbEmissionNode from ansys.aedt.core.emit_core.nodes.generated import TxHarmonicNode from ansys.aedt.core.emit_core.nodes.generated import TxNbEmissionNode From cde2fb0183172105ad9f6ba304a9223905692742 Mon Sep 17 00:00:00 2001 From: jsalant Date: Mon, 27 Oct 2025 11:32:24 -0400 Subject: [PATCH 26/28] add some exception testing --- tests/system/emit/test_emit.py | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/system/emit/test_emit.py b/tests/system/emit/test_emit.py index 2a04d123993..fa8b9529013 100644 --- a/tests/system/emit/test_emit.py +++ b/tests/system/emit/test_emit.py @@ -1974,6 +1974,41 @@ def test_emitters_radios(self, emit_app): except RuntimeError: print("Invalid component can't be deleted.") + @pytest.mark.skipif(config["desktopVersion"] < "2025.2", reason="Skipped on versions earlier than 2025 R2.") + def test_exceptions(self, emit_app): + radio: RadioNode = emit_app.schematic.create_component("New Radio", "Radios") + + try: + radio._get_node(-1) + except Exception as e: + print(f"Invalid {e}") + + try: + radio._set_property("Bad Prop", "Bad Val") + except Exception as e: + print(f"Error: {e}") + + try: + radio._get_property("Bad Prop") + except Exception as e: + print(f"Error: {e}") + + band: Band = radio.children[0] + try: + band.start_frequency = "100 Gbps" + except Exception as e: + print(f"Invalid units: {e}") + + try: + radio._get_child_node_id("Bad Node Name") + except Exception as e: + print(f"Invalid child node name: {e}") + + try: + radio._add_child_node("Bad Type") + except Exception as e: + print(f"Invalid child type: {e}") + @pytest.mark.skipif(config["desktopVersion"] <= "2025.1", reason="Skipped on versions earlier than 2026 R1.") def test_units(self, emit_app): new_radio = emit_app.schematic.create_component("New Radio") From 0261f136e3e597efb4a9a14038b2f158cab7724f Mon Sep 17 00:00:00 2001 From: jsalant Date: Mon, 27 Oct 2025 12:51:59 -0400 Subject: [PATCH 27/28] deprecate a prop instead of removing it --- .../aedt/core/emit_core/nodes/emit_node.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 0e8ddb7ed70..484262cb762 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -129,6 +129,25 @@ def properties(self) -> dict: props = self.props_to_dict(props) return props + @property + def node_warnings(self) -> str: + """Warnings for the node, if any. + + .. deprecated: 0.21.3 + Use warnings property instead + + Returns + ------- + str + Warning message(s). + """ + warnings.warn( + "This property is deprecated in 0.21.3. Use the warnings property instead.", + DeprecationWarning + ) + + return self.warnings + @property def warnings(self) -> str: """Warnings for the node, if any. From 6e7e202c905b91b0dd552d759f5f07ac39faf59c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:52:47 +0000 Subject: [PATCH 28/28] CHORE: Auto fixes from pre-commit hooks --- src/ansys/aedt/core/emit_core/nodes/emit_node.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ansys/aedt/core/emit_core/nodes/emit_node.py b/src/ansys/aedt/core/emit_core/nodes/emit_node.py index 484262cb762..23ceb444695 100644 --- a/src/ansys/aedt/core/emit_core/nodes/emit_node.py +++ b/src/ansys/aedt/core/emit_core/nodes/emit_node.py @@ -141,10 +141,7 @@ def node_warnings(self) -> str: str Warning message(s). """ - warnings.warn( - "This property is deprecated in 0.21.3. Use the warnings property instead.", - DeprecationWarning - ) + warnings.warn("This property is deprecated in 0.21.3. Use the warnings property instead.", DeprecationWarning) return self.warnings