167 lines
4.4 KiB
TOML
167 lines
4.4 KiB
TOML
[project]
|
|
name = "rmi-backend"
|
|
version = "0.1.0"
|
|
description = "RMI (Rug Munch Intelligence) crypto-scam detection backend"
|
|
requires-python = ">=3.11"
|
|
readme = "DESIGN.md"
|
|
|
|
# Pinned versions are kept in requirements.txt for the Docker build.
|
|
# This pyproject.toml defines tool config (ruff/mypy/pytest) and a thin
|
|
# dependency list. `pip install -e .` works in dev; production uses
|
|
# `pip install -r requirements.txt`.
|
|
dependencies = [
|
|
"fastapi>=0.115.0",
|
|
"uvicorn[standard]>=0.32.0",
|
|
"pydantic>=2.9.0",
|
|
"pydantic-settings>=2.6.0",
|
|
"redis[hiredis]>=5.2.0",
|
|
"httpx>=0.27.0",
|
|
"sqlalchemy[asyncio]>=2.0.36",
|
|
"alembic>=1.14.0",
|
|
"structlog>=24.4.0",
|
|
"langfuse>=3.0.0",
|
|
"PyJWT>=2.10.0",
|
|
"python-multipart>=0.0.17",
|
|
"duckdb>=0.10.0",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"ruff>=0.8.0",
|
|
"mypy>=1.13.0",
|
|
"pytest>=8.3.0",
|
|
"pytest-asyncio>=0.24.0",
|
|
"pre-commit>=4.0.0",
|
|
"gitleaks>=8.18.0",
|
|
]
|
|
|
|
[build-system]
|
|
requires = ["setuptools>=68", "wheel"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
# Declare app/ as an installable package so `pip install -e ".[dev]"` registers
|
|
# it on sys.path. Without this, pytest collection fails outside the repo cwd
|
|
# (33/35 test files fail without PYTHONPATH=.).
|
|
# packages.find auto-discovers every sub-package that has __init__.py.
|
|
# Sub-packages without __init__.py are namespace packages and remain out of
|
|
# scope for Phase 1.3 (tracked for Phase 3).
|
|
[tool.setuptools.packages.find]
|
|
where = ["."]
|
|
include = ["app*"]
|
|
exclude = ["app._archive*", "app._archive.**"]
|
|
namespaces = false
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
target-version = "py311"
|
|
extend-exclude = [
|
|
"_legacy_main.py",
|
|
"app/legacy/",
|
|
"app/_archive/",
|
|
"alembic/versions/",
|
|
"build/",
|
|
"dist/",
|
|
]
|
|
|
|
[tool.ruff.lint]
|
|
# Modern 2026 default rule set. Strict but practical.
|
|
select = [
|
|
"E", # pycodestyle errors
|
|
"W", # pycodestyle warnings
|
|
"F", # pyflakes
|
|
"I", # isort
|
|
"N", # pep8-naming
|
|
"UP", # pyupgrade
|
|
"B", # flake8-bugbear
|
|
"C4", # flake8-comprehensions
|
|
"SIM", # flake8-simplify
|
|
"TCH", # flake8-type-checking
|
|
"RUF", # ruff-specific
|
|
"ASYNC",# flake8-async
|
|
"S", # flake8-bandit (security)
|
|
"PIE", # flake8-pie
|
|
"PT", # flake8-pytest-style
|
|
]
|
|
ignore = [
|
|
"E501", # line length (handled by formatter)
|
|
"B008", # function calls in defaults (FastAPI Depends)
|
|
"S101", # assert (we use it in dev paths)
|
|
"N818", # exception naming (we use Error suffix)
|
|
]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
# Tests are allowed to be looser
|
|
"tests/**/*.py" = ["S101", "S105", "S106", "B011"]
|
|
# Legacy code excluded entirely
|
|
"_legacy_main.py" = ["ALL"]
|
|
"app/legacy/**" = ["ALL"]
|
|
|
|
[tool.ruff.lint.isort]
|
|
known-first-party = ["app"]
|
|
combine-as-imports = true
|
|
|
|
[tool.mypy]
|
|
python_version = "3.11"
|
|
strict = true
|
|
plugins = ["pydantic.mypy"]
|
|
# Pragmatic: don't break legacy, but enforce on new code.
|
|
exclude = [
|
|
"_legacy_main.py",
|
|
"app/legacy/",
|
|
"app/_archive/",
|
|
"alembic/versions/",
|
|
"tests/",
|
|
]
|
|
# Tolerate missing imports for libraries without type stubs
|
|
ignore_missing_imports = false
|
|
warn_unused_configs = true
|
|
warn_redundant_casts = true
|
|
warn_unreachable = true
|
|
|
|
[[tool.mypy.overrides]]
|
|
# Domain layer is the strictest — no FastAPI leakage allowed.
|
|
module = ["app.domains.*"]
|
|
disallow_any_explicit = true
|
|
disallow_any_decorated = false # Pydantic decorators need this
|
|
no_implicit_optional = true
|
|
warn_return_any = true
|
|
|
|
[[tool.mypy.overrides]]
|
|
# Core (cross-cutting) is also strict.
|
|
module = ["app.core.*"]
|
|
disallow_any_explicit = true
|
|
no_implicit_optional = true
|
|
|
|
[[tool.mypy.overrides]]
|
|
# Legacy stays relaxed until migrated.
|
|
module = ["_legacy_main", "app.legacy.*"]
|
|
ignore_errors = true
|
|
|
|
[tool.pytest.ini_options]
|
|
minversion = "8.0"
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py", "*_test.py"]
|
|
addopts = [
|
|
"-ra",
|
|
"--strict-markers",
|
|
"--strict-config",
|
|
"--showlocals",
|
|
"--tb=short",
|
|
]
|
|
markers = [
|
|
"slow: marks tests as slow (deselect with -m 'not slow')",
|
|
"integration: marks tests that need docker/compose",
|
|
]
|
|
|
|
# ── Custom size cap (not in pyproject.toml by default) ────────────────
|
|
# Enforced via .pre-commit-config.yaml custom check.
|
|
|
|
[tool.coverage.run]
|
|
source = ["app"]
|
|
omit = ["_legacy_main.py", "app/legacy/*", "tests/*"]
|
|
|
|
[tool.coverage.report]
|
|
show_missing = true
|
|
skip_covered = true
|
|
fail_under = 60 # raise as migration progresses
|