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