Coverage for flogin/settings.py: 100%
46 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 22:51 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 22:51 +0000
1from __future__ import annotations
3import logging
4from typing import TYPE_CHECKING, TypeVar, overload
6log = logging.getLogger(__name__)
8if TYPE_CHECKING:
9 from ._types.json import Jsonable
10 from ._types.settings import RawSettings
12T = TypeVar("T")
14__all__ = ("Settings",)
17class Settings:
18 r"""This class represents the settings that you user has chosen.
20 If a setting is not found, ``None`` is returned instead.
22 .. container:: operations
24 .. describe:: x['setting name']
26 Get a setting by key similiar to a dictionary
28 .. describe:: x['setting name', 'default']
30 Get a setting by key similiar to a dictionary, with a custom default.
32 .. describe:: x['setting name'] = "new value"
34 Change a settings value like a dictionary
36 .. describe:: x.setting_name
38 Get a setting by name like an attribute
40 .. describe:: x.setting_name = "new value"
42 Change a settings value like an attribute
43 """
45 _data: RawSettings
46 _changes: RawSettings
48 def __init__(self, data: RawSettings, *, no_update: bool = False) -> None:
49 self._data = data
50 self._changes = {}
51 self._no_update = no_update
53 @overload
54 def __getitem__(self, key: str, /) -> Jsonable: ...
56 @overload
57 def __getitem__(self, key: tuple[str, T], /) -> Jsonable | T: ...
59 def __getitem__(self, key: tuple[str, T] | str) -> Jsonable | T:
60 if isinstance(key, str):
61 default = None
62 else:
63 key, default = key
64 return self._data.get(key, default)
66 def __setitem__(self, key: str, value: Jsonable) -> None:
67 self._data[key] = value
68 self._changes[key] = value
70 def __getattribute__(self, name: str) -> Jsonable:
71 if name.startswith("_"):
72 try:
73 return super().__getattribute__(name)
74 except AttributeError as e:
75 raise AttributeError(
76 f"{e}. Settings that start with an underscore (_) can only be accessed by the __getitem__ method. Ex: settings['_key']"
77 ) from None
78 return self.__getitem__(name)
80 def __setattr__(self, name: str, value: Jsonable) -> None:
81 if name.startswith("_"):
82 return super().__setattr__(name, value)
83 self.__setitem__(name, value)
85 def _update(self, data: RawSettings) -> None:
86 if self._no_update:
87 log.debug("Received a settings update, ignoring. data=%r", data)
88 else:
89 log.debug("Updating settings. Before: %s, after: %s", self._data, data)
90 self._data = data
92 def _get_updates(self) -> RawSettings:
93 try:
94 return self._changes
95 finally:
96 log.debug("Resetting setting changes: %s", self._changes)
97 self._changes = {}
99 def __repr__(self) -> str:
100 return f"<Settings current={self._data!r}, pending_changes={self._changes}>"