From acc8e34467194fa7a8b8bdac247d08b84909d142 Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Tue, 30 Jun 2026 14:21:37 -0400 Subject: [PATCH 01/10] D1457509: Commit with new github id --- .github/workflows/ci-release.yml | 2 +- .github/workflows/ci_cd.yml | 2 +- .github/workflows/manual_draft.yml | 1 + .github/workflows/nightly-tests.yml | 2 +- .github/workflows/sync-release.yml | 2 +- .../workflows/update-testmondata-cache.yml | 2 +- .github/workflows/weekly-tests.yml | 2 +- doc/changelog.d/7860.fixed.md | 1 + pyproject.toml | 8 +++++ src/ansys/aedt/core/application/design.py | 4 +-- src/ansys/aedt/core/desktop.py | 2 +- src/ansys/aedt/core/filtersolutions.py | 29 ++++++++++--------- .../filtersolutions_core/dll_interface.py | 6 +++- .../filtersolutions_core/export_to_aedt.py | 18 ++++++------ tests/system/filter_solutions/conftest.py | 4 +++ .../filter_solutions/test_desktop_types.py | 12 ++++++++ .../test_export_to_aedt.py | 12 -------- tests/unit/test_desktop.py | 2 ++ uv.lock | 2 ++ 19 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 doc/changelog.d/7860.fixed.md diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 04ee0881842b..ce605660dd6d 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -1096,7 +1096,7 @@ jobs: TESTS_VERSION: ${{ env.TESTS_VERSION }} run: | .venv\Scripts\Activate.ps1 - uv sync --frozen --group tests --extra all + uv sync --frozen --group tests --extra all-dotnet - name: Remove Ansys processes (if any) shell: powershell diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 92f79d1439cb..a6706cbec590 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -1250,7 +1250,7 @@ jobs: TESTS_VERSION: ${{ env.TESTS_VERSION }} run: | .venv\Scripts\Activate.ps1 - uv sync --frozen --group tests --extra all + uv sync --frozen --group tests --extra all-dotnet - name: Wait for master cache update uses: ./.github/actions/check-cache diff --git a/.github/workflows/manual_draft.yml b/.github/workflows/manual_draft.yml index 0223ef251e65..f02fe409478f 100644 --- a/.github/workflows/manual_draft.yml +++ b/.github/workflows/manual_draft.yml @@ -712,6 +712,7 @@ jobs: run: | .venv\Scripts\Activate.ps1 pip install . --group tests + pip install "pywin32>=303" "ansys-pythonnet>=3.1.0rc3" - name: Remove Ansys processes (if any) shell: powershell diff --git a/.github/workflows/nightly-tests.yml b/.github/workflows/nightly-tests.yml index c85c46850625..ce347f18deb5 100644 --- a/.github/workflows/nightly-tests.yml +++ b/.github/workflows/nightly-tests.yml @@ -1015,7 +1015,7 @@ jobs: TESTS_VERSION: ${{ env.TESTS_VERSION }} run: | .venv\Scripts\Activate.ps1 - uv sync --frozen --group tests --extra all + uv sync --frozen --group tests --extra all-dotnet - name: Remove Ansys processes (if any) shell: powershell diff --git a/.github/workflows/sync-release.yml b/.github/workflows/sync-release.yml index a4b6ff7d5ed5..49e184543a4a 100644 --- a/.github/workflows/sync-release.yml +++ b/.github/workflows/sync-release.yml @@ -1254,7 +1254,7 @@ jobs: - name: Install pyaedt and tests dependencies run: | .venv\Scripts\Activate.ps1 - uv sync --frozen --group tests --extra all + uv sync --frozen --group tests --extra all-dotnet - name: Remove Ansys processes (if any) shell: powershell diff --git a/.github/workflows/update-testmondata-cache.yml b/.github/workflows/update-testmondata-cache.yml index a4b89ff25774..dc1474fd0dfa 100644 --- a/.github/workflows/update-testmondata-cache.yml +++ b/.github/workflows/update-testmondata-cache.yml @@ -963,7 +963,7 @@ jobs: TESTS_VERSION: ${{ env.TESTS_VERSION }} run: | .venv\Scripts\Activate.ps1 - uv sync --frozen --group tests --extra all + uv sync --frozen --group tests --extra all-dotnet - name: Restore testmondata cache uses: ./.github/actions/testmon-cache diff --git a/.github/workflows/weekly-tests.yml b/.github/workflows/weekly-tests.yml index 5be88d1eb23a..afb323f3dcab 100644 --- a/.github/workflows/weekly-tests.yml +++ b/.github/workflows/weekly-tests.yml @@ -993,7 +993,7 @@ jobs: TESTS_VERSION: ${{ env.TESTS_VERSION }} run: | .venv\Scripts\Activate.ps1 - uv sync --frozen --group tests --extra all + uv sync --frozen --group tests --extra all-dotnet - name: Remove Ansys processes (if any) diff --git a/doc/changelog.d/7860.fixed.md b/doc/changelog.d/7860.fixed.md new file mode 100644 index 000000000000..f3aca34d183f --- /dev/null +++ b/doc/changelog.d/7860.fixed.md @@ -0,0 +1 @@ +Pyaedt test export to aedt test fail diff --git a/pyproject.toml b/pyproject.toml index 05bf9acca2f4..4d19a481e754 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,6 +131,8 @@ tests = [ "pytest-xdist>=3.5.0", "pytest-testmon>=2.0.0", "cryptography", + "ansys-pythonnet>=3.1.0rc3; platform_system=='Windows'", + "pywin32>=303; platform_system=='Windows'", ] doc = [ "ansys-sphinx-theme>=1.0.0", @@ -365,3 +367,9 @@ directory = "test" name = "Test" showcontent = true +[tool.pyright] +include = ["src", "tests"] +venvPath = "." +venv = ".venv" +pythonVersion = "3.10" +extraPaths = ["src"] diff --git a/src/ansys/aedt/core/application/design.py b/src/ansys/aedt/core/application/design.py index 6c0cfd3dac84..8c8e42881290 100644 --- a/src/ansys/aedt/core/application/design.py +++ b/src/ansys/aedt/core/application/design.py @@ -1211,7 +1211,7 @@ def odesign(self) -> object: >>> oProject.SetActiveDesign >>> oProject.InsertDesign """ - if settings.use_multi_desktop: # pragma: no cover + if settings.use_multi_desktop and self._desktop_class.is_grpc_api: # pragma: no cover self._desktop_class.grpc_plugin.recreate_application(True) if self._design_name: self._odesign = self.oproject.SetActiveDesign(self._design_name) @@ -1258,7 +1258,7 @@ def oproject(self) -> object: >>> oDesktop.SetActiveProject >>> oDesktop.NewProject """ - if settings.use_multi_desktop: # pragma: no cover + if settings.use_multi_desktop and self._desktop_class.is_grpc_api: # pragma: no cover self._desktop_class.grpc_plugin.recreate_application(True) return self._oproject diff --git a/src/ansys/aedt/core/desktop.py b/src/ansys/aedt/core/desktop.py index 7bfab3479a65..dcb9e51d5ed3 100644 --- a/src/ansys/aedt/core/desktop.py +++ b/src/ansys/aedt/core/desktop.py @@ -1197,7 +1197,7 @@ def odesktop(self) -> object: >>> d = Desktop() >>> d.odesktop """ - if settings.use_grpc_api: + if self.is_grpc_api: tries = 0 while tries < 5: try: diff --git a/src/ansys/aedt/core/filtersolutions.py b/src/ansys/aedt/core/filtersolutions.py index 2133dfd385dc..67887542d3d7 100644 --- a/src/ansys/aedt/core/filtersolutions.py +++ b/src/ansys/aedt/core/filtersolutions.py @@ -64,10 +64,6 @@ def __init__(self, version: str | None = None) -> None: ) FilterDesignBase._active_design.close() - if version is not None: - # Clear global state before initialization - settings.aedt_version = None - FilterDesignBase._active_design = self self.version = version if version else settings.aedt_version @@ -122,16 +118,23 @@ def _create_design(self, desktop_version, desktop_process_id): ------- :class:``AEDT`` design object """ - settings.use_grpc_api = None - if isinstance(FilterDesignBase._active_design, LumpedDesign): - return Circuit(version=desktop_version, aedt_process_id=desktop_process_id) - elif isinstance(FilterDesignBase._active_design, DistributedDesign): - if getattr(self, "insert_hfss_3dl_design", True): - return Hfss3dLayout(version=desktop_version, aedt_process_id=desktop_process_id) - elif getattr(self, "insert_hfss_design", True): - return Hfss(version=desktop_version, aedt_process_id=desktop_process_id) - elif getattr(self, "insert_circuit_design", True): + # Preserve the current version to ensure proper session reconnection. + original_version = settings.aedt_version + try: + settings.aedt_version = desktop_version + if isinstance(FilterDesignBase._active_design, LumpedDesign): return Circuit(version=desktop_version, aedt_process_id=desktop_process_id) + elif isinstance(FilterDesignBase._active_design, DistributedDesign): + if getattr(self, "insert_hfss_3dl_design", True): + return Hfss3dLayout(version=desktop_version, aedt_process_id=desktop_process_id) + elif getattr(self, "insert_hfss_design", True): + return Hfss(version=desktop_version, aedt_process_id=desktop_process_id) + elif getattr(self, "insert_circuit_design", True): + return Circuit(version=desktop_version, aedt_process_id=desktop_process_id) + return None + finally: + # Restore the original version in case of early exit or exception. + settings.aedt_version = original_version class LumpedDesign(FilterDesignBase): diff --git a/src/ansys/aedt/core/filtersolutions_core/dll_interface.py b/src/ansys/aedt/core/filtersolutions_core/dll_interface.py index 5d093b4c9383..485af9185476 100644 --- a/src/ansys/aedt/core/filtersolutions_core/dll_interface.py +++ b/src/ansys/aedt/core/filtersolutions_core/dll_interface.py @@ -65,13 +65,17 @@ def _init_dll_path(self, version): ) self.dll_path = os.path.join(aedt_versions.installed_versions[version], "nuhertz", "FilterSolutionsAPI.dll") print("DLL Path:", self.dll_path) + # Ensure the DLL directory is in PATH so Borland BPL dependencies are found + dll_dir = os.path.dirname(self.dll_path) + if dll_dir not in os.environ.get("PATH", ""): + os.environ["PATH"] = dll_dir + os.pathsep + os.environ.get("PATH", "") if not os.path.isfile(self.dll_path): raise RuntimeError(f"The 'FilterSolutions' API DLL was not found at {self.dll_path}.") # pragma: no cover self._version = version def _init_dll(self, show_gui) -> None: """Load DLL and initialize application parameters to default values.""" - self._dll = ctypes.cdll.LoadLibrary(self.dll_path) + self._dll = ctypes.CDLL(self.dll_path, winmode=0) self._define_dll_functions() self.show_gui = show_gui if show_gui: # pragma: no cover diff --git a/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py index 1c45683d8498..7bbfda034d06 100644 --- a/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py +++ b/src/ansys/aedt/core/filtersolutions_core/export_to_aedt.py @@ -1371,15 +1371,15 @@ def substrate_er(self) -> SubstrateType | str: substrate_er_value_str = create_string_buffer(100) status = self._dll.getEr(substrate_er_value_str, byref(substrate_er_index), 100) self._dll_interface.raise_error(status) - if substrate_er_index.value in [e.value for e in SubstrateEr]: + if substrate_er_index.value in SubstrateEr._value2member_map_: return SubstrateEr(substrate_er_index.value) else: return substrate_er_value_str.value.decode("ascii") @substrate_er.setter def substrate_er(self, substrate_input: SubstrateEr | str) -> None: - if substrate_input in list(SubstrateEr): - substrate_er_index = SubstrateEr(substrate_input).value + if isinstance(substrate_input, SubstrateEr): + substrate_er_index = substrate_input.value substrate_er_value = "" elif isinstance(substrate_input, str): substrate_er_value = substrate_input @@ -1405,15 +1405,15 @@ def substrate_resistivity(self) -> SubstrateResistivity | str: substrate_resistivity_value_str = create_string_buffer(100) status = self._dll.getResistivity(substrate_resistivity_value_str, byref(substrate_resistivity_index), 100) self._dll_interface.raise_error(status) - if substrate_resistivity_index.value in [e.value for e in SubstrateResistivity]: + if substrate_resistivity_index.value in SubstrateResistivity._value2member_map_: return SubstrateResistivity(substrate_resistivity_index.value) else: return substrate_resistivity_value_str.value.decode("ascii") @substrate_resistivity.setter def substrate_resistivity(self, substrate_input: SubstrateResistivity | str) -> None: - if substrate_input in list(SubstrateResistivity): - substrate_resistivity_index = SubstrateResistivity(substrate_input).value + if isinstance(substrate_input, SubstrateResistivity): + substrate_resistivity_index = substrate_input.value substrate_resistivity_value = "" elif isinstance(substrate_input, str): substrate_resistivity_value = substrate_input @@ -1439,15 +1439,15 @@ def substrate_loss_tangent(self) -> SubstrateEr | str: substrate_loss_tangent_value_str = create_string_buffer(100) status = self._dll.getLossTangent(substrate_loss_tangent_value_str, byref(substrate_loss_tangent_index), 100) self._dll_interface.raise_error(status) - if substrate_loss_tangent_index.value in [e.value for e in SubstrateEr]: + if substrate_loss_tangent_index.value in SubstrateEr._value2member_map_: return SubstrateEr(substrate_loss_tangent_index.value) else: return substrate_loss_tangent_value_str.value.decode("ascii") @substrate_loss_tangent.setter def substrate_loss_tangent(self, substrate_input: SubstrateEr | str) -> None: - if substrate_input in list(SubstrateEr): - substrate_loss_tangent_index = SubstrateEr(substrate_input).value + if isinstance(substrate_input, SubstrateEr): + substrate_loss_tangent_index = substrate_input.value substrate_loss_tangent_value = "" elif isinstance(substrate_input, str): substrate_loss_tangent_value = substrate_input diff --git a/tests/system/filter_solutions/conftest.py b/tests/system/filter_solutions/conftest.py index 120064a4ba85..4a73fc7c38f5 100644 --- a/tests/system/filter_solutions/conftest.py +++ b/tests/system/filter_solutions/conftest.py @@ -26,9 +26,11 @@ import pytest +from ansys.aedt.core import settings from ansys.aedt.core.filtersolutions import DistributedDesign from ansys.aedt.core.filtersolutions import LumpedDesign from tests.conftest import DESKTOP_VERSION +from tests.conftest import USE_GRPC # Ensure US English locale (with cross-platform fallbacks) for _loc in ("en_US.UTF-8", "English_United States.1252", "en_US"): @@ -45,10 +47,12 @@ @pytest.fixture def lumped_design(): """Fixture for creating a LumpedDesign object.""" + settings.use_grpc_api = USE_GRPC return LumpedDesign(DESKTOP_VERSION) @pytest.fixture def distributed_design(): """Fixture for creating a DistributedDesign object.""" + settings.use_grpc_api = USE_GRPC return DistributedDesign(DESKTOP_VERSION) diff --git a/tests/system/filter_solutions/test_desktop_types.py b/tests/system/filter_solutions/test_desktop_types.py index ab6baa4c6211..48982255ca2b 100644 --- a/tests/system/filter_solutions/test_desktop_types.py +++ b/tests/system/filter_solutions/test_desktop_types.py @@ -29,8 +29,10 @@ from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss from ansys.aedt.core import Hfss3dLayout +from ansys.aedt.core.filtersolutions_core.export_to_aedt import PartLibraries from ansys.aedt.core.generic.settings import is_linux from tests.conftest import DESKTOP_VERSION +from tests.system.filter_solutions.resources import read_resource_file ON_CI = os.getenv("ON_CI", "false").lower() == "true" @@ -53,6 +55,16 @@ def test_lumped_exported_desktop(self, lumped_design): assert variables["C3"].si_value == pytest.approx(6.366e-12) circuit.desktop_class.close_desktop() + def test_import_tuned_variables(self, lumped_design): + lumped_design.export_to_aedt.simulate_after_export_enabled = True + lumped_design.export_to_aedt.optimize_after_export_enabled = True + lumped_design.export_to_aedt.part_libraries = PartLibraries.LUMPED + circuit = lumped_design.export_to_aedt.export_design() + assert lumped_design.export_to_aedt.import_tuned_variables().splitlines() == read_resource_file( + "imported_netlist.ckt", "Lumped" + ) + circuit.desktop_class.close_desktop() + def test_distributed_circuit_exported_desktop(self, distributed_design): schem_name = distributed_design.export_to_aedt.schematic_name schem_name_length = len(schem_name) diff --git a/tests/system/filter_solutions/test_export_to_aedt/test_export_to_aedt.py b/tests/system/filter_solutions/test_export_to_aedt/test_export_to_aedt.py index c326a8f2fdb3..075535170ec5 100644 --- a/tests/system/filter_solutions/test_export_to_aedt/test_export_to_aedt.py +++ b/tests/system/filter_solutions/test_export_to_aedt/test_export_to_aedt.py @@ -35,7 +35,6 @@ from ansys.aedt.core.generic.settings import is_linux from tests.conftest import DESKTOP_VERSION from tests.conftest import SKIP_MODELITHICS -from tests.system.filter_solutions.resources import read_resource_file from tests.system.filter_solutions.resources import resource_path ON_CI = os.getenv("ON_CI", "false").lower() == "true" @@ -474,17 +473,6 @@ def test_save_library_parts_config(self, lumped_design): assert lumped_design.export_to_aedt.substrate_dielectric_height == "3 mm" assert lumped_design.export_to_aedt.substrate_loss_tangent == "0.065 " - @pytest.mark.skipif(DESKTOP_VERSION < "2026.1", reason="Skipped on versions earlier than 2026.1") - def test_import_tuned_variables(self, lumped_design): - lumped_design.export_to_aedt.simulate_after_export_enabled = True - lumped_design.export_to_aedt.optimize_after_export_enabled = True - lumped_design.export_to_aedt.part_libraries = PartLibraries.LUMPED - app = lumped_design.export_to_aedt.export_design() - assert lumped_design.export_to_aedt.import_tuned_variables().splitlines() == read_resource_file( - "imported_netlist.ckt", "Lumped" - ) - app.desktop_class.close_desktop() - def test_part_libraries(self, lumped_design): assert lumped_design.export_to_aedt.part_libraries == PartLibraries.LUMPED assert len(PartLibraries) == 3 diff --git a/tests/unit/test_desktop.py b/tests/unit/test_desktop.py index f588327aa890..65972811161e 100644 --- a/tests/unit/test_desktop.py +++ b/tests/unit/test_desktop.py @@ -102,6 +102,7 @@ def test_get_available_toolkits() -> None: def test_desktop_odesktop_retries(mock_settings, mock_sleep, mock_desktop) -> None: """Test Desktop.odesktop property retries to get the odesktop object.""" desktop = Desktop() + desktop.is_grpc_api = True desktop.grpc_plugin = MagicMock() aedt_app = MagicMock() mock_odesktop = PropertyMock(name="oui", side_effect=[Exception("Failure"), aedt_app]) @@ -116,6 +117,7 @@ def test_desktop_odesktop_retries(mock_settings, mock_sleep, mock_desktop) -> No def test_desktop_odesktop_setter(mock_desktop) -> None: """Test Desktop.odesktop property retries to get the odesktop object.""" desktop = Desktop() + desktop.is_grpc_api = False aedt_app = MagicMock() desktop.grpc_plugin = MagicMock() diff --git a/uv.lock b/uv.lock index 3cc026e1f4da..ec8315e050d2 100644 --- a/uv.lock +++ b/uv.lock @@ -3728,6 +3728,8 @@ tests = [ { name = "pytest-testmon", specifier = ">=2.0.0" }, { name = "pytest-timeout", specifier = ">=2.3.0" }, { name = "pytest-xdist", specifier = ">=3.5.0" }, + { name = "ansys-pythonnet", marker = "sys_platform == 'win32'", specifier = ">=3.1.0rc3" }, + { name = "pywin32", marker = "sys_platform == 'win32'", specifier = ">=303" }, ] [[package]] From 50826c5104dc4de6664c3f5bf322f7001765a330 Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Fri, 3 Jul 2026 12:38:59 -0400 Subject: [PATCH 02/10] D1457509: Comments are applied. --- .github/workflows/manual_draft.yml | 3 +-- doc/changelog.d/7860.fixed.md | 1 - pyproject.toml | 9 --------- uv.lock | 2 -- 4 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 doc/changelog.d/7860.fixed.md diff --git a/.github/workflows/manual_draft.yml b/.github/workflows/manual_draft.yml index f02fe409478f..91527b139658 100644 --- a/.github/workflows/manual_draft.yml +++ b/.github/workflows/manual_draft.yml @@ -711,8 +711,7 @@ jobs: - name: Install pyaedt and tests dependencies run: | .venv\Scripts\Activate.ps1 - pip install . --group tests - pip install "pywin32>=303" "ansys-pythonnet>=3.1.0rc3" + pip install ".[all-dotnet]" --group tests - name: Remove Ansys processes (if any) shell: powershell diff --git a/doc/changelog.d/7860.fixed.md b/doc/changelog.d/7860.fixed.md deleted file mode 100644 index f3aca34d183f..000000000000 --- a/doc/changelog.d/7860.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Pyaedt test export to aedt test fail diff --git a/pyproject.toml b/pyproject.toml index 4d19a481e754..6f586a7161f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,8 +131,6 @@ tests = [ "pytest-xdist>=3.5.0", "pytest-testmon>=2.0.0", "cryptography", - "ansys-pythonnet>=3.1.0rc3; platform_system=='Windows'", - "pywin32>=303; platform_system=='Windows'", ] doc = [ "ansys-sphinx-theme>=1.0.0", @@ -366,10 +364,3 @@ showcontent = true directory = "test" name = "Test" showcontent = true - -[tool.pyright] -include = ["src", "tests"] -venvPath = "." -venv = ".venv" -pythonVersion = "3.10" -extraPaths = ["src"] diff --git a/uv.lock b/uv.lock index ec8315e050d2..3cc026e1f4da 100644 --- a/uv.lock +++ b/uv.lock @@ -3728,8 +3728,6 @@ tests = [ { name = "pytest-testmon", specifier = ">=2.0.0" }, { name = "pytest-timeout", specifier = ">=2.3.0" }, { name = "pytest-xdist", specifier = ">=3.5.0" }, - { name = "ansys-pythonnet", marker = "sys_platform == 'win32'", specifier = ">=3.1.0rc3" }, - { name = "pywin32", marker = "sys_platform == 'win32'", specifier = ">=303" }, ] [[package]] From 06f2a89406c562d9eaa82111539498e52fd45549 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:42:00 +0000 Subject: [PATCH 03/10] chore: adding changelog file 7861.fixed.md [dependabot-skip] --- doc/changelog.d/7861.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/7861.fixed.md diff --git a/doc/changelog.d/7861.fixed.md b/doc/changelog.d/7861.fixed.md new file mode 100644 index 000000000000..1933e3f8225c --- /dev/null +++ b/doc/changelog.d/7861.fixed.md @@ -0,0 +1 @@ +Test_export_to_aedt_test_FAIL_New From 34433b4db46897c7bd3e5af81d7001a5d539cc65 Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Tue, 7 Jul 2026 13:23:46 -0400 Subject: [PATCH 04/10] D1457509: Disable GRPC use for FilterSolutions --- tests/system/filter_solutions/conftest.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/system/filter_solutions/conftest.py b/tests/system/filter_solutions/conftest.py index 4a73fc7c38f5..c5b1aae8fc57 100644 --- a/tests/system/filter_solutions/conftest.py +++ b/tests/system/filter_solutions/conftest.py @@ -30,8 +30,10 @@ from ansys.aedt.core.filtersolutions import DistributedDesign from ansys.aedt.core.filtersolutions import LumpedDesign from tests.conftest import DESKTOP_VERSION -from tests.conftest import USE_GRPC +# Filter Solutions export attaches PyAEDT to the AEDT process started by the DLL. +# That session is typically COM-based (no gRPC port), so force COM for reconnection +# even when the global test config has use_grpc enabled. # Ensure US English locale (with cross-platform fallbacks) for _loc in ("en_US.UTF-8", "English_United States.1252", "en_US"): try: @@ -47,12 +49,12 @@ @pytest.fixture def lumped_design(): """Fixture for creating a LumpedDesign object.""" - settings.use_grpc_api = USE_GRPC + settings.use_grpc_api = False return LumpedDesign(DESKTOP_VERSION) @pytest.fixture def distributed_design(): """Fixture for creating a DistributedDesign object.""" - settings.use_grpc_api = USE_GRPC + settings.use_grpc_api = False return DistributedDesign(DESKTOP_VERSION) From 02b4a2ed2d13542a5413bd8f8778ab9baef12945 Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Fri, 17 Jul 2026 13:31:51 -0400 Subject: [PATCH 05/10] D1457509: Remove ONCI skip line --- tests/system/filter_solutions/test_desktop_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/filter_solutions/test_desktop_types.py b/tests/system/filter_solutions/test_desktop_types.py index 48982255ca2b..33cc78cc4dcf 100644 --- a/tests/system/filter_solutions/test_desktop_types.py +++ b/tests/system/filter_solutions/test_desktop_types.py @@ -39,7 +39,7 @@ @pytest.mark.skipif(is_linux, reason="FilterSolutions API is not supported on Linux.") @pytest.mark.skipif(DESKTOP_VERSION < "2026.1", reason="Skipped on versions earlier than 2026.1") -@pytest.mark.skipif(ON_CI, reason="Lead to access violation issues on CI runners") +# @pytest.mark.skipif(ON_CI, reason="Lead to access violation issues on CI runners") class TestClass: def test_lumped_exported_desktop(self, lumped_design): schem_name = lumped_design.export_to_aedt.schematic_name From be59a6822a6f8cf0613adc5aa8d3fce6affe1b20 Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Tue, 21 Jul 2026 05:58:10 -0400 Subject: [PATCH 06/10] D1457509: Release desktop added --- tests/system/filter_solutions/conftest.py | 38 ++++++++++++++++++- .../filter_solutions/test_desktop_types.py | 13 +++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/tests/system/filter_solutions/conftest.py b/tests/system/filter_solutions/conftest.py index c5b1aae8fc57..2fa1a737ee9f 100644 --- a/tests/system/filter_solutions/conftest.py +++ b/tests/system/filter_solutions/conftest.py @@ -23,17 +23,21 @@ # SOFTWARE. import locale +import subprocess import pytest +import ansys.aedt.core.filtersolutions_core as filtersolutions_core from ansys.aedt.core import settings from ansys.aedt.core.filtersolutions import DistributedDesign +from ansys.aedt.core.filtersolutions import FilterDesignBase from ansys.aedt.core.filtersolutions import LumpedDesign from tests.conftest import DESKTOP_VERSION # Filter Solutions export attaches PyAEDT to the AEDT process started by the DLL. # That session is typically COM-based (no gRPC port), so force COM for reconnection # even when the global test config has use_grpc enabled. +settings.use_grpc_api = False # Ensure US English locale (with cross-platform fallbacks) for _loc in ("en_US.UTF-8", "English_United States.1252", "en_US"): try: @@ -46,15 +50,45 @@ locale.setlocale(locale.LC_ALL, "C") +def _reset_filtersolutions_dll() -> None: + """Reset the FilterSolutions DLL singleton so a new AEDT session can be started.""" + filtersolutions_core._internal_dll_interface = None + FilterDesignBase._active_design = None + + +def _terminate_aedt_process(process_id: int) -> None: + """Terminate an AEDT process started by the FilterSolutions export.""" + subprocess.run(["taskkill", "/F", "/PID", str(process_id)], check=False, capture_output=True) + + +def release_exported_design(design_app) -> None: + """Detach PyAEDT from an exported design without corrupting the FilterSolutions DLL. + + ``close_desktop()`` shuts down AEDT while the DLL still holds references to that + session, which leads to access violations and AEDT communications failures in + subsequent tests. This helper releases the PyAEDT connection, resets the DLL + singleton, and terminates the exported AEDT process. + """ + process_id = design_app.desktop_class.aedt_process_id + design_app.desktop_class.release_desktop(close_projects=False, close_on_exit=False) + _reset_filtersolutions_dll() + if process_id: + _terminate_aedt_process(process_id) + + @pytest.fixture def lumped_design(): """Fixture for creating a LumpedDesign object.""" settings.use_grpc_api = False - return LumpedDesign(DESKTOP_VERSION) + design = LumpedDesign(DESKTOP_VERSION) + yield design + design.close() @pytest.fixture def distributed_design(): """Fixture for creating a DistributedDesign object.""" settings.use_grpc_api = False - return DistributedDesign(DESKTOP_VERSION) + design = DistributedDesign(DESKTOP_VERSION) + yield design + design.close() diff --git a/tests/system/filter_solutions/test_desktop_types.py b/tests/system/filter_solutions/test_desktop_types.py index 33cc78cc4dcf..7fd09d6344e1 100644 --- a/tests/system/filter_solutions/test_desktop_types.py +++ b/tests/system/filter_solutions/test_desktop_types.py @@ -22,8 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import os - import pytest from ansys.aedt.core import Circuit @@ -32,6 +30,7 @@ from ansys.aedt.core.filtersolutions_core.export_to_aedt import PartLibraries from ansys.aedt.core.generic.settings import is_linux from tests.conftest import DESKTOP_VERSION +from tests.system.filter_solutions.conftest import release_exported_design from tests.system.filter_solutions.resources import read_resource_file ON_CI = os.getenv("ON_CI", "false").lower() == "true" @@ -53,7 +52,7 @@ def test_lumped_exported_desktop(self, lumped_design): assert variables["C1"].si_value == pytest.approx(1.967e-12) assert variables["L2"].si_value == pytest.approx(1.288e-8) assert variables["C3"].si_value == pytest.approx(6.366e-12) - circuit.desktop_class.close_desktop() + release_exported_design(circuit) def test_import_tuned_variables(self, lumped_design): lumped_design.export_to_aedt.simulate_after_export_enabled = True @@ -63,7 +62,7 @@ def test_import_tuned_variables(self, lumped_design): assert lumped_design.export_to_aedt.import_tuned_variables().splitlines() == read_resource_file( "imported_netlist.ckt", "Lumped" ) - circuit.desktop_class.close_desktop() + release_exported_design(circuit) def test_distributed_circuit_exported_desktop(self, distributed_design): schem_name = distributed_design.export_to_aedt.schematic_name @@ -81,7 +80,7 @@ def test_distributed_circuit_exported_desktop(self, distributed_design): assert variables["S1"].si_value == pytest.approx(3.362e-3) assert variables["S2"].si_value == pytest.approx(2.172e-2) assert variables["S3"].si_value == pytest.approx(1.008e-2) - circuit.desktop_class.close_desktop() + release_exported_design(circuit) def test_distributed_hfss3dl_exported_desktop(self, distributed_design): schem_name = distributed_design.export_to_aedt.schematic_name @@ -100,7 +99,7 @@ def test_distributed_hfss3dl_exported_desktop(self, distributed_design): assert variables["S1"].si_value == pytest.approx(3.36225452227e-3) assert variables["S2"].si_value == pytest.approx(2.17231965814e-2) assert variables["S3"].si_value == pytest.approx(1.00773795179e-2) - hfss3dl.desktop_class.close_desktop() + release_exported_design(hfss3dl) def test_distributed_hfss_exported_desktop(self, distributed_design): schem_name = distributed_design.export_to_aedt.schematic_name @@ -119,4 +118,4 @@ def test_distributed_hfss_exported_desktop(self, distributed_design): assert variables["S1"].si_value == pytest.approx(3.36225452227e-3) assert variables["S2"].si_value == pytest.approx(2.17231965814e-2) assert variables["S3"].si_value == pytest.approx(1.00773795179e-2) - hfss.desktop_class.close_desktop() + release_exported_design(hfss) From 2602f055ad7301a8adeb29c80ab25dce119126bf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:59:10 +0000 Subject: [PATCH 07/10] CHORE: Auto fixes from pre-commit hooks --- tests/system/filter_solutions/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/filter_solutions/conftest.py b/tests/system/filter_solutions/conftest.py index 2fa1a737ee9f..b34cba5c7615 100644 --- a/tests/system/filter_solutions/conftest.py +++ b/tests/system/filter_solutions/conftest.py @@ -27,11 +27,11 @@ import pytest -import ansys.aedt.core.filtersolutions_core as filtersolutions_core from ansys.aedt.core import settings from ansys.aedt.core.filtersolutions import DistributedDesign from ansys.aedt.core.filtersolutions import FilterDesignBase from ansys.aedt.core.filtersolutions import LumpedDesign +import ansys.aedt.core.filtersolutions_core as filtersolutions_core from tests.conftest import DESKTOP_VERSION # Filter Solutions export attaches PyAEDT to the AEDT process started by the DLL. From abcb205181fe0012e7f63f76df61c86e6f64d5a6 Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Tue, 21 Jul 2026 06:06:01 -0400 Subject: [PATCH 08/10] D1457509: Fix import --- tests/system/filter_solutions/test_desktop_types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/filter_solutions/test_desktop_types.py b/tests/system/filter_solutions/test_desktop_types.py index 7fd09d6344e1..af01ebb16169 100644 --- a/tests/system/filter_solutions/test_desktop_types.py +++ b/tests/system/filter_solutions/test_desktop_types.py @@ -23,6 +23,7 @@ # SOFTWARE. import pytest +import os from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss From fb7bc5180dc2dfa9be4f618930494629422b6290 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:07:17 +0000 Subject: [PATCH 09/10] CHORE: Auto fixes from pre-commit hooks --- tests/system/filter_solutions/test_desktop_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/system/filter_solutions/test_desktop_types.py b/tests/system/filter_solutions/test_desktop_types.py index af01ebb16169..9f3c2a2f4ba2 100644 --- a/tests/system/filter_solutions/test_desktop_types.py +++ b/tests/system/filter_solutions/test_desktop_types.py @@ -22,9 +22,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import pytest import os +import pytest + from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss from ansys.aedt.core import Hfss3dLayout From 073f8731923c5e18201ebf2051ead9bb0c57386c Mon Sep 17 00:00:00 2001 From: ramin4667 Date: Tue, 21 Jul 2026 09:07:48 -0400 Subject: [PATCH 10/10] D1457509: Release retry fix --- src/ansys/aedt/core/filtersolutions.py | 4 ++ tests/system/filter_solutions/conftest.py | 69 +++++++++++++++---- .../filter_solutions/test_desktop_types.py | 10 ++- 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/ansys/aedt/core/filtersolutions.py b/src/ansys/aedt/core/filtersolutions.py index 545ed036dce8..a20943496891 100644 --- a/src/ansys/aedt/core/filtersolutions.py +++ b/src/ansys/aedt/core/filtersolutions.py @@ -135,8 +135,11 @@ def _create_design(self, desktop_version, desktop_process_id): """ # Preserve the current version to ensure proper session reconnection. original_version = settings.aedt_version + original_use_grpc = settings.use_grpc_api try: settings.aedt_version = desktop_version + # FilterSolutions starts AEDT in COM mode; force COM when reconnecting. + settings.use_grpc_api = False if isinstance(FilterDesignBase._active_design, LumpedDesign): return Circuit(version=desktop_version, aedt_process_id=desktop_process_id) elif isinstance(FilterDesignBase._active_design, DistributedDesign): @@ -150,6 +153,7 @@ def _create_design(self, desktop_version, desktop_process_id): finally: # Restore the original version in case of early exit or exception. settings.aedt_version = original_version + settings.use_grpc_api = original_use_grpc class LumpedDesign(FilterDesignBase): diff --git a/tests/system/filter_solutions/conftest.py b/tests/system/filter_solutions/conftest.py index b34cba5c7615..43642b78ee73 100644 --- a/tests/system/filter_solutions/conftest.py +++ b/tests/system/filter_solutions/conftest.py @@ -23,8 +23,9 @@ # SOFTWARE. import locale -import subprocess +import time +import psutil import pytest from ansys.aedt.core import settings @@ -50,15 +51,55 @@ locale.setlocale(locale.LC_ALL, "C") -def _reset_filtersolutions_dll() -> None: - """Reset the FilterSolutions DLL singleton so a new AEDT session can be started.""" - filtersolutions_core._internal_dll_interface = None +def _wait_for_process_exit(process_id: int, timeout: float = 30.0) -> None: + """Wait until an AEDT process has fully exited.""" + try: + psutil.Process(process_id).wait(timeout=timeout) + except (psutil.NoSuchProcess, psutil.TimeoutExpired): + pass + + +def _terminate_aedt_processes(*process_ids: int) -> None: + """Terminate AEDT processes started by FilterSolutions export.""" + for process_id in process_ids: + if not process_id: + continue + try: + psutil.Process(process_id).kill() + except psutil.NoSuchProcess: + pass + _wait_for_process_exit(process_id) + + +def _reinitialize_filtersolutions_dll() -> None: + """Reinitialize the in-process FilterSolutions DLL after an AEDT export session.""" + dll = filtersolutions_core._internal_dll_interface + if dll is not None: + dll.restore_defaults() FilterDesignBase._active_design = None -def _terminate_aedt_process(process_id: int) -> None: - """Terminate an AEDT process started by the FilterSolutions export.""" - subprocess.run(["taskkill", "/F", "/PID", str(process_id)], check=False, capture_output=True) +def _running_aedt_process_ids() -> list[int]: + process_ids = [] + for proc in psutil.process_iter(["pid", "exe", "name"]): + if _is_aedt_process(proc): + process_ids.append(proc.info["pid"]) + return process_ids + + +def prepare_filtersolutions_for_export() -> None: + """Ensure no stale AEDT export sessions interfere with the next export test.""" + _terminate_aedt_processes(*_running_aedt_process_ids()) + _reinitialize_filtersolutions_dll() + time.sleep(1) + + +def _is_aedt_process(process: psutil.Process) -> bool: + try: + exe = (process.info.get("exe") or "").lower() + except (psutil.NoSuchProcess, psutil.AccessDenied): + return False + return "ansys inc" in exe or "ansysem" in exe def release_exported_design(design_app) -> None: @@ -66,14 +107,16 @@ def release_exported_design(design_app) -> None: ``close_desktop()`` shuts down AEDT while the DLL still holds references to that session, which leads to access violations and AEDT communications failures in - subsequent tests. This helper releases the PyAEDT connection, resets the DLL - singleton, and terminates the exported AEDT process. + subsequent tests. This helper releases the PyAEDT connection, terminates the + exported AEDT process, and reinitializes the DLL through ``restore_defaults()``. """ process_id = design_app.desktop_class.aedt_process_id - design_app.desktop_class.release_desktop(close_projects=False, close_on_exit=False) - _reset_filtersolutions_dll() - if process_id: - _terminate_aedt_process(process_id) + try: + design_app.desktop_class.release_desktop(close_projects=False, close_on_exit=False) + except Exception: + pass + _terminate_aedt_processes(process_id) + _reinitialize_filtersolutions_dll() @pytest.fixture diff --git a/tests/system/filter_solutions/test_desktop_types.py b/tests/system/filter_solutions/test_desktop_types.py index af01ebb16169..d2cba16e8a5c 100644 --- a/tests/system/filter_solutions/test_desktop_types.py +++ b/tests/system/filter_solutions/test_desktop_types.py @@ -23,7 +23,6 @@ # SOFTWARE. import pytest -import os from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss @@ -31,15 +30,20 @@ from ansys.aedt.core.filtersolutions_core.export_to_aedt import PartLibraries from ansys.aedt.core.generic.settings import is_linux from tests.conftest import DESKTOP_VERSION +from tests.system.filter_solutions.conftest import prepare_filtersolutions_for_export from tests.system.filter_solutions.conftest import release_exported_design from tests.system.filter_solutions.resources import read_resource_file -ON_CI = os.getenv("ON_CI", "false").lower() == "true" + +@pytest.fixture(autouse=True) +def _prepare_filtersolutions_export_tests(): + prepare_filtersolutions_for_export() + yield + prepare_filtersolutions_for_export() @pytest.mark.skipif(is_linux, reason="FilterSolutions API is not supported on Linux.") @pytest.mark.skipif(DESKTOP_VERSION < "2026.1", reason="Skipped on versions earlier than 2026.1") -# @pytest.mark.skipif(ON_CI, reason="Lead to access violation issues on CI runners") class TestClass: def test_lumped_exported_desktop(self, lumped_design): schem_name = lumped_design.export_to_aedt.schematic_name