Skip to content

Commit 8061111

Browse files
author
Vasileios Karakasis
authored
Merge pull request #1228 from ekouts/feat/deprecate-regtest-override
[feat] Deprecate test syntax that overrides `RegressionTest` methods
2 parents 106a774 + d12895e commit 8061111

File tree

8 files changed

+327
-19
lines changed

8 files changed

+327
-19
lines changed

docs/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Publications
4646

4747

4848
.. toctree::
49-
:caption: Table of Contents:
49+
:caption: Table of Contents
5050
:hidden:
5151

5252
Getting Started <started>
@@ -58,6 +58,7 @@ Publications
5858
Understanding The Mechanism Of Sanity Functions <deferrables>
5959
Running ReFrame <running>
6060
Use cases <usecases>
61+
Migrating to ReFrame 3 <migration_2_to_3>
6162
About ReFrame <about>
6263
Reference Guide <reference>
6364
Sanity Functions Reference <sanity_functions_reference>

docs/migration_2_to_3.rst

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
======================
2+
Migrating to ReFrame 3
3+
======================
4+
5+
6+
Updating your tests
7+
-------------------
8+
9+
10+
ReFrame 2.20 introduced a new powerful mechanism for attaching arbitrary functions hooks at the different pipeline stages.
11+
This mechanism provides an easy way to configure and extend the functionality of a test, eliminating essentially the need to override pipeline stages for this purpose.
12+
ReFrame 3.0 deprecates the old practice for overriding pipeline stage methods in favor of using pipeline hooks.
13+
In the old syntax, it was quite common to override the ``setup()`` method, in order to configure your test based on the current programming environment or the current system partition.
14+
The following is a typical example of that:
15+
16+
17+
.. code:: python
18+
19+
def setup(self, partition, environ, **job_opts):
20+
if environ.name == 'gnu':
21+
self.build_system.cflags = ['-fopenmp']
22+
elif environ.name == 'intel':
23+
self.build_system.cflags = ['-qopenmp']
24+
25+
super().setup(partition, environ, **job_opts)
26+
27+
28+
Alternatively, this example could have been written as follows:
29+
30+
.. code:: python
31+
32+
def setup(self, partition, environ, **job_opts):
33+
super().setup(partition, environ, **job_opts)
34+
if self.current_environ.name == 'gnu':
35+
self.build_system.cflags = ['-fopenmp']
36+
elif self.current_environ.name == 'intel':
37+
self.build_system.cflags = ['-qopenmp']
38+
39+
40+
This syntax now issues a deprecation warning.
41+
Rewriting this using pipeline hooks is quite straightforward and leads to nicer and more intuitive code:
42+
43+
.. code:: python
44+
45+
@rfm.run_before('compile')
46+
def setflags(self):
47+
if self.current_environ.name == 'gnu':
48+
self.build_system.cflags = ['-fopenmp']
49+
elif self.current_environ.name == 'intel':
50+
self.build_system.cflags = ['-qopenmp']
51+
52+
53+
You could equally attach this function to run after the "setup" phase with ``@rfm.run_after('setup')``, as in the original example, but attaching it to the "compile" phase makes more sense.
54+
However, you can't attach this function *before* the "setup" phase, because the ``current_environ`` will not be available and it will be still ``None``.
55+
56+
57+
Force override a pipeline method
58+
================================
59+
60+
Although pipeline hooks should be able to cover almost all the cases for writing tests in ReFrame, there might be corner cases that you need to override one of the pipeline methods, e.g., because you want to implement a stage differently.
61+
In this case, all you have to do is mark your test class as "special", and ReFrame will not issue any deprecation warning if you override pipeline stage methods:
62+
63+
.. code:: python
64+
65+
class MyExtendedTest(rfm.RegressionTest, special=True):
66+
def setup(self, partition, environ, **job_opts):
67+
# do your custom stuff
68+
super().setup(partition, environ, **job_opts)
69+
70+
71+
If you try to override the ``setup()`` method in any of the subclasses of ``MyExtendedTest``, you will still get a deprecation warning, which a desired behavior since the subclasses should be normal tests.
72+
73+
74+
Suppressing deprecation warnings
75+
================================
76+
77+
You can suppress any deprecation warning issued by ReFrame by passing the ``--no-deprecation-warnings`` flag.
78+

docs/tutorial.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,12 +461,16 @@ Notice that in order to redefine a hook, you need not only redefine the method i
461461
Otherwise, the base class hook will be executed.
462462

463463

464-
.. note::
465-
You may still configure your test per programming environment and per system partition by overriding the :func:`setup <reframe.core.pipeline.RegressionTest.setup>` method, as in ReFrame versions prior to 2.20, but this is now discouraged since it is more error prone, as you have to memorize the signature of the pipeline methods that you override and also remember to call ``super()``.
464+
.. warning::
465+
Configuring your test per programming environment and per system partition by overriding the :func:`setup() <reframe.core.pipeline.RegressionTest.setup>` method is deprecated.
466+
Please refer to the `Migrate to ReFrame 3 <migration_2_to_3.html#updating-your-tests>`__ guide for more details.
466467

468+
.. versionchanged:: 3.0
467469

468470
.. warning::
469-
Setting the compiler flags in the programming environment has been dropped completely in version 2.17.
471+
Support for setting the compiler flags in the programming environment has been dropped completely.
472+
473+
.. versionchanged:: 2.17
470474

471475

472476
An alternative implementation using dictionaries

reframe/core/meta.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
# Met-class for creating regression tests.
88
#
99

10+
from reframe.core.exceptions import user_deprecation_warning
11+
1012

1113
class RegressionTestMeta(type):
1214
def __init__(cls, name, bases, namespace, **kwargs):
@@ -33,3 +35,22 @@ def __init__(cls, name, bases, namespace, **kwargs):
3335

3436
hooks['post_setup'] = fn_with_deps + hooks.get('post_setup', [])
3537
cls._rfm_pipeline_hooks = hooks
38+
39+
cls._final_methods = {v.__name__ for v in namespace.values()
40+
if hasattr(v, '_rfm_final')}
41+
42+
# Add the final functions from its parents
43+
cls._final_methods.update(*(b._final_methods for b in bases
44+
if hasattr(b, '_final_methods')))
45+
46+
if hasattr(cls, '_rfm_special_test') and cls._rfm_special_test:
47+
return
48+
49+
for v in namespace.values():
50+
for b in bases:
51+
if callable(v) and v.__name__ in b._final_methods:
52+
msg = (f"'{cls.__qualname__}.{v.__name__}' attempts to "
53+
f"override final method "
54+
f"'{b.__qualname__}.{v.__name__}'; "
55+
f"consider using the reframe hooks instead")
56+
user_deprecation_warning(msg)

0 commit comments

Comments
 (0)