Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ci-scripts/ci-runner.bash
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ if [ $CI_GENERIC -eq 1 ]; then
# Run unit tests for the public release
echo "[INFO] Running unit tests with generic settings"
checked_exec ./test_reframe.py --workers=auto --forked \
-W=error::reframe.core.exceptions.ReframeDeprecationWarning -ra
-W=error::reframe.core.warnings.ReframeDeprecationWarning -ra
checked_exec ! ./bin/reframe.py --system=generic -l 2>&1 | \
grep -- '--- Logging error ---'
elif [ $CI_TUTORIAL -eq 1 ]; then
Expand Down Expand Up @@ -174,15 +174,15 @@ else
echo "[INFO] Running unit tests with ${backend}"
TMPDIR=$tempdir checked_exec ./test_reframe.py --workers=auto --forked \
--rfm-user-config=config/cscs-ci.py \
-W=error::reframe.core.exceptions.ReframeDeprecationWarning \
-W=error::reframe.core.warnings.ReframeDeprecationWarning \
--rfm-user-system=dom:${backend} -ra
done
export PATH=$PATH_save
else
echo "[INFO] Running unit tests"
TMPDIR=$tempdir checked_exec ./test_reframe.py --workers=auto --forked \
--rfm-user-config=config/cscs-ci.py \
-W=error::reframe.core.exceptions.ReframeDeprecationWarning -ra
-W=error::reframe.core.warnings.ReframeDeprecationWarning -ra
fi

if [ $CI_EXITCODE -eq 0 ]; then
Expand Down
5 changes: 2 additions & 3 deletions reframe/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
import reframe.utility as util
import reframe.utility.osext as osext
import reframe.utility.typecheck as types
from reframe.core.exceptions import (ConfigError,
ReframeDeprecationWarning,
ReframeFatalError)
from reframe.core.exceptions import ConfigError, ReframeFatalError
from reframe.core.logging import getlogger
from reframe.core.warnings import ReframeDeprecationWarning
from reframe.utility import ScopedDict


Expand Down
2 changes: 0 additions & 2 deletions reframe/core/deferrable.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import builtins
import functools

from reframe.core.exceptions import user_deprecation_warning


def deferrable(func):
'''Function decorator for converting a function to a deferred
Expand Down
28 changes: 0 additions & 28 deletions reframe/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,6 @@ class DependencyError(ReframeError):
'''Raised when a dependency problem is encountered.'''


class ReframeDeprecationWarning(DeprecationWarning):
'''Warning raised for deprecated features of the framework.'''


warnings.filterwarnings('default', category=ReframeDeprecationWarning)


def user_frame(tb):
if not inspect.istraceback(tb):
raise ValueError('could not retrieve frame: argument not a traceback')
Expand Down Expand Up @@ -326,24 +319,3 @@ def format_user_frame(frame):

exc_str = ''.join(traceback.format_exception(exc_type, exc_value, tb))
return 'unexpected error: %s\n%s' % (exc_value, exc_str)


def user_deprecation_warning(message):
'''Raise a deprecation warning at the user stack frame that eventually
calls this function.

As "user stack frame" is considered a stack frame that is outside the
:py:mod:`reframe` base module.
'''

# Unroll the stack and issue the warning from the first stack frame that is
# outside the framework.
stack_level = 1
for s in inspect.stack():
module = inspect.getmodule(s.frame)
if module is None or not module.__name__.startswith('reframe'):
break

stack_level += 1

warnings.warn(message, ReframeDeprecationWarning, stacklevel=stack_level)
2 changes: 1 addition & 1 deletion reframe/core/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import re

import reframe.utility.typecheck as types
from reframe.core.exceptions import user_deprecation_warning
from reframe.core.warnings import user_deprecation_warning
from reframe.utility import ScopedDict


Expand Down
2 changes: 1 addition & 1 deletion reframe/core/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# Met-class for creating regression tests.
#

from reframe.core.exceptions import user_deprecation_warning
from reframe.core.warnings import user_deprecation_warning


class RegressionTestMeta(type):
Expand Down
3 changes: 2 additions & 1 deletion reframe/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@
from reframe.core.deferrable import _DeferredExpression
from reframe.core.exceptions import (BuildError, DependencyError,
PipelineError, SanityError,
PerformanceError, user_deprecation_warning)
PerformanceError)
from reframe.core.meta import RegressionTestMeta
from reframe.core.schedulers import Job
from reframe.core.warnings import user_deprecation_warning


# Dependency kinds
Expand Down
2 changes: 1 addition & 1 deletion reframe/core/systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def launcher(self):
Please use :attr:`launcher_type` instead.
'''

from reframe.core.exceptions import user_deprecation_warning
from reframe.core.warnings import user_deprecation_warning

user_deprecation_warning("the 'launcher' attribute is deprecated; "
"please use 'launcher_type' instead")
Expand Down
65 changes: 65 additions & 0 deletions reframe/core/warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import contextlib
import inspect
import warnings

from reframe.core.exceptions import ReframeFatalError


