Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
pcrespov committed Oct 31, 2024
1 parent 1e1d862 commit 9aec7ae
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
51 changes: 50 additions & 1 deletion packages/settings-library/src/settings_library/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
from pydantic import ValidationInfo, field_validator
from pydantic.fields import FieldInfo
from pydantic_core import ValidationError
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic_settings import (
BaseSettings,
EnvSettingsSource,
PydanticBaseSettingsSource,
SettingsConfigDict,
)

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -46,6 +51,33 @@ def _default_factory():
return _default_factory


class CustomEnvSettingsSource(EnvSettingsSource):
def __init__(self, settings_cls: BaseSettings, env_settings: EnvSettingsSource):
super().__init__(
settings_cls,
env_settings.case_sensitive,
env_settings.env_prefix,
env_settings.env_nested_delimiter,
env_settings.env_ignore_empty,
env_settings.env_parse_none_str,
env_settings.env_parse_enums,
)

def prepare_field_value(
self,
field_name: str,
field: FieldInfo,
value: Any,
value_is_complex: bool, # noqa: FBT001
) -> Any:
prepared_value = super().prepare_field_value(
field_name, field, value, value_is_complex
)
if field.default_factory and field.default is None and prepared_value == {}:
prepared_value = field.default_factory()
return prepared_value


class BaseCustomSettings(BaseSettings):
"""
- Customized configuration for all settings
Expand Down Expand Up @@ -126,3 +158,20 @@ def create_from_envs(cls, **overrides):
# Optional to use to make the code more readable
# More explicit and pylance seems to get less confused
return cls(**overrides)

@classmethod
def settings_customise_sources(
cls,
settings_cls: BaseSettings,
init_settings: PydanticBaseSettingsSource,
env_settings: PydanticBaseSettingsSource,
dotenv_settings: PydanticBaseSettingsSource,
file_secret_settings: PydanticBaseSettingsSource,
) -> tuple[PydanticBaseSettingsSource, ...]:
assert env_settings # nosec
return (
init_settings,
CustomEnvSettingsSource(settings_cls, env_settings=env_settings),
dotenv_settings,
file_secret_settings,
)
9 changes: 5 additions & 4 deletions packages/settings-library/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import settings_library.base
from pydantic import BaseModel, ValidationError
from pydantic.fields import Field
from pydantic_settings import BaseSettings
from pydantic_settings import BaseSettings, SettingsConfigDict
from pytest_mock import MockerFixture
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_envfile
from pytest_simcore.helpers.typing_env import EnvVarsDict
Expand All @@ -22,7 +22,6 @@
DefaultFromEnvFactoryError,
)
from settings_library.email import SMTPSettings
from settings_library.utils_logging import MixinLoggingSettings

S2 = json.dumps({"S_VALUE": 2})
S3 = json.dumps({"S_VALUE": 3})
Expand Down Expand Up @@ -344,10 +343,12 @@ class SettingsClassThatFailed(BaseCustomSettings):
def test_upgrade_failure_to_pydantic_settings_2_6(
mock_env_devel_environment: EnvVarsDict,
):
class ProblematicSettings(BaseCustomSettings, MixinLoggingSettings):
class ProblematicSettings(BaseCustomSettings):
WEBSERVER_EMAIL: SMTPSettings | None = Field(
json_schema_extra={"auto_default_from_env": True}
)

settings = ProblematicSettings.create_from_envs()
model_config = SettingsConfigDict(nested_model_default_partial_update=True)

settings = ProblematicSettings()
assert settings.WEBSERVER_EMAIL is not None

0 comments on commit 9aec7ae

Please sign in to comment.