sources/reports/base.py — контракт ReportParser (плагины: sniff/parse, чистые функции без БД). registry.py выбирает парсер по содержимому файла, CSV последним: он узнаёт файл по набору колонок и иначе перехватил бы чужой формат. Комиссия капитализируется в сделку, отдельным событием не эмитится: и Сбер, и ВТБ печатают её дважды — колонками в сделках и строками в движении денег, суммы совпадают, второе прочтение задвоило бы её. Расчётные строки («Сделка от …», «Сальдо расчетов по сделкам») не эмитятся — это денежные ноги уже учтённых сделок. У Сбера таблица «Информация о зачислениях на ИИС» кумулятивна за календарный год и в леджер не идёт, иначе два пересекающихся отчёта задвоили бы пополнения. CSV Snowball сводный по всем брокерам — годится как сверка потоков и сделок на уровне портфеля, но не позиций по счетам; CUSTOM_HOLDING_PRICE не событие, а цена — уходит в meta для price_manual. Обезличивание — anonymize.py + scripts/anonymize_reports.py, секреты собираются по всему корпусу отчётов разом (Snowball цитирует номер договора Сбера в примечании к переводу). test_fixtures_anonymized.py падает, если в tests/fixtures/reports/ вне raw/ найдётся ИНН, ФИО или номер счёта — и по форме (работает в CI без raw/), и по фактическому содержимому raw/, когда оно на месте.
85 lines
1.9 KiB
TOML
85 lines
1.9 KiB
TOML
[project]
|
|
name = "fintracker"
|
|
version = "0.1.0"
|
|
description = "Personal finance + investment analytics: ZenMoney and brokers in one place"
|
|
readme = "README.md"
|
|
requires-python = ">=3.12"
|
|
dependencies = [
|
|
"fastapi>=0.115",
|
|
"uvicorn[standard]>=0.30",
|
|
"sqlalchemy[asyncio]>=2.0.36",
|
|
"asyncpg>=0.30",
|
|
"alembic>=1.14",
|
|
"pydantic[email]>=2.9",
|
|
"pydantic-settings>=2.5",
|
|
"httpx[socks]>=0.27",
|
|
"pyjwt>=2.9",
|
|
"pwdlib[argon2]>=0.2",
|
|
"typer>=0.12",
|
|
"apscheduler>=3.10,<4",
|
|
"python-multipart>=0.0.12",
|
|
"t-tech-investments>=1.51.0",
|
|
"pyxirr>=0.10.8",
|
|
"openpyxl>=3.1",
|
|
"lxml>=5.3",
|
|
]
|
|
|
|
[project.scripts]
|
|
fintracker = "fintracker.cli:app"
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=8.3",
|
|
"pytest-asyncio>=0.24",
|
|
"pytest-postgresql>=6.1",
|
|
"psycopg[binary]>=3.2",
|
|
"ruff>=0.7",
|
|
"pyright>=1.1.380",
|
|
"respx>=0.21",
|
|
]
|
|
|
|
# T-Invest SDK lives on T-Bank's own index (public PyPI copy is quarantined).
|
|
[[tool.uv.index]]
|
|
name = "tbank-invest"
|
|
url = "https://opensource.tbank.ru/api/v4/projects/238/packages/pypi/simple"
|
|
explicit = true
|
|
|
|
[tool.uv.sources]
|
|
t-tech-investments = { index = "tbank-invest" }
|
|
|
|
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/fintracker"]
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
src = ["src", "tests"]
|
|
target-version = "py312"
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
ignore = ["RUF001", "RUF002", "RUF003"] # cyrillic in strings/comments is intended
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"tests/*" = ["E501"]
|
|
"alembic/versions/*" = ["E501"]
|
|
|
|
[tool.pyright]
|
|
venvPath = "."
|
|
venv = ".venv"
|
|
include = ["src", "tests"]
|
|
extraPaths = ["src"]
|
|
pythonVersion = "3.12"
|
|
typeCheckingMode = "standard"
|
|
reportMissingImports = "warning"
|
|
|
|
[tool.pytest.ini_options]
|
|
pythonpath = ["src"]
|
|
testpaths = ["tests"]
|
|
asyncio_mode = "auto"
|
|
asyncio_default_fixture_loop_scope = "session"
|
|
asyncio_default_test_loop_scope = "session"
|