Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class QueryExtensionGetRequest(APIRequest):
class QueryExtensionPostRequest(BaseModel):
"""Query Extension POST request model."""

query: Optional[Dict[str, Dict[str, Any]]] = Field(
query: Optional[Dict[str, Dict[str, Any]]] = Field( # type: ignore
None,
description="Allows additional filtering based on the properties of Item objects", # noqa: E501
openapi_examples={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class SortExtensionGetRequest(APIRequest):
class SortExtensionPostRequest(BaseModel):
"""Sortby parameter for POST requests."""

sortby: Optional[List[PostSortModel]] = Field(
sortby: Optional[List[PostSortModel]] = Field( # type: ignore
None,
description="An array of property (field) names, and direction in form of '{'field': '<property_name>', 'direction':'<direction>'}'", # noqa: E501
openapi_examples={
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
23 changes: 13 additions & 10 deletions stac_fastapi/types/stac_fastapi/types/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,11 @@ def str2list(x: str) -> Optional[List[str]]:
return None


def str2bbox(x: str) -> Optional[BBox]:
def str2bbox(x: str) -> BBox:
"""Convert string to BBox based on , delimiter."""
if x:
t = tuple(float(v) for v in str2list(x))
assert len(t) in [4, 6], f"BBox '{x}' must have 4 or 6 values."
return t

return None
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


def _collection_converter(
Expand All @@ -54,7 +51,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 +69,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 +86,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]