Skip to content
This repository was archived by the owner on Apr 2, 2025. It is now read-only.

Commit 21e6312

Browse files
author
Phil Varner
committed
add typing to order api route
1 parent c4e8cd7 commit 21e6312

File tree

7 files changed

+115
-17
lines changed

7 files changed

+115
-17
lines changed

bin/server.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ async def create_order(
7070
"""
7171
Create a new order.
7272
"""
73-
order = Order(
73+
order = Order[MyOpportunityProperties, MyOrderParameters](
7474
id=str(uuid4()),
7575
geometry=payload.geometry,
7676
properties={
@@ -91,11 +91,11 @@ async def create_order(
9191
return order
9292

9393

94-
class TestSpotlightProperties(OpportunityProperties):
94+
class MyOpportunityProperties(OpportunityProperties):
9595
off_nadir: int
9696

9797

98-
class TestOrderParameters(OrderParameters):
98+
class MyOrderParameters(OrderParameters):
9999
s3_path: str
100100

101101

@@ -118,8 +118,8 @@ class TestOrderParameters(OrderParameters):
118118
keywords=["test", "satellite"],
119119
providers=[provider],
120120
links=[],
121-
constraints=TestSpotlightProperties,
122-
order_parameters=TestOrderParameters,
121+
constraints=MyOpportunityProperties,
122+
order_parameters=MyOrderParameters,
123123
backend=product_backend,
124124
)
125125

poetry.lock

Lines changed: 84 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ fastapi = "^0.115.0"
1414
pydantic = "^2.9.2"
1515
geojson-pydantic = "^1.1.1"
1616
pygeofilter = "^0.2.4"
17+
cql2 = "^0.3.1"
1718

1819
[tool.poetry.group.dev]
1920
optional = true

src/stapi_fastapi/models/order.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Generic, Literal, TypeVar
1+
from typing import Any, Generic, Literal, TypeVar
22

33
from geojson_pydantic import Feature, FeatureCollection
44
from geojson_pydantic.geometries import Geometry
@@ -11,11 +11,11 @@
1111

1212

1313
class OrderParameters(BaseModel):
14-
model_config = ConfigDict(extra="allow")
14+
model_config = ConfigDict(extra="forbid")
1515

1616

17-
ORP = TypeVar("ORP", bound=OrderParameters)
1817
OPP = TypeVar("OPP", bound=OpportunityProperties)
18+
ORP = TypeVar("ORP", bound=OrderParameters)
1919

2020

2121
class OrderRequest(BaseModel, Generic[ORP]):
@@ -24,7 +24,7 @@ class OrderRequest(BaseModel, Generic[ORP]):
2424
# TODO: validate the CQL2 filter?
2525
filter: CQL2Filter | None = None
2626

27-
order_parameters: ORP
27+
order_parameters: dict[str, Any]
2828

2929
model_config = ConfigDict(strict=True)
3030

@@ -41,14 +41,14 @@ class OrderProperties(BaseModel, Generic[OPP, ORP]):
4141
model_config = ConfigDict(extra="allow")
4242

4343

44-
class Order(Feature[Geometry, OrderProperties]):
44+
class Order(Feature[Geometry, OrderProperties[OPP, ORP]]):
4545
# We need to enforce that orders have an id defined, as that is required to
4646
# retrieve them via the API
4747
id: StrictInt | StrictStr
4848
type: Literal["Feature"] = "Feature"
4949
links: list[Link] = Field(default_factory=list)
5050

5151

52-
class OrderCollection(FeatureCollection[Order]):
52+
class OrderCollection(FeatureCollection[Order[OPP, ORP]]):
5353
type: Literal["FeatureCollection"] = "FeatureCollection"
5454
links: list[Link] = Field(default_factory=list)

src/stapi_fastapi/routers/product_router.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ def __init__(
7171
summary="Get order parameters for the product",
7272
)
7373

74+
# This wraps `self.create_order` to explicitly parameterize `OrderRequest`
75+
# for this Product. This must be done programmatically instead of with a type
76+
# annotation because it's setting the type dynamically instead of statically, and
77+
# pydantic needs this type annotation when doing object conversion. This cannot be done
78+
# directly to `self.create_order` because doing it there changes
79+
# the annotation on every `ProductRouter` instance's `create_order`, not just
80+
# this one's.
7481
async def _create_order(
7582
payload: OrderRequest,
7683
request: Request,
@@ -79,7 +86,10 @@ async def _create_order(
7986
return await self.create_order(payload, request, response)
8087

8188
_create_order.__annotations__["payload"] = OrderRequest[
82-
product.order_parameters # type: ignore
89+
self.product.order_parameters # type: ignore
90+
]
91+
_create_order.__annotations__["return"] = Order[
92+
self.product.constraints, self.product.order_parameters # type: ignore
8393
]
8494

8595
self.add_api_route(
@@ -88,6 +98,9 @@ async def _create_order(
8898
name=f"{self.root_router.name}:{self.product.id}:create-order",
8999
methods=["POST"],
90100
response_class=GeoJSONResponse,
101+
response_model=Order[
102+
self.product.constraints, self.product.order_parameters # type: ignore
103+
],
91104
status_code=status.HTTP_201_CREATED,
92105
summary="Create an order for the product",
93106
tags=["Products"],

tests/backends.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from stapi_fastapi.models.order import Order, OrderCollection, OrderRequest
1010
from stapi_fastapi.routers.product_router import ProductRouter
1111

12+
from .shared import SpotlightOpportunityProperties, SpotlightOrderParameters
13+
1214

1315
class MockOrderDB(dict[int | str, Order]):
1416
pass
@@ -58,7 +60,7 @@ async def create_order(
5860
Create a new order.
5961
"""
6062
if any(allowed == payload for allowed in self._allowed_payloads):
61-
order = Order(
63+
order = Order[SpotlightOpportunityProperties, SpotlightOrderParameters](
6264
id=str(uuid4()),
6365
geometry=payload.geometry,
6466
properties={

tests/order_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from stapi_fastapi.models.order import OrderRequest
1111

1212
from .backends import MockProductBackend
13-
from .shared import SpotlightOrderParameters, find_link
13+
from .shared import find_link
1414

1515
NOW = datetime.now(UTC)
1616
START = NOW
@@ -29,7 +29,7 @@ def create_order_allowed_payloads() -> list[OrderRequest]:
2929
datetime.fromisoformat("2024-11-15T18:55:33Z"),
3030
),
3131
filter=None,
32-
order_parameters=SpotlightOrderParameters(s3_path="BUCKET"),
32+
order_parameters={"s3_path": "BUCKET"},
3333
),
3434
]
3535

0 commit comments

Comments
 (0)