diff --git a/.gitignore b/.gitignore index 4befed3..274a208 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,27 @@ +# OS .DS_Store .idea +.vscode + +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +dist/ +.venv/ +.ruff_cache/ + +# Secrets +.env +.env.* + +# Data & Models (large files, local only) +data/ +weights/ + +# Database +*.db +*.sqlite3 + +# Tile cache +tile_cache/ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dbe16c1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,41 @@ +[project] +name = "gps-denied-onboard" +version = "0.1.0" +description = "GPS-denied UAV geolocalization service" +requires-python = ">=3.11" +dependencies = [ + "fastapi>=0.115", + "uvicorn[standard]>=0.34", + "pydantic>=2.0", + "pydantic-settings>=2.0", + "sqlalchemy>=2.0", + "alembic>=1.14", + "sse-starlette>=2.0", + "aiosqlite>=0.20", +] + +[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 = 100 + +[tool.ruff.lint] +select = ["E", "F", "I", "W"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +asyncio_mode = "auto" diff --git a/src/gps_denied/__init__.py b/src/gps_denied/__init__.py new file mode 100644 index 0000000..5894694 --- /dev/null +++ b/src/gps_denied/__init__.py @@ -0,0 +1,3 @@ +"""GPS-Denied Onboard — UAV geolocalization service.""" + +__version__ = "0.1.0" diff --git a/src/gps_denied/__main__.py b/src/gps_denied/__main__.py new file mode 100644 index 0000000..b619db8 --- /dev/null +++ b/src/gps_denied/__main__.py @@ -0,0 +1,16 @@ +"""Entry point: python -m gps_denied.""" + +import uvicorn + + +def main() -> None: + uvicorn.run( + "gps_denied.app:app", + host="127.0.0.1", + port=8000, + reload=True, + ) + + +if __name__ == "__main__": + main() diff --git a/src/gps_denied/app.py b/src/gps_denied/app.py new file mode 100644 index 0000000..fecd751 --- /dev/null +++ b/src/gps_denied/app.py @@ -0,0 +1,23 @@ +"""FastAPI application factory.""" + +from fastapi import FastAPI + +from gps_denied import __version__ + + +def create_app() -> FastAPI: + """Create and configure the FastAPI application.""" + application = FastAPI( + title="GPS-Denied Onboard", + version=__version__, + description="UAV geolocalization service for GPS-denied environments", + ) + + @application.get("/health") + async def health() -> dict: + return {"status": "ok"} + + return application + + +app = create_app() diff --git a/tests/test_health.py b/tests/test_health.py new file mode 100644 index 0000000..61524bf --- /dev/null +++ b/tests/test_health.py @@ -0,0 +1,16 @@ +"""Tests for the health endpoint.""" + +import pytest +from httpx import ASGITransport, AsyncClient + +from gps_denied.app import app + + +@pytest.mark.asyncio +async def test_health_returns_ok(): + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + response = await client.get("/health") + + assert response.status_code == 200 + assert response.json() == {"status": "ok"}