From 03b385fb0ad86d1ec81dfb33063c04c08a62a089 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Fri, 19 Apr 2024 17:03:01 +0200 Subject: [PATCH 1/8] REFACT: Clean up variables.py file --- pyaedt/application/Variables.py | 67 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/pyaedt/application/Variables.py b/pyaedt/application/Variables.py index 96bed7e90db..57174cafced 100644 --- a/pyaedt/application/Variables.py +++ b/pyaedt/application/Variables.py @@ -16,6 +16,7 @@ from __future__ import absolute_import # noreorder from __future__ import division +import ast import os import re import types @@ -156,14 +157,17 @@ def __getitem__(self, item): if variable in key_string: found_variable = True break - assert found_variable, "Input string {} is not a key of the data dictionary.".format(variable) + if not found_variable: + raise KeyError("Input string {} is not a key of the data dictionary.".format(variable)) data_out._data[variable] = self._data[key_string] data_out._header.append(variable) return data_out @pyaedt_function_handler() def __add__(self, other): - assert self.number_of_columns == other.number_of_columns, "Inconsistent number of columns" + if self.number_of_columns != other.number_of_columns: + raise ValueError("Inconsistent number of columns.") + # Create a new object to return, avoiding changing the original inputs new_dataset = CSVDataset() # Add empty columns to new_dataset @@ -198,7 +202,8 @@ def __iadd__(self, other): for column in other.data: self._data[column] = [] - assert self.number_of_columns == other.number_of_columns, "Inconsistent number of columns" + if self.number_of_columns != other.number_of_columns: + raise ValueError("Inconsistent number of columns.") # Append the data from 'other' for column, row_data in other.data.items(): @@ -1056,7 +1061,7 @@ def set_variable( self._logger.clear_messages() return except Exception: - pass + self._logger.debug("Failed to delete delimiter {}.".format(variable_name)) else: raise Exception("Unhandled input type to the design property or project variable.") # pragma: no cover @@ -1188,7 +1193,7 @@ def delete_separator(self, separator_name): ) return True except Exception: - pass + self._logger.debug("Failed to change desktop object property.") return False @pyaedt_function_handler() @@ -1229,7 +1234,7 @@ def delete_variable(self, var_name): ] ) except Exception: # pragma: no cover - pass + self._logger.debug("Failed to change desktop object property.") else: self._cleanup_variables() return True @@ -1424,9 +1429,12 @@ def __init__( self._value = self._calculated_value # If units have been specified, check for a conflict and otherwise use the specified unit system if units: - assert not self._units, "The unit specification {} is inconsistent with the identified units {}.".format( - specified_units, self._units - ) + if self._units and self._units != specified_units: + raise RuntimeError( + "The unit specification {} is inconsistent with the identified units {}.".format( + specified_units, self._units + ) + ) self._units = specified_units if not si_value and is_number(self._value): @@ -1493,7 +1501,7 @@ def _set_prop_val(self, prop, val, n_times=10): break i += 1 except Exception: - pass + self._app.logger.debug("Failed to set property '{}' value.".format(prop)) @pyaedt_function_handler() def _get_prop_val(self, prop): @@ -1515,7 +1523,7 @@ def _get_prop_val(self, prop): name = "LocalVariables" return self._app.get_oo_object(self._aedt_obj, "{}/{}".format(name, self._variable_name)).GetPropValue(prop) except Exception: - pass + self._app.logger.debug("Failed to get property '{}' value.".format(prop)) @property def name(self): @@ -1724,7 +1732,7 @@ def expression(self, value): def numeric_value(self): """Numeric part of the expression as a float value.""" if is_array(self._value): - return list(eval(self._value)) + return list(ast.literal_eval(self._value)) try: var_obj = self._aedt_obj.GetChildObject("Variables").GetChildObject(self._variable_name) val, _ = decompose_variable_value(var_obj.GetPropEvaluatedValue("EvaluatedValue")) @@ -1818,9 +1826,12 @@ def rescale_to(self, units): """ new_unit_system = unit_system(units) - assert ( - new_unit_system == self.unit_system - ), "New unit system {0} is inconsistent with the current unit system {1}." + if new_unit_system != self.unit_system: + raise ValueError( + "New unit system {} is inconsistent with the current unit system {}.".format( + new_unit_system, self.unit_system + ) + ) self._units = units return self @@ -1891,7 +1902,9 @@ def __mul__(self, other): >>> assert result_3.unit_system == "Power" """ - assert is_number(other) or isinstance(other, Variable), "Multiplier must be a scalar quantity or a variable." + if not is_number(other) and not isinstance(other, Variable): + raise ValueError("Multiplier must be a scalar quantity or a variable.") + if is_number(other): result_value = self.numeric_value * other result_units = self.units @@ -1936,10 +1949,11 @@ def __add__(self, other): >>> assert result.unit_system == "Current" """ - assert isinstance(other, Variable), "You can only add a variable with another variable." - assert ( - self.unit_system == other.unit_system - ), "Only ``Variable`` objects with the same unit system can be added." + if not isinstance(other, Variable): + raise ValueError("You can only add a variable with another variable.") + if self.unit_system != other.unit_system: + raise ValueError("Only ``Variable`` objects with the same unit system can be added.") + result_value = self.value + other.value result_units = SI_UNITS[self.unit_system] # If the units of the two operands are different, return SI-Units @@ -1978,10 +1992,11 @@ def __sub__(self, other): >>> assert result_2.unit_system == "Current" """ - assert isinstance(other, Variable), "You can only subtract a variable from another variable." - assert ( - self.unit_system == other.unit_system - ), "Only ``Variable`` objects with the same unit system can be subtracted." + if not isinstance(other, Variable): + raise ValueError("You can only subtract a variable from another variable.") + if self.unit_system != other.unit_system: + raise ValueError("Only ``Variable`` objects with the same unit system can be subtracted.") + result_value = self.value - other.value result_units = SI_UNITS[self.unit_system] # If the units of the two operands are different, return SI-Units @@ -2023,7 +2038,9 @@ def __truediv__(self, other): >>> assert result_1.unit_system == "Current" """ - assert is_number(other) or isinstance(other, Variable), "Divisor must be a scalar quantity or a variable." + if not is_number(other) and not isinstance(other, Variable): + raise ValueError("Divisor must be a scalar quantity or a variable.") + if is_number(other): result_value = self.numeric_value / other result_units = self.units From e98324b139c6c210b839ca0d9d49f7296f430f5f Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Tue, 23 Apr 2024 13:57:37 +0200 Subject: [PATCH 2/8] TESTS: Fix expected error type raised --- _unittest/test_09_VariableManager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_unittest/test_09_VariableManager.py b/_unittest/test_09_VariableManager.py index df4adad7f8d..7f934255478 100644 --- a/_unittest/test_09_VariableManager.py +++ b/_unittest/test_09_VariableManager.py @@ -252,10 +252,10 @@ def test_07_addition(self): v2 = Variable(3) v3 = Variable("3mA") v4 = Variable("10A") - with pytest.raises(AssertionError): + with pytest.raises(ValueError): v1 + v2 - with pytest.raises(AssertionError): + with pytest.raises(ValueError): v2 + v1 result_1 = v2 + v2 result_2 = v3 + v4 @@ -278,10 +278,10 @@ def test_08_subtraction(self): v3 = Variable("3mA") v4 = Variable("10A") - with pytest.raises(AssertionError): + with pytest.raises(ValueError): v1 - v2 - with pytest.raises(AssertionError): + with pytest.raises(ValueError): v2 - v1 result_1 = v2 - v2 From e39e5fe02ac6c77eaebe92fe0434c0b299d23dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:02:59 +0200 Subject: [PATCH 3/8] Update pyaedt/application/Variables.py --- pyaedt/application/Variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/application/Variables.py b/pyaedt/application/Variables.py index 57174cafced..22a97fb3558 100644 --- a/pyaedt/application/Variables.py +++ b/pyaedt/application/Variables.py @@ -1061,7 +1061,7 @@ def set_variable( self._logger.clear_messages() return except Exception: - self._logger.debug("Failed to delete delimiter {}.".format(variable_name)) + self._logger.debug("Something went wrong when deleting '{}'.".format(variable_name)) else: raise Exception("Unhandled input type to the design property or project variable.") # pragma: no cover From 7b1e75a42fac04a03ffa08d5a5cc7beddba84b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Morais?= <146729917+SMoraisAnsys@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:06:26 +0200 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- pyaedt/application/Variables.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyaedt/application/Variables.py b/pyaedt/application/Variables.py index 22a97fb3558..ec3e31e5432 100644 --- a/pyaedt/application/Variables.py +++ b/pyaedt/application/Variables.py @@ -166,7 +166,7 @@ def __getitem__(self, item): @pyaedt_function_handler() def __add__(self, other): if self.number_of_columns != other.number_of_columns: - raise ValueError("Inconsistent number of columns.") + raise ValueError("Number of columns is inconsistent.") # Create a new object to return, avoiding changing the original inputs new_dataset = CSVDataset() @@ -203,7 +203,7 @@ def __iadd__(self, other): self._data[column] = [] if self.number_of_columns != other.number_of_columns: - raise ValueError("Inconsistent number of columns.") + raise ValueError("Number of columns is inconsistent.") # Append the data from 'other' for column, row_data in other.data.items(): @@ -1952,7 +1952,7 @@ def __add__(self, other): if not isinstance(other, Variable): raise ValueError("You can only add a variable with another variable.") if self.unit_system != other.unit_system: - raise ValueError("Only ``Variable`` objects with the same unit system can be added.") + raise ValueError("Only Variable objects with the same unit system can be added.") result_value = self.value + other.value result_units = SI_UNITS[self.unit_system] @@ -1995,7 +1995,7 @@ def __sub__(self, other): if not isinstance(other, Variable): raise ValueError("You can only subtract a variable from another variable.") if self.unit_system != other.unit_system: - raise ValueError("Only ``Variable`` objects with the same unit system can be subtracted.") + raise ValueError("Only Variable objects with the same unit system can be subtracted.") result_value = self.value - other.value result_units = SI_UNITS[self.unit_system] From d1a204989d68333828acccb115abe25add97d7be Mon Sep 17 00:00:00 2001 From: gmalinve <103059376+gmalinve@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:58:01 +0200 Subject: [PATCH 5/8] fix export field plot streamline (#4579) --- _unittest/test_28_Maxwell3D.py | 1 + examples/03-Maxwell/Maxwell2D_Electrostatic.py | 7 ------- pyaedt/modules/AdvancedPostProcessing.py | 4 ++-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/_unittest/test_28_Maxwell3D.py b/_unittest/test_28_Maxwell3D.py index 281e2fbe4b9..92f87bc5cab 100644 --- a/_unittest/test_28_Maxwell3D.py +++ b/_unittest/test_28_Maxwell3D.py @@ -198,6 +198,7 @@ def test_05a_assign_coil(self): def test_05_draw_region(self): assert self.aedtapp.modeler.create_air_region(*[300] * 6) + @pytest.mark.skipif(desktop_version == "2024.2", reason="GetDisplacementCurrent not working in 2024.2") def test_06_eddycurrent(self): assert self.aedtapp.eddy_effects_on(["Plate"], enable_eddy_effects=True) oModule = self.aedtapp.odesign.GetModule("BoundarySetup") diff --git a/examples/03-Maxwell/Maxwell2D_Electrostatic.py b/examples/03-Maxwell/Maxwell2D_Electrostatic.py index 6eb50df7baf..3f044ffd9bc 100644 --- a/examples/03-Maxwell/Maxwell2D_Electrostatic.py +++ b/examples/03-Maxwell/Maxwell2D_Electrostatic.py @@ -198,13 +198,6 @@ M2D.post.export_field_plot(plot_name="LineTracesTest", output_dir=M2D.toolkit_directory, file_format="fldplt") -########################################################## -# Export a field plot to an image file -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Export the flux lines plot to an image file using PyVista Python package. - -M2D.post.plot_field_from_fieldplot(plot.name, show=False) - ########################################################## # Export the mesh field plot # ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/pyaedt/modules/AdvancedPostProcessing.py b/pyaedt/modules/AdvancedPostProcessing.py index a2b76fb55f3..6b5650d6074 100644 --- a/pyaedt/modules/AdvancedPostProcessing.py +++ b/pyaedt/modules/AdvancedPostProcessing.py @@ -328,6 +328,8 @@ def plot_field_from_fieldplot( ): """Export a field plot to an image file (JPG or PNG) using Python PyVista. + This method does not support streamlines plot. + .. note:: The PyVista module rebuilds the mesh and the overlap fields on the mesh. @@ -392,8 +394,6 @@ def plot_field_from_fieldplot( else: self.ofieldsreporter.UpdateQuantityFieldsPlots(plot_folder) - if self.field_plots[plot_name].field_type == "DC R/L Fields": - file_format = "fldplt" file_to_add = self.export_field_plot(plot_name, self._app.working_directory, file_format=file_format) model = self.get_model_plotter_geometries( generate_mesh=False, From 56369f9e35db48d10a0f41596c079a6ec91f9155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Apr 2024 08:42:07 +0200 Subject: [PATCH 6/8] MAINT: Update scikit-rf requirement from <0.33,>=0.30.0 to >=0.30.0,<1.1 (#4584) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0d57d7120e6..02091f7a6a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ tests = [ "pyedb>=0.5.0,<0.9; python_version > '3.7'", "pyvista>=0.38.0,<0.44", "scikit-learn>=1.0.0,<1.5", - "scikit-rf>=0.30.0,<0.33", + "scikit-rf>=0.30.0,<1.1", "SRTM.py", "utm", "vtk==9.2.6", @@ -84,7 +84,7 @@ doc = [ "pyvista>=0.38.0,<0.44", "recommonmark", #"scikit-learn", - "scikit-rf>=0.30.0,<0.33", + "scikit-rf>=0.30.0,<1.1", "Sphinx==5.3.0; python_version == '3.7'", "Sphinx>=7.1.0,<7.4; python_version > '3.7'", "sphinx-autobuild==2021.3.14; python_version == '3.7'", @@ -128,7 +128,7 @@ all = [ "osmnx>=1.1.0,<1.10", "pandas>=1.1.0,<2.3", "pyvista>=0.38.0,<0.44", - "scikit-rf>=0.30.0,<0.33", + "scikit-rf>=0.30.0,<1.1", "SRTM.py", "utm", "vtk==9.2.6", From 075d82083ba7385858707c7a256ca9100b205c57 Mon Sep 17 00:00:00 2001 From: svandenb-dev <74993647+svandenb-dev@users.noreply.github.com> Date: Wed, 24 Apr 2024 08:42:26 +0200 Subject: [PATCH 7/8] FIX: Export from 3D layout to 3D modeler with keeping net names bug fix (#4582) --- pyaedt/modules/SolveSetup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyaedt/modules/SolveSetup.py b/pyaedt/modules/SolveSetup.py index 743a7267150..5597f9ff439 100644 --- a/pyaedt/modules/SolveSetup.py +++ b/pyaedt/modules/SolveSetup.py @@ -1979,7 +1979,7 @@ def _get_primitives_points_per_net(self): while len(primitive_dict[net]) < len(net_primitives[net]): if n > 1000: # adding 1000 as maximum value to prevent infinite loop return - n += 20 + n += 10 primitive_dict[net] = [] for prim in primitives: layer = edb.stackup.signal_layers[prim.layer_name] From 87739a9ea3223ee8e57d3d7c6ca7569a4f18eefe Mon Sep 17 00:00:00 2001 From: Devin <38879940+dcrawforAtAnsys@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:11:41 +0200 Subject: [PATCH 8/8] Doc/4547 keyword conventions (#4559) Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- doc/source/Getting_started/Contributing.rst | 63 +++++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/doc/source/Getting_started/Contributing.rst b/doc/source/Getting_started/Contributing.rst index c7392e86e40..b62237fa983 100644 --- a/doc/source/Getting_started/Contributing.rst +++ b/doc/source/Getting_started/Contributing.rst @@ -41,12 +41,13 @@ for switching from viewing the documentation for the latest stable release to viewing the documentation for the development version or previously released versions. -Adhere to code style --------------------- -PyAEDT is compliant with `PyAnsys code style -`_. It uses the tool -`pre-commit `_ to check the code style. You can install -and activate this tool with: +Code style +---------- +PyAEDT complies with the `PyAnsys code style +`_. +`pre-commit `_ is applied within the CI/CD to ensure compliance. +The ``pre-commit`` Python package can be installed +and run as follows: .. code:: bash @@ -73,6 +74,56 @@ For example:: Validate GitHub Workflows................................................Passed blacken-docs.............................................................Passed +Naming conventions +~~~~~~~~~~~~~~~~~~ +Consistency of names helps improve readability and +ease of use. Starting with release 0.8 a concerted effort +has been made to +improve consistency of naming and adherence to +:ref:`PEP-8`_. + +For example, methods used to create or access entities in +AEDT require that a name be passed to the method or function +as an argument. +It is tempting to +include context as part of that variable name. For example, while it is tempting to use +``setupname`` +as an argument to :meth:`Hfss.create_setup`_, +the context "setup" is +explicitly defined by the method name. The variable ``name`` provides +a more compact +description of the variable in this context. + +In previous PyAEDT versions, you can also find both ``setup_name`` and ``setupname`` used +for various methods or classes. +Improving naming consistency improves maintainability and readability. + +The following table illustrates the recommended conventions: + +.. list-table:: Keywords and object names + :widths: 25 25 50 + :header-rows: 1 + + * - Old name + - New name + - Example + * - ``setupname``, ``setup_name``, ``sweepname`` + - ``name`` + - ``Hfss.create_setup()``, ``Hfss.create_linear_step_sweep()`` + * - ``usethickness`` + - ``thickness`` + - ``Hfss.assign_coating()`` + * - ``entities`` + - ``assignment`` + - ``Maxwell.assign_current_density()`` + * - ``entity_list`` + - ``assignment`` + - ``Maxwell.assign_symmetry()`` + +Take care to use descriptive names for +variables and classes that adhere to PEP-8 and are consistent with conventions already +used in PyAEDT. + Log errors ~~~~~~~~~~ PyAEDT has an internal logging tool named ``Messenger``