Skip to content

Commit

Permalink
Use tmp files instead of app.state
Browse files Browse the repository at this point in the history
  • Loading branch information
jterry64 committed Feb 19, 2025
1 parent a0f36cc commit 5ceeca6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 94 deletions.
2 changes: 1 addition & 1 deletion app/models/pydantic/datamart.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

class TreeCoverLossByDriverIn(StrictBaseModel):
geostore_id: UUID
canopy_cover: int
canopy_cover: int = 30
162 changes: 76 additions & 86 deletions app/routes/datamart/land.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"""Run analysis on registered datasets."""

import os
import random
import uuid
from uuid import UUID

from fastapi import APIRouter, Depends, Path, Query, Request
from fastapi.logger import logger
from fastapi import APIRouter, Depends, Path, Query
from fastapi.openapi.models import APIKey
from fastapi.responses import ORJSONResponse

from app.models.pydantic.datamart import TreeCoverLossByDriverIn
from app.settings.globals import API_URL

from ...authentication.api_keys import get_api_key
from ...models.pydantic.responses import Response
Expand All @@ -26,108 +27,100 @@
async def tree_cover_loss_by_driver_search(
*,
geostore_id: UUID = Query(..., title="Geostore ID"),
canopy_cover: int = Query(..., alias="canopy_cover", title="Canopy Cover Percent"),
request: Request,
canopy_cover: int = Query(30, alias="canopy_cover", title="Canopy Cover Percent"),
api_key: APIKey = Depends(get_api_key),
):
"""Search if a resource exists for a given geostore and canopy cover."""
# create mock_ids state if it doesn't exist
if not hasattr(request.app.state, "mock_ids"):
request.app.state.mock_ids = {}

try:
resource_id = request.app.state.mock_ids[f"{geostore_id}_{canopy_cover}"]["id"]
resource_id = _get_resource_id(geostore_id, canopy_cover)

if os.path.exists(f"/tmp/{resource_id}"):
return ORJSONResponse(
status_code=200,
content={
"status": "success",
"data": {"link": f"/v0/land/tree-cover-loss-by-driver/{resource_id}"},
},
)
return
except KeyError:
return ORJSONResponse(
status_code=404,
content={
"status": "failed",
"message": "Not Found",
"data": {
"link": f"{API_URL}/v0/land/tree-cover-loss-by-driver/{resource_id}"
},
},
)

return ORJSONResponse(
status_code=404,
content={
"status": "failed",
"message": "Not Found",
},
)


@router.get(
"/tree-cover-loss-by-driver/{uuid}",
"/tree-cover-loss-by-driver/{resource_id}",
response_class=ORJSONResponse,
response_model=Response,
tags=["Land"],
)
async def tree_cover_loss_by_driver_get(
*,
uuid: UUID = Path(..., title="Tree cover loss by driver ID"),
request: Request,
resource_id: UUID = Path(..., title="Tree cover loss by driver ID"),
api_key: APIKey = Depends(get_api_key),
):
"""Retrieve a tree cover loss by drivers resource."""
# create mock_ids state if it doesn't exist
if not hasattr(request.app.state, "mock_ids"):
request.app.state.mock_ids = {}

logger.info(request.app.state.mock_ids)

resource = None
for mock_id in request.app.state.mock_ids.values():
if mock_id["id"] == uuid:
resource = mock_id

if resource is None:
try:
with open(f"/tmp/{resource_id}", "r") as f:
retries = int(f.read().strip())

if retries < 3:
retries += 1
with open(f"/tmp/{resource_id}", "w") as f:
f.write(str(retries))

