Skip to content

Commit

Permalink
Clean up warning capture (#577)
Browse files Browse the repository at this point in the history
* Clean up warning capture
* Move from DeprecationWarning (dev-focussed) to FutureWarning (user-focussed)
  • Loading branch information
brynpickering committed Mar 1, 2024
1 parent 9e13524 commit 6fd9084
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 26 deletions.
20 changes: 5 additions & 15 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,12 @@ class BackendWarning(Warning):
pass


def warn(message, _class=ModelWarning):
def warn(message: str, _class: type[Warning] = ModelWarning):
warnings.formatwarning = (
lambda message, category, *args, **kwargs: f"{category.__name__}: {message}\n"
)
warnings.warn(message, _class)
warnings.formatwarning = warnings._formatwarning_orig


def print_warnings_and_raise_errors(
Expand Down
5 changes: 2 additions & 3 deletions src/calliope/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from __future__ import annotations

import logging
import warnings
from pathlib import Path
from typing import TYPE_CHECKING, Callable, Optional, TypeVar, Union

Expand Down Expand Up @@ -482,10 +481,10 @@ def run(self, force_rerun=False, **kwargs):
Additional kwargs are passed to the backend.
"""
warnings.warn(
exceptions.warn(
"`run()` is deprecated and will be removed in a "
"future version. Use `model.build()` followed by `model.solve()`.",
DeprecationWarning,
FutureWarning,
)
self.build(force=force_rerun)
self.solve(force=force_rerun)
Expand Down
2 changes: 1 addition & 1 deletion src/calliope/preprocess/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _apply_overrides(
exceptions.warn(
"`locations` has been renamed to `nodes` and will stop working "
"in v0.7.1. Please update your model configuration accordingly.",
DeprecationWarning,
FutureWarning,
)
model_def_copy["nodes"] = model_def_copy["locations"]
del model_def_copy["locations"]
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
8 changes: 4 additions & 4 deletions tests/test_core_future_warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
from .common.util import check_error_or_warning


class TestDeprecationWarnings:
def test_run_deprecationwarning(self):
class TestFutureWarnings:
def test_run_futurewarning(self):
model = build_model(scenario="simple_supply,two_hours,investment_costs")

with pytest.warns(DeprecationWarning) as warning:
with pytest.warns(FutureWarning) as warning:
model.run()

assert check_error_or_warning(warning, "`run()` is deprecated")
assert hasattr(model, "backend")
assert hasattr(model, "results")

def test_locations_instead_of_nodes(self):
with pytest.warns(DeprecationWarning) as warning:
with pytest.warns(FutureWarning) as warning:
model = build_model(
scenario="simple_supply_locations,one_day,investment_costs"
)
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

0 comments on commit 6fd9084

Please sign in to comment.