Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add minimum DPF version logic to examples #783

Merged
merged 9 commits into from
Feb 7, 2023
13 changes: 13 additions & 0 deletions .ci/run_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@
import subprocess
import sys

import ansys.dpf.core as dpf
from ansys.dpf.core.examples import get_example_required_minimum_dpf_version


os.environ["PYVISTA_OFF_SCREEN"] = "true"
os.environ["MPLBACKEND"] = "Agg"

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

# Get the DPF server version
server = dpf.server.get_or_create_server(None)
server_version = server.version
server.shutdown()
print(f"Server version: {server_version}")

for root, subdirectories, files in os.walk(os.path.join(actual_path, os.path.pardir, "examples")):
for subdirectory in subdirectories:
Expand All @@ -19,6 +28,10 @@
continue
print("\n--------------------------------------------------")
print(file)
minimum_version_str = get_example_required_minimum_dpf_version(file)
if float(server_version) - float(minimum_version_str) < -0.05:
print(f"Example skipped as it requires DPF {minimum_version_str}.")
continue
try:
subprocess.check_call([sys.executable, file])
except subprocess.CalledProcessError as e:
Expand Down
30 changes: 28 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import os
from glob import glob
from datetime import datetime

import numpy as np
import pyvista
from ansys.dpf.core import __version__
from ansys.dpf.core import __version__, server, server_factory
from ansys.dpf.core.examples import get_example_required_minimum_dpf_version
from ansys_sphinx_theme import pyansys_logo_black, ansys_favicon, get_version_match

# Manage errors
Expand Down Expand Up @@ -36,6 +38,28 @@
# The full version, including alpha/beta/rc tags
release = __version__

# -- Rename files to be ignored with the ignored pattern ---------------------

# Get the DPF server version
server_instance = server.start_local_server(
as_global=False,
config=server_factory.AvailableServerConfigs.GrpcServer,
)
server_version = server_instance.version
server.shutdown_all_session_servers()
print(f"DPF version: {server_version}")

# Build ignore pattern
ignored_pattern = r"(ignore"
header_flag = "\"\"\""
note_flag = r".. note::"
for example in glob(r"../../examples/**/*.py"):
minimum_version_str = get_example_required_minimum_dpf_version(example)
if float(server_version) - float(minimum_version_str) < -0.05:
example_name = example.split(os.path.sep)[-1]
print(f"Example {example_name} skipped as it requires DPF {minimum_version_str}.")
ignored_pattern += f"|{example_name}"
ignored_pattern += r")"

# -- General configuration ---------------------------------------------------

Expand Down Expand Up @@ -120,7 +144,7 @@ def reset_servers(gallery_conf, fname, when):
nb_procs += 1
except psutil.NoSuchProcess:
pass
print(f"Counted {nb_procs} {proc_name} processes {when} the example.")
print(f"Counted {nb_procs} {proc_name} processes {when} example {fname}.")


sphinx_gallery_conf = {
Expand All @@ -134,6 +158,8 @@ def reset_servers(gallery_conf, fname, when):
"gallery_dirs": ["examples"],
# Pattern to search for example files
"filename_pattern": r"\.py",
# Pattern to search for example files to be ignored
"ignore_pattern": ignored_pattern,
# Remove the "Download all examples" button from the top level gallery
"download_all_examples": False,
# Sort gallery example by file name instead of number of lines (default)
Expand Down
4 changes: 4 additions & 0 deletions examples/08-averaging/01-average_across_bodies.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
dealing with ``Nodal`` variables. It also illustrates how the end results
of a postprocessing workflow can be different when averaging and when not.

.. note::
This example requires DPF 6.1 or above.
For more information, see :ref:`ref_compatibility`.

.. note::
This example requires the Premium Server Context.
For more information, see :ref:`user_guide_server_context`.
Expand Down
37 changes: 37 additions & 0 deletions src/ansys/dpf/core/examples/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,43 @@
distributed_msup_folder = os.path.join(_module_path, "msup_distributed")


def get_example_required_minimum_dpf_version(file: os.PathLike) -> str:
"""Returns the minimal DPF server version required to run the example, as declared in a note.

Parameters
----------
file:
Path to the example file in question.

Returns
-------
Returns the minimal DPF server version required.
"""
# Read the minimal server version required for the example
header_flag = '"""'
note_flag = r".. note::"
version_flag = "This example requires DPF"
in_header = False
previous_line_is_note = False
minimum_version_str = "0.0"
with open(file, "r") as f:
for line in f:
if line[:3] == header_flag:
if not in_header:
in_header = True
continue
else:
break
if (version_flag in line) and previous_line_is_note and in_header:
minimum_version_str = line.strip(version_flag).split()[0]
break
if note_flag in line:
previous_line_is_note = True
else:
previous_line_is_note = False
return minimum_version_str


def find_files(local_path, should_upload=True, server=None, return_local_path=False):
"""Make the result file available server side, if the server is remote the file is uploaded
server side. Returns the path on the file.
Expand Down
36 changes: 36 additions & 0 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,39 @@ def test_license_agr(set_context_back_to_premium):
dpf.start_local_server(config=config, as_global=True)
assert "static" in examples.find_static_rst()
assert dpf.Operator("stream_provider") is not None


def test_get_example_required_minimum_dpf_version(tmp_path):
# Check version is parsed
example_header = """
\"\"\"
.. _ref_average_across_bodies:

Average across bodies
~~~~~~~~~~~~~~~~~~~~~
.. note::
This example requires DPF 6.1 or above.
For more information, see :ref:`ref_compatibility`.
\"\"\"
"""
p = tmp_path / "test_example_version_0.py"
p.write_text(example_header)
assert examples.get_example_required_minimum_dpf_version(p) == "6.1"
# Check default version is 0.0, and versions declared outside a note in a header do not work
example_header = """
\"\"\"
.. _ref_average_across_bodies:

Average across bodies
~~~~~~~~~~~~~~~~~~~~~
.. note::
This example requires Premium

This example requires DPF 1.2 or above.
\"\"\"
This example requires DPF 2.3 or above.
from ansys.dpf import core as dpf
"""
p = tmp_path / "test_example_version_1.py"
p.write_text(example_header)
assert examples.get_example_required_minimum_dpf_version(p) == "0.0"