Skip to content

Commit ed1c53c

Browse files
tooling: Log errors related to new checks as Infos (#976)
Implement a new function that logs errors related to new checks as Infos and not normal warnings with a message requesting to fix them before the new project version realize.
1 parent 1b2cbe2 commit ed1c53c

3 files changed

Lines changed: 81 additions & 13 deletions

File tree

tooling/docs/_tooling/extensions/score_metamodel/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ def is_check_enabled(check: local_check_function | graph_check_function):
103103
if log.has_warnings:
104104
log.warning("Some needs have issues. See the log for more information.")
105105

106+
if log.has_infos:
107+
log.info(
108+
"Some needs have issues related to the new checks. See the log for more information."
109+
)
110+
# TODO: exit code
111+
106112

107113
def load_metamodel_data():
108114
"""

tooling/docs/_tooling/extensions/score_metamodel/log.py

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
class CheckLogger:
2222
def __init__(self, log: SphinxLoggerAdapter, prefix: str):
2323
self._log = log
24-
self._count = 0
24+
self._info_count = 0
25+
self._warning_count = 0
2526
self._prefix = prefix
2627

2728
@staticmethod
@@ -41,25 +42,53 @@ def get(key: str) -> Any:
4142
return f"{matching_file}:{need['lineno']}"
4243
return None
4344

44-
def warning_for_option(self, need: NeedsInfoType, option: str, msg: str):
45-
self.warning(
46-
f"{need['id']}.{option} ({need.get(option, None)}): " + msg,
47-
location=CheckLogger._location(need, self._prefix),
48-
)
45+
def warning_for_option(
46+
self, need: NeedsInfoType, option: str, msg: str, new_check: bool = False
47+
):
48+
full_msg = f"{need['id']}.{option} ({need.get(option, None)}): {msg}"
49+
location = CheckLogger._location(need, self._prefix)
50+
self._log_message(full_msg, location, new_check)
4951

50-
def warning_for_need(self, need: NeedsInfoType, msg: str):
51-
self.warning(
52-
f"{need['id']}: " + msg, location=CheckLogger._location(need, self._prefix)
53-
)
52+
def warning_for_need(self, need: NeedsInfoType, msg: str, new_check: bool = False):
53+
full_msg = f"{need['id']}: {msg}"
54+
location = CheckLogger._location(need, self._prefix)
55+
self._log_message(full_msg, location, new_check)
56+
57+
def _log_message(
58+
self,
59+
msg: str,
60+
location: None | str | tuple[str | None, int | None] | Node = None,
61+
is_info: bool = False,
62+
):
63+
if is_info:
64+
msg += (
65+
"\nPlease fix this warning related to the new check "
66+
"before the release of the next version of Score."
67+
)
68+
self.info(msg, location)
69+
else:
70+
self.warning(msg, location)
71+
72+
def info(
73+
self,
74+
msg: str,
75+
location: None | str | tuple[str | None, int | None] | Node = None,
76+
):
77+
self._log.info(msg, type="score_metamodel", location=location)
78+
self._info_count += 1
5479

5580
def warning(
5681
self,
5782
msg: str,
5883
location: None | str | tuple[str | None, int | None] | Node = None,
5984
):
6085
self._log.warning(msg, type="score_metamodel", location=location)
61-
self._count += 1
86+
self._warning_count += 1
6287

6388
@property
6489
def has_warnings(self):
65-
return self._count > 0
90+
return self._warning_count > 0
91+
92+
@property
93+
def has_infos(self):
94+
return self._info_count > 0

tooling/docs/_tooling/extensions/score_metamodel/tests/__init__.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class FakeCheckLogger(CheckLogger):
2626
def __init__(self):
2727
self._mock_logger = MagicMock(spec=SphinxLoggerAdapter)
2828
self._mock_logger.warning = MagicMock()
29+
self._mock_logger.info = MagicMock()
2930
app_path = MagicMock()
3031
super().__init__(self._mock_logger, app_path)
3132

@@ -36,9 +37,16 @@ def assert_no_warnings(self):
3637
)
3738
pytest.fail(f"Expected no warnings, but got:\n{warnings}")
3839

40+
def assert_no_infos(self):
41+
if self.has_infos:
42+
infos = "\n".join(
43+
f"* {call}" for call in self._mock_logger.info.call_args_list
44+
)
45+
pytest.fail(f"Expected no infos, but got:\n{infos}")
46+
3947
def assert_warning(self, expected_substring: str, expect_location: bool = True):
4048
"""
41-
Assert that the logger was called exactly once with a message containing
49+
Assert that the logger warning was called exactly once with a message containing
4250
a specific substring.
4351
4452
This also verifies that the defaults from need() are used correctly.
@@ -61,6 +69,31 @@ def assert_warning(self, expected_substring: str, expect_location: bool = True):
6169
if expect_location:
6270
assert kwargs["location"] == "docname.rst:42"
6371

72+
def assert_info(self, expected_substring: str, expect_location: bool = True):
73+
"""
74+
Assert that the logger info was called exactly once with a message containing
75+
a specific substring.
76+
77+
This also verifies that the defaults from need() are used correctly.
78+
So you must use need() to create the need object that is passed
79+
to the checks.
80+
"""
81+
self._mock_logger.info.assert_called_once()
82+
83+
# Retrieve the call arguments
84+
args, kwargs = self._mock_logger.info.call_args
85+
log_message = args[0]
86+
87+
assert expected_substring in log_message, f"Expected substring '{
88+
expected_substring
89+
}' not found in log message: '{log_message}'"
90+
91+
# All our checks shall report themselves as score_metamodel checks
92+
assert kwargs["type"] == "score_metamodel"
93+
94+
if expect_location:
95+
assert kwargs["location"] == "docname.rst:42"
96+
6497
return FakeCheckLogger()
6598

6699

0 commit comments

Comments
 (0)