Andrey Epifancev e705d75520 feat(parser): контрольные суммы §1.4, статусы, OsvParser как парсер по умолчанию, лимиты
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
2026-10-05 14:37:21 +04:00

66 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()