Source code for scholar_flux.utils.settings_utils

# /utils/settings_utils.py
"""Defines settings utility helpers for handling settings with potentially sensitive information in the console."""

from __future__ import annotations

from typing import Any, Annotated
from typing_extensions import TypeGuard, TypeVar
from collections import UserDict
from pydantic import BeforeValidator, GetCoreSchemaHandler

from pydantic_core import CoreSchema, core_schema

from scholar_flux.security import masker
from scholar_flux.utils.helpers import handle_exception


[docs] class SettingsDict(UserDict[str, Any]): """Dictionary wrapper defining the types of key-value pairs, masking sensitive data representations when printed.""" def __repr__(self) -> str: """Masks output by default when viewing the current dictionary.""" masked_dict = masker.mask_value(self.data) return str(masked_dict) def __setitem__( self, key: str, value: Any, ) -> None: """Overrides the `__setitem__` dictionary method to validate the type of the key before its addition. Args: key (str): The setting to add to the `SettingsDict`. value (Any): The value associated with the setting to add to the `SettingsDict`. """ if not isinstance(key, str): raise TypeError( f"The key provided to the SettingsDict is invalid. Expected a str, but received {type(key)}" ) super().__setitem__(key, value)
[docs] @classmethod def validate_settings_dict(cls, data: dict[str, Any] | SettingsDict) -> SettingsDict: """Validates the current dictionary, returning a `SettingsDict` when valid.""" return data if cls.is_settings_like(data, raise_on_error=True) and isinstance(data, SettingsDict) else cls(data)
[docs] @classmethod def is_settings_like( cls, data: object | SettingsLike, *, verbose: bool | None = None, raise_on_error: bool = False ) -> TypeGuard[SettingsLike]: """Identifies whether an object is a SettingsDict containing keyword parameters or a settings-like mapping.""" try: if not isinstance(data, (dict, SettingsDict)): raise TypeError(f"Expected a valid settings dictionary, but received type {type(data).__name__}.") if not all(isinstance(field, str) for field in data): raise ValueError("Expected a valid settings dictionary, but at least one field is not a string.") return True except (TypeError, ValueError) as e: log_exception = verbose if verbose is not None else bool(raise_on_error) handle_exception(e, raise_on_error=raise_on_error, verbose=log_exception) return False
@classmethod def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: """Retrieves the schema defining the SettingsDict data type for compatibility with Pydantic.""" # This tells Pydantic to validate it as a standard dict return core_schema.dict_schema( keys_schema=handler.generate_schema(str), values_schema=handler.generate_schema(Any), )
SettingsLike = TypeVar("SettingsLike", bound=dict[str, Any] | SettingsDict) SettingsDictType = Annotated[ SettingsLike, BeforeValidator(SettingsDict.validate_settings_dict), ] __all__ = ["SettingsDict", "SettingsLike", "SettingsDictType"]