Конфигурация через pydantic-settings
Порядок работы
- Извлечь точные поля, типы, обязательность, источники и приоритеты.
- Предложить пользователю значения по умолчанию для параметров, у которых есть
безопасное ожидаемое значение; не назначать их без согласования и не добавлять
остальные несогласованные поля.
- Разделить top-level settings worker-а, общий runtime, настройки каждой задачи
и вложенные технологические блоки.
- Реализовать immutable-модели, loader и startup preflight.
- Обновить минимальный и полный YAML-примеры, а также затронутую
deployment-конфигурацию.
- Проверить модели, источники, примеры, ошибки загрузки и preflight тестами.
Граница ответственности
- Конфигурация является infrastructure-адаптером и не импортируется из domain или
application.
- Settings содержат данные и чистые производные значения, но не создают pool,
client, worker, logger и другие runtime-ресурсы.
- Adapter factory преобразует settings в точные kwargs клиента; не передавать
model_dump() вслепую.
- Сетевые проверки, чтение секретов и writable-проверки не выполнять в pydantic
validators.
- Не определять поля и defaults, отсутствующие в требованиях.
Структура
Для малого сервиса допустима плоская структура:
infrastructure/config/
├── __init__.py
├── base.py
├── workers.py
├── postgres.py
└── nats.py
При более чем трёх top-level worker settings либо смешении несвязанных
зависимостей перейти к:
infrastructure/config/
├── __init__.py
├── base.py
├── worker/
│ ├── api.py
│ ├── nats_consumer.py
│ └── publisher.py
├── postgres.py
└── nats.py
base.py содержит общие базовые модели, loader и source strategy.
- Один top-level worker config композирует только нужные ему concern-блоки.
- Общий runtime-блок содержит только параметры lifecycle всего процесса. Интервал,
timeout операции, задержка по результату, progress heartbeat и readiness
принадлежат блоку конкретной долгоживущей задачи.
- Для нескольких задач создавать отдельный блок каждой задачи. Не поднимать их
параметры в общий блок только потому, что текущие значения совпадают.
- Для стандартных файловых probe headless worker-а хранить
heartbeat_file,
readiness_file и heartbeat_timeout_ms в блоке задачи-владельца. Пути
оставлять обязательными, безопасный timeout предлагать пользователю как default.
- Concern-модуль называть по технологии:
postgres.py, а не общий db.py.
__init__.py содержит только re-export и алфавитный __all__.
- Не выполнять массовое перемещение автоматически в небольшой задаче.
Модели
Два уровня
- Только top-level worker settings наследуется от
BaseSettings.
- Вложенные concern-блоки наследуются от общей immutable
BaseModel.
- Не вкладывать
BaseSettings в BaseSettings.
Неизменяемость и строгость
- Использовать
frozen=True, extra="forbid", strict=True и
validate_default=True.
- Использовать
tuple, а не list, для коллекций.
- Не менять settings после загрузки и не применять
model_copy(update=...) как
runtime reload.
- Для env-источника отдельно реализовать контролируемое преобразование строк:
строгая YAML-валидация не означает произвольную env-coercion.
- Неизвестный ключ и неверный тип должны останавливать запуск.
Обязательность
Обязательный блок объявлять без default_factory:
postgres: PostgresSettings
default_factory использовать только для полностью необязательного блока с
безопасными defaults.
Адреса внешних систем, имена БД/stream-ов, пользователи и важные пути не
угадывать.
Не использовать пустую строку вместо обязательного значения.
Подробности: модели и валидация.
Источники и загрузчик
- Состав и приоритет источников определять требованиями.
- Перечислять источники явно через
settings_customise_sources; первый элемент
tuple имеет высший приоритет.
- Не смешивать YAML, env, dotenv и secrets автоматически.
- YAML-only через
CONFIG_FILE остаётся рекомендуемым вариантом для текущих
сервисов, но не универсальным правилом.
- Не читать
CONFIG_FILE при импорте модуля.
- Загрузчик при вызове проверяет env, абсолютный путь, существование и читаемость,
затем создаёт новый settings-объект.
- Не создавать глобальный
settings = ... и не кешировать loader неявно.
- Один worker получает один immutable top-level config в composition root.
Подробности: источники и загрузчик.
Секреты и внешние файлы
- Хранить путь к секрету как обязательный
Path.
- Не хранить plaintext в YAML/env, если контракт использует file-based secret.
- Не создавать property с DSN, содержащим открытый пароль.
- Секрет читает отдельный provider при создании клиента; для временного хранения
использовать
SecretStr.
- Не включать секреты в repr, dump, логи, metrics, traces и health responses.
- Startup preflight проверяет файлы, директории и другие внешние артефакты после
структурной валидации.
- Для файловых heartbeat/readiness проверять абсолютные пути и writable-каталоги;
healthcheck entrypoint не выполняет этот preflight повторно.
- Ротация требует явного перечитывания и пересоздания зависимого клиента/pool;
property с повторным чтением файла сама по себе ротацию не обеспечивает.
Подробности: секреты и preflight.
Валидация
- Простые ограничения задавать через
Annotated и Field.
field_validator использовать для необходимой нормализации одного поля.
model_validator(mode="after") использовать для связей нескольких полей.
- Проверять
min_size <= max_size и другие заданные взаимосвязи.
- Единицы выражать
timedelta либо явным суффиксом _ms, _seconds, _bytes и
т. п. В одном контракте не смешивать сокращённое и полное обозначение одной
единицы.
- Конечные наборы задавать
StrEnum или Literal, а не свободным str.
- Не нормализовать значимое значение без требования.
- Собственные сообщения об ошибках писать по-русски без исходных секретов.
Совместимость
- Считать имена и типы полей deployment-контрактом worker-а.
- При добавлении обязательного поля обновлять все затронутые examples и manifests.
- Переименование/удаление согласовывать с порядком развёртывания.
- Временный alias добавлять только на обозначенный переходный период.
- Одновременную передачу старого и нового имени считать ошибкой.
- Не менять единицу измерения под прежним именем поля.
Документирование конфигурации
- Для каждого top-level worker settings поддерживать два валидных примера:
минимальный — только обязательные поля, полный — все доступные поля явно.
- Существующий
*.worker.example.yaml считать минимальным примером, а полный
называть *.worker.full.example.yaml.
- В минимальном примере не повторять поля с defaults: он показывает достаточный
контракт запуска и делает изменение обязательности заметным.
- В полном примере явно указывать также default-поля и необязательные блоки: он
служит каталогом доступных настроек, а не альтернативным источником defaults.
- Использовать безопасные демонстрационные значения и пути к файлам секретов;
plaintext-секреты и значения production-среды не публиковать.
- Оба примера загружать тем же loader-ом и валидировать тем же классом settings,
который использует worker.
- README может кратко описывать способ передачи конфигурации и ссылаться на эти
файлы, но схема полей и правила примеров принадлежат этому скилу.
Конфигурация логера и ошибки
- Не логировать
model_dump() целиком.
- Разрешено описывать и валидировать типизированные параметры логера и явно
преобразовывать их в настройки logging adapter-а.
- Settings, loader, preflight и adapter factory не создают записей в логах.
- Loader/preflight не подавляют ошибки и не переходят к defaults после сбоя.
- Loader/preflight возвращают или пробрасывают ошибку с безопасным контекстом и
ничего не логируют.
- Завершать процесс до создания runtime-ресурсов.
Примеры технологий
Читать только относящийся к задаче материал:
- PostgreSQL, пул psycopg и yoyo
- NATS и JetStream
- FastAPI, Uvicorn и CORS
- Логирование
- Worker подписок
- Runtime и независимые фоновые задачи
- Шаблон новой технологии
Примеры являются предложением полей, а не контрактом. Сверять параметры с
официальным API установленной версии. Не добавлять все параметры клиента на
будущее.
Тестирование
- Создавать модели обычной валидацией; не использовать
model_construct() как
стандартную фикстуру.
- Отдельно тестировать structural validation, source priority и preflight.
- Параметризованно загружать минимальный и полный
*.example.yaml
соответствующим классом.
- Проверять неизвестный ключ, неверный тип, отсутствие обязательной секции,
повреждённый YAML и недоступный внешний файл.
- Проверять immutable-модели и отсутствие mutable collections.
- Использовать
tmp_path для preflight file tests.
- Не проверять внутреннюю реализацию pydantic-settings.
Антипаттерны
BaseSettings во вложенном блоке.
- Mutable settings и коллекции.
extra="ignore" внутри выбранного worker config.
getenv() в class body или module-level settings instance.
Field(default_factory=...) для обязательной внешней зависимости.
- Production-sensitive default, похожий на рабочее значение.
- I/O или создание клиента в validator/property.
- Полный DSN с паролем в обычной строке.
model_dump() конфигурации в логах.
- Автоматическое смешение источников.
model_construct() как основной путь тестирования.
- Универсальный
config.py со всеми технологиями и worker-ами.
- Общий
operation_timeout, interval или retry delay для независимых задач.
Критерии готовности
- Реализованы только согласованные поля и источники.
- Top-level и вложенные модели глубоко неизменяемы.
- Неизвестные поля запрещены, defaults валидируются.
- Обязательные блоки нельзя пропустить.
- Loader не читает env во время импорта.
- Секреты не материализуются в serializable settings.
- Preflight отделён от structural validation.
- Клиентские kwargs строятся явным adapter factory.
- Для каждого worker-а минимальный и полный примеры проходят валидацию и не
содержат plaintext-секреты.
- Изменение deployment-контракта отражено во всех потребителях.
- Unit-тесты и проверки репозитория прошли.
Материалы
- Модели и валидация
- Источники и загрузчик
- Секреты и preflight
- Чеклисты
1---2name: python-pydantic-settings-config-writing3description: Используй при реализации или правке типизированной конфигурации Python-сервиса в infrastructure через pydantic-settings и pydantic: top-level settings worker-а, вложенных технологических блоков, YAML/env/custom sources, загрузчика CONFIG_FILE, строгой валидации, file-based secrets, startup preflight и примеров конфигурации. Не применять для domain/application-логики, реализации runtime-клиентов и presentation worker-ов.4---56# Конфигурация через pydantic-settings78## Порядок работы9101. Извлечь точные поля, типы, обязательность, источники и приоритеты.112. Предложить пользователю значения по умолчанию для параметров, у которых есть12 безопасное ожидаемое значение; не назначать их без согласования и не добавлять13 остальные несогласованные поля.143. Разделить top-level settings worker-а, общий runtime, настройки каждой задачи15 и вложенные технологические блоки.164. Реализовать immutable-модели, loader и startup preflight.175. Обновить минимальный и полный YAML-примеры, а также затронутую18 deployment-конфигурацию.196. Проверить модели, источники, примеры, ошибки загрузки и preflight тестами.2021## Граница ответственности2223- Конфигурация является infrastructure-адаптером и не импортируется из domain или24 application.25- Settings содержат данные и чистые производные значения, но не создают pool,26 client, worker, logger и другие runtime-ресурсы.27- Adapter factory преобразует settings в точные kwargs клиента; не передавать28 `model_dump()` вслепую.29- Сетевые проверки, чтение секретов и writable-проверки не выполнять в pydantic30 validators.31- Не определять поля и defaults, отсутствующие в требованиях.3233## Структура3435Для малого сервиса допустима плоская структура:3637```text38infrastructure/config/39├── __init__.py40├── base.py41├── workers.py42├── postgres.py43└── nats.py44```4546При более чем трёх top-level worker settings либо смешении несвязанных47зависимостей перейти к:4849```text50infrastructure/config/51├── __init__.py52├── base.py53├── worker/54│ ├── api.py55│ ├── nats_consumer.py56│ └── publisher.py57├── postgres.py58└── nats.py59```6061- `base.py` содержит общие базовые модели, loader и source strategy.62- Один top-level worker config композирует только нужные ему concern-блоки.63- Общий runtime-блок содержит только параметры lifecycle всего процесса. Интервал,64 timeout операции, задержка по результату, progress heartbeat и readiness65 принадлежат блоку конкретной долгоживущей задачи.66- Для нескольких задач создавать отдельный блок каждой задачи. Не поднимать их67 параметры в общий блок только потому, что текущие значения совпадают.68- Для стандартных файловых probe headless worker-а хранить `heartbeat_file`,69 `readiness_file` и `heartbeat_timeout_ms` в блоке задачи-владельца. Пути70 оставлять обязательными, безопасный timeout предлагать пользователю как default.71- Concern-модуль называть по технологии: `postgres.py`, а не общий `db.py`.72- `__init__.py` содержит только re-export и алфавитный `__all__`.73- Не выполнять массовое перемещение автоматически в небольшой задаче.7475## Модели7677### Два уровня7879- Только top-level worker settings наследуется от `BaseSettings`.80- Вложенные concern-блоки наследуются от общей immutable `BaseModel`.81- Не вкладывать `BaseSettings` в `BaseSettings`.8283### Неизменяемость и строгость8485- Использовать `frozen=True`, `extra="forbid"`, `strict=True` и86 `validate_default=True`.87- Использовать `tuple`, а не `list`, для коллекций.88- Не менять settings после загрузки и не применять `model_copy(update=...)` как89 runtime reload.90- Для env-источника отдельно реализовать контролируемое преобразование строк:91 строгая YAML-валидация не означает произвольную env-coercion.92- Неизвестный ключ и неверный тип должны останавливать запуск.9394### Обязательность9596- Обязательный блок объявлять без `default_factory`:9798 ```python99 postgres: PostgresSettings100 ```101102- `default_factory` использовать только для полностью необязательного блока с103 безопасными defaults.104- Адреса внешних систем, имена БД/stream-ов, пользователи и важные пути не105 угадывать.106- Не использовать пустую строку вместо обязательного значения.107108Подробности: [модели и валидация](references/models_and_validation.md).109110## Источники и загрузчик111112- Состав и приоритет источников определять требованиями.113- Перечислять источники явно через `settings_customise_sources`; первый элемент114 tuple имеет высший приоритет.115- Не смешивать YAML, env, dotenv и secrets автоматически.116- YAML-only через `CONFIG_FILE` остаётся рекомендуемым вариантом для текущих117 сервисов, но не универсальным правилом.118- Не читать `CONFIG_FILE` при импорте модуля.119- Загрузчик при вызове проверяет env, абсолютный путь, существование и читаемость,120 затем создаёт новый settings-объект.121- Не создавать глобальный `settings = ...` и не кешировать loader неявно.122- Один worker получает один immutable top-level config в composition root.123124Подробности: [источники и загрузчик](references/sources_and_loader.md).125126## Секреты и внешние файлы127128- Хранить путь к секрету как обязательный `Path`.129- Не хранить plaintext в YAML/env, если контракт использует file-based secret.130- Не создавать property с DSN, содержащим открытый пароль.131- Секрет читает отдельный provider при создании клиента; для временного хранения132 использовать `SecretStr`.133- Не включать секреты в repr, dump, логи, metrics, traces и health responses.134- Startup preflight проверяет файлы, директории и другие внешние артефакты после135 структурной валидации.136- Для файловых heartbeat/readiness проверять абсолютные пути и writable-каталоги;137 healthcheck entrypoint не выполняет этот preflight повторно.138- Ротация требует явного перечитывания и пересоздания зависимого клиента/pool;139 property с повторным чтением файла сама по себе ротацию не обеспечивает.140141Подробности: [секреты и preflight](references/secrets_and_preflight.md).142143## Валидация144145- Простые ограничения задавать через `Annotated` и `Field`.146- `field_validator` использовать для необходимой нормализации одного поля.147- `model_validator(mode="after")` использовать для связей нескольких полей.148- Проверять `min_size <= max_size` и другие заданные взаимосвязи.149- Единицы выражать `timedelta` либо явным суффиксом `_ms`, `_seconds`, `_bytes` и150 т. п. В одном контракте не смешивать сокращённое и полное обозначение одной151 единицы.152- Конечные наборы задавать `StrEnum` или `Literal`, а не свободным `str`.153- Не нормализовать значимое значение без требования.154- Собственные сообщения об ошибках писать по-русски без исходных секретов.155156## Совместимость157158- Считать имена и типы полей deployment-контрактом worker-а.159- При добавлении обязательного поля обновлять все затронутые examples и manifests.160- Переименование/удаление согласовывать с порядком развёртывания.161- Временный alias добавлять только на обозначенный переходный период.162- Одновременную передачу старого и нового имени считать ошибкой.163- Не менять единицу измерения под прежним именем поля.164165## Документирование конфигурации166167- Для каждого top-level worker settings поддерживать два валидных примера:168 минимальный — только обязательные поля, полный — все доступные поля явно.169- Существующий `*.worker.example.yaml` считать минимальным примером, а полный170 называть `*.worker.full.example.yaml`.171- В минимальном примере не повторять поля с defaults: он показывает достаточный172 контракт запуска и делает изменение обязательности заметным.173- В полном примере явно указывать также default-поля и необязательные блоки: он174 служит каталогом доступных настроек, а не альтернативным источником defaults.175- Использовать безопасные демонстрационные значения и пути к файлам секретов;176 plaintext-секреты и значения production-среды не публиковать.177- Оба примера загружать тем же loader-ом и валидировать тем же классом settings,178 который использует worker.179- README может кратко описывать способ передачи конфигурации и ссылаться на эти180 файлы, но схема полей и правила примеров принадлежат этому скилу.181182## Конфигурация логера и ошибки183184- Не логировать `model_dump()` целиком.185- Разрешено описывать и валидировать типизированные параметры логера и явно186 преобразовывать их в настройки logging adapter-а.187- Settings, loader, preflight и adapter factory не создают записей в логах.188- Loader/preflight не подавляют ошибки и не переходят к defaults после сбоя.189- Loader/preflight возвращают или пробрасывают ошибку с безопасным контекстом и190 ничего не логируют.191- Завершать процесс до создания runtime-ресурсов.192193## Примеры технологий194195Читать только относящийся к задаче материал:196197- [PostgreSQL, пул psycopg и yoyo](references/postgres_settings.md)198- [NATS и JetStream](references/nats_settings.md)199- [FastAPI, Uvicorn и CORS](references/fastapi_uvicorn_settings.md)200- [Логирование](references/logging_settings.md)201- [Worker подписок](references/subscription_settings.md)202- [Runtime и независимые фоновые задачи](references/background_worker_settings.md)203- [Шаблон новой технологии](references/example_template.md)204205Примеры являются предложением полей, а не контрактом. Сверять параметры с206официальным API установленной версии. Не добавлять все параметры клиента на207будущее.208209## Тестирование210211- Создавать модели обычной валидацией; не использовать `model_construct()` как212 стандартную фикстуру.213- Отдельно тестировать structural validation, source priority и preflight.214- Параметризованно загружать минимальный и полный `*.example.yaml`215 соответствующим классом.216- Проверять неизвестный ключ, неверный тип, отсутствие обязательной секции,217 повреждённый YAML и недоступный внешний файл.218- Проверять immutable-модели и отсутствие mutable collections.219- Использовать `tmp_path` для preflight file tests.220- Не проверять внутреннюю реализацию pydantic-settings.221222## Антипаттерны223224- `BaseSettings` во вложенном блоке.225- Mutable settings и коллекции.226- `extra="ignore"` внутри выбранного worker config.227- `getenv()` в class body или module-level settings instance.228- `Field(default_factory=...)` для обязательной внешней зависимости.229- Production-sensitive default, похожий на рабочее значение.230- I/O или создание клиента в validator/property.231- Полный DSN с паролем в обычной строке.232- `model_dump()` конфигурации в логах.233- Автоматическое смешение источников.234- `model_construct()` как основной путь тестирования.235- Универсальный `config.py` со всеми технологиями и worker-ами.236- Общий `operation_timeout`, `interval` или retry delay для независимых задач.237238## Критерии готовности239240- Реализованы только согласованные поля и источники.241- Top-level и вложенные модели глубоко неизменяемы.242- Неизвестные поля запрещены, defaults валидируются.243- Обязательные блоки нельзя пропустить.244- Loader не читает env во время импорта.245- Секреты не материализуются в serializable settings.246- Preflight отделён от structural validation.247- Клиентские kwargs строятся явным adapter factory.248- Для каждого worker-а минимальный и полный примеры проходят валидацию и не249 содержат plaintext-секреты.250- Изменение deployment-контракта отражено во всех потребителях.251- Unit-тесты и проверки репозитория прошли.252253## Материалы254255- [Модели и валидация](references/models_and_validation.md)256- [Источники и загрузчик](references/sources_and_loader.md)257- [Секреты и preflight](references/secrets_and_preflight.md)258- [Чеклисты](references/checklists.md)