mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 12:05:07 +00:00
refactor(config): log the duplicate-key warning without the python warning prefix
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@@ -17,22 +17,25 @@ def test_duplicate_key_lines_follows_aliases_without_looping(compose) -> None:
|
||||
assert duplicate_key_lines(compose(ALIASES)) == [(2, 3), (7, 8)]
|
||||
|
||||
|
||||
def test_load_yaml_warns_with_lines_and_keeps_the_later_copy(tmp_path: Path) -> None:
|
||||
def test_load_yaml_warns_once_with_lines_and_keeps_the_later_copy(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
path = tmp_path / "unshackle.yaml"
|
||||
path.write_text("credentials:\n EXAMPLE: first-secret\n EXAMPLE: second-secret\n", encoding="utf-8")
|
||||
with pytest.warns(UserWarning) as caught:
|
||||
with caplog.at_level(logging.WARNING, logger="config"):
|
||||
data = load_yaml(path)
|
||||
load_yaml(path)
|
||||
assert data == {"credentials": {"EXAMPLE": "second-secret"}}
|
||||
message = str(caught[0].message)
|
||||
assert message == f"{path}: duplicate key on lines 2 and 3. Unshackle uses the later one."
|
||||
assert "EXAMPLE" not in message and "secret" not in message
|
||||
assert caplog.messages == [f"{path}: duplicate key on lines 2 and 3. Unshackle uses the later one."]
|
||||
assert "EXAMPLE" not in caplog.text and "secret" not in caplog.text
|
||||
|
||||
|
||||
def test_config_from_yaml_warns_on_a_duplicate_key(tmp_path: Path) -> None:
|
||||
def test_config_from_yaml_warns_on_a_duplicate_key(tmp_path: Path, caplog: pytest.LogCaptureFixture) -> None:
|
||||
path = tmp_path / "unshackle.yaml"
|
||||
path.write_text("tag: first\ntag: second\n", encoding="utf-8")
|
||||
with pytest.warns(UserWarning, match="duplicate key on lines 1 and 2"):
|
||||
with caplog.at_level(logging.WARNING, logger="config"):
|
||||
assert Config.from_yaml(path).tag == "second"
|
||||
assert "duplicate key on lines 1 and 2" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -40,9 +43,11 @@ def test_config_from_yaml_warns_on_a_duplicate_key(tmp_path: Path) -> None:
|
||||
["a: 1\nb: [1, 2]\n", "", "a: &a\n x: 1\nb: &b\n y: 2\nc:\n <<: *a\n <<: *b\n"],
|
||||
ids=["valid", "empty", "two-merges"],
|
||||
)
|
||||
def test_load_yaml_matches_safe_load_without_a_warning(tmp_path: Path, text: str) -> None:
|
||||
def test_load_yaml_matches_safe_load_without_a_warning(
|
||||
tmp_path: Path, text: str, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
path = tmp_path / "config.yaml"
|
||||
path.write_text(text, encoding="utf-8")
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("error")
|
||||
with caplog.at_level(logging.WARNING, logger="config"):
|
||||
assert load_yaml(path) == yaml.safe_load(text)
|
||||
assert not caplog.records
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
@@ -411,6 +412,9 @@ def duplicate_key_message(name: str, pairs: list[tuple[int, int]], line: int = 0
|
||||
return f"{name}: duplicate key on {where}. Unshackle uses the later one."
|
||||
|
||||
|
||||
_warned: set[str] = set()
|
||||
|
||||
|
||||
def load_yaml(path: Path) -> Any:
|
||||
"""yaml.safe_load a file, and warn with the lines of each duplicate key, which PyYAML takes silently."""
|
||||
loader = yaml.SafeLoader(path.read_text(encoding="utf8"))
|
||||
@@ -418,8 +422,9 @@ def load_yaml(path: Path) -> Any:
|
||||
node = loader.get_single_node()
|
||||
if node is None:
|
||||
return None
|
||||
if pairs := duplicate_key_lines(node):
|
||||
warnings.warn(duplicate_key_message(str(path), pairs), stacklevel=2)
|
||||
if (pairs := duplicate_key_lines(node)) and (message := duplicate_key_message(str(path), pairs)) not in _warned:
|
||||
_warned.add(message)
|
||||
logging.getLogger("config").warning(message)
|
||||
return loader.construct_document(node)
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
Reference in New Issue
Block a user