Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Fixed

- Remove defaults in OpenAPI schemas
- Type Hints for TypedDict

### Added

Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/api/stac_fastapi/api/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:

await self.app(scope, receive, send)

def _get_forwarded_url_parts(self, scope: Scope) -> Tuple[str]:
def _get_forwarded_url_parts(self, scope: Scope) -> Tuple[str, str, str]:
proto = scope.get("scheme", "http")
header_host = self._get_header_value_by_name(scope, "host")
if header_host is None:
Expand Down Expand Up @@ -127,7 +127,7 @@ def _get_header_value_by_name(
@staticmethod
def _replace_header_value_by_name(
scope: Scope, header_name: str, new_value: str
) -> List[Tuple[str]]:
) -> List[Tuple[str, str]]:
return [
(name, value)
for name, value in scope["headers"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,34 @@

from typing import Any, Dict, List, Literal, Optional, Union

from pydantic import Field
from typing_extensions import TypedDict
from typing_extensions import NotRequired, TypedDict

from stac_fastapi.types.rfc3339 import DateTimeType

Bucket = TypedDict(
"Bucket",
{
"key": str,
"data_type": str,
"frequency": NotRequired[Dict],
# we can't use the `class Bucket` notation because `from` is a reserved key
"from": NotRequired[Union[int, float]],
"to": NotRequired[Optional[Union[int, float]]],
},
)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't caught that when reviewing the original PR but it was defining a type: TypedDict with Pydantic field 🤷


class Bucket(TypedDict, total=False):
"""A STAC aggregation bucket."""

key: str
data_type: str
frequency: Optional[Dict] = None
_from: Optional[Union[int, float]] = Field(alias="from", default=None)
to: Optional[Optional[Union[int, float]]] = None


class Aggregation(TypedDict, total=False):
class Aggregation(TypedDict):
"""A STAC aggregation."""

name: str
data_type: str
buckets: Optional[List[Bucket]] = None
overflow: Optional[int] = None
value: Optional[Union[str, int, DateTimeType]] = None
buckets: NotRequired[List[Bucket]]
overflow: NotRequired[int]
value: NotRequired[Union[str, int, DateTimeType]]


class AggregationCollection(TypedDict, total=False):
class AggregationCollection(TypedDict):
"""STAC Item Aggregation Collection."""

type: Literal["AggregationCollection"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pydantic import BaseModel, Field
from typing_extensions import Annotated

from stac_fastapi.types.search import APIRequest, str2list
from stac_fastapi.types.search import APIRequest


def _ft_converter(
Expand All @@ -22,7 +22,9 @@ def _ft_converter(
),
] = None,
) -> Optional[List[str]]:
return str2list(val)
if val:
return val.split(",")
return None


@attr.s
Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/types/stac_fastapi/types/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ def item_collection(
bbox: Optional[BBox] = None,
datetime: Optional[str] = None,
limit: int = 10,
token: str = None,
token: Optional[str] = None,
**kwargs,
) -> stac.ItemCollection:
"""Get all items from a specific collection.
Expand Down Expand Up @@ -744,7 +744,7 @@ async def item_collection(
bbox: Optional[BBox] = None,
datetime: Optional[str] = None,
limit: int = 10,
token: str = None,
token: Optional[str] = None,
**kwargs,
) -> stac.ItemCollection:
"""Get all items from a specific collection.
Expand Down
2 changes: 1 addition & 1 deletion stac_fastapi/types/stac_fastapi/types/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ApiExtension(abc.ABC):
GET = None
POST = None

def get_request_model(self, verb: Optional[str] = "GET") -> Optional[BaseModel]:
def get_request_model(self, verb: str = "GET") -> Optional[BaseModel]:
"""Return the request model for the extension.method.

The model can differ based on HTTP verb
Expand Down
2 changes: 1 addition & 1 deletion stac_fastapi/types/stac_fastapi/types/rfc3339.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]:
status_code=400, detail="Start datetime cannot be before end datetime."
)

return start, end
return start, end # type: ignore


def now_in_utc() -> datetime:
Expand Down
14 changes: 10 additions & 4 deletions stac_fastapi/types/stac_fastapi/types/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def str2list(x: str) -> Optional[List[str]]:
def str2bbox(x: str) -> Optional[BBox]:
"""Convert string to BBox based on , delimiter."""
if x:
t = tuple(float(v) for v in str2list(x))
t = tuple(float(v) for v in x.split(","))
assert len(t) in [4, 6], f"BBox '{x}' must have 4 or 6 values."
return t

Expand All @@ -54,7 +54,9 @@ def _collection_converter(
),
] = None,
) -> Optional[List[str]]:
return str2list(val)
if val:
return val.split(",")
return None


def _ids_converter(
Expand All @@ -70,7 +72,9 @@ def _ids_converter(
),
] = None,
) -> Optional[List[str]]:
return str2list(val)
if val:
return val.split(",")
return None


def _bbox_converter(
Expand All @@ -85,7 +89,9 @@ def _bbox_converter(
),
] = None,
) -> Optional[BBox]:
return str2bbox(val)
if val:
return str2bbox(val)
return None


def _validate_datetime(instance, attribute, value):
Expand Down
39 changes: 15 additions & 24 deletions stac_fastapi/types/stac_fastapi/types/stac.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
"""STAC types."""

import sys
from typing import Any, Dict, List, Literal, Optional, Union
from typing import Any, Dict, List, Literal, Union

from stac_pydantic.shared import BBox

# Avoids a Pydantic error:
# TypeError: You should use `typing_extensions.TypedDict` instead of
# `typing.TypedDict` with Python < 3.12.0. Without it, there is no way to
# differentiate required and optional fields when subclassed.
if sys.version_info < (3, 12, 0):
from typing_extensions import TypedDict
else:
from typing import TypedDict
from typing_extensions import NotRequired, TypedDict

NumType = Union[float, int]


class Catalog(TypedDict, total=False):
class Catalog(TypedDict):
"""STAC Catalog."""

type: str
stac_version: str
stac_extensions: Optional[List[str]]
stac_extensions: NotRequired[List[str]]
id: str
title: Optional[str]
title: NotRequired[str]
description: str
links: List[Dict[str, Any]]


class LandingPage(Catalog, total=False):
class LandingPage(Catalog):
"""STAC Landing Page."""

conformsTo: List[str]
Expand All @@ -41,7 +32,7 @@ class Conformance(TypedDict):
conformsTo: List[str]


class Collection(Catalog, total=False):
class Collection(Catalog):
"""STAC Collection."""

keywords: List[str]
Expand All @@ -52,12 +43,12 @@ class Collection(Catalog, total=False):
assets: Dict[str, Any]


class Item(TypedDict, total=False):
class Item(TypedDict):
"""STAC Item."""

type: Literal["Feature"]
stac_version: str
stac_extensions: Optional[List[str]]
stac_extensions: NotRequired[List[str]]
id: str
geometry: Dict[str, Any]
bbox: BBox
Expand All @@ -67,22 +58,22 @@ class Item(TypedDict, total=False):
collection: str


class ItemCollection(TypedDict, total=False):
class ItemCollection(TypedDict):
"""STAC Item Collection."""

type: Literal["FeatureCollection"]
features: List[Item]
links: List[Dict[str, Any]]
numberMatched: Optional[int]
numberReturned: Optional[int]
numberMatched: NotRequired[int]
numberReturned: NotRequired[int]


class Collections(TypedDict, total=False):
class Collections(TypedDict):
"""All collections endpoint.
https://github.com/radiantearth/stac-api-spec/tree/master/collections
"""

collections: List[Collection]
links: List[Dict[str, Any]]
numberMatched: Optional[int] = None
numberReturned: Optional[int] = None
numberMatched: NotRequired[int]
numberReturned: NotRequired[int]