[project]
name = "gps-denied-onboard"
version = "0.1.0"
description = "GPS-denied UAV geolocalization service"
requires-python = ">=3.11"
dependencies = [
    "fastapi",
    "uvicorn[standard]",
    "pydantic>=2",
    "pydantic-settings>=2",
    "sqlalchemy>=2",
    "alembic>=1.14",
    "sse-starlette>=2.0",
    "aiosqlite>=0.20",
    "python-multipart>=0.0.9",
    "httpx>=0.27",
    "diskcache>=5.6",
    "numpy>=1.26,<2.0",  # NumPy 2.0 silently breaks GTSAM Python bindings (issue #2264)
    "opencv-python-headless>=4.9,<4.11",  # 4.11+ requires numpy>=2.0 (incompatible with GTSAM)
    "gtsam>=4.3a0",
    "pymavlink>=2.4",
]

[project.optional-dependencies]
dev = [
    "ruff>=0.9",
    "pytest>=8.0",
    "pytest-asyncio>=0.24",
    "httpx>=0.28",
]

[build-system]
requires = ["setuptools>=75"]
build-backend = "setuptools.build_meta"

[tool.setuptools.packages.find]
where = ["src"]

[tool.ruff]
target-version = "py311"
line-length = 120

[tool.ruff.lint.per-file-ignores]
# Abstract interfaces have long method signatures — allow up to 170
"src/gps_denied/core/graph.py" = ["E501"]
"src/gps_denied/core/metric.py" = ["E501"]
"src/gps_denied/core/chunk_manager.py" = ["E501"]

[tool.ruff.lint]
select = ["E", "F", "I", "W"]

[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
markers = [
    "e2e: end-to-end test against a real dataset",
    "e2e_slow: e2e test that takes > 2 minutes, nightly-only",
    "needs_dataset: test requires an external dataset to be downloaded",
]
