checks.py: тождество сальдо по каждой строке, суммы родителя = Σ детей того же data_type (CURRENCY/QUANTITY исключены; обороты — по колонкам, сальдо — по колонкам или по нетто при свёрнутом сальдо родителя), «Итого» = корневой счёт (R-13: нет корня — «Итого» пусто/0; R-20: нет «Итого» — false и предупреждение). osv.py: OsvParser — лимит размера, чтение по сигнатуре, листы по содержимому (формы ББ/ОФР и прочие — пропуск с предупреждением), карта исходов D-6, кооперативный дедлайн, metrics (rows без TOTAL, warnings с «sheet=<имя> hierarchy=<стратегия>» первой записью по листу). get_parser(settings, rules_dir=…) → OsvParser (словари грузятся при создании: битый словарь — падение старта); PARSE_MAX_BYTES / PARSE_TIMEOUT_SECONDS в Settings и .env.*; app.py передаёт настройки. test_null_parser.py → test_parser_factory.py. Тесты: юнит-карта статусов, «Испорченная сумма», «Пустая ОСВ», два листа ОСВ, новый синоним без релиза кода (R-8); property-тест на 66 реальных файлах (все done, < 5 с, схема v1.1). test_app и интеграционный round-trip ждут ошибку реального парсера вместо NOT_IMPLEMENTED. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
66 lines
2.8 KiB
Python
66 lines
2.8 KiB
Python
import os
|
||
from typing import Literal
|
||
|
||
from pydantic import NonNegativeInt, PositiveInt
|
||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||
|
||
|
||
class MinioSettings(BaseSettings):
|
||
MINIO_URL: str
|
||
MINIO_ADMIN_LOGIN: str
|
||
MINIO_ADMIN_PASSWORD: str
|
||
MINIO_BUCKET: str
|
||
MINIO_SECURE: bool = True # https (платформа); false — http (MinIO из docker compose)
|
||
|
||
|
||
class NATSSettings(BaseSettings):
|
||
NATS_URL: str
|
||
NATS_SEED: str = "" # пусто — подключение к NATS без nkeys (локальная разработка, тесты)
|
||
NATS_JWT: str = ""
|
||
|
||
|
||
class OpenBAOSettings(BaseSettings):
|
||
MINIO: MinioSettings
|
||
NATS: NATSSettings
|
||
|
||
|
||
class ServerSettings(BaseSettings):
|
||
HOST: str = "0.0.0.0"
|
||
PORT: int = 8000
|
||
|
||
|
||
class Settings(BaseSettings):
|
||
"""Настройки сервиса.
|
||
|
||
Файл окружения выбирается переменной ``ENV_FILE`` (по умолчанию ``.env``; значение читается при импорте модуля,
|
||
относительный путь считается от текущего каталога — ``api/``). Тесты используют ``.env.test``.
|
||
"""
|
||
|
||
OPENBAO: OpenBAOSettings
|
||
DEBUG: bool = False
|
||
server: ServerSettings = ServerSettings()
|
||
ROOT_PATH: str = "/"
|
||
VERSION: str = "1.0.0"
|
||
|
||
# `service.name` конвертов контракта (enum ServiceName); queue group NATS — константа REQUEST_QUEUE_GROUP в nats.py
|
||
SERVICE_NAME: Literal["tabular-parser"] = "tabular-parser"
|
||
NATS_ENABLED: bool = True # false — приложение не подключается к NATS (воркер не стартует)
|
||
WORKER_CONCURRENCY: PositiveInt = 1 # число заданий, обрабатываемых одновременно
|
||
PUBLISH_RETRIES: NonNegativeInt = 3 # повторы публикации ack/результата после первой попытки (0 — без повторов)
|
||
DONE_CACHE_SIZE: PositiveInt = 1000 # размер process-local LRU обработанных job_id
|
||
# Лимиты разбора (design D-8): файл больше лимита — UNSUPPORTED_FORMAT без чтения; превышение времени — TIMEOUT
|
||
# (кооперативно: между листами, стратегиями и блоками строк). Оба ниже reply_deadline ядра (5 мин)
|
||
PARSE_MAX_BYTES: PositiveInt = 50 * 1024 * 1024
|
||
PARSE_TIMEOUT_SECONDS: PositiveInt = 120
|
||
|
||
model_config = SettingsConfigDict(
|
||
extra="ignore",
|
||
env_file=os.environ.get("ENV_FILE", ".env"),
|
||
env_nested_delimiter="__",
|
||
nested_model_default_partial_update=False,
|
||
)
|
||
|
||
|
||
def get_settings() -> Settings:
|
||
return Settings()
|