Skip to content

Commit 01e2cfd

Browse files
committed
Test helper functions, replace use of deprecated logging function
1 parent d24171f commit 01e2cfd

File tree

5 files changed

+133
-4
lines changed

5 files changed

+133
-4
lines changed

mreg_cli/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def start_logging(
181181
try:
182182
logging.basicConfig(
183183
filename=logfile,
184-
level=logging.getLevelName(level),
184+
level=level.as_int(),
185185
format=LOGGING_FORMAT,
186186
datefmt="%Y-%m-%d %H:%M:%S",
187187
)

mreg_cli/outputmanager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from mreg_cli.errorbuilder import build_error_message
2323
from mreg_cli.exceptions import CliError, FileError
24-
from mreg_cli.types import JsonMapping, RecordingEntry, TimeInfo
24+
from mreg_cli.types import Json, JsonMapping, RecordingEntry, TimeInfo
2525

2626
logger = logging.getLogger(__name__)
2727

@@ -77,8 +77,8 @@ def remove_comments(line: str) -> str:
7777
return find_char_outside_quotes(line, "#", False).rstrip(" ")
7878

7979

80-
def remove_dict_key_recursive(obj: object, key: str) -> None:
81-
"""Remove a key from a dict, recursively.
80+
def remove_dict_key_recursive(obj: Json, key: str) -> None:
81+
"""Remove a key from a dict or list of dicts, recursively.
8282
8383
This is a destructive operation, and will modify the object in place.
8484
"""

mreg_cli/types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import argparse
66
import ipaddress
7+
import logging
78
from collections.abc import Callable
89
from enum import StrEnum
910
from functools import lru_cache
@@ -161,6 +162,18 @@ def choices(cls) -> list[str]:
161162
"""Return a list of all log levels as strings."""
162163
return [str(c) for c in list(cls)]
163164

165+
def as_int(self) -> int:
166+
"""Convert the log level to an integer."""
167+
# logging.getLevelName considered a mistake - let's implement our own
168+
_nameToLevel = {
169+
self.CRITICAL: logging.CRITICAL,
170+
self.ERROR: logging.ERROR,
171+
self.WARNING: logging.WARNING,
172+
self.INFO: logging.INFO,
173+
self.DEBUG: logging.DEBUG,
174+
}
175+
return _nameToLevel[self]
176+
164177

165178
T = TypeVar("T")
166179

tests/test_outputmanager.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from __future__ import annotations
2+
3+
from copy import deepcopy
4+
5+
import pytest
6+
7+
from mreg_cli.outputmanager import remove_dict_key_recursive
8+
from mreg_cli.types import Json
9+
10+
11+
@pytest.mark.parametrize(
12+
"inp,key,expected",
13+
[
14+
pytest.param(
15+
{"a": 1, "b": 2},
16+
"a",
17+
{"b": 2},
18+
id="simple_single_key_dict",
19+
),
20+
pytest.param(
21+
{"a": {"b": 2, "c": 3}, "d": 4},
22+
"b",
23+
{"a": {"c": 3}, "d": 4},
24+
id="nested_dict_removal",
25+
),
26+
pytest.param(
27+
[{"a": 1}, {"a": 2}, {"b": 3}],
28+
"a",
29+
[{}, {}, {"b": 3}],
30+
id="list_of_dicts",
31+
),
32+
pytest.param(
33+
{"a": [{"b": 1, "c": 2}, {"b": 3, "d": 4}], "e": {"b": 5, "f": {"b": 6}}},
34+
"b",
35+
{"a": [{"c": 2}, {"d": 4}], "e": {"f": {}}},
36+
id="complex_nested_structure",
37+
),
38+
pytest.param(
39+
{"a": 1, "b": 2},
40+
"c",
41+
{"a": 1, "b": 2},
42+
id="key_not_present",
43+
),
44+
pytest.param(
45+
{},
46+
"a",
47+
{},
48+
id="empty_dict",
49+
),
50+
pytest.param(
51+
[],
52+
"a",
53+
[],
54+
id="empty_list",
55+
),
56+
pytest.param(
57+
{"a": 1, "b": "string", "c": True, "d": None, "e": 1.5, "f": {"a": 2}},
58+
"a",
59+
{"b": "string", "c": True, "d": None, "e": 1.5, "f": {}},
60+
id="mixed_types_with_nested_removal",
61+
),
62+
pytest.param(
63+
[[[{"a": 1}]], [[{"a": 2}]]],
64+
"a",
65+
[[[{}]], [[{}]]],
66+
id="deeply_nested_lists",
67+
),
68+
], # type: ignore
69+
)
70+
def test_remove_dict_key_recursive(inp: Json, key: str, expected: Json) -> None:
71+
"""Test remove_dict_key_recursive with a variety of inputs."""
72+
# Call the function
73+
remove_dict_key_recursive(inp, key)
74+
75+
# Assert the result matches expected
76+
assert inp == expected
77+
78+
79+
def test_none_value_handling() -> None:
80+
"""Test that the function handles None values appropriately"""
81+
obj: Json = None
82+
remove_dict_key_recursive(obj, "any_key") # Should not raise any exception
83+
assert obj is None
84+
85+
86+
@pytest.mark.parametrize(
87+
"inp",
88+
[
89+
"string",
90+
123,
91+
1.5,
92+
True,
93+
False,
94+
None,
95+
],
96+
)
97+
def test_primitive_value_handling(inp: Json) -> None:
98+
"""Test that the function handles primitive values appropriately."""
99+
original = deepcopy(inp)
100+
remove_dict_key_recursive(inp, "any_key") # Should not raise any exception
101+
assert inp == original # Should not modify primitive values

tests/test_types.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from __future__ import annotations
2+
3+
from inline_snapshot import snapshot
4+
5+
from mreg_cli.types import LogLevel
6+
7+
8+
def test_loglevel_as_int() -> None:
9+
"""Test that all LogLevel members have an integer representation."""
10+
for level in list(LogLevel):
11+
# If it doesn't implement as_int, this will raise a KeyError
12+
assert level.as_int() is not None
13+
14+
# Snapshot so we can see if any values are changed
15+
assert [lvl.as_int() for lvl in list(LogLevel)] == snapshot([10, 20, 30, 40, 50])

0 commit comments

Comments
 (0)