return ORJSONResponse(
status_code=200,
headers={"Retry-After": "1"},
content={"data": {"status": "pending"}, "status": "success"},
)
else:
return ORJSONResponse(
status_code=200,
content={
"data": {
"self": f"/v0/land/tree-cover-loss-by-driver/{resource_id}",
"treeCoverLossByDriver": {
"Permanent agriculture": 10,
"Hard commodities": 12,
"Shifting cultivation": 7,
"Forest management": 93.4,
"Wildfires": 42,
"Settlements and infrastructure": 13.562,
"Other natural disturbances": 6,
},
"metadata": {
"sources": [
{"dataset": "umd_tree_cover_loss", "version": "v1.11"},
{
"dataset": "wri_google_tree_cover_loss_by_drivers",
"version": "v1.11",
},
{
"dataset": "umd_tree_cover_density_2000",
"version": "v1.11",
},
]
},
},
"status": "success",
},
)
except FileNotFoundError:
return ORJSONResponse(
status_code=404,
content={
"status": "status",
"status": "failed",
"message": "Not Found",
},
)

if resource["retries"] < 3:
resource["retries"] += 1
return ORJSONResponse(
status_code=200,
headers={"Retry-After": "1"},
content={"data": {"status": "pending"}, "status": "success"},
)
else:
return ORJSONResponse(
status_code=200,
content={
"data": {
"self": f"/v0/land/tree-cover-loss-by-driver/{resource['id']}",
"treeCoverLossByDriver": {
"Permanent agriculture": 10,
"Hard commodities": 12,
"Shifting cultivation": 7,
"Forest management": 93.4,
"Wildfires": 42,
"Settlements and infrastructure": 13.562,
"Other natural disturbances": 6,
},
"metadata": {
"sources": [
{"dataset": "umd_tree_cover_loss", "version": "v1.11"},
{
"dataset": "wri_google_tree_cover_loss_by_drivers",
"version": "v1.11",
},
{
"dataset": "umd_tree_cover_density_2000",
"version": "v1.11",
},
]
},
},
"status": "success",
},
)


@router.post(
"/tree-cover-loss-by-driver",
Expand All @@ -138,7 +131,6 @@ async def tree_cover_loss_by_driver_get(
)
async def tree_cover_loss_by_driver_post(
data: TreeCoverLossByDriverIn,
request: Request,
api_key: APIKey = Depends(get_api_key),
):
"""Create new tree cover loss by drivers resource for a given geostore and
Expand All @@ -147,25 +139,23 @@ async def tree_cover_loss_by_driver_post(
# create initial Job item as pending
# trigger background task to create item
# return 202 accepted
resource_id = uuid.uuid4()

# create mock_ids state if it doesn't exist
if not hasattr(request.app.state, "mock_ids"):
request.app.state.mock_ids = {}
resource_id = _get_resource_id(data.geostore_id, data.canopy_cover)

# mocks randomness of analysis time
retries = random.randint(0, 3)
request.app.state.mock_ids[f"{data.geostore_id}_{data.canopy_cover}"] = {
"id": resource_id,
"retries": retries,
}
with open(f"/tmp/{resource_id}", "w") as f:
f.write(str(retries))

return ORJSONResponse(
status_code=202,
content={
"data": {
"link": f"/v0/land/tree-cover-loss-by-driver/{resource_id}",
"link": f"{API_URL}/v0/land/tree-cover-loss-by-driver/{resource_id}",
},
"status": "success",
},
)


def _get_resource_id(geostore_id, canopy_cover):
return uuid.uuid5(uuid.NAMESPACE_OID, f"{geostore_id}_{canopy_cover}")
7 changes: 0 additions & 7 deletions tests_v2/unit/app/routes/datamart/test_land.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ async def test_post_tree_cover_loss_by_drivers(
"/v0/land/tree-cover-loss-by-driver", headers=headers, json=payload
)

print("HERE")
print(response.json())
assert response.status_code == 202

Expand Down Expand Up @@ -77,12 +76,6 @@ async def test_get_tree_cover_loss_by_drivers_after_create(
assert body["status"] == "success"

link = body["data"]["link"]
response = await async_client.get(link, headers=headers)

assert response.status_code == 200
assert "Retry-After" in response.headers
assert int(response.headers["Retry-After"]) == 1

retries = 0
while retries < 3:
response = await async_client.get(link, headers=headers)
Expand Down

0 comments on commit 5ceeca6

Please sign in to comment.