mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 06:17:23 +00:00
refactor(settings): treat unset spellings of every optional string as None
Review follow-up. The per-group secret validators normalised a hand-picked list of API keys, which left other optional credentials and overrides (OPEN_ROUTER_API_KEY, S3 and Daytona keys, ELASTIC_PASSWORD, the OIDC trio, connector client ids, MICROSOFT_AUTHORITY, MCP_OAUTH_REDIRECT_URI) holding the literal "None" or "" a .env file spells "unset" with, so truthiness checks and fallbacks downstream saw a value. One rule on the group base replaces those lists: every Optional[str] field maps "", "None" and whitespace to None and strips real values. Plain str fields are left alone. The OIDC required-settings check therefore also rejects those spellings. EMBEDDINGS_POOLING is Literal["cls", "mean"] with case-insensitive parsing; its consumer silently ignored anything else. Bounds added where the consumer rejects or misbehaves on the value: SCHEDULE_RUN_OUTPUT_RETENTION_DAYS and MESSAGE_EVENTS_RETENTION_DAYS (the cleanup repositories raise on <= 0), EMBEDDINGS_DELEGATE_TIMEOUT, the remote-device idle/pairing/invocation TTLs and CELERY_VISIBILITY_TIMEOUT (> 0), REMOTE_DEVICE_CMD_QUEUE_TTL_SECONDS (> 605, the documented drain deadline), GRAPHRAG_MAX_CHUNKS_FOR_EXTRACTION (>= 0; negative would slice the pending list from the end). The generated reference now renders generic type arguments (dict[str, int] rather than dict).
This commit is contained in:
1 parent
f882ef49a7
commit
5578039c19
13 files changed
+113
-67
No files matched your search
@@ -9,16 +9,43 @@ domain's definitions live in their own module.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import types
|
||||
import typing
|
||||
from typing import Any, Optional
|
||||
|
||||
from pydantic import model_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
def _is_optional_str(annotation: Any) -> bool:
|
||||
if typing.get_origin(annotation) not in (typing.Union, types.UnionType):
|
||||
return False
|
||||
return set(typing.get_args(annotation)) == {str, type(None)}
|
||||
|
||||
|
||||
class SettingsGroup(BaseSettings):
|
||||
"""Base for one domain's settings; groups are composed into ``Settings``."""
|
||||
"""Base for one domain's settings; groups are composed into ``Settings``.
|
||||
|
||||
Every ``Optional[str]`` field 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
|
||||
stripped. Fields typed ``str`` keep whatever they are given.
|
||||
"""
|
||||
|
||||
model_config = SettingsConfigDict(extra="ignore")
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def _unset_optional_strings(cls, data: Any) -> Any:
|
||||
if not isinstance(data, dict):
|
||||
return data
|
||||
data = dict(data)
|
||||
for name, field in cls.model_fields.items():
|
||||
if name in data and _is_optional_str(field.annotation):
|
||||
data[name] = normalize_secret(data[name])
|
||||
return data
|
||||
|
||||
|
||||
def normalize_choice(value: Any) -> Any:
|
||||
"""Case-fold a closed-choice setting so ``PGVector`` and ``pgvector`` are the same choice."""
|
||||
|
||||
Reference in new issue
Block a user