From 6fdcb39b203196e39668a89d2d5632aab4cd1bbb Mon Sep 17 00:00:00 2001 From: Zac Deziel Date: Wed, 14 Aug 2024 08:32:23 -0700 Subject: [PATCH] Feature/deploy (#25) * Setup database ingestion * Update path to requirements in CI * Refactor project structure for cdk deployment * Update tests for new deployment structure * Update timeout of lambda function * Add custom domain for API Separate settings into deployment and application. * Transition to API Gateway v2 * Update path to requirements in CI workflow * Update memory setting for lambda to improve performance * Add pytest dependency installation to CI workflow * Update pattern for env files --- .github/workflows/ci.yml | 4 +- .gitignore | 6 +- notebooks/space2stats_api_demo.ipynb | 127 ++++++------------ postgres/deploy.md | 7 + postgres/load_nyc_sample.sh | 16 ++- postgres/load_parquet_chunks.sh | 17 ++- postgres/load_to_prod.sh | 30 +++++ space2stats_api/app/main.py | 13 -- space2stats_api/app/models/summary.py | 0 space2stats_api/app/settings.py | 15 --- space2stats_api/cdk/app.py | 17 +++ space2stats_api/cdk/aws_stack.py | 52 +++++++ space2stats_api/cdk/cdk.json | 4 + space2stats_api/cdk/settings.py | 16 +++ space2stats_api/pytest.ini | 2 + .../{app/models => src/app}/__init__.py | 0 space2stats_api/src/app/main.py | 23 ++++ .../{ => src}/app/routers/__init__.py | 0 space2stats_api/{ => src}/app/routers/api.py | 4 +- space2stats_api/src/app/settings.py | 10 ++ .../{ => src}/app/utils/__init__.py | 0 .../{ => src}/app/utils/db_utils.py | 4 +- .../{ => src}/app/utils/h3_utils.py | 0 space2stats_api/{ => src}/requirements.txt | 4 +- space2stats_api/tests/test_api.py | 2 +- space2stats_api/tests/test_db_utils.py | 2 +- space2stats_api/tests/test_h3_utils.py | 2 +- 27 files changed, 237 insertions(+), 140 deletions(-) create mode 100644 postgres/deploy.md create mode 100755 postgres/load_to_prod.sh delete mode 100644 space2stats_api/app/main.py delete mode 100644 space2stats_api/app/models/summary.py delete mode 100644 space2stats_api/app/settings.py create mode 100644 space2stats_api/cdk/app.py create mode 100644 space2stats_api/cdk/aws_stack.py create mode 100644 space2stats_api/cdk/cdk.json create mode 100644 space2stats_api/cdk/settings.py create mode 100644 space2stats_api/pytest.ini rename space2stats_api/{app/models => src/app}/__init__.py (100%) create mode 100644 space2stats_api/src/app/main.py rename space2stats_api/{ => src}/app/routers/__init__.py (100%) rename space2stats_api/{ => src}/app/routers/api.py (91%) create mode 100644 space2stats_api/src/app/settings.py rename space2stats_api/{ => src}/app/utils/__init__.py (100%) rename space2stats_api/{ => src}/app/utils/db_utils.py (96%) rename space2stats_api/{ => src}/app/utils/h3_utils.py (100%) rename space2stats_api/{ => src}/requirements.txt (75%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7687425..c0f436b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r space2stats_api/requirements.txt - pip install pre-commit + pip install -r space2stats_api/src/requirements.txt + pip install pre-commit pytest - name: Set PYTHONPATH run: echo "PYTHONPATH=$(pwd)/space2stats_api" >> $GITHUB_ENV diff --git a/.gitignore b/.gitignore index 32a76a8..4edf48e 100644 --- a/.gitignore +++ b/.gitignore @@ -100,4 +100,8 @@ db.env # data *.parquet *.duckdb -.pgdata \ No newline at end of file +.pgdata +space2stats_api/space2stats_env +*.env +cdk.out +lambda_layer \ No newline at end of file diff --git a/notebooks/space2stats_api_demo.ipynb b/notebooks/space2stats_api_demo.ipynb index 62dec03..971688a 100644 --- a/notebooks/space2stats_api_demo.ipynb +++ b/notebooks/space2stats_api_demo.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 8, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -21,18 +21,18 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ - "BASE_URL = \"http://localhost:8000\"\n", + "BASE_URL = \"https://space2stats.ds.io\"\n", "FIELDS_ENDPOINT = f\"{BASE_URL}/fields\"\n", "SUMMARY_ENDPOINT = f\"{BASE_URL}/summary\"" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -54,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -115,7 +115,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -123,7 +123,7 @@ "request_payload = {\n", " \"aoi\": aoi,\n", " \"spatial_join_method\": \"centroid\",\n", - " \"fields\": [\"sum_pop_2020\", \"sum_pop_f_2020\", \"sum_pop_m_2020\"], \n", + " \"fields\": [\"sum_pop_2020\"], \n", " \"geometry\": \"point\"\n", "}\n", "\n", @@ -138,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -165,135 +165,98 @@ " hex_id\n", " geometry\n", " sum_pop_2020\n", - " sum_pop_f_2020\n", - " sum_pop_m_2020\n", " \n", " \n", " \n", " \n", " 0\n", " 866a4a48fffffff\n", - " POINT (36.31771 2.23633)\n", + " POINT (35.76352 2.99589)\n", " 399.860905\n", - " 189.675539\n", - " 210.185366\n", " \n", " \n", " 1\n", " 866a4a497ffffff\n", - " POINT (40.18159 0.05763)\n", + " POINT (40.58048 -3.79365)\n", " 582.555159\n", - " 276.337255\n", - " 306.217904\n", " \n", " \n", " 2\n", " 866a4a49fffffff\n", - " POINT (38.59096 0.13944)\n", + " POINT (41.10421 3.37873)\n", " 749.911237\n", - " 355.723245\n", - " 394.187992\n", " \n", " \n", " 3\n", " 866a4a4d7ffffff\n", - " POINT (35.07124 0.80971)\n", + " POINT (37.26153 3.74581)\n", " 863.888290\n", - " 418.309236\n", - " 445.579054\n", " \n", " \n", " 4\n", " 866a5820fffffff\n", - " POINT (37.4356 3.35699)\n", + " POINT (40.01148 1.53124)\n", " 525.085147\n", - " 249.076134\n", - " 276.009012\n", " \n", " \n", " ...\n", " ...\n", " ...\n", " ...\n", - " ...\n", - " ...\n", " \n", " \n", " 16212\n", " 867b5dd77ffffff\n", - " POINT (39.15438 -1.51437)\n", + " POINT (34.94474 1.24558)\n", " -36.000000\n", - " -18.000000\n", - " -18.000000\n", " \n", " \n", " 16213\n", " 867b5dd87ffffff\n", - " POINT (35.80252 0.90823)\n", + " POINT (40.95343 -1.83280)\n", " -36.000000\n", - " -18.000000\n", - " -18.000000\n", " \n", " \n", " 16214\n", " 867b5dd8fffffff\n", - " POINT (37.93845 0.83454)\n", + " POINT (35.20290 -0.29666)\n", " -36.000000\n", - " -18.000000\n", - " -18.000000\n", " \n", " \n", " 16215\n", " 867b5dd9fffffff\n", - " POINT (38.65824 -2.60028)\n", + " POINT (41.28333 -1.08552)\n", " -36.000000\n", - " -18.000000\n", - " -18.000000\n", " \n", " \n", " 16216\n", " 867b5ddafffffff\n", - " POINT (36.6641 2.37083)\n", + " POINT (36.63048 1.35038)\n", " -36.000000\n", - " -18.000000\n", - " -18.000000\n", " \n", " \n", "\n", - "

16217 rows × 5 columns

\n", + "

16217 rows × 3 columns

\n", "" ], "text/plain": [ - " hex_id geometry sum_pop_2020 \\\n", - "0 866a4a48fffffff POINT (36.31771 2.23633) 399.860905 \n", - "1 866a4a497ffffff POINT (40.18159 0.05763) 582.555159 \n", - "2 866a4a49fffffff POINT (38.59096 0.13944) 749.911237 \n", - "3 866a4a4d7ffffff POINT (35.07124 0.80971) 863.888290 \n", - "4 866a5820fffffff POINT (37.4356 3.35699) 525.085147 \n", - "... ... ... ... \n", - "16212 867b5dd77ffffff POINT (39.15438 -1.51437) -36.000000 \n", - "16213 867b5dd87ffffff POINT (35.80252 0.90823) -36.000000 \n", - "16214 867b5dd8fffffff POINT (37.93845 0.83454) -36.000000 \n", - "16215 867b5dd9fffffff POINT (38.65824 -2.60028) -36.000000 \n", - "16216 867b5ddafffffff POINT (36.6641 2.37083) -36.000000 \n", - "\n", - " sum_pop_f_2020 sum_pop_m_2020 \n", - "0 189.675539 210.185366 \n", - "1 276.337255 306.217904 \n", - "2 355.723245 394.187992 \n", - "3 418.309236 445.579054 \n", - "4 249.076134 276.009012 \n", - "... ... ... \n", - "16212 -18.000000 -18.000000 \n", - "16213 -18.000000 -18.000000 \n", - "16214 -18.000000 -18.000000 \n", - "16215 -18.000000 -18.000000 \n", - "16216 -18.000000 -18.000000 \n", + " hex_id geometry sum_pop_2020\n", + "0 866a4a48fffffff POINT (35.76352 2.99589) 399.860905\n", + "1 866a4a497ffffff POINT (40.58048 -3.79365) 582.555159\n", + "2 866a4a49fffffff POINT (41.10421 3.37873) 749.911237\n", + "3 866a4a4d7ffffff POINT (37.26153 3.74581) 863.888290\n", + "4 866a5820fffffff POINT (40.01148 1.53124) 525.085147\n", + "... ... ... ...\n", + "16212 867b5dd77ffffff POINT (34.94474 1.24558) -36.000000\n", + "16213 867b5dd87ffffff POINT (40.95343 -1.83280) -36.000000\n", + "16214 867b5dd8fffffff POINT (35.20290 -0.29666) -36.000000\n", + "16215 867b5dd9fffffff POINT (41.28333 -1.08552) -36.000000\n", + "16216 867b5ddafffffff POINT (36.63048 1.35038) -36.000000\n", "\n", - "[16217 rows x 5 columns]" + "[16217 rows x 3 columns]" ] }, - "execution_count": 17, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -306,24 +269,24 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "f9d4a524b5bf4d1a950f1cb8cc8d5b54", + "model_id": "00bbfea95ae440d3a73ebb161e3142ab", "version_major": 2, - "version_minor": 1 + "version_minor": 0 }, "text/plain": [ - "Map(layers=[ScatterplotLayer(get_fill_color=\n", + "Map(layers=[ScatterplotLayer(get_fill_color=\n", "[\n", " [\n", " 2…" ] }, - "execution_count": 18, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -338,20 +301,6 @@ "m = Map(layer)\n", "m\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/postgres/deploy.md b/postgres/deploy.md new file mode 100644 index 0000000..ffa9b2b --- /dev/null +++ b/postgres/deploy.md @@ -0,0 +1,7 @@ +## Deployment Notes + +- Create database instance +- Update configuration in `db.env` +- Ingest parquet file with `load_to_prod.sh` (may require `chmod +x load_to_prod.sh`) +- Create index on hex_id (for performance):`CREATE INDEX idx_hex_id ON space2stats (hex_id)` - critical for performance of our queries +- Test with the [example notebook](notebooks/space2stats_api_demo.ipynb) \ No newline at end of file diff --git a/postgres/load_nyc_sample.sh b/postgres/load_nyc_sample.sh index cb73169..276956c 100755 --- a/postgres/load_nyc_sample.sh +++ b/postgres/load_nyc_sample.sh @@ -1,11 +1,15 @@ #!/bin/bash -# Database connection details -DB_HOST="localhost" -DB_PORT="5439" -DB_NAME="postgis" -DB_USER="username" -DB_PASSWORD="password" +# Load environment variables from db.env file +if [ -f db.env ]; then + export $(cat db.env | grep -v '#' | awk '/=/ {print $1}') +fi + +# Check if required environment variables are set +if [ -z "$DB_HOST" ] || [ -z "$DB_PORT" ] || [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then + echo "One or more required environment variables are missing." + exit 1 +fi # Path to the sample Parquet file PARQUET_FILE="nyc_sample.parquet" diff --git a/postgres/load_parquet_chunks.sh b/postgres/load_parquet_chunks.sh index 18c1dd4..8f79d8b 100755 --- a/postgres/load_parquet_chunks.sh +++ b/postgres/load_parquet_chunks.sh @@ -1,11 +1,16 @@ #!/bin/bash -# Database connection details -DB_HOST="localhost" -DB_PORT="5439" -DB_NAME="postgis" -DB_USER="username" -DB_PASSWORD="password" + +# Load environment variables from db.env file +if [ -f db.env ]; then + export $(cat db.env | grep -v '#' | awk '/=/ {print $1}') +fi + +# Check if required environment variables are set +if [ -z "$DB_HOST" ] || [ -z "$DB_PORT" ] || [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then + echo "One or more required environment variables are missing." + exit 1 +fi # Directory containing the Parquet chunks CHUNKS_DIR="parquet_chunks" diff --git a/postgres/load_to_prod.sh b/postgres/load_to_prod.sh new file mode 100755 index 0000000..3149e7b --- /dev/null +++ b/postgres/load_to_prod.sh @@ -0,0 +1,30 @@ +#!/bin/bash + + +# Load environment variables from db.env file +if [ -f db.env ]; then + export $(cat db.env | grep -v '#' | awk '/=/ {print $1}') +fi + +# Check if required environment variables are set +if [ -z "$DB_HOST" ] || [ -z "$DB_PORT" ] || [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then + echo "One or more required environment variables are missing." + exit 1 +fi + +# Directory containing the Parquet chunks +CHUNKS_DIR="parquet_chunks" + +# Name of the target table +TABLE_NAME="space2stats" +PARQUET_FILE=space2stats_updated.parquet + +echo "Starting" + +ogr2ogr -progress -f "PostgreSQL" \ + PG:"host=$DB_HOST port=$DB_PORT dbname=$DB_NAME user=$DB_USER password=$DB_PASSWORD" \ + "$PARQUET_FILE" \ + -nln $TABLE_NAME \ + -append \ + -lco SPATIAL_INDEX=NONE + diff --git a/space2stats_api/app/main.py b/space2stats_api/app/main.py deleted file mode 100644 index b28e3f0..0000000 --- a/space2stats_api/app/main.py +++ /dev/null @@ -1,13 +0,0 @@ -from fastapi import FastAPI - -from .routers import api - - -app = FastAPI() - -app.include_router(api.router) - - -@app.get("/") -def read_root(): - return {"message": "Welcome to Space2Stats!"} diff --git a/space2stats_api/app/models/summary.py b/space2stats_api/app/models/summary.py deleted file mode 100644 index e69de29..0000000 diff --git a/space2stats_api/app/settings.py b/space2stats_api/app/settings.py deleted file mode 100644 index e6f48eb..0000000 --- a/space2stats_api/app/settings.py +++ /dev/null @@ -1,15 +0,0 @@ -from pydantic_settings import BaseSettings, SettingsConfigDict - - -class Settings(BaseSettings): - DB_HOST: str - DB_PORT: int - DB_NAME: str - DB_USER: str - DB_PASSWORD: str - DB_TABLE_NAME: str - - model_config = SettingsConfigDict(env_file='db.env') - - -settings = Settings() diff --git a/space2stats_api/cdk/app.py b/space2stats_api/cdk/app.py new file mode 100644 index 0000000..2b9f419 --- /dev/null +++ b/space2stats_api/cdk/app.py @@ -0,0 +1,17 @@ +from aws_cdk import App, Environment +from aws_stack import Space2StatsStack +from settings import DeploymentSettings + + +settings = DeploymentSettings(_env_file="aws_deployment.env") + +env = Environment( + account=settings.CDK_DEFAULT_ACCOUNT, + region=settings.CDK_DEFAULT_REGION +) + +app = App() + +Space2StatsStack(app, "Space2StatsStack", env=env) + +app.synth() \ No newline at end of file diff --git a/space2stats_api/cdk/aws_stack.py b/space2stats_api/cdk/aws_stack.py new file mode 100644 index 0000000..50d08c8 --- /dev/null +++ b/space2stats_api/cdk/aws_stack.py @@ -0,0 +1,52 @@ +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.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) + + app_settings = AppSettings(_env_file="./aws_app.env") + deployment_settings = DeploymentSettings(_env_file="./aws_deployment.env") + + lambda_function = PythonFunction( + self, "Space2StatsFunction", + entry="../src", + runtime=_lambda.Runtime.PYTHON_3_11, + index="app/main.py", + timeout=Duration.seconds(120), + handler="handler", + environment=app_settings.model_dump(), + memory_size=1024 + ) + + certificate = acm.Certificate.from_certificate_arn(self, "Certificate", deployment_settings.CDK_CERTIFICATE_ARN) + + domain_name = apigatewayv2.DomainName( + self, "DomainName", + domain_name=deployment_settings.CDK_DOMAIN_NAME, + certificate=certificate + ) + + http_api = apigatewayv2.HttpApi( + self, "Space2StatsHttpApi", + default_integration=integrations.HttpLambdaIntegration( + "LambdaIntegration", + handler=lambda_function + ) + ) + + apigatewayv2.ApiMapping( + self, "ApiMapping", + api=http_api, + domain_name=domain_name, + stage=http_api.default_stage + ) \ No newline at end of file diff --git a/space2stats_api/cdk/cdk.json b/space2stats_api/cdk/cdk.json new file mode 100644 index 0000000..5ad42b5 --- /dev/null +++ b/space2stats_api/cdk/cdk.json @@ -0,0 +1,4 @@ +{ + "app": "python app.py", + "watch": { "include": ["../src/**", "."], "exclude": ["**/*.pyc"] } +} diff --git a/space2stats_api/cdk/settings.py b/space2stats_api/cdk/settings.py new file mode 100644 index 0000000..c8903e4 --- /dev/null +++ b/space2stats_api/cdk/settings.py @@ -0,0 +1,16 @@ +from pydantic_settings import BaseSettings + + +class AppSettings(BaseSettings): + DB_HOST: str + DB_PORT: str + DB_NAME: str + DB_USER: str + DB_PASSWORD: str + DB_TABLE_NAME: str + +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 diff --git a/space2stats_api/pytest.ini b/space2stats_api/pytest.ini new file mode 100644 index 0000000..343729c --- /dev/null +++ b/space2stats_api/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +env_files = db.env \ No newline at end of file diff --git a/space2stats_api/app/models/__init__.py b/space2stats_api/src/app/__init__.py similarity index 100% rename from space2stats_api/app/models/__init__.py rename to space2stats_api/src/app/__init__.py diff --git a/space2stats_api/src/app/main.py b/space2stats_api/src/app/main.py new file mode 100644 index 0000000..3e02954 --- /dev/null +++ b/space2stats_api/src/app/main.py @@ -0,0 +1,23 @@ +from fastapi import FastAPI +from mangum import Mangum +from fastapi.middleware.cors import CORSMiddleware + +from .routers import api + +app = FastAPI() + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +app.include_router(api.router) + +@app.get("/") +def read_root(): + return {"message": "Welcome to Space2Stats!"} + +handler = Mangum(app) \ No newline at end of file diff --git a/space2stats_api/app/routers/__init__.py b/space2stats_api/src/app/routers/__init__.py similarity index 100% rename from space2stats_api/app/routers/__init__.py rename to space2stats_api/src/app/routers/__init__.py diff --git a/space2stats_api/app/routers/api.py b/space2stats_api/src/app/routers/api.py similarity index 91% rename from space2stats_api/app/routers/api.py rename to space2stats_api/src/app/routers/api.py index 9dabf67..54da23e 100644 --- a/space2stats_api/app/routers/api.py +++ b/space2stats_api/src/app/routers/api.py @@ -4,8 +4,8 @@ from pydantic import BaseModel from geojson_pydantic import Feature, Polygon -from app.utils.h3_utils import generate_h3_ids, generate_h3_geometries -from app.utils.db_utils import get_available_fields, get_summaries +from ..utils.h3_utils import generate_h3_ids, generate_h3_geometries +from ..utils.db_utils import get_available_fields, get_summaries router = APIRouter() diff --git a/space2stats_api/src/app/settings.py b/space2stats_api/src/app/settings.py new file mode 100644 index 0000000..77b0403 --- /dev/null +++ b/space2stats_api/src/app/settings.py @@ -0,0 +1,10 @@ +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + DB_HOST: str + DB_PORT: int + DB_NAME: str + DB_USER: str + DB_PASSWORD: str + DB_TABLE_NAME: str diff --git a/space2stats_api/app/utils/__init__.py b/space2stats_api/src/app/utils/__init__.py similarity index 100% rename from space2stats_api/app/utils/__init__.py rename to space2stats_api/src/app/utils/__init__.py diff --git a/space2stats_api/app/utils/db_utils.py b/space2stats_api/src/app/utils/db_utils.py similarity index 96% rename from space2stats_api/app/utils/db_utils.py rename to space2stats_api/src/app/utils/db_utils.py index c95ef82..a565efd 100644 --- a/space2stats_api/app/utils/db_utils.py +++ b/space2stats_api/src/app/utils/db_utils.py @@ -1,5 +1,7 @@ import psycopg as pg -from ..settings import settings +from ..settings import Settings + +settings = Settings() DB_HOST = settings.DB_HOST DB_PORT = settings.DB_PORT diff --git a/space2stats_api/app/utils/h3_utils.py b/space2stats_api/src/app/utils/h3_utils.py similarity index 100% rename from space2stats_api/app/utils/h3_utils.py rename to space2stats_api/src/app/utils/h3_utils.py diff --git a/space2stats_api/requirements.txt b/space2stats_api/src/requirements.txt similarity index 75% rename from space2stats_api/requirements.txt rename to space2stats_api/src/requirements.txt index 1f46cef..a064fb7 100644 --- a/space2stats_api/requirements.txt +++ b/space2stats_api/src/requirements.txt @@ -1,12 +1,12 @@ fastapi uvicorn +mangum pandas python-dotenv shapely h3 -pytest psycopg[binary] httpx geojson-pydantic shapely -pydantic-settings>=2.0.0 \ No newline at end of file +pydantic-settings>=2.0.0 diff --git a/space2stats_api/tests/test_api.py b/space2stats_api/tests/test_api.py index 649f12b..f5ec0c7 100644 --- a/space2stats_api/tests/test_api.py +++ b/space2stats_api/tests/test_api.py @@ -2,7 +2,7 @@ import pytest from unittest.mock import patch -from app.main import app +from src.app.main import app client = TestClient(app) diff --git a/space2stats_api/tests/test_db_utils.py b/space2stats_api/tests/test_db_utils.py index a320156..61a661f 100644 --- a/space2stats_api/tests/test_db_utils.py +++ b/space2stats_api/tests/test_db_utils.py @@ -1,6 +1,6 @@ import unittest from unittest.mock import patch, Mock -from app.utils.db_utils import get_summaries, get_available_fields +from src.app.utils.db_utils import get_summaries, get_available_fields from psycopg.sql import SQL, Identifier diff --git a/space2stats_api/tests/test_h3_utils.py b/space2stats_api/tests/test_h3_utils.py index 8813581..7813dda 100644 --- a/space2stats_api/tests/test_h3_utils.py +++ b/space2stats_api/tests/test_h3_utils.py @@ -1,6 +1,6 @@ import pytest from shapely.geometry import Polygon, mapping -from app.utils.h3_utils import generate_h3_ids, generate_h3_geometries +from src.app.utils.h3_utils import generate_h3_ids, generate_h3_geometries polygon_coords = [ [-74.3, 40.5],