From 26b8f02c20eaff6211d270625243abbdabf1f0ba Mon Sep 17 00:00:00 2001 From: Devin Date: Fri, 6 Feb 2026 11:46:51 -0600 Subject: [PATCH 01/12] Fix local download - Fix #7202 (incorrect handling of file) - Remove incorrectly handled debug statements. - Add unit test when using local repo to test example data. --- src/ansys/aedt/core/examples/downloads.py | 23 ++- .../core/visualization/post/solution_data.py | 4 +- tests/unit/test_downloads.py | 190 ++++++++++++++++++ 3 files changed, 209 insertions(+), 8 deletions(-) diff --git a/src/ansys/aedt/core/examples/downloads.py b/src/ansys/aedt/core/examples/downloads.py index e0f2163218c..c5e26f63437 100644 --- a/src/ansys/aedt/core/examples/downloads.py +++ b/src/ansys/aedt/core/examples/downloads.py @@ -118,13 +118,24 @@ def _copy_local_example( source_relative_path: str, target_path: Optional[Union[str, Path]] = None, ) -> Path: # pragma: no cover - """Copy a folder from a local copy of the examples repo.""" - dst = Path(target_path) / Path(source_relative_path).name + """Copy a file or folder from a local copy of the examples repo.""" + pyaedt_logger.debug(f"Retrieving local example from '{settings.local_example_folder}'") + source = Path(settings.local_example_folder) / source_relative_path + target_path = Path(target_path) + + if source.is_file(): + target_path.mkdir(parents=True, exist_ok=True) + dst = target_path / source.name + try: + shutil.copy2(source, dst) + except Exception as e: + raise AEDTRuntimeError(f"Failed to copy {str(source)}.") from e + return dst + + dst = target_path / Path(source_relative_path).name dst.mkdir(parents=True, exist_ok=True) - pyaedt_logger.debug(f"Retrieving local folder from '{settings.local_example_folder}'") - source_folder = Path(settings.local_example_folder) / source_relative_path - for p in source_folder.rglob("*"): - target = dst / p.relative_to(source_folder) + for p in source.rglob("*"): + target = dst / p.relative_to(source) if p.is_dir(): target.mkdir(parents=True, exist_ok=True) else: diff --git a/src/ansys/aedt/core/visualization/post/solution_data.py b/src/ansys/aedt/core/visualization/post/solution_data.py index b362a603340..18cbc9b02f2 100644 --- a/src/ansys/aedt/core/visualization/post/solution_data.py +++ b/src/ansys/aedt/core/visualization/post/solution_data.py @@ -72,11 +72,11 @@ def __init__(self, aedtdata): else: self._primary_sweep = self._sweeps_names[0] end = time.time() - start - print(f"Time to initialize solution data:{end}") + settings.logger.debug(f"Time to initialize solution data:{end}") self.init_solutions_data() self._ifft = None end = time.time() - start - print(f"Time to initialize solution data:{end}") + settings.logger.debug(f"Time to initialize solution data:{end}") @property def active_variation(self): diff --git a/tests/unit/test_downloads.py b/tests/unit/test_downloads.py index d7837ecaf3a..e5668f021b2 100644 --- a/tests/unit/test_downloads.py +++ b/tests/unit/test_downloads.py @@ -23,12 +23,15 @@ # SOFTWARE. from pathlib import Path +from unittest.mock import patch import pytest from ansys.aedt.core.examples import downloads +from ansys.aedt.core.examples.downloads import _copy_local_example from ansys.aedt.core.generic.file_utils import generate_unique_name from ansys.aedt.core.generic.settings import is_linux +from ansys.aedt.core.internal.errors import AEDTRuntimeError @pytest.fixture(scope="module", autouse=True) @@ -120,3 +123,190 @@ def test_download_icepak_3d_component(test_tmp_dir): def test_download_fss_file(test_tmp_dir): example_folder = downloads.download_fss_3dcomponent(local_path=test_tmp_dir) assert Path(example_folder).exists() + + +# ================================ +# _copy_local_example unit tests +# ================================ + + +@pytest.fixture +def local_example_folder(test_tmp_dir): + """Create a mock local example folder structure for testing.""" + example_root = test_tmp_dir / "mock_example_data" + example_root.mkdir(parents=True, exist_ok=True) + return example_root + + +@pytest.fixture +def mock_settings(local_example_folder): + """Patch settings.local_example_folder to use the mock folder.""" + with patch("ansys.aedt.core.examples.downloads.settings") as mock_settings: + mock_settings.local_example_folder = str(local_example_folder) + yield mock_settings + + +class TestCopyLocalExampleFile: + """Tests for _copy_local_example when source is a file.""" + + def test_copy_single_file(self, test_tmp_dir, local_example_folder, mock_settings): + """Test copying a single file to target directory.""" + # Create a source file + source_file = local_example_folder / "test_file.txt" + source_file.write_text("test content") + + # Copy the file + target_dir = test_tmp_dir / "target" + result = _copy_local_example("test_file.txt", target_dir) + + # Verify + assert result.exists() + assert result.is_file() + assert result.name == "test_file.txt" + assert result.parent == target_dir + assert result.read_text() == "test content" + + def test_copy_file_in_subdirectory(self, test_tmp_dir, local_example_folder, mock_settings): + """Test copying a file from a subdirectory.""" + # Create a source file in a subdirectory + subdir = local_example_folder / "pyaedt" / "sbr" + subdir.mkdir(parents=True) + source_file = subdir / "Cassegrain.aedt" + source_file.write_text("aedt file content") + + # Copy the file + target_dir = test_tmp_dir / "target" + result = _copy_local_example("pyaedt/sbr/Cassegrain.aedt", target_dir) + + # Verify + assert result.exists() + assert result.is_file() + assert result.name == "Cassegrain.aedt" + assert result.parent == target_dir + assert result.read_text() == "aedt file content" + + def test_copy_file_creates_target_directory(self, test_tmp_dir, local_example_folder, mock_settings): + """Test that target directory is created if it doesn't exist.""" + # Create a source file + source_file = local_example_folder / "test_file.txt" + source_file.write_text("test content") + + # Copy to a non-existent nested target directory + target_dir = test_tmp_dir / "nested" / "target" / "dir" + assert not target_dir.exists() + + result = _copy_local_example("test_file.txt", target_dir) + + # Verify target directory was created + assert target_dir.exists() + assert result.exists() + + +class TestCopyLocalExampleFolder: + """Tests for _copy_local_example when source is a folder.""" + + def test_copy_folder_with_files(self, test_tmp_dir, local_example_folder, mock_settings): + """Test copying a folder containing multiple files.""" + # Create a source folder with files + source_folder = local_example_folder / "test_folder" + source_folder.mkdir() + (source_folder / "file1.txt").write_text("content 1") + (source_folder / "file2.txt").write_text("content 2") + + # Copy the folder + target_dir = test_tmp_dir / "target" + result = _copy_local_example("test_folder", target_dir) + + # Verify + assert result.exists() + assert result.is_dir() + assert result.name == "test_folder" + assert (result / "file1.txt").read_text() == "content 1" + assert (result / "file2.txt").read_text() == "content 2" + + def test_copy_folder_with_nested_structure(self, test_tmp_dir, local_example_folder, mock_settings): + """Test copying a folder with nested subdirectories.""" + # Create a source folder with nested structure + source_folder = local_example_folder / "parent_folder" + source_folder.mkdir() + (source_folder / "root_file.txt").write_text("root content") + + nested = source_folder / "subdir1" / "subdir2" + nested.mkdir(parents=True) + (nested / "nested_file.txt").write_text("nested content") + + # Copy the folder + target_dir = test_tmp_dir / "target" + result = _copy_local_example("parent_folder", target_dir) + + # Verify + assert result.exists() + assert (result / "root_file.txt").read_text() == "root content" + assert (result / "subdir1" / "subdir2" / "nested_file.txt").read_text() == "nested content" + + def test_copy_folder_preserves_empty_subdirectories(self, test_tmp_dir, local_example_folder, mock_settings): + """Test that empty subdirectories are preserved when copying.""" + # Create a source folder with an empty subdirectory + source_folder = local_example_folder / "folder_with_empty" + source_folder.mkdir() + (source_folder / "empty_subdir").mkdir() + (source_folder / "file.txt").write_text("content") + + # Copy the folder + target_dir = test_tmp_dir / "target" + result = _copy_local_example("folder_with_empty", target_dir) + + # Verify empty subdirectory exists + assert (result / "empty_subdir").exists() + assert (result / "empty_subdir").is_dir() + + def test_copy_folder_from_subdirectory(self, test_tmp_dir, local_example_folder, mock_settings): + """Test copying a folder from a subdirectory path.""" + # Create nested source folder + pyaedt = local_example_folder / "pyaedt" + pyaedt.mkdir() + source_folder = pyaedt / "custom_reports" + source_folder.mkdir() + (source_folder / "report.json").write_text('{"key": "value"}') + + # Copy the folder + target_dir = test_tmp_dir / "target" + result = _copy_local_example("pyaedt/custom_reports", target_dir) + + # Verify + assert result.exists() + assert result.name == "custom_reports" + assert (result / "report.json").read_text() == '{"key": "value"}' + + +class TestCopyLocalExampleErrors: + """Tests for error handling in _copy_local_example.""" + + def test_copy_file_raises_error_on_failure(self, test_tmp_dir, local_example_folder, mock_settings): + """Test that AEDTRuntimeError is raised when file copy fails.""" + # Create a source file + source_file = local_example_folder / "test_file.txt" + source_file.write_text("test content") + + target_dir = test_tmp_dir / "target" + + # Mock shutil.copy2 to raise an exception + with patch("ansys.aedt.core.examples.downloads.shutil.copy2") as mock_copy: + mock_copy.side_effect = PermissionError("Access denied") + with pytest.raises(AEDTRuntimeError, match="Failed to copy"): + _copy_local_example("test_file.txt", target_dir) + + def test_copy_folder_raises_error_on_failure(self, test_tmp_dir, local_example_folder, mock_settings): + """Test that AEDTRuntimeError is raised when folder file copy fails.""" + # Create a source folder with a file + source_folder = local_example_folder / "test_folder" + source_folder.mkdir() + (source_folder / "file.txt").write_text("content") + + target_dir = test_tmp_dir / "target" + + # Mock shutil.copy2 to raise an exception + with patch("ansys.aedt.core.examples.downloads.shutil.copy2") as mock_copy: + mock_copy.side_effect = PermissionError("Access denied") + with pytest.raises(AEDTRuntimeError, match="Failed to copy"): + _copy_local_example("test_folder", target_dir) From c547b03595cb841aa68cfb163a18ac0c8459c86e Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:51:52 +0000 Subject: [PATCH 02/12] chore: adding changelog file 7212.fixed.md [dependabot-skip] --- doc/changelog.d/7212.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/7212.fixed.md diff --git a/doc/changelog.d/7212.fixed.md b/doc/changelog.d/7212.fixed.md new file mode 100644 index 00000000000..5df6470b769 --- /dev/null +++ b/doc/changelog.d/7212.fixed.md @@ -0,0 +1 @@ +Local access to file in example-data repo From dd53d4e8b733efc5a3bd8af0c06a9e804a29cbc3 Mon Sep 17 00:00:00 2001 From: Devin Date: Sat, 7 Feb 2026 08:57:03 -0600 Subject: [PATCH 03/12] Convert test_tmp_dir from a return fixture to a yield fixture. cleans up its own directory after teardown, preventing race conditions when pytest-xdist workers tear down module-scoped file_tmp_root while function-scoped fixtures still need the directory. --- tests/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 08341f9e007..6cda5611f72 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -263,7 +263,8 @@ def test_tmp_dir(file_tmp_root, request): if d.exists(): shutil.rmtree(d, ignore_errors=True) d.mkdir(parents=True, exist_ok=True) - return d + yield d + shutil.rmtree(d, ignore_errors=True) @pytest.fixture From 03a747f1f86f1fdd8f21c344094a2bc2e2916463 Mon Sep 17 00:00:00 2001 From: Devin Date: Sat, 7 Feb 2026 15:08:13 -0600 Subject: [PATCH 04/12] Allow for delay after simulation is started - Add while loop in test_analyze.py test_3dl_analyze_setup() --- tests/system/solvers/test_analyze.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/system/solvers/test_analyze.py b/tests/system/solvers/test_analyze.py index 9cf016d6db3..0aebb0170a4 100644 --- a/tests/system/solvers/test_analyze.py +++ b/tests/system/solvers/test_analyze.py @@ -152,7 +152,12 @@ def test_3dl_analyze_setup(hfss3dl_solve): with pytest.raises(AEDTRuntimeError): hfss3dl_solve.set_export_touchstone() assert hfss3dl_solve.analyze_setup("Setup1", cores=4, blocking=False) - assert hfss3dl_solve.are_there_simulations_running + running = hfss3dl_solve.are_there_simulations_running + start = time.time() + while not running and time.time() - start < 10: + time.sleep(0.5) + running = hfss3dl_solve.are_there_simulations_running + assert running assert hfss3dl_solve.stop_simulations() while hfss3dl_solve.are_there_simulations_running: time.sleep(1) From 534beaf914e4ef6e811e2e8ce3302e9f7cd79e49 Mon Sep 17 00:00:00 2001 From: Devin Date: Sun, 8 Feb 2026 13:20:15 -0600 Subject: [PATCH 05/12] Add logging to help debug test failure on Linux --- tests/system/solvers/test_analyze.py | 67 ++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/tests/system/solvers/test_analyze.py b/tests/system/solvers/test_analyze.py index 0aebb0170a4..f1b39ba9d5b 100644 --- a/tests/system/solvers/test_analyze.py +++ b/tests/system/solvers/test_analyze.py @@ -144,30 +144,91 @@ def test_3dl_generate_mesh(hfss3dl_solve): @pytest.mark.skipif(DESKTOP_VERSION < "2023.2", reason="Working only from 2023 R2") def test_3dl_analyze_setup(hfss3dl_solve): + logger = hfss3dl_solve.logger + logger.info("test_3dl_analyze_setup: START") + logger.info(f"test_3dl_analyze_setup: project_name={hfss3dl_solve.project_name}") + logger.info(f"test_3dl_analyze_setup: design_name={hfss3dl_solve.design_name}") + logger.info(f"test_3dl_analyze_setup: setup_names={hfss3dl_solve.setup_names}") + logger.info(f"test_3dl_analyze_setup: DESKTOP_VERSION={DESKTOP_VERSION}") + logger.info(f"test_3dl_analyze_setup: project_list={hfss3dl_solve.desktop_class.project_list}") + assert hfss3dl_solve.export_touchstone_on_completion(export=False) + logger.info("test_3dl_analyze_setup: export_touchstone_on_completion(False) OK") assert hfss3dl_solve.export_touchstone_on_completion(export=True) + logger.info("test_3dl_analyze_setup: export_touchstone_on_completion(True) OK") if DESKTOP_VERSION > "2024.2": assert hfss3dl_solve.set_export_touchstone() + logger.info("test_3dl_analyze_setup: set_export_touchstone() OK") else: with pytest.raises(AEDTRuntimeError): hfss3dl_solve.set_export_touchstone() - assert hfss3dl_solve.analyze_setup("Setup1", cores=4, blocking=False) + logger.info("test_3dl_analyze_setup: set_export_touchstone() raised AEDTRuntimeError as expected") + + logger.info("test_3dl_analyze_setup: calling analyze_setup('Setup1', cores=4, blocking=False)") + analyze_result = hfss3dl_solve.analyze_setup("Setup1", cores=4, blocking=False) + logger.info(f"test_3dl_analyze_setup: analyze_setup returned {analyze_result}") + assert analyze_result + running = hfss3dl_solve.are_there_simulations_running + logger.info(f"test_3dl_analyze_setup: initial are_there_simulations_running={running}") start = time.time() + poll_count = 0 while not running and time.time() - start < 10: time.sleep(0.5) running = hfss3dl_solve.are_there_simulations_running - assert running - assert hfss3dl_solve.stop_simulations() + poll_count += 1 + logger.info( + f"test_3dl_analyze_setup: poll #{poll_count} at {time.time() - start:.1f}s, " + f"are_there_simulations_running={running}" + ) + elapsed_poll = time.time() - start + logger.info( + f"test_3dl_analyze_setup: polling loop done after {elapsed_poll:.1f}s, " + f"poll_count={poll_count}, running={running}" + ) + + if not running: + setup_solved = hfss3dl_solve.setups[0].is_solved if hfss3dl_solve.setups else None + logger.warning( + f"test_3dl_analyze_setup: simulations NOT detected as running. " + f"setup_solved={setup_solved}, num_setups={len(hfss3dl_solve.setups)}" + ) + assert running, ( + f"Simulations not detected as running after {elapsed_poll:.1f}s " + f"(poll_count={poll_count}). Check AEDT logs for errors." + ) + + stop_result = hfss3dl_solve.stop_simulations() + logger.info(f"test_3dl_analyze_setup: stop_simulations returned {stop_result}") + assert stop_result + + wait_start = time.time() + wait_count = 0 while hfss3dl_solve.are_there_simulations_running: time.sleep(1) + wait_count += 1 + logger.info( + f"test_3dl_analyze_setup: waiting for simulations to stop, " + f"iteration #{wait_count}, elapsed={time.time() - wait_start:.1f}s" + ) + logger.info( + f"test_3dl_analyze_setup: simulations stopped after {time.time() - wait_start:.1f}s, " + f"wait_count={wait_count}" + ) + profile = hfss3dl_solve.setups[0].get_profile() + logger.info(f"test_3dl_analyze_setup: profile keys={list(profile.keys()) if profile else None}") key0 = list(profile.keys())[0] assert key0 == "Setup1" assert isinstance(profile[key0], SimulationProfile) + logger.info( + f"test_3dl_analyze_setup: elapsed_time={profile[key0].elapsed_time}, " + f"product={profile[key0].product}, max_memory={profile[key0].max_memory()}" + ) assert profile[key0].elapsed_time > timedelta(0) assert profile[key0].product == "HFSS3DLayout" assert profile[key0].max_memory() > MemoryGB(0.01) + logger.info("test_3dl_analyze_setup: PASS") def test_3dl_export_profile(hfss3dl_solved, test_tmp_dir): From f60815dcca50e04a6dc5fcb0f009303b30913522 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 19:21:09 +0000 Subject: [PATCH 06/12] CHORE: Auto fixes from pre-commit hooks --- tests/system/solvers/test_analyze.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/system/solvers/test_analyze.py b/tests/system/solvers/test_analyze.py index f1b39ba9d5b..de19bb2bf2e 100644 --- a/tests/system/solvers/test_analyze.py +++ b/tests/system/solvers/test_analyze.py @@ -212,8 +212,7 @@ def test_3dl_analyze_setup(hfss3dl_solve): f"iteration #{wait_count}, elapsed={time.time() - wait_start:.1f}s" ) logger.info( - f"test_3dl_analyze_setup: simulations stopped after {time.time() - wait_start:.1f}s, " - f"wait_count={wait_count}" + f"test_3dl_analyze_setup: simulations stopped after {time.time() - wait_start:.1f}s, wait_count={wait_count}" ) profile = hfss3dl_solve.setups[0].get_profile() From fd110e64b7ac429695784e0b74cf9f068dca4b3d Mon Sep 17 00:00:00 2001 From: Devin Date: Sun, 8 Feb 2026 14:43:05 -0600 Subject: [PATCH 07/12] Minimal logging in test_3dl_analyze_setup --- tests/system/solvers/test_analyze.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/system/solvers/test_analyze.py b/tests/system/solvers/test_analyze.py index f1b39ba9d5b..216fac59887 100644 --- a/tests/system/solvers/test_analyze.py +++ b/tests/system/solvers/test_analyze.py @@ -145,24 +145,14 @@ def test_3dl_generate_mesh(hfss3dl_solve): @pytest.mark.skipif(DESKTOP_VERSION < "2023.2", reason="Working only from 2023 R2") def test_3dl_analyze_setup(hfss3dl_solve): logger = hfss3dl_solve.logger - logger.info("test_3dl_analyze_setup: START") - logger.info(f"test_3dl_analyze_setup: project_name={hfss3dl_solve.project_name}") - logger.info(f"test_3dl_analyze_setup: design_name={hfss3dl_solve.design_name}") - logger.info(f"test_3dl_analyze_setup: setup_names={hfss3dl_solve.setup_names}") - logger.info(f"test_3dl_analyze_setup: DESKTOP_VERSION={DESKTOP_VERSION}") - logger.info(f"test_3dl_analyze_setup: project_list={hfss3dl_solve.desktop_class.project_list}") assert hfss3dl_solve.export_touchstone_on_completion(export=False) - logger.info("test_3dl_analyze_setup: export_touchstone_on_completion(False) OK") assert hfss3dl_solve.export_touchstone_on_completion(export=True) - logger.info("test_3dl_analyze_setup: export_touchstone_on_completion(True) OK") if DESKTOP_VERSION > "2024.2": assert hfss3dl_solve.set_export_touchstone() - logger.info("test_3dl_analyze_setup: set_export_touchstone() OK") else: with pytest.raises(AEDTRuntimeError): hfss3dl_solve.set_export_touchstone() - logger.info("test_3dl_analyze_setup: set_export_touchstone() raised AEDTRuntimeError as expected") logger.info("test_3dl_analyze_setup: calling analyze_setup('Setup1', cores=4, blocking=False)") analyze_result = hfss3dl_solve.analyze_setup("Setup1", cores=4, blocking=False) @@ -207,29 +197,15 @@ def test_3dl_analyze_setup(hfss3dl_solve): while hfss3dl_solve.are_there_simulations_running: time.sleep(1) wait_count += 1 - logger.info( - f"test_3dl_analyze_setup: waiting for simulations to stop, " - f"iteration #{wait_count}, elapsed={time.time() - wait_start:.1f}s" - ) - logger.info( - f"test_3dl_analyze_setup: simulations stopped after {time.time() - wait_start:.1f}s, " - f"wait_count={wait_count}" - ) profile = hfss3dl_solve.setups[0].get_profile() logger.info(f"test_3dl_analyze_setup: profile keys={list(profile.keys()) if profile else None}") key0 = list(profile.keys())[0] assert key0 == "Setup1" assert isinstance(profile[key0], SimulationProfile) - logger.info( - f"test_3dl_analyze_setup: elapsed_time={profile[key0].elapsed_time}, " - f"product={profile[key0].product}, max_memory={profile[key0].max_memory()}" - ) assert profile[key0].elapsed_time > timedelta(0) assert profile[key0].product == "HFSS3DLayout" assert profile[key0].max_memory() > MemoryGB(0.01) - logger.info("test_3dl_analyze_setup: PASS") - def test_3dl_export_profile(hfss3dl_solved, test_tmp_dir): profile_file = test_tmp_dir / "temp.prof" From 319ecebc27ffb70cd1f710c322a8bbd1c9d3c33b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:48:32 +0000 Subject: [PATCH 08/12] CHORE: Auto fixes from pre-commit hooks --- tests/system/solvers/test_analyze.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/solvers/test_analyze.py b/tests/system/solvers/test_analyze.py index 216fac59887..85c7c3dffc2 100644 --- a/tests/system/solvers/test_analyze.py +++ b/tests/system/solvers/test_analyze.py @@ -207,6 +207,7 @@ def test_3dl_analyze_setup(hfss3dl_solve): assert profile[key0].product == "HFSS3DLayout" assert profile[key0].max_memory() > MemoryGB(0.01) + def test_3dl_export_profile(hfss3dl_solved, test_tmp_dir): profile_file = test_tmp_dir / "temp.prof" profile_file = Path(hfss3dl_solved.export_profile("Setup1", output_file=profile_file)) From 63905384c9ad127e262c636ed6d2ba7a687821aa Mon Sep 17 00:00:00 2001 From: Devin Date: Tue, 10 Feb 2026 05:55:59 -0600 Subject: [PATCH 09/12] Change return to yield before removing test temp dir. --- tests/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5bf5e0c2598..5f068261311 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -262,7 +262,8 @@ def test_tmp_dir(file_tmp_root, request): if d.exists(): shutil.rmtree(d, ignore_errors=True) d.mkdir(parents=True, exist_ok=True) - return d + yield d + shutil.rmtree(d, ignore_errors=True) @pytest.fixture From 2c78b7cbb43afd9b8405f3b876117ba23e6255cf Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:59:36 +0000 Subject: [PATCH 10/12] chore: adding changelog file 7231.fixed.md [dependabot-skip] --- doc/changelog.d/7231.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/7231.fixed.md diff --git a/doc/changelog.d/7231.fixed.md b/doc/changelog.d/7231.fixed.md new file mode 100644 index 00000000000..03b1aebf1f1 --- /dev/null +++ b/doc/changelog.d/7231.fixed.md @@ -0,0 +1 @@ +Test Temp dir race condition From 79e054be4ea00f9b4a687d62eee609b770422a30 Mon Sep 17 00:00:00 2001 From: Devin <38879940+Devin-Crawford@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:24:55 -0600 Subject: [PATCH 11/12] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- tests/conftest.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5f068261311..7433f7ae642 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -263,7 +263,10 @@ def test_tmp_dir(file_tmp_root, request): shutil.rmtree(d, ignore_errors=True) d.mkdir(parents=True, exist_ok=True) yield d - shutil.rmtree(d, ignore_errors=True) + try: + shutil.rmtree(d, ignore_errors=True) + except Exception: + pyaedt_logger.warning(f"Failed to cleanup temporary directory {d}") @pytest.fixture From 07e7114773bedf72ad1da2474fded95b39bf79fa Mon Sep 17 00:00:00 2001 From: Devin Date: Sat, 14 Feb 2026 12:19:10 +0100 Subject: [PATCH 12/12] Teardown after yield in conftest --- tests/conftest.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 7433f7ae642..331677d3e9c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -259,9 +259,6 @@ def desktop(tmp_path_factory, request): def test_tmp_dir(file_tmp_root, request): d = file_tmp_root / request.node.name.split("[", 1)[0] - if d.exists(): - shutil.rmtree(d, ignore_errors=True) - d.mkdir(parents=True, exist_ok=True) yield d try: shutil.rmtree(d, ignore_errors=True)