Skip to content

Commit 2088859

Browse files
feat: add reuse flag to override gallery flag (#1564)
Co-authored-by: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com>
1 parent f3a3696 commit 2088859

9 files changed

Lines changed: 91 additions & 5 deletions

File tree

.github/labels.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@
7474
description: Issues fixed in Ansys Mechanical version 271
7575
color: FFDD33
7676

77+
- name: fixed-in-next-release
78+
description: Issues fixed in the upcoming Ansys Mechanical release
79+
color: FFEE66
80+
7781
- name: 24R2
7882
description: Bug observed in PyMechanical with Mechanical version 24R2
7983
color: 804000

doc/changelog.d/1564.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add reuse flag to override gallery flag

doc/source/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
import ansys.mechanical.core as pymechanical
2323
from ansys.mechanical.core.embedding.initializer import SUPPORTED_MECHANICAL_EMBEDDING_VERSIONS
2424

25-
# necessary when building the sphinx gallery
25+
# Documentation gallery: enables Sphinx-Gallery and embedded ``App`` instance
26+
# reuse across gallery scripts. Per-constructor opt-out: ``App(..., reuse_instance=True)``.
2627
pymechanical.BUILDING_GALLERY = True
2728

2829
# Ensure that offscreen rendering is used for docs generation

doc/source/user_guide/embedding/globals.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ not for the ``globals`` argument of the ``App`` class:
4343
4444
app = App()
4545
app.update_globals(globals(), False)
46+

src/ansys/mechanical/core/__init__.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,19 @@
7676
from ansys.mechanical.core.pool import LocalMechanicalPool
7777

7878
BUILDING_GALLERY = False
79-
"""Whether or not to build gallery examples."""
79+
"""Control documentation gallery behavior and embedded-app instance sharing.
80+
81+
When ``True``:
82+
83+
- Sphinx enables the example gallery during documentation builds (see ``doc/source/conf.py``).
84+
- For the embedded :class:`~ansys.mechanical.core.embedding.app.App`, multiple
85+
``App()`` constructions reuse one underlying Mechanical instance so examples can
86+
run without exhausting resources.
87+
88+
To opt out of embedded instance sharing for a single ``App`` while leaving this
89+
flag unchanged (for example when ``BUILDING_GALLERY`` is set globally), pass
90+
``reuse_instance=True`` to the constructor.
91+
"""
8092

8193
__all__ = [
8294
"__version__",

src/ansys/mechanical/core/embedding/app.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ class App:
193193
feature_flags : list, optional
194194
List of feature flag names to enable. Default is [].
195195
Available flags include: 'ThermalShells', 'MultistageHarmonic', 'CPython'.
196+
reuse_instance : bool, optional
197+
When ``True``, gallery instance sharing is skipped for this constructor,
198+
so initialization follows the same path as when the module-level
199+
``BUILDING_GALLERY`` flag is ``False``. Use this to opt out of gallery
200+
sharing without assigning ``pymechanical.BUILDING_GALLERY = False`` (for
201+
example when the flag is set globally for documentation builds).
202+
Default is ``False``.
196203
197204
Examples
198205
--------
@@ -236,12 +243,16 @@ def __init__(
236243
self,
237244
db_file: str | None = None,
238245
private_appdata: bool = False,
246+
*,
247+
reuse_instance: bool = False,
239248
**kwargs: typing.Any,
240249
) -> None:
241250
"""Construct an instance of the mechanical Application."""
242251
global INSTANCES
243252
from ansys.mechanical.core import BUILDING_GALLERY
244253

254+
use_gallery_sharing = BUILDING_GALLERY and not reuse_instance
255+
245256
self._enable_logging = kwargs.get("enable_logging", True)
246257
if self._enable_logging:
247258
self._log = LOG
@@ -270,7 +281,7 @@ def __init__(
270281

271282
# If the building gallery flag is set, we need to share the instance
272283
# This can apply to running the `make -C doc html` command
273-
if BUILDING_GALLERY:
284+
if use_gallery_sharing:
274285
if len(INSTANCES) != 0:
275286
# Get the first instance of the app
276287
instance: App = INSTANCES[0]
@@ -668,7 +679,8 @@ def _share(self, other) -> None:
668679
"""Shares the state of self with other.
669680
670681
Other is another instance of App.
671-
This is used when the BUILDING_GALLERY flag is on.
682+
This is used when the BUILDING_GALLERY flag is on and the constructor
683+
was not called with ``reuse_instance=True``.
672684
In that mode, multiple instance of App are used, but
673685
they all point to the same underlying application
674686
object. Because of that, special care needs to be

tests/embedding/test_app.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,8 @@ def test_building_gallery(pytestconfig, run_subprocess, rootdir):
325325
"""Test for building gallery check.
326326
327327
When building the gallery, each example file creates another instance of the app.
328-
When the BUILDING_GALLERY flag is enabled, only one instance is kept.
328+
When the BUILDING_GALLERY flag is enabled, only one instance is kept (unless a
329+
constructor uses ``reuse_instance=True`` to opt out of sharing).
329330
This is to test the bug fixed in https://github.com/ansys/pymechanical/pull/784
330331
and will fail on PyMechanical version 0.11.0
331332
"""
@@ -350,6 +351,16 @@ def test_building_gallery(pytestconfig, run_subprocess, rootdir):
350351
assert "Multiple App launched with building gallery flag on" in stdout
351352

352353

354+
@pytest.mark.embedding_scripts
355+
def test_reuse_instance_bypasses_gallery_sharing(pytestconfig, run_subprocess, rootdir):
356+
"""When BUILDING_GALLERY is True, ``reuse_instance=True`` skips the sharing path."""
357+
version = pytestconfig.getoption("ansys_version")
358+
script = Path(rootdir) / "tests" / "scripts" / "reuse_instance_test.py"
359+
_process, stdout, stderr = run_subprocess([sys.executable, str(script), version])
360+
stdout = stdout.decode()
361+
assert "reuse_instance bypassed gallery sharing as expected" in stdout
362+
363+
353364
@pytest.mark.embedding
354365
def test_shims_import_material(embedded_app, assets):
355366
"""Test deprecation warning for shims import material."""

tests/embedding/test_globals.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def test_globals_kwarg_building_gallery(run_subprocess, pytestconfig, rootdir):
111111
112112
Test ViewOrientationType exists and messages are printed when
113113
BUILDING_GALLERY is True and globals are updated during the app initialization.
114+
(Gallery instance sharing can be skipped per ``App`` via ``reuse_instance=True``.)
114115
"""
115116
version = pytestconfig.getoption("ansys_version")
116117
embedded_py = Path(rootdir) / "tests" / "scripts" / "run_embedded_app.py"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (C) 2022 - 2026 ANSYS, Inc. and/or its affiliates.
2+
# SPDX-License-Identifier: MIT
3+
#
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
"""Exercise App(reuse_instance=...) when BUILDING_GALLERY is True."""
24+
25+
import sys
26+
27+
import ansys.mechanical.core as pymechanical
28+
29+
30+
if __name__ == "__main__":
31+
version = int(sys.argv[1])
32+
pymechanical.BUILDING_GALLERY = True
33+
34+
_ = pymechanical.App(version=version)
35+
try:
36+
pymechanical.App(version=version, reuse_instance=True)
37+
except RuntimeError as exc:
38+
if "Cannot have more than one embedded mechanical instance" in str(exc):
39+
print("reuse_instance bypassed gallery sharing as expected")
40+
else:
41+
raise
42+
else:
43+
raise AssertionError("Expected RuntimeError for second App with reuse_instance=True")

0 commit comments

Comments
 (0)