class ReframeDeprecationWarning(DeprecationWarning):
'''Warning raised for deprecated features of the framework.'''


warnings.filterwarnings('default', category=ReframeDeprecationWarning)


_format_warning_orig = warnings.formatwarning


def _format_warning(message, category, filename, lineno, line=None):
import reframe.core.runtime as rt
import reframe.utility.color as color

if category != ReframeDeprecationWarning:
return _format_warning_orig(message, category, filename, lineno, line)

if line is None:
# Read in the line from the file
with open(filename) as fp:
try:
line = fp.readlines()[lineno-1]
except IndexError:
line = '<no line information>'

message = f'{filename}:{lineno}: WARNING: {message}\n{line}\n'

# Ignore coloring if runtime has not been initialized; this can happen
# when generating the documentation of deprecated APIs
with contextlib.suppress(ReframeFatalError):
if rt.runtime().get_option('general/0/colorize'):
message = color.colorize(message, color.YELLOW)

return message


warnings.formatwarning = _format_warning


def user_deprecation_warning(message):
'''Raise a deprecation warning at the user stack frame that eventually
calls this function.

As "user stack frame" is considered a stack frame that is outside the
:py:mod:`reframe` base module.
'''

# Unroll the stack and issue the warning from the first stack frame that is
# outside the framework.
stack_level = 1
for s in inspect.stack():
module = inspect.getmodule(s.frame)
if module is None or not module.__name__.startswith('reframe'):
break

stack_level += 1

warnings.warn(message, ReframeDeprecationWarning, stacklevel=stack_level)
3 changes: 2 additions & 1 deletion reframe/frontend/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
import reframe.utility.osext as osext
from reframe.core.exceptions import (
EnvironError, ConfigError, ReframeError,
ReframeDeprecationWarning, ReframeFatalError, format_exception
ReframeFatalError, format_exception
)
from reframe.core.warnings import ReframeDeprecationWarning
from reframe.frontend.executors import Runner, generate_testcases
from reframe.frontend.executors.policies import (SerialExecutionPolicy,
AsynchronousExecutionPolicy)
Expand Down
3 changes: 2 additions & 1 deletion unittests/resources/checks_unlisted/deprecated_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import reframe as rfm
import reframe.utility.sanity as sn
from reframe.core.exceptions import user_deprecation_warning

from reframe.core.warnings import user_deprecation_warning


@rfm.simple_test
Expand Down
3 changes: 2 additions & 1 deletion unittests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import pytest

import reframe.core.config as config
from reframe.core.exceptions import (ConfigError, ReframeDeprecationWarning)
from reframe.core.exceptions import ConfigError
from reframe.core.systems import System
from reframe.core.warnings import ReframeDeprecationWarning


def test_load_config_fallback(monkeypatch):
Expand Down
2 changes: 1 addition & 1 deletion unittests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytest

import reframe.core.fields as fields
from reframe.core.exceptions import ReframeDeprecationWarning
from reframe.core.warnings import ReframeDeprecationWarning
from reframe.utility import ScopedDict


Expand Down
2 changes: 1 addition & 1 deletion unittests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

import reframe as rfm
from reframe.core.exceptions import (ConfigError, NameConflictError,
ReframeDeprecationWarning,
RegressionTestLoadError)
from reframe.core.systems import System
from reframe.core.warnings import ReframeDeprecationWarning
from reframe.frontend.loader import RegressionCheckLoader


Expand Down
51 changes: 51 additions & 0 deletions unittests/test_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest
import warnings

import reframe.core.runtime as rt
import reframe.core.warnings as warn
import reframe.utility.color as color
import unittests.fixtures as fixtures


@pytest.fixture(params=['colors', 'nocolors'])
def with_colors(request):
with rt.temp_runtime(fixtures.BUILTIN_CONFIG_FILE, 'generic',
{'general/colorize': request.param == 'colors'}):
yield request.param == 'colors'


def test_deprecation_warning():
with pytest.warns(warn.ReframeDeprecationWarning):
warn.user_deprecation_warning('deprecated')


def test_deprecation_warning_formatting(with_colors):
message = warnings.formatwarning(
'deprecated', warn.ReframeDeprecationWarning, 'file', 10, 'a = 1'
)
expected = 'file:10: WARNING: deprecated\na = 1\n'
if with_colors:
expected = color.colorize(expected, color.YELLOW)

assert message == expected


def test_deprecation_warning_formatting_noline(tmp_path, with_colors):
srcfile = tmp_path / 'file'
srcfile.touch()

message = warnings.formatwarning(
'deprecated', warn.ReframeDeprecationWarning, srcfile, 10
)
expected = f'{srcfile}:10: WARNING: deprecated\n<no line information>\n'
if with_colors:
expected = color.colorize(expected, color.YELLOW)

assert message == expected


def test_random_warning_formatting():
message = warnings.formatwarning(
'deprecated', UserWarning, 'file', 10, 'a = 1'
)
assert message == f'file:10: UserWarning: deprecated\n a = 1\n'