Skip to content

Clean up warning capture #577

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

Merged
merged 5 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
25 changes: 11 additions & 14 deletions src/calliope/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,6 @@
import warnings
from typing import Optional, Union

# Enable simple format when printing ModelWarnings
formatwarning_orig = warnings.showwarning


def _formatwarning(message, category, filename, lineno, file=None, line=None):
"""Formats ModelWarnings as "Warning: message" without extra crud"""
if category == ModelWarning:
return "Warning: " + str(message) + "\n"
else:
return formatwarning_orig(message, category, filename, lineno, file, line)


warnings.showwarning = _formatwarning


class ModelError(Exception):
"""
Expand Down Expand Up @@ -52,8 +38,19 @@ class BackendWarning(Warning):
pass


def _formatwarning(message, category, *args, **kwargs):
"""Formats ModelWarnings as "ModelWarning: message" without extra crud"""

if category in [ModelWarning, BackendWarning]:
return f"{category.__name__}: {message}\n"
else:
return warnings._formatwarning_orig(message, category, *args, **kwargs)


def warn(message, _class=ModelWarning):
warnings.formatwarning = _formatwarning
warnings.warn(message, _class)
warnings.formatwarning = warnings._formatwarning_orig


def print_warnings_and_raise_errors(
Expand Down
7 changes: 6 additions & 1 deletion src/calliope/util/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

_time_format = "%Y-%m-%d %H:%M:%S"

_orig_py_warning_handlers = logging.getLogger("py.warnings").handlers


def setup_root_logger(
verbosity: str | int, capture_warnings: bool = True
Expand Down Expand Up @@ -49,12 +51,15 @@ def setup_root_logger(
root_logger.addHandler(console)
root_logger.setLevel(verbosity)

py_warnings_logger = logging.getLogger("py.warnings")
if capture_warnings:
logging.captureWarnings(True)
logging.getLogger("py.warnings").setLevel(verbosity)
py_warnings_logger.handlers = _orig_py_warning_handlers + [console]
py_warnings_logger.setLevel(verbosity)
else:
logging.captureWarnings(False)
logging.getLogger("py.warnings").setLevel("WARNING")
py_warnings_logger.handlers = _orig_py_warning_handlers

return root_logger

Expand Down
12 changes: 10 additions & 2 deletions tests/test_core_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,19 @@ def test_timing_log(self):
time_since_solve_start=True,
)

@pytest.mark.parametrize(["capture", "expected_level"], [(True, 20), (False, 30)])
def test_capture_warnings(self, capture, expected_level):
@pytest.mark.parametrize(
["capture", "expected_level", "n_handlers"], [(True, 20, 1), (False, 30, 0)]
)
def test_capture_warnings(self, capture, expected_level, n_handlers):
calliope.set_log_verbosity("info", capture_warnings=capture)

assert logging.getLogger("py.warnings").getEffectiveLevel() == expected_level
assert len(logging.getLogger("py.warnings").handlers) == n_handlers

def test_capture_warnings_handlers_dont_append(self):
for level in ["critical", "warning", "info", "debug"]:
calliope.set_log_verbosity(level, capture_warnings=True)
assert len(logging.getLogger("py.warnings").handlers) == 1


class TestGenerateRuns:
Expand Down