diff --git a/space2stats_api/cdk/app.py b/space2stats_api/cdk/app.py index 2b9f419..fdf3e7d 100644 --- a/space2stats_api/cdk/app.py +++ b/space2stats_api/cdk/app.py @@ -2,7 +2,6 @@ from aws_stack import Space2StatsStack from settings import DeploymentSettings - settings = DeploymentSettings(_env_file="aws_deployment.env") env = Environment( @@ -14,4 +13,4 @@ Space2StatsStack(app, "Space2StatsStack", env=env) -app.synth() \ No newline at end of file +app.synth() diff --git a/space2stats_api/cdk/aws_stack.py b/space2stats_api/cdk/aws_stack.py index 50d08c8..eaec78f 100644 --- a/space2stats_api/cdk/aws_stack.py +++ b/space2stats_api/cdk/aws_stack.py @@ -1,15 +1,13 @@ -from aws_cdk import ( - Stack, - aws_apigatewayv2 as apigatewayv2, - aws_apigatewayv2_integrations as integrations, - aws_lambda as _lambda, - aws_certificatemanager as acm, - Duration -) +from aws_cdk import Duration, Stack +from aws_cdk import aws_apigatewayv2 as apigatewayv2 +from aws_cdk import aws_apigatewayv2_integrations as integrations +from aws_cdk import aws_certificatemanager as acm +from aws_cdk import aws_lambda as _lambda from aws_cdk.aws_lambda_python_alpha import PythonFunction from constructs import Construct from settings import AppSettings, DeploymentSettings + class Space2StatsStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) @@ -28,7 +26,10 @@ def __init__(self, scope: Construct, id: str, **kwargs) -> None: memory_size=1024 ) - certificate = acm.Certificate.from_certificate_arn(self, "Certificate", deployment_settings.CDK_CERTIFICATE_ARN) + certificate = acm.Certificate.from_certificate_arn( + self, "Certificate", + deployment_settings.CDK_CERTIFICATE_ARN + ) domain_name = apigatewayv2.DomainName( self, "DomainName", @@ -49,4 +50,4 @@ def __init__(self, scope: Construct, id: str, **kwargs) -> None: api=http_api, domain_name=domain_name, stage=http_api.default_stage - ) \ No newline at end of file + ) diff --git a/space2stats_api/cdk/settings.py b/space2stats_api/cdk/settings.py index c8903e4..fd22267 100644 --- a/space2stats_api/cdk/settings.py +++ b/space2stats_api/cdk/settings.py @@ -13,4 +13,4 @@ class DeploymentSettings(BaseSettings): CDK_DEFAULT_ACCOUNT: str CDK_DEFAULT_REGION: str CDK_CERTIFICATE_ARN: str - CDK_DOMAIN_NAME: str \ No newline at end of file + CDK_DOMAIN_NAME: str diff --git a/space2stats_api/src/app/main.py b/space2stats_api/src/app/main.py index 3e02954..70e659d 100644 --- a/space2stats_api/src/app/main.py +++ b/space2stats_api/src/app/main.py @@ -1,6 +1,6 @@ from fastapi import FastAPI -from mangum import Mangum from fastapi.middleware.cors import CORSMiddleware +from mangum import Mangum from .routers import api @@ -8,7 +8,7 @@ app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], @@ -20,4 +20,4 @@ def read_root(): return {"message": "Welcome to Space2Stats!"} -handler = Mangum(app) \ No newline at end of file +handler = Mangum(app) diff --git a/space2stats_api/src/app/routers/api.py b/space2stats_api/src/app/routers/api.py index 2a00dea..ba9069e 100644 --- a/space2stats_api/src/app/routers/api.py +++ b/space2stats_api/src/app/routers/api.py @@ -1,12 +1,11 @@ -from typing import List, Dict, Any, Literal, Optional, TypeAlias -from fastapi import APIRouter +from typing import Any, Dict, List, Literal, Optional, TypeAlias -from pydantic import BaseModel +from fastapi import APIRouter from geojson_pydantic import Feature, Polygon +from pydantic import BaseModel -from ..utils.h3_utils import generate_h3_ids, generate_h3_geometries from ..utils.db_utils import get_available_fields, get_summaries - +from ..utils.h3_utils import generate_h3_geometries, generate_h3_ids router = APIRouter() @@ -57,4 +56,4 @@ def get_summary(request: SummaryRequest): @router.get("/fields", response_model=List[str]) def fields(): - return get_available_fields() \ No newline at end of file + return get_available_fields() diff --git a/space2stats_api/src/app/settings.py b/space2stats_api/src/app/settings.py index e2fbc58..9c07e99 100644 --- a/space2stats_api/src/app/settings.py +++ b/space2stats_api/src/app/settings.py @@ -11,4 +11,6 @@ class Settings(BaseSettings): @property def DB_CONNECTION_STRING(self) -> str: - return f"host={self.DB_HOST} port={self.DB_PORT} dbname={self.DB_NAME} user={self.DB_USER} password={self.DB_PASSWORD}" \ No newline at end of file + host_port = f"host={self.DB_HOST} port={self.DB_PORT}" + db_user = f"dbname={self.DB_NAME} user={self.DB_USER}" + return f"{host_port} {db_user} password={self.DB_PASSWORD}" diff --git a/space2stats_api/src/app/utils/db_utils.py b/space2stats_api/src/app/utils/db_utils.py index 651f5ac..cc091b2 100644 --- a/space2stats_api/src/app/utils/db_utils.py +++ b/space2stats_api/src/app/utils/db_utils.py @@ -1,5 +1,6 @@ import psycopg as pg from psycopg_pool import ConnectionPool + from ..settings import Settings settings = Settings() @@ -56,4 +57,4 @@ def get_available_fields(): except Exception as e: raise e - return columns \ No newline at end of file + return columns diff --git a/space2stats_api/src/app/utils/h3_utils.py b/space2stats_api/src/app/utils/h3_utils.py index 44bf9da..9a84e64 100644 --- a/space2stats_api/src/app/utils/h3_utils.py +++ b/space2stats_api/src/app/utils/h3_utils.py @@ -1,7 +1,7 @@ -from typing import Dict, Any, List, Optional +from typing import Any, Dict, List, Optional import h3 -from shapely.geometry import shape, Polygon, Point, mapping +from shapely.geometry import Point, Polygon, mapping, shape def generate_h3_ids( @@ -55,7 +55,8 @@ def generate_h3_geometries( Parameters: h3_ids (List[str]): A list of H3 hexagon IDs. - geometry_type (Optional[str]): The type of geometry to generate ('polygon' or 'point'). + geometry_type (Optional[str]): + The type of geometry to generate ('polygon' or 'point'). Returns: List[Dict[str, Any]]: A list of geometries in GeoJSON format. diff --git a/space2stats_api/tests/test_api.py b/space2stats_api/tests/test_api.py index a6a3d00..baf688c 100644 --- a/space2stats_api/tests/test_api.py +++ b/space2stats_api/tests/test_api.py @@ -1,7 +1,8 @@ -from fastapi.testclient import TestClient -import pytest from unittest.mock import patch +import pytest +from fastapi.testclient import TestClient + from src.app.main import app client = TestClient(app) @@ -32,7 +33,10 @@ def test_read_root(): @patch("src.app.routers.api.get_summaries") def test_get_summary(mock_get_summaries): - mock_get_summaries.return_value = [("hex_1", 100, 200)], ["hex_id", "sum_pop_2020", "sum_pop_f_10_2020"] + mock_get_summaries.return_value = ( + [("hex_1", 100, 200)], + ["hex_id", "sum_pop_2020", "sum_pop_f_10_2020"] + ) request_payload = { "aoi": aoi, @@ -50,12 +54,16 @@ def test_get_summary(mock_get_summaries): assert "hex_id" in summary for field in request_payload["fields"]: assert field in summary - assert len(summary) == len(request_payload["fields"]) + 1 # +1 for the 'hex_id' + # +1 for the 'hex_id' + assert len(summary) == len(request_payload["fields"]) + 1 @patch("src.app.routers.api.get_summaries") def test_get_summary_with_geometry_polygon(mock_get_summaries): - mock_get_summaries.return_value = [("hex_1", 100, 200)], ["hex_id", "sum_pop_2020", "sum_pop_f_10_2020"] + mock_get_summaries.return_value = ( + [("hex_1", 100, 200)], + ["hex_id", "sum_pop_2020", "sum_pop_f_10_2020"] + ) request_payload = { "aoi": aoi, @@ -76,12 +84,16 @@ def test_get_summary_with_geometry_polygon(mock_get_summaries): assert summary["geometry"]["type"] == "Polygon" for field in request_payload["fields"]: assert field in summary - assert len(summary) == len(request_payload["fields"]) + 2 # +1 for the 'hex_id' and +1 for 'geometry' + # +1 for the 'hex_id' and +1 for 'geometry' + assert len(summary) == len(request_payload["fields"]) + 2 @patch("src.app.routers.api.get_summaries") def test_get_summary_with_geometry_point(mock_get_summaries): - mock_get_summaries.return_value = [("hex_1", 100, 200)], ["hex_id", "sum_pop_2020", "sum_pop_f_10_2020"] + mock_get_summaries.return_value = ( + [("hex_1", 100, 200)], + ["hex_id", "sum_pop_2020", "sum_pop_f_10_2020"] + ) request_payload = { "aoi": aoi, @@ -102,22 +114,25 @@ def test_get_summary_with_geometry_point(mock_get_summaries): assert summary["geometry"]["type"] == "Point" for field in request_payload["fields"]: assert field in summary - assert len(summary) == len(request_payload["fields"]) + 2 # +1 for the 'hex_id' and +1 for 'geometry' + # +1 for the 'hex_id' and +1 for 'geometry' + assert len(summary) == len(request_payload["fields"]) + 2 @patch("src.app.routers.api.get_available_fields") def test_get_fields(mock_get_available_fields): - mock_get_available_fields.return_value = ["sum_pop_2020", "sum_pop_f_10_2020", "field3"] + mock_get_available_fields.return_value = ["sum_pop_2020", + "sum_pop_f_10_2020", + "field3"] response = client.get("/fields") assert response.status_code == 200 response_json = response.json() - + expected_fields = ["sum_pop_2020", "sum_pop_f_10_2020", "field3"] for field in expected_fields: assert field in response_json if __name__ == "__main__": - pytest.main() \ No newline at end of file + pytest.main() diff --git a/space2stats_api/tests/test_db_utils.py b/space2stats_api/tests/test_db_utils.py index 171f1cd..222f035 100644 --- a/space2stats_api/tests/test_db_utils.py +++ b/space2stats_api/tests/test_db_utils.py @@ -1,6 +1,7 @@ import pytest from shapely.geometry import Polygon, mapping -from src.app.utils.h3_utils import generate_h3_ids, generate_h3_geometries + +from src.app.utils.h3_utils import generate_h3_geometries, generate_h3_ids polygon_coords = [ [-74.3, 40.5], @@ -64,4 +65,4 @@ def test_generate_h3_geometries_invalid_type(): if __name__ == "__main__": - pytest.main() \ No newline at end of file + pytest.main() diff --git a/space2stats_api/tests/test_h3_utils.py b/space2stats_api/tests/test_h3_utils.py index 7813dda..222f035 100644 --- a/space2stats_api/tests/test_h3_utils.py +++ b/space2stats_api/tests/test_h3_utils.py @@ -1,6 +1,7 @@ import pytest from shapely.geometry import Polygon, mapping -from src.app.utils.h3_utils import generate_h3_ids, generate_h3_geometries + +from src.app.utils.h3_utils import generate_h3_geometries, generate_h3_ids polygon_coords = [ [-74.3, 40.5],