mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 10:31:50 +01:00
chore: improve dicts module
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
|
||||
import copy, json, os # isort: skip
|
||||
from collections import defaultdict
|
||||
from collections.abc import Callable
|
||||
from gettext import gettext as _
|
||||
from importlib.resources import read_text as get_resource_as_string
|
||||
@@ -12,6 +13,7 @@ from typing import Any, Final
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
from . import files, loggers # pylint: disable=cyclic-import
|
||||
from .misc import K, V
|
||||
|
||||
LOG:Final[loggers.Logger] = loggers.get_logger(__name__)
|
||||
|
||||
@@ -23,30 +25,50 @@ def apply_defaults(
|
||||
override:Callable[[Any, Any], bool] = lambda _k, _v: False
|
||||
) -> dict[Any, Any]:
|
||||
"""
|
||||
>>> apply_defaults({}, {"foo": "bar"})
|
||||
{'foo': 'bar'}
|
||||
>>> apply_defaults({"foo": "foo"}, {"foo": "bar"})
|
||||
{'foo': 'foo'}
|
||||
>>> apply_defaults({"foo": ""}, {"foo": "bar"})
|
||||
{'foo': ''}
|
||||
>>> apply_defaults({}, {"foo": "bar"}, ignore = lambda k, _: k == "foo")
|
||||
>>> apply_defaults({}, {'a': 'b'})
|
||||
{'a': 'b'}
|
||||
>>> apply_defaults({'a': 'b'}, {'a': 'c'})
|
||||
{'a': 'b'}
|
||||
>>> apply_defaults({'a': ''}, {'a': 'b'})
|
||||
{'a': ''}
|
||||
>>> apply_defaults({}, {'a': 'b'}, ignore = lambda k, _: k == 'a')
|
||||
{}
|
||||
>>> apply_defaults({"foo": ""}, {"foo": "bar"}, override = lambda _, v: v == "")
|
||||
{'foo': 'bar'}
|
||||
>>> apply_defaults({"foo": None}, {"foo": "bar"}, override = lambda _, v: v == "")
|
||||
{'foo': None}
|
||||
>>> apply_defaults({'a': ''}, {'a': 'b'}, override = lambda _, v: v == '')
|
||||
{'a': 'b'}
|
||||
>>> apply_defaults({'a': None}, {'a': 'b'}, override = lambda _, v: v == '')
|
||||
{'a': None}
|
||||
>>> apply_defaults({'a': {'x': 1}}, {'a': {'x': 0, 'y': 2}})
|
||||
{'a': {'x': 1, 'y': 2}}
|
||||
>>> apply_defaults({'a': {'b': False}}, {'a': { 'b': True}})
|
||||
{'a': {'b': False}}
|
||||
"""
|
||||
for key, default_value in defaults.items():
|
||||
if key in target:
|
||||
if isinstance(target[key], dict) and isinstance(default_value, dict):
|
||||
apply_defaults(target[key], default_value, ignore = ignore)
|
||||
elif override(key, target[key]):
|
||||
apply_defaults(
|
||||
target = target[key],
|
||||
defaults = default_value,
|
||||
ignore = ignore,
|
||||
override = override
|
||||
)
|
||||
elif override(key, target[key]): # force overwrite if override says so
|
||||
target[key] = copy.deepcopy(default_value)
|
||||
elif not ignore(key, default_value):
|
||||
elif not ignore(key, default_value): # only set if not explicitly ignored
|
||||
target[key] = copy.deepcopy(default_value)
|
||||
return target
|
||||
|
||||
|
||||
def defaultdict_to_dict(d: defaultdict[K, V]) -> dict[K, V]:
|
||||
"""Recursively convert defaultdict to dict."""
|
||||
result: dict[K, V] = {}
|
||||
for key, value in d.items():
|
||||
if isinstance(value, defaultdict):
|
||||
result[key] = defaultdict_to_dict(value) # type: ignore[assignment]
|
||||
else:
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
|
||||
def load_dict(filepath:str, content_label:str = "") -> dict[str, Any]:
|
||||
"""
|
||||
:raises FileNotFoundError
|
||||
|
||||
@@ -11,6 +11,8 @@ from . import i18n
|
||||
|
||||
# https://mypy.readthedocs.io/en/stable/generics.html#generic-functions
|
||||
T = TypeVar("T")
|
||||
K = TypeVar("K")
|
||||
V = TypeVar("V")
|
||||
|
||||
|
||||
def ensure(
|
||||
|
||||
Reference in New Issue
Block a user