From eed9b7a3e246acc2cfa8d30bf231de436507bc11 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 09:44:16 +0100 Subject: [PATCH 01/30] tests: add test on plot method --- tests/core/test_lxp.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index ca9d8c002..861f0d6e0 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -23,10 +23,13 @@ """Test basic using lxp.""" from pathlib import Path +from unittest.mock import patch import ansys.speos.core.lxp as lxp from ansys.speos.core.speos import Speos from tests.conftest import test_path +import pyvista as pv + def test_light_path_finder_direct(speos: Speos): @@ -123,3 +126,11 @@ def test_light_path_finder_inverse(speos: Speos): lpf.filter_error_rays() assert len(lpf.filtered_rays) == 0 assert lpf.rays[50].get() == expected_ray + + +@patch.object(pv.Plotter, "show") +def test_light_path_finder_preview(speos: Speos): + """Test for direct simulation lpf.""" + path = str(Path(test_path) / "basic_DirectSimu.lpf") + lpf = lxp.LightPathFinder(speos=speos, path=path) + lpf.preview() From 3245ebcc260c57bb20237135b32ad71886a35214 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 27 Mar 2025 08:54:28 +0000 Subject: [PATCH 02/30] chore: adding changelog file 521.test.md [dependabot-skip] --- doc/changelog.d/521.test.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/521.test.md diff --git a/doc/changelog.d/521.test.md b/doc/changelog.d/521.test.md new file mode 100644 index 000000000..2f51bdc97 --- /dev/null +++ b/doc/changelog.d/521.test.md @@ -0,0 +1 @@ +add tests on plot method \ No newline at end of file From de7baf2b429216892bd987844e4e76054a188ead Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 10:43:51 +0100 Subject: [PATCH 03/30] test: avoid patch and use xvfb --- .github/workflows/ci_cd.yml | 13 ++++++++++++- tests/core/test_lxp.py | 1 - 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 74636d6db..513d2f468 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -95,6 +95,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Start container + shell: bash env: ANSYSLMD_LICENSE_FILE: 1055@${{ secrets.LICENSE_SERVER }} run: | @@ -109,6 +110,7 @@ jobs: dependencies: "pandoc" needs-quarto: true - name: Stop container + shell: bash run: | docker kill speos-rpc docker rm speos-rpc @@ -122,18 +124,24 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Installing OS packages + shell: bash + run: sudo apt-get update && apt install -y libgl1-mesa-glx xvfb libgomp1 + - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.MAIN_PYTHON_VERSION }} - name: Create Python virtual environment + shell: bash run: | python -m venv .venv source .venv/bin/activate python -c "import sys; print(sys.executable)" - name: Install packages for testing + shell: bash run: | . .venv/bin/activate python -m pip install --upgrade pip @@ -150,13 +158,15 @@ jobs: - name: Start container env: ANSYSLMD_LICENSE_FILE: 1055@${{ secrets.LICENSE_SERVER }} + shell: bash run: | docker run --detach --name speos-rpc -p 50098:50098 -e SPEOS_LOG_LEVEL=2 -e ANSYSLMD_LICENSE_FILE=${{ env.ANSYSLMD_LICENSE_FILE }} -v "${{ github.workspace }}/tests/assets:/app/assets" --entrypoint /app/SpeosRPC_Server.x ghcr.io/ansys/speos-rpc:dev - name: Run pytest + shell: bash run: | . .venv/bin/activate - pytest -xs + xvfb-run pytest -xs - name: Upload Coverage Results if: always() @@ -174,6 +184,7 @@ jobs: files: .cov/xml - name: Stop container + shell: bash run: | docker kill speos-rpc docker rm speos-rpc diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index 861f0d6e0..0c1d17a00 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -128,7 +128,6 @@ def test_light_path_finder_inverse(speos: Speos): assert lpf.rays[50].get() == expected_ray -@patch.object(pv.Plotter, "show") def test_light_path_finder_preview(speos: Speos): """Test for direct simulation lpf.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") From 34fad26c0334554286db14122bd8ac428ab5ce34 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 09:44:04 +0000 Subject: [PATCH 04/30] ci: auto fixes from pre-commit.com hooks. for more information, see https://pre-commit.ci --- tests/core/test_lxp.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index 0c1d17a00..6e024d852 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -23,13 +23,10 @@ """Test basic using lxp.""" from pathlib import Path -from unittest.mock import patch import ansys.speos.core.lxp as lxp from ansys.speos.core.speos import Speos from tests.conftest import test_path -import pyvista as pv - def test_light_path_finder_direct(speos: Speos): From 1354d333b717fd8699b8f3020ecc7fc75ed902fc Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 11:25:25 +0100 Subject: [PATCH 05/30] ci: split install in two steps --- .github/workflows/ci_cd.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 513d2f468..8cb0d4504 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -126,7 +126,9 @@ jobs: - name: Installing OS packages shell: bash - run: sudo apt-get update && apt install -y libgl1-mesa-glx xvfb libgomp1 + run: | + sudo apt-get update + sudo apt install -y libgl1-mesa-glx xvfb libgomp1 - name: Set up Python uses: actions/setup-python@v5 From 55ba34890a8d0adccaed81e7bfd0e9f6cbe07045 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 11:58:45 +0100 Subject: [PATCH 06/30] ci: update libs to match ubuntu 24.04 --- .github/workflows/ci_cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 8cb0d4504..f52c3ce0b 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -128,7 +128,7 @@ jobs: shell: bash run: | sudo apt-get update - sudo apt install -y libgl1-mesa-glx xvfb libgomp1 + sudo apt install -y libgl1 libglx-mesa0 xvfb libgomp1 - name: Set up Python uses: actions/setup-python@v5 From 3e044e31ee372f85ac47a23262f7f85c6bf4685e Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 14:50:27 +0100 Subject: [PATCH 07/30] feature: allow saving image in tests dir --- src/ansys/speos/core/lxp.py | 13 ++++++++++--- src/ansys/speos/core/project.py | 16 ++++++++++++---- src/ansys/speos/core/workflow/open_result.py | 2 +- tests/conftest.py | 1 + tests/core/test_lxp.py | 4 ++-- tests/image_results/.gitignore | 2 ++ 6 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 tests/image_results/.gitignore diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index aeebba083..0eea95101 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -29,7 +29,8 @@ from __future__ import annotations import os -from typing import Union +from pathlib import Path +from typing import Optional, Union import pyvista as pv @@ -452,6 +453,7 @@ def preview( max_ray_length: float = 50.0, ray_filter: bool = False, project: Project = None, + screenshot: Optional[Union[str, Path]] = None, ) -> LightPathFinder: """Preview LPF file with pyvista. @@ -465,12 +467,17 @@ def preview( Boolean to decide if filtered rays or all rays should be shown. project : ansys.speos.core.project.Project Speos Project/Geometry to be added to pyvista visualisation. + screenshot : str or Path or ``None`` + Path to save a screenshot of the plotter. Returns ------- ansys.speos.core.lxp.LightPathFinder LightPathFinder Instance. """ + if screenshot is not None: + screenshot = Path(screenshot) + if ray_filter: if len(self._filtered_rays) > 0: temp_rays = self._filtered_rays @@ -496,9 +503,9 @@ def preview( for i in range(nb_ray): self.__add_ray_to_pv(plotter, temp_rays[i], max_ray_length) if os.environ.get("DOCUMENTATION_BUILDING", "true") == "true": - plotter.show(jupyter_backend="html") + plotter.show(screenshot=screenshot, jupyter_backend="html") else: - plotter.show() + plotter.show(screenshot=screenshot) return self diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index ae665de5f..9a09f48e8 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -24,6 +24,7 @@ from __future__ import annotations import os +from pathlib import Path import re from typing import List, Mapping, Optional, Union import uuid @@ -924,7 +925,7 @@ def _create_preview(self, viz_args=None) -> pv.Plotter: p.add_mesh(_preview_mesh, show_edges=True, **viz_args) return p - def preview(self, viz_args=None) -> None: + def preview(self, viz_args=None, screenshot: Optional[Union[str, Path]] = None,) -> None: """Preview cad bodies inside the project's scene. Parameters @@ -934,12 +935,19 @@ def preview(self, viz_args=None) -> None: e.g. - {'style': 'wireframe'}, - {'style': 'surface', 'color':'white'}, - - {'opacity': 0.7, 'color':'white', 'show_edges': False}, + - {'opacity': 0.7, 'color':'white', 'show_edges': False}. + + screenshot : str or Path or ``None`` + Path to save a screenshot of the plotter. + """ if viz_args is None: viz_args = {"opacity": 1} + if screenshot is not None: + screenshot = Path(screenshot) + p = self._create_preview(viz_args=viz_args) if os.environ.get("DOCUMENTATION_BUILDING", "true") == "true": - p.show(jupyter_backend="html") + p.show(screenshot=screenshot, jupyter_backend="html") else: - p.show() + p.show(screenshot=screenshot) diff --git a/src/ansys/speos/core/workflow/open_result.py b/src/ansys/speos/core/workflow/open_result.py index b36f77102..f3b592ba8 100644 --- a/src/ansys/speos/core/workflow/open_result.py +++ b/src/ansys/speos/core/workflow/open_result.py @@ -77,7 +77,7 @@ def _find_correct_result( return file_path -def _display_image(img: ndarray): +def _display_image(img: ndarray, screenshot=None): if img is not None: plt.imshow(img) plt.axis("off") # turns off axes diff --git a/tests/conftest.py b/tests/conftest.py index 5a40bb36f..c9da29321 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -38,6 +38,7 @@ from ansys.speos.core import LOG from ansys.speos.core.speos import Speos +IMAGE_RESULTS_DIR = Path(Path(__file__).parent, "image_results") @pytest.fixture(scope="session") def speos(): diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index 6e024d852..6099341a6 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -26,7 +26,7 @@ import ansys.speos.core.lxp as lxp from ansys.speos.core.speos import Speos -from tests.conftest import test_path +from tests.conftest import IMAGE_RESULTS_DIR, test_path def test_light_path_finder_direct(speos: Speos): @@ -129,4 +129,4 @@ def test_light_path_finder_preview(speos: Speos): """Test for direct simulation lpf.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") lpf = lxp.LightPathFinder(speos=speos, path=path) - lpf.preview() + lpf.preview(screenshot=Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png"),) diff --git a/tests/image_results/.gitignore b/tests/image_results/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/tests/image_results/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From c924eb748f0f2cd4caf70797015b7ff19bd1bfd7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:51:36 +0000 Subject: [PATCH 08/30] ci: auto fixes from pre-commit.com hooks. for more information, see https://pre-commit.ci --- src/ansys/speos/core/lxp.py | 2 +- src/ansys/speos/core/project.py | 6 +++++- tests/conftest.py | 1 + tests/core/test_lxp.py | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 0eea95101..08733ee13 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -477,7 +477,7 @@ def preview( """ if screenshot is not None: screenshot = Path(screenshot) - + if ray_filter: if len(self._filtered_rays) > 0: temp_rays = self._filtered_rays diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index 9a09f48e8..db9c13fb5 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -925,7 +925,11 @@ def _create_preview(self, viz_args=None) -> pv.Plotter: p.add_mesh(_preview_mesh, show_edges=True, **viz_args) return p - def preview(self, viz_args=None, screenshot: Optional[Union[str, Path]] = None,) -> None: + def preview( + self, + viz_args=None, + screenshot: Optional[Union[str, Path]] = None, + ) -> None: """Preview cad bodies inside the project's scene. Parameters diff --git a/tests/conftest.py b/tests/conftest.py index c9da29321..5233979db 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,6 +40,7 @@ IMAGE_RESULTS_DIR = Path(Path(__file__).parent, "image_results") + @pytest.fixture(scope="session") def speos(): """Pytest ficture to create Speos objects for all unit, integration and workflow tests. diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index 6099341a6..f12bfe7f4 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -129,4 +129,6 @@ def test_light_path_finder_preview(speos: Speos): """Test for direct simulation lpf.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") lpf = lxp.LightPathFinder(speos=speos, path=path) - lpf.preview(screenshot=Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png"),) + lpf.preview( + screenshot=Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png"), + ) From a7adb7b5942321ad21ec3fa4cc714a8221529ef4 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 15:22:23 +0100 Subject: [PATCH 09/30] test: add off_screen=true by default --- tests/conftest.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 5233979db..c26ed0490 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -38,6 +38,13 @@ from ansys.speos.core import LOG from ansys.speos.core.speos import Speos +try: + import pyvista as pv + pv.OFF_SCREEN = True + pv.global_theme.window_size = [500, 500] +except ImportError: + pass + IMAGE_RESULTS_DIR = Path(Path(__file__).parent, "image_results") From 30de62a59c15106287ef723005c171ecdc54e27b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 14:22:38 +0000 Subject: [PATCH 10/30] ci: auto fixes from pre-commit.com hooks. for more information, see https://pre-commit.ci --- tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/conftest.py b/tests/conftest.py index c26ed0490..b6f94501b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,6 +40,7 @@ try: import pyvista as pv + pv.OFF_SCREEN = True pv.global_theme.window_size = [500, 500] except ImportError: From 948bb63afef8f3032f77b220e53eba8d6ed106e6 Mon Sep 17 00:00:00 2001 From: Sebastien Morais Date: Thu, 27 Mar 2025 15:57:27 +0100 Subject: [PATCH 11/30] test: extend test with asserts --- tests/core/test_lxp.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index f12bfe7f4..d5c8153b8 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -126,9 +126,11 @@ def test_light_path_finder_inverse(speos: Speos): def test_light_path_finder_preview(speos: Speos): - """Test for direct simulation lpf.""" + """Test lpf preview.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") + screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") lpf = lxp.LightPathFinder(speos=speos, path=path) - lpf.preview( - screenshot=Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png"), - ) + lpf.preview(screenshot=screenshot) + + assert screenshot.exists() + assert screenshot.stat().st_size > 0 From 3d445e3c81b3ac114704fe40cbd992fbbcdb1c49 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 14:58:40 +0000 Subject: [PATCH 12/30] ci: auto fixes from pre-commit.com hooks. for more information, see https://pre-commit.ci --- tests/core/test_lxp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index d5c8153b8..1983a0702 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -131,6 +131,6 @@ def test_light_path_finder_preview(speos: Speos): screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") lpf = lxp.LightPathFinder(speos=speos, path=path) lpf.preview(screenshot=screenshot) - + assert screenshot.exists() assert screenshot.stat().st_size > 0 From a42dced928709a2d624676dd79f3b56206a07d13 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 27 Mar 2025 15:03:00 +0000 Subject: [PATCH 13/30] chore: adding changelog file 521.added.md [dependabot-skip] --- doc/changelog.d/521.added.md | 1 + doc/changelog.d/521.test.md | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/changelog.d/521.added.md delete mode 100644 doc/changelog.d/521.test.md diff --git a/doc/changelog.d/521.added.md b/doc/changelog.d/521.added.md new file mode 100644 index 000000000..91c1c3853 --- /dev/null +++ b/doc/changelog.d/521.added.md @@ -0,0 +1 @@ +add screenshot in pyvista related methods \ No newline at end of file diff --git a/doc/changelog.d/521.test.md b/doc/changelog.d/521.test.md deleted file mode 100644 index 2f51bdc97..000000000 --- a/doc/changelog.d/521.test.md +++ /dev/null @@ -1 +0,0 @@ -add tests on plot method \ No newline at end of file From 5961e87d6a1295f5080216f4d9ddf74b3c817066 Mon Sep 17 00:00:00 2001 From: sthoene Date: Fri, 28 Mar 2025 07:45:16 +0100 Subject: [PATCH 14/30] fix bug and improve tests --- src/ansys/speos/core/lxp.py | 2 +- tests/core/test_lxp.py | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 08733ee13..0472cad83 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -432,7 +432,7 @@ def __add_ray_to_pv(plotter: pv.Plotter, ray: RayPath, max_ray_length: float): max_ray_length : float Length of the last ray. """ - temp = ray.impacts + temp = ray.impacts.copy() if not 7 <= ray.intersection_type[-1] <= 15: temp.append( [ diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index 1983a0702..ac2a6890c 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -25,6 +25,7 @@ from pathlib import Path import ansys.speos.core.lxp as lxp +from ansys.speos.core.project import Project from ansys.speos.core.speos import Speos from tests.conftest import IMAGE_RESULTS_DIR, test_path @@ -33,6 +34,8 @@ def test_light_path_finder_direct(speos: Speos): """Test for direct simulation lpf.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") lpf = lxp.LightPathFinder(speos=speos, path=path) + screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") + lpf.preview(screenshot=screenshot) expected_ray = { "nb_impacts": 4, "impacts": [ @@ -125,12 +128,30 @@ def test_light_path_finder_inverse(speos: Speos): assert lpf.rays[50].get() == expected_ray -def test_light_path_finder_preview(speos: Speos): - """Test lpf preview.""" +def test_lpf_preview_with_project(speos: Speos): + """Test for visualizing lpf data.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") + p = Project( + speos=speos, + path=str( + Path(test_path) / "LG_50M_Colorimetric_short.sv5" / "LG_50M_Colorimetric_short.sv5" + ), + ) lpf = lxp.LightPathFinder(speos=speos, path=path) - lpf.preview(screenshot=screenshot) + lpf.preview(project=p, screenshot=screenshot) + assert screenshot.exists() + assert screenshot.stat().st_size > 0 + +def test_lpf_preview_without_project(speos: Speos): + """Test for visualizing lpf data.""" + path = str(Path(test_path) / "basic_DirectSimu.lpf") + screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") + lpf1 = lxp.LightPathFinder(speos=speos, path=path) + lpf1.filter_by_body_ids([3601101451]) + lpf1.filter_by_face_ids([3866239813], new=False) + lpf1.remove_error_rays() + lpf1.preview(ray_filter=True, screenshot=screenshot) assert screenshot.exists() assert screenshot.stat().st_size > 0 From 675724e174c627a0690472955fe9c04fb41ebd39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Th=C3=B6ne?= <86405327+StefanThoene@users.noreply.github.com> Date: Mon, 31 Mar 2025 09:51:46 +0200 Subject: [PATCH 15/30] 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> --- src/ansys/speos/core/workflow/open_result.py | 2 +- tests/core/test_lxp.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/speos/core/workflow/open_result.py b/src/ansys/speos/core/workflow/open_result.py index f3b592ba8..b36f77102 100644 --- a/src/ansys/speos/core/workflow/open_result.py +++ b/src/ansys/speos/core/workflow/open_result.py @@ -77,7 +77,7 @@ def _find_correct_result( return file_path -def _display_image(img: ndarray, screenshot=None): +def _display_image(img: ndarray): if img is not None: plt.imshow(img) plt.axis("off") # turns off axes diff --git a/tests/core/test_lxp.py b/tests/core/test_lxp.py index ac2a6890c..1cac804fd 100644 --- a/tests/core/test_lxp.py +++ b/tests/core/test_lxp.py @@ -131,7 +131,7 @@ def test_light_path_finder_inverse(speos: Speos): def test_lpf_preview_with_project(speos: Speos): """Test for visualizing lpf data.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") - screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") + screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_direct.png") p = Project( speos=speos, path=str( @@ -147,7 +147,7 @@ def test_lpf_preview_with_project(speos: Speos): def test_lpf_preview_without_project(speos: Speos): """Test for visualizing lpf data.""" path = str(Path(test_path) / "basic_DirectSimu.lpf") - screenshot = Path(IMAGE_RESULTS_DIR, "test_light_path_finder_preview.png") + screenshot = Path(IMAGE_RESULTS_DIR, "test_lpf_preview_without_project.png") lpf1 = lxp.LightPathFinder(speos=speos, path=path) lpf1.filter_by_body_ids([3601101451]) lpf1.filter_by_face_ids([3866239813], new=False) From 89e3eac3f035f628e9718cf283279cc386c56e6a Mon Sep 17 00:00:00 2001 From: sthoene Date: Mon, 31 Mar 2025 17:19:09 +0200 Subject: [PATCH 16/30] add notes to highlight correct way to close pyvista --- src/ansys/speos/core/lxp.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 0472cad83..8bb7b5638 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -474,10 +474,13 @@ def preview( ------- ansys.speos.core.lxp.LightPathFinder LightPathFinder Instance. - """ - if screenshot is not None: - screenshot = Path(screenshot) + Notes + ----- + Please use the ``q``-key to close the plotter as some + operating systems (namely Windows) will experience issues + saving a screenshot if the exit button in the GUI is pressed. + """ if ray_filter: if len(self._filtered_rays) > 0: temp_rays = self._filtered_rays @@ -502,7 +505,7 @@ def preview( else: for i in range(nb_ray): self.__add_ray_to_pv(plotter, temp_rays[i], max_ray_length) - if os.environ.get("DOCUMENTATION_BUILDING", "true") == "true": + if os.environ.get("DOCUMENTATION_BUILDING", "false") == "true": plotter.show(screenshot=screenshot, jupyter_backend="html") else: plotter.show(screenshot=screenshot) From 6aa1bd57040530269c03fba271c9258f1b168f7d Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:06:06 +0200 Subject: [PATCH 17/30] switch to ansys-tools-visualization-interface --- pyproject.toml | 6 +++++- src/ansys/speos/core/lxp.py | 14 ++++++++------ src/ansys/speos/core/project.py | 9 ++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3ae46e057..b1e6d98a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,11 +32,15 @@ dependencies=[ "grpcio-health-checking>=1.45.0,<1.68", "ansys-api-speos==0.14.2", "numpy>=1.20.3,<3", - "pyvista>=0.40.0,<0.45", + "comtypes>=1.4,<1.5", ] [project.optional-dependencies] +graphics = [ + "pyvista>=0.40.0,<0.45", + "ansys-tools-visualization-interface>=0.8.3" +] tests = [ "pytest==8.3.5", "ansys-platform-instancemanagement>=1.0.3", diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 8bb7b5638..87880096c 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -37,6 +37,7 @@ import ansys.api.speos.lpf.v2.lpf_file_reader_pb2 as lpf_file_reader__v2__pb2 import ansys.api.speos.lpf.v2.lpf_file_reader_pb2_grpc as lpf_file_reader__v2__pb2_grpc from ansys.speos.core.project import Project, Speos +from ansys.tools.visualization_interface import Plotter ERROR_IDS = [7, 8, 9, 10, 11, 12, 13, 14, 15] """Intersection types indicating an error state.""" @@ -420,13 +421,13 @@ def remove_error_rays(self) -> LightPathFinder: return self @staticmethod - def __add_ray_to_pv(plotter: pv.Plotter, ray: RayPath, max_ray_length: float): + def __add_ray_to_pv(plotter: Plotter, ray: RayPath, max_ray_length: float): """Add a ray to pyvista plotter. Parameters ---------- - plotter : pv.Plotter - Pyvista plotter object to which rays should be added. + plotter : Plotter + Ansys plotter object to which rays should be added. ray : script.RayPath RayPath object which contains ray information to be added. max_ray_length : float @@ -445,7 +446,7 @@ def __add_ray_to_pv(plotter: pv.Plotter, ray: RayPath, max_ray_length: float): mesh = pv.MultipleLines(temp) else: mesh = pv.Line(temp[0], temp[1]) - plotter.add_mesh(mesh, color=wavelength_to_rgb(ray.wl), line_width=2) + plotter.plot(mesh, color=wavelength_to_rgb(ray.wl), line_width=2) def preview( self, @@ -468,7 +469,8 @@ def preview( project : ansys.speos.core.project.Project Speos Project/Geometry to be added to pyvista visualisation. screenshot : str or Path or ``None`` - Path to save a screenshot of the plotter. + Path to save a screenshot of the plotter. If defined Plotter will only create the + screenshot Returns ------- @@ -490,7 +492,7 @@ def preview( else: temp_rays = self._rays if not project: - plotter = pv.Plotter() + plotter = Plotter() if nb_ray > len(temp_rays): for ray in temp_rays: self.__add_ray_to_pv(plotter, ray, max_ray_length) diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index db9c13fb5..2f7dec98e 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -58,6 +58,7 @@ SourceSurface, ) from ansys.speos.core.speos import Speos +from ansys.tools.visualization_interface import Plotter class Project: @@ -921,8 +922,9 @@ def _create_preview(self, viz_args=None) -> pv.Plotter: poly_data = self.__extract_part_mesh_info(part_data=root_part_data) if poly_data is not None: _preview_mesh = _preview_mesh.append_polydata(poly_data) - p = pv.Plotter() - p.add_mesh(_preview_mesh, show_edges=True, **viz_args) + p = Plotter() + viz_args["show_edges"] = True + p.add_mesh(_preview_mesh, **viz_args) return p def preview( @@ -942,7 +944,8 @@ def preview( - {'opacity': 0.7, 'color':'white', 'show_edges': False}. screenshot : str or Path or ``None`` - Path to save a screenshot of the plotter. + Path to save a screenshot of the plotter. If defined Plotter will only create the + screenshot """ if viz_args is None: From 22faa970e7ba734a8aa38f25f43a889ee150c0b7 Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:14:55 +0200 Subject: [PATCH 18/30] add test requirements --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b1e6d98a8..4f9ef7e38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,10 +39,12 @@ dependencies=[ [project.optional-dependencies] graphics = [ "pyvista>=0.40.0,<0.45", - "ansys-tools-visualization-interface>=0.8.3" + "ansys-tools-visualization-interface>=0.8.3", ] tests = [ "pytest==8.3.5", + "pyvista>=0.40.0,<0.45", + "ansys-tools-visualization-interface>=0.8.3", "ansys-platform-instancemanagement>=1.0.3", "pytest-cov==6.0.0", ] From 531595a05d0d79b48f6bf9b633156da090f83565 Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:15:27 +0200 Subject: [PATCH 19/30] add jupyter requirements --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4f9ef7e38..cf781fa20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ jupyter = [ "jupyterlab>=3", "ipywidgets", "pyvista[jupyter]>=0.43,<0.45", + "ansys-tools-visualization-interface>=0.8.3", "notebook==7.3.3", ] doc = [ From c3518c462ca0d29aac5e59bb4dbfc97205b70287 Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:15:46 +0200 Subject: [PATCH 20/30] add jupyter and doc requirements --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index cf781fa20..beca4d150 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,6 +72,7 @@ doc = [ "jupyter-server==2.15.0", "nbconvert==7.16.6", "pyvista[jupyter]>=0.43,<0.45", + "ansys-tools-visualization-interface>=0.8.3", ] [project.urls] From 54e248b3167b39f6671664533f7d0566616380ff Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:21:19 +0200 Subject: [PATCH 21/30] add jupyter and doc requirements --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index beca4d150..359d2944f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,6 @@ dependencies=[ "grpcio-health-checking>=1.45.0,<1.68", "ansys-api-speos==0.14.2", "numpy>=1.20.3,<3", - "comtypes>=1.4,<1.5", ] From 588072db1b349335ab6bea8e390d501f5c5f84c5 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Tue, 1 Apr 2025 09:22:28 +0000 Subject: [PATCH 22/30] chore: adding changelog file 532.added.md [dependabot-skip] --- doc/changelog.d/532.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/532.added.md diff --git a/doc/changelog.d/532.added.md b/doc/changelog.d/532.added.md new file mode 100644 index 000000000..4b13c707e --- /dev/null +++ b/doc/changelog.d/532.added.md @@ -0,0 +1 @@ +switch to ansys tools \ No newline at end of file From 1d98b4d4feafecfbfc10db7987e9ed21a707bb04 Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:28:05 +0200 Subject: [PATCH 23/30] change add_mesh to plot --- src/ansys/speos/core/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index 2f7dec98e..7858d070f 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -924,7 +924,7 @@ def _create_preview(self, viz_args=None) -> pv.Plotter: _preview_mesh = _preview_mesh.append_polydata(poly_data) p = Plotter() viz_args["show_edges"] = True - p.add_mesh(_preview_mesh, **viz_args) + p.plot(_preview_mesh, **viz_args) return p def preview( From 85f2689f3f95986f1f26082688c9359629716d5b Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:56:22 +0200 Subject: [PATCH 24/30] add simple error management and warnings warning when importing module error when executing function --- src/ansys/speos/core/lxp.py | 18 +++++++++++++++--- src/ansys/speos/core/project.py | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 87880096c..2f9b8bca0 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -31,13 +31,22 @@ import os from pathlib import Path from typing import Optional, Union - -import pyvista as pv +import warnings import ansys.api.speos.lpf.v2.lpf_file_reader_pb2 as lpf_file_reader__v2__pb2 import ansys.api.speos.lpf.v2.lpf_file_reader_pb2_grpc as lpf_file_reader__v2__pb2_grpc from ansys.speos.core.project import Project, Speos -from ansys.tools.visualization_interface import Plotter + +try: + import pyvista as pv + + from ansys.tools.visualization_interface import Plotter + + GRAPHICS = True +except ImportError: + GRAPHICS_ERROR = "Preview unsupported without 'ansys-tools-visualization_interface' installed " + warnings.warn(GRAPHICS_ERROR) + GRAPHICS = False ERROR_IDS = [7, 8, 9, 10, 11, 12, 13, 14, 15] """Intersection types indicating an error state.""" @@ -483,6 +492,9 @@ def preview( operating systems (namely Windows) will experience issues saving a screenshot if the exit button in the GUI is pressed. """ + if not GRAPHICS: + raise ModuleNotFoundError(GRAPHICS_ERROR) + if ray_filter: if len(self._filtered_rays) > 0: temp_rays = self._filtered_rays diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index 7858d070f..0f54f2437 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -28,10 +28,10 @@ import re from typing import List, Mapping, Optional, Union import uuid +import warnings from google.protobuf.internal.containers import RepeatedScalarFieldContainer import numpy as np -import pyvista as pv import ansys.speos.core.body as body import ansys.speos.core.face as face @@ -58,7 +58,17 @@ SourceSurface, ) from ansys.speos.core.speos import Speos -from ansys.tools.visualization_interface import Plotter + +try: + import pyvista as pv + + from ansys.tools.visualization_interface import Plotter + + GRAPHICS = True +except ImportError: + GRAPHICS_ERROR = "Preview unsupported without 'ansys-tools-visualization_interface' installed " + warnings.warn(GRAPHICS_ERROR) + GRAPHICS = False class Project: @@ -948,6 +958,8 @@ def preview( screenshot """ + if not GRAPHICS: + raise ModuleNotFoundError(GRAPHICS_ERROR) if viz_args is None: viz_args = {"opacity": 1} if screenshot is not None: From 08ca049809cb32dd9a18a0873fa1b70773924665 Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 11:59:45 +0200 Subject: [PATCH 25/30] improve error msg --- src/ansys/speos/core/lxp.py | 5 ++++- src/ansys/speos/core/project.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 2f9b8bca0..46832fc7d 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -44,7 +44,10 @@ GRAPHICS = True except ImportError: - GRAPHICS_ERROR = "Preview unsupported without 'ansys-tools-visualization_interface' installed " + GRAPHICS_ERROR = ( + "Preview unsupported without 'ansys-tools-visualization_interface' installed." + "You can install this using `pip install ansys-speos-core[graphics]`." + ) warnings.warn(GRAPHICS_ERROR) GRAPHICS = False diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index 0f54f2437..a4b20b297 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -66,7 +66,10 @@ GRAPHICS = True except ImportError: - GRAPHICS_ERROR = "Preview unsupported without 'ansys-tools-visualization_interface' installed " + GRAPHICS_ERROR = ( + "Preview unsupported without 'ansys-tools-visualization_interface' installed." + "You can install this using `pip install ansys-speos-core[graphics]`." + ) warnings.warn(GRAPHICS_ERROR) GRAPHICS = False From fd0c57894e6aed98a37380510f3a4346aa8f14b6 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:02:10 +0000 Subject: [PATCH 26/30] chore: adding changelog file 532.added.md [dependabot-skip] --- doc/changelog.d/532.added.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.d/532.added.md b/doc/changelog.d/532.added.md index 4b13c707e..ef4bb2805 100644 --- a/doc/changelog.d/532.added.md +++ b/doc/changelog.d/532.added.md @@ -1 +1 @@ -switch to ansys tools \ No newline at end of file +switch to ansys tools and decouple requirements \ No newline at end of file From b9b4e1b2be209562652c868e8acd1f651e15daf5 Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 12:10:41 +0200 Subject: [PATCH 27/30] add coverage info --- src/ansys/speos/core/lxp.py | 2 +- src/ansys/speos/core/project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 46832fc7d..1a8e51b14 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -43,7 +43,7 @@ from ansys.tools.visualization_interface import Plotter GRAPHICS = True -except ImportError: +except ImportError: # pragma: no cover GRAPHICS_ERROR = ( "Preview unsupported without 'ansys-tools-visualization_interface' installed." "You can install this using `pip install ansys-speos-core[graphics]`." diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index a4b20b297..e98516594 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -65,7 +65,7 @@ from ansys.tools.visualization_interface import Plotter GRAPHICS = True -except ImportError: +except ImportError: # pragma: no cover GRAPHICS_ERROR = ( "Preview unsupported without 'ansys-tools-visualization_interface' installed." "You can install this using `pip install ansys-speos-core[graphics]`." From a8ff6f7c9c123e22622da5813f0bd93f3e243b0c Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 12:55:40 +0200 Subject: [PATCH 28/30] switch to decorator --- .../speos/core/generic/general_methods.py | 46 +++++++++++++++++++ src/ansys/speos/core/lxp.py | 23 ++++------ src/ansys/speos/core/project.py | 25 +++++----- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/ansys/speos/core/generic/general_methods.py b/src/ansys/speos/core/generic/general_methods.py index 5a47fdc03..21c398d96 100644 --- a/src/ansys/speos/core/generic/general_methods.py +++ b/src/ansys/speos/core/generic/general_methods.py @@ -28,6 +28,12 @@ from functools import wraps import warnings +__GRAPHICS_AVAILABLE = None +GRAPHICS_ERROR = ( + "Preview unsupported without 'ansys-tools-visualization_interface' installed. " + "You can install this using `pip install ansys-speos-core[graphics]`." +) + def deprecate_kwargs(old_arguments: dict, removed_version="0.3.0"): """Issues deprecation warnings for arguments. @@ -62,3 +68,43 @@ def wrapper(*args, **kwargs): return wrapper return decorator + + +def run_if_graphics_required(warning=False): + """Check if graphics are available.""" + global __GRAPHICS_AVAILABLE + if __GRAPHICS_AVAILABLE is None: + try: # pragma: no cover + import pyvista as pv # noqa: F401 + + from ansys.tools.visualization_interface import Plotter # noqa: F401 + + __GRAPHICS_AVAILABLE = True + except ImportError: + __GRAPHICS_AVAILABLE = False + + if (__GRAPHICS_AVAILABLE and warning) is False: + raise ImportError(GRAPHICS_ERROR) + elif __GRAPHICS_AVAILABLE is False: + warnings.warn(GRAPHICS_ERROR) + + +def graphics_required(method): + """Decorate a method as requiring graphics. + + Parameters + ---------- + method : callable + Method to decorate. + + Returns + ------- + callable + Decorated method. + """ + + def wrapper(*args, **kwargs): + run_if_graphics_required() + return method(*args, **kwargs) + + return wrapper diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index 1a8e51b14..a677ca57f 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -30,26 +30,23 @@ import os from pathlib import Path -from typing import Optional, Union -import warnings +from typing import TYPE_CHECKING, Optional, Union import ansys.api.speos.lpf.v2.lpf_file_reader_pb2 as lpf_file_reader__v2__pb2 import ansys.api.speos.lpf.v2.lpf_file_reader_pb2_grpc as lpf_file_reader__v2__pb2_grpc +from ansys.speos.core.generic.general_methods import graphics_required from ansys.speos.core.project import Project, Speos -try: +if TYPE_CHECKING: # pragma: no cover import pyvista as pv from ansys.tools.visualization_interface import Plotter +try: + from ansys.speos.core.generic.general_methods import run_if_graphics_required - GRAPHICS = True -except ImportError: # pragma: no cover - GRAPHICS_ERROR = ( - "Preview unsupported without 'ansys-tools-visualization_interface' installed." - "You can install this using `pip install ansys-speos-core[graphics]`." - ) - warnings.warn(GRAPHICS_ERROR) - GRAPHICS = False + run_if_graphics_required(warning=True) +except ImportError as err: # pragma: no cover + raise err ERROR_IDS = [7, 8, 9, 10, 11, 12, 13, 14, 15] """Intersection types indicating an error state.""" @@ -460,6 +457,7 @@ def __add_ray_to_pv(plotter: Plotter, ray: RayPath, max_ray_length: float): mesh = pv.Line(temp[0], temp[1]) plotter.plot(mesh, color=wavelength_to_rgb(ray.wl), line_width=2) + @graphics_required def preview( self, nb_ray: int = 100, @@ -495,9 +493,6 @@ def preview( operating systems (namely Windows) will experience issues saving a screenshot if the exit button in the GUI is pressed. """ - if not GRAPHICS: - raise ModuleNotFoundError(GRAPHICS_ERROR) - if ray_filter: if len(self._filtered_rays) > 0: temp_rays = self._filtered_rays diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index e98516594..19e307ca5 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -26,15 +26,15 @@ import os from pathlib import Path import re -from typing import List, Mapping, Optional, Union +from typing import TYPE_CHECKING, List, Mapping, Optional, Union import uuid -import warnings from google.protobuf.internal.containers import RepeatedScalarFieldContainer import numpy as np import ansys.speos.core.body as body import ansys.speos.core.face as face +from ansys.speos.core.generic.general_methods import graphics_required from ansys.speos.core.kernel.body import BodyLink from ansys.speos.core.kernel.face import FaceLink from ansys.speos.core.kernel.part import ProtoPart @@ -60,19 +60,17 @@ from ansys.speos.core.speos import Speos try: + from ansys.speos.core.generic.general_methods import run_if_graphics_required + + run_if_graphics_required(warning=True) +except ImportError as err: # pragma: no cover + raise err + +if TYPE_CHECKING: # pragma: no cover import pyvista as pv from ansys.tools.visualization_interface import Plotter - GRAPHICS = True -except ImportError: # pragma: no cover - GRAPHICS_ERROR = ( - "Preview unsupported without 'ansys-tools-visualization_interface' installed." - "You can install this using `pip install ansys-speos-core[graphics]`." - ) - warnings.warn(GRAPHICS_ERROR) - GRAPHICS = False - class Project: """A project describes all Speos features. @@ -902,7 +900,7 @@ def local2absolute(local_vertice: np.ndarray, coordinates) -> np.ndarray: part_mesh_info = part_mesh_info.append_polydata(face_mesh_data) return part_mesh_info - def _create_preview(self, viz_args=None) -> pv.Plotter: + def _create_preview(self, viz_args=None) -> Plotter: """Create preview pyvista plotter object. Parameters @@ -940,6 +938,7 @@ def _create_preview(self, viz_args=None) -> pv.Plotter: p.plot(_preview_mesh, **viz_args) return p + @graphics_required def preview( self, viz_args=None, @@ -961,8 +960,6 @@ def preview( screenshot """ - if not GRAPHICS: - raise ModuleNotFoundError(GRAPHICS_ERROR) if viz_args is None: viz_args = {"opacity": 1} if screenshot is not None: From 5fefcdc3aff6265081e7ee898a20bfce5f91329f Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 13:12:21 +0200 Subject: [PATCH 29/30] fix tests --- src/ansys/speos/core/generic/general_methods.py | 2 +- src/ansys/speos/core/lxp.py | 7 +++++-- src/ansys/speos/core/project.py | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ansys/speos/core/generic/general_methods.py b/src/ansys/speos/core/generic/general_methods.py index 21c398d96..06e290912 100644 --- a/src/ansys/speos/core/generic/general_methods.py +++ b/src/ansys/speos/core/generic/general_methods.py @@ -83,7 +83,7 @@ def run_if_graphics_required(warning=False): except ImportError: __GRAPHICS_AVAILABLE = False - if (__GRAPHICS_AVAILABLE and warning) is False: + if __GRAPHICS_AVAILABLE is False and warning is False: raise ImportError(GRAPHICS_ERROR) elif __GRAPHICS_AVAILABLE is False: warnings.warn(GRAPHICS_ERROR) diff --git a/src/ansys/speos/core/lxp.py b/src/ansys/speos/core/lxp.py index a677ca57f..9c79deecd 100644 --- a/src/ansys/speos/core/lxp.py +++ b/src/ansys/speos/core/lxp.py @@ -38,8 +38,6 @@ from ansys.speos.core.project import Project, Speos if TYPE_CHECKING: # pragma: no cover - import pyvista as pv - from ansys.tools.visualization_interface import Plotter try: from ansys.speos.core.generic.general_methods import run_if_graphics_required @@ -430,6 +428,7 @@ def remove_error_rays(self) -> LightPathFinder: return self @staticmethod + @graphics_required def __add_ray_to_pv(plotter: Plotter, ray: RayPath, max_ray_length: float): """Add a ray to pyvista plotter. @@ -442,6 +441,8 @@ def __add_ray_to_pv(plotter: Plotter, ray: RayPath, max_ray_length: float): max_ray_length : float Length of the last ray. """ + import pyvista as pv + temp = ray.impacts.copy() if not 7 <= ray.intersection_type[-1] <= 15: temp.append( @@ -493,6 +494,8 @@ def preview( operating systems (namely Windows) will experience issues saving a screenshot if the exit button in the GUI is pressed. """ + from ansys.tools.visualization_interface import Plotter + if ray_filter: if len(self._filtered_rays) > 0: temp_rays = self._filtered_rays diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index 19e307ca5..b29a4f16a 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -841,6 +841,7 @@ def __extract_part_mesh_info( pv.PolyData mesh data extracted. """ + import pyvista as pv def local2absolute(local_vertice: np.ndarray, coordinates) -> np.ndarray: """Convert local coordinate to global coordinate. @@ -900,6 +901,7 @@ def local2absolute(local_vertice: np.ndarray, coordinates) -> np.ndarray: part_mesh_info = part_mesh_info.append_polydata(face_mesh_data) return part_mesh_info + @graphics_required def _create_preview(self, viz_args=None) -> Plotter: """Create preview pyvista plotter object. @@ -912,6 +914,10 @@ def _create_preview(self, viz_args=None) -> Plotter: - {'style': 'surface', 'color':'white'}, - {'opacity': 0.7, 'color':'white', 'show_edges': False}, """ + import pyvista as pv + + from ansys.tools.visualization_interface import Plotter + if viz_args is None: viz_args = {} _preview_mesh = pv.PolyData() From fbaf28430fdc0e9b3e5e2839b801a4ab0e22736e Mon Sep 17 00:00:00 2001 From: sthoene Date: Tue, 1 Apr 2025 13:19:37 +0200 Subject: [PATCH 30/30] correct coverage information in general_methods.py --- src/ansys/speos/core/generic/general_methods.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ansys/speos/core/generic/general_methods.py b/src/ansys/speos/core/generic/general_methods.py index 06e290912..eb8676fef 100644 --- a/src/ansys/speos/core/generic/general_methods.py +++ b/src/ansys/speos/core/generic/general_methods.py @@ -74,18 +74,18 @@ def run_if_graphics_required(warning=False): """Check if graphics are available.""" global __GRAPHICS_AVAILABLE if __GRAPHICS_AVAILABLE is None: - try: # pragma: no cover + try: import pyvista as pv # noqa: F401 from ansys.tools.visualization_interface import Plotter # noqa: F401 __GRAPHICS_AVAILABLE = True - except ImportError: + except ImportError: # pragma: no cover __GRAPHICS_AVAILABLE = False - if __GRAPHICS_AVAILABLE is False and warning is False: + if __GRAPHICS_AVAILABLE is False and warning is False: # pragma: no cover raise ImportError(GRAPHICS_ERROR) - elif __GRAPHICS_AVAILABLE is False: + elif __GRAPHICS_AVAILABLE is False: # pragma: no cover warnings.warn(GRAPHICS_ERROR)