lexora / pyproject.toml
Abdr007's picture
Lexora β€” deployed tree
547ce6e
Raw
History Blame Contribute Delete
6.69 kB
# ─────────────────────────────────────────────────────────────────────────────
# Lexora β€” repo-root tooling configuration.
#
# This file configures ruff / mypy / pytest for EVERY Python file in the repo
# (apps/api, corpus, eval, scripts) so there is a single source of truth for the
# "zero warnings" gate. Package metadata and runtime dependencies live in
# apps/api/pyproject.toml.
# ─────────────────────────────────────────────────────────────────────────────
[tool.ruff]
line-length = 100
target-version = "py312"
extend-exclude = [
"**/.venv",
"var",
"apps/web",
"corpus/pdf",
]
[tool.ruff.lint]
select = [
"E", "W", # pycodestyle
"F", # pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # comprehensions
"DTZ", # flake8-datetimez
"T20", # flake8-print
"PT", # pytest style
"RET", # flake8-return
"SIM", # flake8-simplify
"TID", # tidy imports
"ARG", # unused arguments
"PTH", # prefer pathlib
"PL", # pylint
"TRY", # tryceratops
"RUF", # ruff-specific
"S", # flake8-bandit (security)
"ASYNC", # flake8-async
"ANN", # flake8-annotations
]
ignore = [
"ANN401", # `Any` is unavoidable at a few third-party SDK boundaries
"TRY003", # an inline message beats a bespoke exception class per error site
"PLR0913", # pipeline constructors legitimately take many explicit knobs
"TRY400", # logger.error with an explicit message is intentional in handlers
# Deferred imports are deliberate throughout: they break import cycles between the
# retrieval modules and keep multi-hundred-megabyte ONNX runtimes off the import path
# of anything that does not actually run inference. Each site is a considered choice.
"PLC0415",
# Typographic characters (em dash, middle dot, non-breaking hyphen) appear in prose
# strings and in the corpus's own text. Flagging them is noise, not safety.
"RUF001", "RUF002", "RUF003",
]
[tool.ruff.lint.per-file-ignores]
# CLI entrypoints are meant to print to the terminal.
"corpus/download.py" = ["T201"]
"eval/*.py" = ["T201"]
"scripts/*.py" = ["T201"]
"apps/api/app/rag/index.py" = ["T201"]
# `_looks_like_title` is a chain of independent disqualifying tests. Collapsing eight
# early returns into nested conditionals would make it harder to read, not safer.
"apps/api/app/rag/parse.py" = ["PLR0911"]
# Tests assert, use magic numbers, and take fixtures they do not always read.
# ANN2 is off for tests only: every test function returns None, so annotating 100 of
# them adds noise without adding a single guarantee. Production code keeps ANN in full.
"apps/api/tests/**" = ["S101", "PLR2004", "ARG001", "PLR0915", "ANN"]
# FastAPI's dependency-injection idiom IS a call in a default argument (`Depends(...)`),
# and the framework requires it. Nothing else in the file relies on B008.
"apps/api/app/main.py" = ["B008"]
[tool.ruff.lint.isort]
# Both are first-party. Without naming `tests` explicitly, ruff infers it from the
# working directory β€” which resolved differently on CI than locally and produced an
# import-order failure that could not be reproduced on a developer machine.
known-first-party = ["app", "tests"]
[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"
[tool.ruff.format]
docstring-code-format = true
# ─────────────────────────────────────────────────────────────────────────────
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
disallow_untyped_defs = true
disallow_any_generics = true
no_implicit_reexport = true
show_error_codes = true
mypy_path = "apps/api"
# Without this, `apps/api/tests/conftest.py` is discovered both as `conftest` (because
# apps/api is on mypy_path) and as `tests.conftest`, which mypy rejects outright.
explicit_package_bases = true
namespace_packages = true
files = ["apps/api/app", "apps/api/tests", "corpus", "eval", "scripts"]
exclude = "(^|/)(\\.venv|var|corpus/pdf)/"
[[tool.mypy.overrides]]
# Third-party packages that ship no inline types / no py.typed marker.
module = [
"rank_bm25.*",
"fastembed.*",
"fastembed",
"langfuse.*",
"slowapi.*",
"fitz",
"pytesseract",
"docx",
"docx.*",
# Optional heavyweight reranker backend, imported lazily and never installed by default.
"sentence_transformers.*",
]
ignore_missing_imports = true
[[tool.mypy.overrides]]
# Same policy as ruff's ANN ignore for tests: every test function returns None, so
# annotating a hundred of them adds noise without adding a guarantee. Production code
# stays under full --strict.
module = ["tests.*"]
disallow_untyped_defs = false
disallow_incomplete_defs = false
# ─────────────────────────────────────────────────────────────────────────────
[tool.pytest.ini_options]
minversion = "8.0"
testpaths = ["apps/api/tests"]
pythonpath = ["apps/api"]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
addopts = "-q --strict-markers --strict-config"
filterwarnings = [
"error",
# PyMuPDF's SWIG bindings emit this at import time. Under `-W error` the exception is
# raised *inside* a C-extension initialiser, which segfaults the interpreter during
# collection rather than failing a test β€” so it must be filtered, not fixed here.
"ignore:builtin type .* has no __module__ attribute:DeprecationWarning",
"ignore::DeprecationWarning:importlib._bootstrap",
# Deprecations raised inside third-party packages that we neither trigger
# from our own code nor can fix from here.
"ignore::DeprecationWarning:websockets.*",
"ignore::DeprecationWarning:httpx.*",
"ignore::DeprecationWarning:starlette.*",
]
markers = [
"integration: exercises the real on-disk index (requires `make index` first)",
"live_llm: calls the real Anthropic API (requires ANTHROPIC_API_KEY)",
]