Skip to content

Commit b747593

Browse files
authored
Add minimum DPF version logic to examples (#783)
* Add a version note to 01-average_across_bodies.py * Treat the DPF version note of the examples in the run_examples.py script. * Treat the DPF version note of the examples in the run_examples.py script. * Treat the DPF version note of the examples in the documentation script. * Fix: had to switch to grpc config otherwise the first example run crashed * Move the minimum version parsing logic to dpf.core.examples.get_example_required_minimum_dpf_version * Fix reference link to compatibility table (with server versions) * Switch back to check_call in run_examples.py * Add coverage and fix default version to "0.0"
1 parent a5c32a7 commit b747593

File tree

5 files changed

+118
-2
lines changed

5 files changed

+118
-2
lines changed

.ci/run_examples.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@
44
import subprocess
55
import sys
66

7+
import ansys.dpf.core as dpf
8+
from ansys.dpf.core.examples import get_example_required_minimum_dpf_version
9+
10+
711
os.environ["PYVISTA_OFF_SCREEN"] = "true"
812
os.environ["MPLBACKEND"] = "Agg"
913

1014
actual_path = pathlib.Path(__file__).parent.absolute()
1115
print(os.path.join(actual_path, os.path.pardir, "examples"))
1216

17+
# Get the DPF server version
18+
server = dpf.server.get_or_create_server(None)
19+
server_version = server.version
20+
server.shutdown()
21+
print(f"Server version: {server_version}")
1322

1423
for root, subdirectories, files in os.walk(os.path.join(actual_path, os.path.pardir, "examples")):
1524
for subdirectory in subdirectories:
@@ -19,6 +28,10 @@
1928
continue
2029
print("\n--------------------------------------------------")
2130
print(file)
31+
minimum_version_str = get_example_required_minimum_dpf_version(file)
32+
if float(server_version) - float(minimum_version_str) < -0.05:
33+
print(f"Example skipped as it requires DPF {minimum_version_str}.")
34+
continue
2235
try:
2336
subprocess.check_call([sys.executable, file])
2437
except subprocess.CalledProcessError as e:

docs/source/conf.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import os
2+
from glob import glob
23
from datetime import datetime
34

45
import numpy as np
56
import pyvista
6-
from ansys.dpf.core import __version__
7+
from ansys.dpf.core import __version__, server, server_factory
8+
from ansys.dpf.core.examples import get_example_required_minimum_dpf_version
79
from ansys_sphinx_theme import pyansys_logo_black, ansys_favicon, get_version_match
810

911
# Manage errors
@@ -36,6 +38,28 @@
3638
# The full version, including alpha/beta/rc tags
3739
release = __version__
3840

41+
# -- Rename files to be ignored with the ignored pattern ---------------------
42+
43+
# Get the DPF server version
44+
server_instance = server.start_local_server(
45+
as_global=False,
46+
config=server_factory.AvailableServerConfigs.GrpcServer,
47+
)
48+
server_version = server_instance.version
49+
server.shutdown_all_session_servers()
50+
print(f"DPF version: {server_version}")
51+
52+
# Build ignore pattern
53+
ignored_pattern = r"(ignore"
54+
header_flag = "\"\"\""
55+
note_flag = r".. note::"
56+
for example in glob(r"../../examples/**/*.py"):
57+
minimum_version_str = get_example_required_minimum_dpf_version(example)
58+
if float(server_version) - float(minimum_version_str) < -0.05:
59+
example_name = example.split(os.path.sep)[-1]
60+
print(f"Example {example_name} skipped as it requires DPF {minimum_version_str}.")
61+
ignored_pattern += f"|{example_name}"
62+
ignored_pattern += r")"
3963

4064
# -- General configuration ---------------------------------------------------
4165

@@ -120,7 +144,7 @@ def reset_servers(gallery_conf, fname, when):
120144
nb_procs += 1
121145
except psutil.NoSuchProcess:
122146
pass
123-
print(f"Counted {nb_procs} {proc_name} processes {when} the example.")
147+
print(f"Counted {nb_procs} {proc_name} processes {when} example {fname}.")
124148

125149

126150
sphinx_gallery_conf = {
@@ -134,6 +158,8 @@ def reset_servers(gallery_conf, fname, when):
134158
"gallery_dirs": ["examples"],
135159
# Pattern to search for example files
136160
"filename_pattern": r"\.py",
161+
# Pattern to search for example files to be ignored
162+
"ignore_pattern": ignored_pattern,
137163
# Remove the "Download all examples" button from the top level gallery
138164
"download_all_examples": False,
139165
# Sort gallery example by file name instead of number of lines (default)

examples/08-averaging/01-average_across_bodies.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
dealing with ``Nodal`` variables. It also illustrates how the end results
1616
of a postprocessing workflow can be different when averaging and when not.
1717
18+
.. note::
19+
This example requires DPF 6.1 or above.
20+
For more information, see :ref:`ref_compatibility`.
21+
1822
.. note::
1923
This example requires the Premium Server Context.
2024
For more information, see :ref:`user_guide_server_context`.

src/ansys/dpf/core/examples/examples.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,43 @@
3333
distributed_msup_folder = os.path.join(_module_path, "msup_distributed")
3434

3535

36+
def get_example_required_minimum_dpf_version(file: os.PathLike) -> str:
37+
"""Returns the minimal DPF server version required to run the example, as declared in a note.
38+
39+
Parameters
40+
----------
41+
file:
42+
Path to the example file in question.
43+
44+
Returns
45+
-------
46+
Returns the minimal DPF server version required.
47+
"""
48+
# Read the minimal server version required for the example
49+
header_flag = '"""'
50+
note_flag = r".. note::"
51+
version_flag = "This example requires DPF"
52+
in_header = False
53+
previous_line_is_note = False
54+
minimum_version_str = "0.0"
55+
with open(file, "r") as f:
56+
for line in f:
57+
if line[:3] == header_flag:
58+
if not in_header:
59+
in_header = True
60+
continue
61+
else:
62+
break
63+
if (version_flag in line) and previous_line_is_note and in_header:
64+
minimum_version_str = line.strip(version_flag).split()[0]
65+
break
66+
if note_flag in line:
67+
previous_line_is_note = True
68+
else:
69+
previous_line_is_note = False
70+
return minimum_version_str
71+
72+
3673
def find_files(local_path, should_upload=True, server=None, return_local_path=False):
3774
"""Make the result file available server side, if the server is remote the file is uploaded
3875
server side. Returns the path on the file.

tests/test_examples.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,39 @@ def test_license_agr(set_context_back_to_premium):
116116
dpf.start_local_server(config=config, as_global=True)
117117
assert "static" in examples.find_static_rst()
118118
assert dpf.Operator("stream_provider") is not None
119+
120+
121+
def test_get_example_required_minimum_dpf_version(tmp_path):
122+
# Check version is parsed
123+
example_header = """
124+
\"\"\"
125+
.. _ref_average_across_bodies:
126+
127+
Average across bodies
128+
~~~~~~~~~~~~~~~~~~~~~
129+
.. note::
130+
This example requires DPF 6.1 or above.
131+
For more information, see :ref:`ref_compatibility`.
132+
\"\"\"
133+
"""
134+
p = tmp_path / "test_example_version_0.py"
135+
p.write_text(example_header)
136+
assert examples.get_example_required_minimum_dpf_version(p) == "6.1"
137+
# Check default version is 0.0, and versions declared outside a note in a header do not work
138+
example_header = """
139+
\"\"\"
140+
.. _ref_average_across_bodies:
141+
142+
Average across bodies
143+
~~~~~~~~~~~~~~~~~~~~~
144+
.. note::
145+
This example requires Premium
146+
147+
This example requires DPF 1.2 or above.
148+
\"\"\"
149+
This example requires DPF 2.3 or above.
150+
from ansys.dpf import core as dpf
151+
"""
152+
p = tmp_path / "test_example_version_1.py"
153+
p.write_text(example_header)
154+
assert examples.get_example_required_minimum_dpf_version(p) == "0.0"

0 commit comments

Comments
 (0)