refactor(settings): apply the unset rule to optional string Literals too

Review follow-up. EMBEDDINGS_POOLING became Optional[Literal["cls", "mean"]],
but the group-base rule that maps "", "None" and whitespace to None only
matched Optional[str], so EMBEDDINGS_POOLING= in a .env file would have
failed validation. The rule now also covers an Optional Literal whose
choices are all strings, which lets the AUTH_TYPE validator drop its own
copy of that handling.
This commit is contained in:
arc53-machine committed 2026-09-17 11:51:28 +01:00
1 parent 5578039c19
commit 41135fc894
3 files changed
+20 -8

No files matched your search

+11 -2
View File
@@ -18,15 +18,24 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
def _is_optional_str(annotation: Any) -> bool:
"""``Optional[str]`` or ``Optional[Literal[...]]`` whose choices are all strings."""
if typing.get_origin(annotation) not in (typing.Union, types.UnionType):
return False
return set(typing.get_args(annotation)) == {str, type(None)}
members = set(typing.get_args(annotation))
if type(None) not in members or len(members) != 2:
return False
(member,) = members - {type(None)}
if member is str:
return True
return typing.get_origin(member) is typing.Literal and all(
isinstance(choice, str) for choice in typing.get_args(member)
)
class SettingsGroup(BaseSettings):
"""Base for one domain's settings; groups are composed into ``Settings``.
Every ``Optional[str]`` field treats the spellings an unset value has in a
Every ``Optional[str]`` field (and optional string ``Literal``) treats the spellings an unset value has in a
``.env`` file (``KEY=``, ``KEY=None``, whitespace) as ``None``, so a check
like ``if settings.OIDC_ISSUER`` or a fallback like ``settings.X or default``
sees "unset" rather than a truthy placeholder string. Real values are
+3 -3
View File
@@ -6,7 +6,7 @@ from typing import Literal, Optional
from pydantic import Field, field_validator, model_validator
from docsgpt.core.settings._shared import SettingsGroup, normalize_choice, normalize_secret
from docsgpt.core.settings._shared import SettingsGroup, normalize_choice
#: Settings an OIDC deployment cannot run without; checked when AUTH_TYPE=oidc.
@@ -88,8 +88,8 @@ class AuthSettings(SettingsGroup):
@field_validator("AUTH_TYPE", mode="before")
@classmethod
def _normalize_auth_type(cls, v):
# ``AUTH_TYPE=None`` and ``AUTH_TYPE=`` in .env both mean "no authentication".
return normalize_choice(normalize_secret(v))
# Unset spellings ("None", "") became None on the group base; this only case-folds a value.
return normalize_choice(v)
@model_validator(mode="after")
def _require_oidc_settings(self):