tools (config): QoL improvements:
- correct the case of `dynamicSettingsRegister` and `dynamicSettings` which are `dict`, not classes. - Use new `DynamicSettingsCollection` as base class for classes dynamically built during parsing, to avoid name conflict. - Use `DynamicSettingsCollection` instead of `dict` in dynamic field (`plugin` and `component`). This correct inconsistency, and make linters happy. - Catch `TOMLDecodeError` when parsing config, to show a more readable error message instead of full backtrace.
This commit is contained in:
parent
685193602e
commit
60753f4d71
1 changed files with 32 additions and 22 deletions
|
|
@ -22,8 +22,15 @@
|
|||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from socket import getfqdn
|
||||
from typing import Annotated, Any, Literal, Self, TypeVar, cast
|
||||
from tomllib import TOMLDecodeError
|
||||
from typing import Annotated, Literal, Self, TypeVar, cast
|
||||
|
||||
from libervia.backend.core import exceptions
|
||||
from libervia.backend.core.constants import Const as C, xdg_data_home
|
||||
from libervia.backend.core.i18n import _
|
||||
from libervia.backend.core.log import getLogger
|
||||
from libervia.backend.models.types import JIDType
|
||||
from libervia.backend.tools.common.files_utils import get_downloads_dir
|
||||
from pydantic import (
|
||||
AfterValidator,
|
||||
BaseModel,
|
||||
|
|
@ -42,21 +49,14 @@ from pydantic_settings import (
|
|||
TomlConfigSettingsSource,
|
||||
)
|
||||
|
||||
from libervia.backend.core import exceptions
|
||||
from libervia.backend.core.constants import Const as C, xdg_data_home
|
||||
from libervia.backend.core.i18n import _
|
||||
from libervia.backend.core.log import getLogger
|
||||
from libervia.backend.models.types import JIDType
|
||||
from libervia.backend.tools.common.files_utils import get_downloads_dir
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
expanduser_validator = AfterValidator(lambda p: p.expanduser().resolve())
|
||||
|
||||
cached_config: "Settings|None" = None
|
||||
DynamicSettingsRegister = dict[str, "type[DynamicSettingsBase]"]
|
||||
DynamicSettings: dict[str, DynamicSettingsRegister | type["DynamicSettingsBase"]] = (
|
||||
defaultdict(DynamicSettingsRegister)
|
||||
dynamicSettingsRegister = dict[str, "type[DynamicSettingsBase]"]
|
||||
dynamicSettings: dict[str, dynamicSettingsRegister | type["DynamicSettingsBase"]] = (
|
||||
defaultdict(dynamicSettingsRegister)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ class DynamicSettingsBase(ConfigOptions):
|
|||
# normalized on plugin import.
|
||||
sub_key = sub_key.replace("-", "_").lower()
|
||||
cls._sub_key = sub_key
|
||||
register = DynamicSettings[key]
|
||||
register = dynamicSettings[key]
|
||||
assert isinstance(register, dict)
|
||||
if sub_key in register:
|
||||
raise exceptions.ConflictError(
|
||||
|
|
@ -133,7 +133,7 @@ class DynamicSettingsBase(ConfigOptions):
|
|||
cls._import_name = plugin_info.get(C.PI_IMPORT_NAME)
|
||||
else:
|
||||
cls._sub_key = None
|
||||
DynamicSettings[key] = cls
|
||||
dynamicSettings[key] = cls
|
||||
|
||||
|
||||
class PluginSettings(DynamicSettingsBase):
|
||||
|
|
@ -189,6 +189,10 @@ class FrontendSettings(DynamicSettingsBase):
|
|||
super()._init_subclass(key=key)
|
||||
|
||||
|
||||
class DynamicSettingsCollection(BaseModel):
|
||||
"""Base class for collection of DynamicSettings."""
|
||||
|
||||
|
||||
D = TypeVar("D", bound=DynamicSettingsBase)
|
||||
|
||||
|
||||
|
|
@ -414,9 +418,12 @@ class Settings(BaseSettings):
|
|||
default_factory=dict,
|
||||
description="Application specific settings, used by app manager.",
|
||||
)
|
||||
plugin: dict = Field(default_factory=dict, description="Plugin specific settings.")
|
||||
component: dict = Field(
|
||||
default_factory=dict, description="Component specific settings."
|
||||
plugin: DynamicSettingsCollection = Field(
|
||||
default_factory=DynamicSettingsCollection, description="Plugin specific settings."
|
||||
)
|
||||
component: DynamicSettingsCollection = Field(
|
||||
default_factory=DynamicSettingsCollection,
|
||||
description="Component specific settings.",
|
||||
)
|
||||
|
||||
@field_validator("bridges", mode="after")
|
||||
|
|
@ -519,10 +526,11 @@ def parse_main_conf(log_filenames: bool = False, ignore_cache=False) -> Settings
|
|||
|
||||
if ignore_cache or cached_config is None:
|
||||
dynamic_settings_kw = {}
|
||||
for key, settings in DynamicSettings.items():
|
||||
for key, settings in dynamicSettings.items():
|
||||
if isinstance(settings, dict):
|
||||
NewSettingsModel = create_model(
|
||||
f"{key.title()}Settings",
|
||||
f"{key.title()}SettingsCollection",
|
||||
__base__=DynamicSettingsCollection,
|
||||
**cast(
|
||||
dict,
|
||||
{
|
||||
|
|
@ -549,10 +557,12 @@ def parse_main_conf(log_filenames: bool = False, ignore_cache=False) -> Settings
|
|||
try:
|
||||
cached_config = LiberviaSettings()
|
||||
except ValidationError as e:
|
||||
log.error(f"Settings are invalid, please fix your configuration: {e}")
|
||||
raise exceptions.ConfigError
|
||||
except:
|
||||
raise exceptions.ConfigError(e)
|
||||
except TOMLDecodeError as e:
|
||||
log.error(f"You configuration file is invalid: {e}")
|
||||
raise exceptions.ConfigError from e
|
||||
except Exception as e:
|
||||
log.exception("Can't parse settings.")
|
||||
raise exceptions.InternalError
|
||||
raise exceptions.InternalError from e
|
||||
|
||||
return cached_config
|
||||
|
|
|
|||
Loading…
Reference in a new issue