diff --git a/README.md b/README.md index e309e93c..2ecfe5f5 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ The set of long-running services can include: - irv-autopkg-worker: Autopackage data processing (clipping, serialisation, etc.) - irv-autopkg-api: Autopackage service coordination -If you're running [your own FE](https://github.com/nismod/irv-frontend/) +If you're running your own [frontend](https://github.com/nismod/irv-frontend/) development server, or connecting to a remotely hosted database, or not using the [autopackage API](https://github.com/nismod/irv-autopkg), you may not need all these services. diff --git a/containers/backend/README.md b/containers/backend/README.md index 4061aa7f..7e7e7e1a 100644 --- a/containers/backend/README.md +++ b/containers/backend/README.md @@ -21,7 +21,15 @@ docker-compose -f docker-compose-prod-build.yaml build backend ### Running Locally ```bash -cd containers/backend/backend +# cd to this backend app directory +cd containers/backend + +# create a virtual environment (using venv or another method if you prefer) +python -m venv venv +source venv/bin/activate +pip install -e .[dev] + +# run the application uvicorn app.main:app --port 8888 --reload ``` diff --git a/containers/backend/backend/app/internal/attribute_access.py b/containers/backend/backend/app/internal/attribute_access.py index 285cfc80..f8e347ac 100644 --- a/containers/backend/backend/app/internal/attribute_access.py +++ b/containers/backend/backend/app/internal/attribute_access.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Callable +from typing import Callable, Optional from sqlalchemy import Column from sqlalchemy.orm import Query from sqlalchemy.sql import functions @@ -16,7 +16,7 @@ def add_damages_expected_value_query( dimensions: schemas.ExpectedDamagesDimensions, field: str, field_params: schemas.DataParameters, -): +) -> Query: q = fq.join(models.Feature.damages_expected) q = q.filter_by(rcp=dimensions.rcp, epoch=dimensions.epoch) agg = False @@ -78,7 +78,7 @@ class DataGroupConfig: add_value_query: Callable[ [Query, schemas.DataDimensions, str, schemas.DataParameters | None], Query ] - field_parameters_schemas: dict[str, schemas.DataParameters] = None + field_parameters_schemas: Optional[dict[str, schemas.DataParameters]] = None DATA_GROUP_CONFIGS: dict[str, DataGroupConfig] = { @@ -136,8 +136,8 @@ def add_value_query( field_group: str, field_dimensions: schemas.DataDimensions, field: str, - field_params: schemas.DataParameters = None, -): + field_params: Optional[schemas.DataParameters] = None, +) -> Query: data_group_config = DATA_GROUP_CONFIGS.get(field_group) if data_group_config is not None: diff --git a/containers/backend/backend/app/internal/helpers.py b/containers/backend/backend/app/internal/helpers.py index 2cded158..74be3741 100644 --- a/containers/backend/backend/app/internal/helpers.py +++ b/containers/backend/backend/app/internal/helpers.py @@ -2,6 +2,7 @@ Singleton Helpers """ +import logging import traceback from config import TILEDB_URI @@ -14,7 +15,7 @@ def build_driver_path(database: str, tiledb_uri: str = TILEDB_URI) -> str: return tiledb_uri + "/" + database -def handle_exception(logger, err: Exception): +def handle_exception(logger: logging.Logger, err: Exception): """ Handle generic exceptions """ diff --git a/containers/backend/backend/app/routers/tiles.py b/containers/backend/backend/app/routers/tiles.py index 0b70cf05..73e41e6f 100644 --- a/containers/backend/backend/app/routers/tiles.py +++ b/containers/backend/backend/app/routers/tiles.py @@ -4,7 +4,7 @@ from collections import OrderedDict from sys import getsizeof -from typing import BinaryIO, List, Tuple, Union +from typing import BinaryIO, List, Optional, Tuple, Union import json import inspect @@ -31,7 +31,7 @@ router = APIRouter(tags=["tiles"]) -def _parse_keys(keys: str) -> List: +def _parse_keys(keys: str) -> Tuple[str, List[str]]: """ Parse tiles URL key str """ @@ -44,7 +44,7 @@ def _parse_keys(keys: str) -> List: def _get_singleband_image( database: str, keys: List[str], - tile_xyz: Tuple[int, int, int] = None, + tile_xyz: Optional[Tuple[int, int, int]] = None, options: dict = {}, ) -> BinaryIO: """ @@ -92,7 +92,7 @@ def _tile_db_from_domain(domain: str) -> str: return domain_to_db[domain] -def _source_options(source_db: str) -> List[dict]: +def _source_options(source_db: str) -> List[dict[str, str]]: """ Gather all URL key combinations available in the given source diff --git a/containers/backend/backend/app/schemas.py b/containers/backend/backend/app/schemas.py index fa6cf48b..cb1bbf25 100644 --- a/containers/backend/backend/app/schemas.py +++ b/containers/backend/backend/app/schemas.py @@ -116,7 +116,7 @@ class AdaptationCostBenefitRatioParameters(DataParameters): eael_days: conint(ge=1, le=30) @validator("eael_days") - def fix_eael_days(cls, eael_days) -> float: + def fix_eael_days(cls, eael_days: int) -> float: """ The data for `AdaptationCostBenefit.avoided_eael_mean` is erroneous and should be modified in the meantime. This validator adds a fudge factor @@ -175,19 +175,19 @@ class FeatureListItemOut(BaseModel, Generic[SortFieldT]): # Tile Server metadata class TileSourceMeta(BaseModel): - id: int = None + id: Optional[int] = None domain: str name: str group: str description: str license: str - keys: list + keys: list[str] model_config = ConfigDict(from_attributes=True) class TileSourceDomains(BaseModel): - domains: List[dict] + domains: List[dict[str, str]] class ColorMapOptions(BaseModel): diff --git a/containers/backend/pyproject.toml b/containers/backend/pyproject.toml index 4dbb3251..22304dde 100644 --- a/containers/backend/pyproject.toml +++ b/containers/backend/pyproject.toml @@ -14,8 +14,14 @@ dependencies = [ "fastapi==0.109.1", "geoalchemy2==0.12.5", "uvicorn==0.18.3", - "psycopg2-binary==2.9.3", + "psycopg2-binary==2.9.10", "fastapi-pagination==0.10.0", "terracotta==0.8.3", "sqlalchemy==1.4.41", ] + +[project.optional-dependencies] +dev = ["types-sqlalchemy"] + +[tool.pyright] +exclude = ["venv", ".venv"]