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
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## [Unreleased]

## [6.1.4] - 2025-12-12

### Fixed

- improve type hints
- `api.app.StacAPI.search_get_request_model` now defined as `Type[APIRequest]`
- `api.app.StacAPI.search_post_request_model` now defined as `Type[BaseModel]`

## [6.1.3] - 2025-12-09

### Fixed
Expand Down
9 changes: 3 additions & 6 deletions stac_fastapi/api/stac_fastapi/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from brotli_asgi import BrotliMiddleware
from fastapi import APIRouter, FastAPI
from fastapi.params import Depends
from pydantic import BaseModel
from stac_pydantic import api
from stac_pydantic.shared import MimeTypes
from stac_pydantic.version import STAC_VERSION
Expand Down Expand Up @@ -114,12 +115,8 @@ class StacApi:
converter=update_openapi, # type: ignore
)
router: APIRouter = attr.ib(default=attr.Factory(APIRouter))
search_get_request_model: Type[BaseSearchGetRequest] = attr.ib(
default=BaseSearchGetRequest
)
search_post_request_model: Type[BaseSearchPostRequest] = attr.ib(
default=BaseSearchPostRequest
)
search_get_request_model: Type[APIRequest] = attr.ib(default=BaseSearchGetRequest)
search_post_request_model: Type[BaseModel] = attr.ib(default=BaseSearchPostRequest)
collections_get_request_model: Type[APIRequest] = attr.ib(default=EmptyRequest)
collection_get_request_model: Type[APIRequest] = attr.ib(default=CollectionUri)
items_get_request_model: Type[APIRequest] = attr.ib(default=ItemCollectionUri)
Expand Down
2 changes: 1 addition & 1 deletion stac_fastapi/api/stac_fastapi/api/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,5 @@ def request_validation_exception_handler(
# TODO: Argument 2 to "add_exception_handler" of "Starlette" has incompatible type
app.add_exception_handler(
RequestValidationError,
request_validation_exception_handler, # type: ignore
request_validation_exception_handler, # type: ignore [arg-type]
)
22 changes: 13 additions & 9 deletions stac_fastapi/api/stac_fastapi/api/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Api request/response models."""

from typing import List, Literal, Optional, Type, Union
from typing import List, Literal, Optional, Type, Union, cast

import attr
from fastapi import Path, Query
Expand All @@ -24,7 +24,7 @@
import orjson # noqa
from fastapi.responses import ORJSONResponse as JSONResponse
except ImportError: # pragma: nocover
from starlette.responses import JSONResponse # type: ignore
from starlette.responses import JSONResponse # type: ignore [assignment]


def create_request_model(
Expand All @@ -49,43 +49,47 @@ def create_request_model(

# Handle GET requests
if all([issubclass(m, APIRequest) for m in models]):
return attr.make_class(model_name, attrs={}, bases=tuple(models))
get_model = attr.make_class(model_name, attrs={}, bases=tuple(models))
return cast(Type[APIRequest], get_model)

# Handle POST requests
elif all([issubclass(m, BaseModel) for m in models]):
for model in models:
for k, field_info in model.model_fields.items(): # type: ignore
fields[k] = (field_info.annotation, field_info)

return create_model(model_name, **fields, __base__=base_model) # type: ignore
post_model = create_model(model_name, **fields, __base__=base_model) # type: ignore
return cast(Type[BaseModel], post_model)

raise TypeError("Mixed Request Model types. Check extension request types.")


def create_get_request_model(
extensions: Optional[List[ApiExtension]],
base_model: Type[BaseSearchGetRequest] = BaseSearchGetRequest,
base_model: Type[APIRequest] = BaseSearchGetRequest,
) -> Type[APIRequest]:
"""Wrap create_request_model to create the GET request model."""
return create_request_model( # type: ignore
model = create_request_model(
"SearchGetRequest",
base_model=base_model,
extensions=extensions,
request_type="GET",
)
return cast(Type[APIRequest], model)


def create_post_request_model(
extensions: Optional[List[ApiExtension]],
base_model: Type[BaseSearchPostRequest] = BaseSearchPostRequest,
base_model: Type[BaseModel] = BaseSearchPostRequest,
) -> Type[BaseModel]:
"""Wrap create_request_model to create the POST request model."""
return create_request_model( # type: ignore
model = create_request_model(
"SearchPostRequest",
base_model=base_model,
extensions=extensions,
request_type="POST",
)
return cast(Type[BaseModel], model)


@attr.s
Expand Down Expand Up @@ -121,7 +125,7 @@ class ItemCollectionUri(APIRequest, DatetimeMixin):
description="Limits the number of results that are included in each page of the response (capped to 10_000)." # noqa: E501
),
] = attr.ib(default=10)
bbox: Optional[BBox] = attr.ib(default=None, converter=_bbox_converter) # type: ignore
bbox: Optional[BBox] = attr.ib(default=None, converter=_bbox_converter) # type: ignore [misc]
datetime: DateTimeQueryType = attr.ib(default=None, validator=_validate_datetime)


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Collection-Search extension."""

from enum import Enum
from typing import List, Optional, Type, Union
from typing import List, Optional, Type, Union, cast

import attr
from fastapi import APIRouter, FastAPI
Expand Down Expand Up @@ -87,15 +87,18 @@ def from_extensions(
for ext in extensions:
conformance_classes.extend(ext.conformance_classes)

get_request_model = create_request_model(
model_name="CollectionsGetRequest",
base_model=BaseCollectionSearchGetRequest,
extensions=extensions,
request_type="GET",
get_request_model = cast(
Type[APIRequest],
create_request_model(
model_name="CollectionsGetRequest",
base_model=BaseCollectionSearchGetRequest,
extensions=extensions,
request_type="GET",
),
)

return cls(
GET=get_request_model, # type: ignore
GET=get_request_model,
conformance_classes=conformance_classes,
schema_href=schema_href,
)
Expand Down Expand Up @@ -164,7 +167,7 @@ def register(self, app: FastAPI) -> None:
app.include_router(self.router)

@classmethod
def from_extensions( # type: ignore
def from_extensions( # type: ignore [override]
cls,
extensions: List[ApiExtension],
*,
Expand All @@ -181,25 +184,31 @@ def from_extensions( # type: ignore
for ext in extensions:
conformance_classes.extend(ext.conformance_classes)

get_request_model = create_request_model(
model_name="CollectionsGetRequest",
base_model=BaseCollectionSearchGetRequest,
extensions=extensions,
request_type="GET",
get_request_model = cast(
Type[APIRequest],
create_request_model(
model_name="CollectionsGetRequest",
base_model=BaseCollectionSearchGetRequest,
extensions=extensions,
request_type="GET",
),
)

post_request_model = create_request_model(
model_name="CollectionsPostRequest",
base_model=BaseCollectionSearchPostRequest,
extensions=extensions,
request_type="POST",
post_request_model = cast(
Type[BaseModel],
create_request_model(
model_name="CollectionsPostRequest",
base_model=BaseCollectionSearchPostRequest,
extensions=extensions,
request_type="POST",
),
)

return cls(
client=client,
settings=settings,
GET=get_request_model, # type: ignore
POST=post_request_model, # type: ignore
GET=get_request_model,
POST=post_request_model,
conformance_classes=conformance_classes,
router=router or APIRouter(),
schema_href=schema_href,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __iter__(self):
return iter(self.items.values())


@attr.s # type: ignore
@attr.s
class BaseBulkTransactionsClient(abc.ABC):
"""BulkTransactionsClient."""

Expand Down Expand Up @@ -63,7 +63,7 @@ def bulk_item_insert(
raise NotImplementedError


@attr.s # type: ignore
@attr.s
class AsyncBaseBulkTransactionsClient(abc.ABC):
"""BulkTransactionsClient."""

Expand Down
1 change: 1 addition & 0 deletions stac_fastapi/types/stac_fastapi/types/rfc3339.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]:
raise HTTPException(
status_code=400, detail="Double open-ended intervals are not allowed."
)

if start is not None and end is not None and start > end:
raise HTTPException(
status_code=400, detail="Start datetime cannot be before end datetime."
Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/types/stac_fastapi/types/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

"""
from datetime import datetime as dt
from typing import Dict, List, Optional, Union
from typing import Dict, List, Optional, Union, cast

import attr
from fastapi import HTTPException, Query
Expand Down Expand Up @@ -44,7 +44,7 @@ def str2bbox(x: str) -> Optional[BBox]:
status_code=400, detail=f"BBox '{x}' must have 4 or 6 values."
)

return t # type: ignore
return cast(BBox, t)

return None

Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.