diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index 375f43fd7..2e2f93feb 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -35,6 +35,7 @@ jobs: if: ${{ matrix.python-version == env.LATEST_PY_VERSION }} run: | uv run pre-commit run --all-files + uv run --with mypy --with types-attrs mypy -p stac_fastapi - name: Run tests run: uv run pytest -svvv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ccefc364e..19bbaf97c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.15.0 + rev: v1.19.0 hooks: - id: mypy language_version: python diff --git a/CHANGES.md b/CHANGES.md index 1831cb666..6bee1a485 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,9 +6,11 @@ - support for python 3.9 and 3.10 +## [6.1.3] - 2025-12-09 + ### Fixed -- fixed output type for `api.models.create_request_model` and `api.models.create_get_request_model` methods +- fixed type hints ## [6.1.2] - 2025-12-09 @@ -686,7 +688,8 @@ Full changelog: https://stac-utils.github.io/stac-fastapi/migrations/v3.0.0/#cha * First PyPi release! -[Unreleased]: +[Unreleased]: +[6.1.3]: [6.1.2]: [6.1.1]: [6.1.0]: diff --git a/VERSION b/VERSION index f3b5af39e..88d06f108 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.1.1 +6.1.3 diff --git a/pyproject.toml b/pyproject.toml index df4e3bfc7..df6f69ace 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "stac-fastapi" -version = "6.1.1" +version = "6.1.3" description = "Python library for building a STAC-compliant FastAPI application." requires-python = ">=3.11" readme = "README.md" @@ -81,7 +81,7 @@ explicit_package_bases = true exclude = ["tests", ".venv"] [tool.bumpversion] -current_version = "6.1.1" +current_version = "6.1.3" parse = """(?x) (?P\\d+)\\. (?P\\d+)\\. diff --git a/stac_fastapi/api/stac_fastapi/api/errors.py b/stac_fastapi/api/stac_fastapi/api/errors.py index 14fbc9b9e..8aa52ec74 100644 --- a/stac_fastapi/api/stac_fastapi/api/errors.py +++ b/stac_fastapi/api/stac_fastapi/api/errors.py @@ -93,6 +93,8 @@ def request_validation_exception_handler( status_code=status.HTTP_400_BAD_REQUEST, ) + # TODO: Argument 2 to "add_exception_handler" of "Starlette" has incompatible type app.add_exception_handler( - RequestValidationError, request_validation_exception_handler + RequestValidationError, + request_validation_exception_handler, # type: ignore ) diff --git a/stac_fastapi/api/stac_fastapi/api/middleware.py b/stac_fastapi/api/stac_fastapi/api/middleware.py index 0e7ece7e9..b1579a796 100644 --- a/stac_fastapi/api/stac_fastapi/api/middleware.py +++ b/stac_fastapi/api/stac_fastapi/api/middleware.py @@ -86,7 +86,7 @@ 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: - domain, port = scope.get("server") + domain, port = scope["server"] else: header_host_parts = header_host.split(":") if len(header_host_parts) == 2: diff --git a/stac_fastapi/api/stac_fastapi/api/models.py b/stac_fastapi/api/stac_fastapi/api/models.py index ce645d504..445bf21a9 100644 --- a/stac_fastapi/api/stac_fastapi/api/models.py +++ b/stac_fastapi/api/stac_fastapi/api/models.py @@ -24,7 +24,7 @@ import orjson # noqa from fastapi.responses import ORJSONResponse as JSONResponse except ImportError: # pragma: nocover - from starlette.responses import JSONResponse + from starlette.responses import JSONResponse # type: ignore def create_request_model( @@ -32,11 +32,11 @@ def create_request_model( base_model: Union[Type[BaseModel], Type[APIRequest]] = BaseSearchGetRequest, extensions: Optional[List[ApiExtension]] = None, mixins: Optional[Union[List[Type[BaseModel]], List[Type[APIRequest]]]] = None, - request_type: Optional[str] = "GET", + request_type: str = "GET", ) -> Union[Type[BaseModel], Type[APIRequest]]: """Create a pydantic model for validating request bodies.""" fields = {} - extension_models = [] + extension_models: List[Union[Type[BaseModel], Type[APIRequest]]] = [] # Check extensions for additional parameters to search for extension in extensions or []: @@ -54,7 +54,7 @@ def create_request_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(): + 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 @@ -64,11 +64,10 @@ def create_request_model( def create_get_request_model( extensions: Optional[List[ApiExtension]], - base_model: BaseSearchGetRequest = BaseSearchGetRequest, + base_model: Type[BaseSearchGetRequest] = BaseSearchGetRequest, ) -> Type[APIRequest]: """Wrap create_request_model to create the GET request model.""" - - return create_request_model( + return create_request_model( # type: ignore "SearchGetRequest", base_model=base_model, extensions=extensions, @@ -78,10 +77,10 @@ def create_get_request_model( def create_post_request_model( extensions: Optional[List[ApiExtension]], - base_model: BaseSearchPostRequest = BaseSearchPostRequest, + base_model: Type[BaseSearchPostRequest] = BaseSearchPostRequest, ) -> Type[BaseModel]: """Wrap create_request_model to create the POST request model.""" - return create_request_model( + return create_request_model( # type: ignore "SearchPostRequest", base_model=base_model, extensions=extensions, diff --git a/stac_fastapi/api/stac_fastapi/api/openapi.py b/stac_fastapi/api/stac_fastapi/api/openapi.py index 9b886a881..a7ca15072 100644 --- a/stac_fastapi/api/stac_fastapi/api/openapi.py +++ b/stac_fastapi/api/stac_fastapi/api/openapi.py @@ -14,8 +14,11 @@ def update_openapi(app: FastAPI) -> FastAPI: content-type response header. """ # Find the route for the openapi_url in the app + # TODO: Type info is Route, while it shoukd maybe be APIRoute? Check FastAPI source. openapi_route: Route = next( - route for route in app.router.routes if route.path == app.openapi_url + route + for route in app.router.routes + if route.path == app.openapi_url # type: ignore ) # Store the old endpoint function so we can call it from the patched function old_endpoint = openapi_route.endpoint diff --git a/stac_fastapi/api/stac_fastapi/api/routes.py b/stac_fastapi/api/stac_fastapi/api/routes.py index 5d02eb18b..061cb26c6 100644 --- a/stac_fastapi/api/stac_fastapi/api/routes.py +++ b/stac_fastapi/api/stac_fastapi/api/routes.py @@ -16,7 +16,7 @@ from starlette.routing import BaseRoute, Match from starlette.status import HTTP_204_NO_CONTENT -from stac_fastapi.api.models import APIRequest +from stac_fastapi.types.search import APIRequest def _wrap_response(resp: Any) -> Any: @@ -58,7 +58,7 @@ async def _endpoint(request: Request, request_data: Dict[str, Any]): elif issubclass(request_model, APIRequest): - async def _endpoint(request: Request, request_data=Depends(request_model)): + async def _endpoint(request: Request, request_data=Depends(request_model)): # type: ignore """Endpoint.""" return _wrap_response(await func(request=request, **request_data.kwargs())) @@ -100,10 +100,14 @@ def add_route_dependencies( _scope = copy.deepcopy(scope) for route in routes: if scope["path"] == "*": - _scope["path"] = route.path + # NOTE: ignore type, because BaseRoute has no "path" attribute + # but APIRoute does. + _scope["path"] = route.path # type: ignore + # NOTE: ignore type, because BaseRoute has no "method" attribute + # but APIRoute does. if scope["method"] == "*": - _scope["method"] = list(route.methods)[0] + _scope["method"] = list(route.methods)[0] # type: ignore match, _ = route.matches({"type": "http", **_scope}) if match != Match.FULL: @@ -119,7 +123,10 @@ def add_route_dependencies( route.dependant.dependencies.insert( 0, get_parameterless_sub_dependant( - depends=depends, path=route.path_format + # NOTE: ignore type, because BaseRoute has no "path_format" + # attribute but APIRoute does. + depends=depends, + path=route.path_format, # type: ignore ), ) @@ -128,7 +135,9 @@ def add_route_dependencies( # app.include_router(router)) # https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/applications.py#L337-L360 # https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/routing.py#L677-L678 - route.dependencies.extend(dependencies) + # NOTE: ignore type, because BaseRoute has no "dependencies" attribute + # but APIRoute does. + route.dependencies.extend(dependencies) # type: ignore def add_direct_response(app: FastAPI) -> None: diff --git a/stac_fastapi/api/stac_fastapi/api/version.py b/stac_fastapi/api/stac_fastapi/api/version.py index 0911e1fa2..e725d696c 100644 --- a/stac_fastapi/api/stac_fastapi/api/version.py +++ b/stac_fastapi/api/stac_fastapi/api/version.py @@ -1,3 +1,3 @@ """Library version.""" -__version__ = "6.1.1" +__version__ = "6.1.3" diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/aggregation/aggregation.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/aggregation/aggregation.py index c6e892914..d646df45f 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/aggregation/aggregation.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/aggregation/aggregation.py @@ -1,13 +1,15 @@ """Aggregation Extension.""" from enum import Enum -from typing import List, Union +from typing import List, Type, Union import attr from fastapi import APIRouter, FastAPI +from pydantic import BaseModel from stac_fastapi.api.models import CollectionUri, EmptyRequest from stac_fastapi.api.routes import create_async_endpoint from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .client import AsyncBaseAggregationClient, BaseAggregationClient from .request import AggregationExtensionGetRequest, AggregationExtensionPostRequest @@ -50,8 +52,8 @@ class AggregationExtension(ApiExtension): conformance_classes: Conformance classes provided by the extension """ - GET = AggregationExtensionGetRequest - POST = AggregationExtensionPostRequest + GET: Type[APIRequest] = AggregationExtensionGetRequest + POST: Type[BaseModel] = AggregationExtensionPostRequest client: Union[AsyncBaseAggregationClient, BaseAggregationClient] = attr.ib( factory=BaseAggregationClient diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/collection_search/collection_search.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/collection_search/collection_search.py index 384911b06..adb45e6af 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/collection_search/collection_search.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/collection_search/collection_search.py @@ -1,10 +1,11 @@ """Collection-Search extension.""" from enum import Enum -from typing import List, Optional, Union +from typing import List, Optional, Type, Union import attr from fastapi import APIRouter, FastAPI +from pydantic import BaseModel from stac_pydantic.api.collections import Collections from stac_pydantic.shared import MimeTypes @@ -12,6 +13,7 @@ from stac_fastapi.api.routes import create_async_endpoint from stac_fastapi.types.config import ApiSettings from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .client import AsyncBaseCollectionSearchClient, BaseCollectionSearchClient from .request import BaseCollectionSearchGetRequest, BaseCollectionSearchPostRequest @@ -47,8 +49,8 @@ class CollectionSearchExtension(ApiExtension): the extension """ - GET: BaseCollectionSearchGetRequest = attr.ib(default=BaseCollectionSearchGetRequest) # type: ignore - POST = attr.ib(init=False) + GET: Type[APIRequest] = attr.ib(default=BaseCollectionSearchGetRequest) + POST: Optional[Type[BaseModel]] = attr.ib(init=False) conformance_classes: List[str] = attr.ib( default=[ @@ -93,7 +95,7 @@ def from_extensions( ) return cls( - GET=get_request_model, + GET=get_request_model, # type: ignore conformance_classes=conformance_classes, schema_href=schema_href, ) @@ -127,10 +129,8 @@ class CollectionSearchPostExtension(CollectionSearchExtension): schema_href: Optional[str] = attr.ib(default=None) router: APIRouter = attr.ib(factory=APIRouter) - GET: BaseCollectionSearchGetRequest = attr.ib(default=BaseCollectionSearchGetRequest) # type: ignore - POST: BaseCollectionSearchPostRequest = attr.ib( # type: ignore - default=BaseCollectionSearchPostRequest - ) + GET: Type[APIRequest] = attr.ib(default=BaseCollectionSearchGetRequest) + POST: Type[BaseModel] = attr.ib(default=BaseCollectionSearchPostRequest) def register(self, app: FastAPI) -> None: """Register the extension with a FastAPI application. @@ -198,8 +198,8 @@ def from_extensions( # type: ignore return cls( client=client, settings=settings, - GET=get_request_model, - POST=post_request_model, + GET=get_request_model, # type: ignore + POST=post_request_model, # type: ignore conformance_classes=conformance_classes, router=router or APIRouter(), schema_href=schema_href, diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/fields/fields.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/fields/fields.py index 0b6e4177d..537ded0e5 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/fields/fields.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/fields/fields.py @@ -1,12 +1,14 @@ """Fields extension.""" from enum import Enum -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import FieldsExtensionGetRequest, FieldsExtensionPostRequest @@ -42,8 +44,8 @@ class FieldsExtension(ApiExtension): the extension """ - GET = FieldsExtensionGetRequest - POST = FieldsExtensionPostRequest + GET: Type[APIRequest] = FieldsExtensionGetRequest + POST: Type[BaseModel] = FieldsExtensionPostRequest conformance_classes: List[str] = attr.ib( factory=lambda: [ diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/filter/filter.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/filter/filter.py index c967755bb..e6f1a0deb 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/filter/filter.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/filter/filter.py @@ -5,11 +5,13 @@ import attr from fastapi import APIRouter, FastAPI +from pydantic import BaseModel from starlette.responses import Response from stac_fastapi.api.models import CollectionUri, EmptyRequest, JSONSchemaResponse from stac_fastapi.api.routes import create_async_endpoint from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .client import AsyncBaseFiltersClient, BaseFiltersClient from .request import FilterExtensionGetRequest, FilterExtensionPostRequest @@ -71,8 +73,8 @@ class FilterExtension(ApiExtension): conformance_classes: Conformance classes provided by the extension """ - GET = FilterExtensionGetRequest - POST = FilterExtensionPostRequest + GET: Type[APIRequest] = FilterExtensionGetRequest + POST: Type[BaseModel] = FilterExtensionPostRequest client: Union[AsyncBaseFiltersClient, BaseFiltersClient] = attr.ib( factory=BaseFiltersClient diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/free_text/free_text.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/free_text/free_text.py index 67aaa2b27..78753439b 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/free_text/free_text.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/free_text/free_text.py @@ -1,12 +1,14 @@ """Free-text extension.""" from enum import Enum -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import ( FreeTextAdvancedExtensionGetRequest, @@ -51,8 +53,8 @@ class FreeTextExtension(ApiExtension): """ - GET = FreeTextExtensionGetRequest - POST = FreeTextExtensionPostRequest + GET: Type[APIRequest] = FreeTextExtensionGetRequest + POST: Type[BaseModel] = FreeTextExtensionPostRequest conformance_classes: List[str] = attr.ib( default=[ @@ -84,8 +86,8 @@ class FreeTextAdvancedExtension(ApiExtension): """ - GET = FreeTextAdvancedExtensionGetRequest - POST = FreeTextAdvancedExtensionPostRequest + GET: Type[APIRequest] = FreeTextAdvancedExtensionGetRequest + POST: Type[BaseModel] = FreeTextAdvancedExtensionPostRequest conformance_classes: List[str] = attr.ib( default=[ diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/offset_pagination.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/offset_pagination.py index 81c1429dc..bb82a943d 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/offset_pagination.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/offset_pagination.py @@ -1,11 +1,13 @@ """Offset Pagination API extension.""" -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import GETOffsetPagination, POSTOffsetPagination @@ -20,8 +22,8 @@ class OffsetPaginationExtension(ApiExtension): request model for OpenAPI generation. """ - GET = GETOffsetPagination - POST = POSTOffsetPagination + GET: Type[APIRequest] = GETOffsetPagination + POST: Type[BaseModel] = POSTOffsetPagination conformance_classes: List[str] = attr.ib(factory=list) schema_href: Optional[str] = attr.ib(default=None) diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/pagination.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/pagination.py index 7959b0357..2f25ec044 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/pagination.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/pagination.py @@ -1,11 +1,13 @@ """Pagination API extension.""" -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import GETPagination, POSTPagination @@ -20,8 +22,8 @@ class PaginationExtension(ApiExtension): request model for OpenAPI generation. """ - GET = GETPagination - POST = POSTPagination + GET: Type[APIRequest] = GETPagination + POST: Type[BaseModel] = POSTPagination conformance_classes: List[str] = attr.ib(factory=list) schema_href: Optional[str] = attr.ib(default=None) diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/token_pagination.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/token_pagination.py index 11ccfb35b..08e882d5e 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/token_pagination.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/pagination/token_pagination.py @@ -1,11 +1,13 @@ """Token pagination API extension.""" -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import GETTokenPagination, POSTTokenPagination @@ -20,8 +22,8 @@ class TokenPaginationExtension(ApiExtension): request model for OpenAPI generation. """ - GET = GETTokenPagination - POST = POSTTokenPagination + GET: Type[APIRequest] = GETTokenPagination + POST: Type[BaseModel] = POSTTokenPagination conformance_classes: List[str] = attr.ib(factory=list) schema_href: Optional[str] = attr.ib(default=None) diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/query/query.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/query/query.py index 9f4c8cb0c..412a4e98d 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/query/query.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/query/query.py @@ -1,12 +1,14 @@ """Query extension.""" from enum import Enum -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import QueryExtensionGetRequest, QueryExtensionPostRequest @@ -32,8 +34,8 @@ class QueryExtension(ApiExtension): https://github.com/stac-api-extensions/query """ - GET = QueryExtensionGetRequest - POST = QueryExtensionPostRequest + GET: Type[APIRequest] = QueryExtensionGetRequest + POST: Type[BaseModel] = QueryExtensionPostRequest conformance_classes: List[str] = attr.ib( factory=lambda: [ diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/sort/sort.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/sort/sort.py index 77984719f..ff3ce5ba3 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/sort/sort.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/sort/sort.py @@ -1,12 +1,14 @@ """Sort extension.""" from enum import Enum -from typing import List, Optional +from typing import List, Optional, Type import attr from fastapi import FastAPI +from pydantic import BaseModel from stac_fastapi.types.extension import ApiExtension +from stac_fastapi.types.search import APIRequest from .request import SortExtensionGetRequest, SortExtensionPostRequest @@ -32,8 +34,8 @@ class SortExtension(ApiExtension): https://github.com/stac-api-extensions/sort """ - GET = SortExtensionGetRequest - POST = SortExtensionPostRequest + GET: Type[APIRequest] = SortExtensionGetRequest + POST: Type[BaseModel] = SortExtensionPostRequest conformance_classes: List[str] = attr.ib( factory=lambda: [ diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/core/transaction/request.py b/stac_fastapi/extensions/stac_fastapi/extensions/core/transaction/request.py index da3b0745c..c534833d3 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/core/transaction/request.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/core/transaction/request.py @@ -94,7 +94,7 @@ def merge_to_operations(data: Dict) -> List[PatchOperation]: Returns: List: list of RF6902 operations. """ - operations = [] + operations: List[PatchOperation] = [] for key, value in data.copy().items(): if value is None: diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/version.py b/stac_fastapi/extensions/stac_fastapi/extensions/version.py index 0911e1fa2..e725d696c 100644 --- a/stac_fastapi/extensions/stac_fastapi/extensions/version.py +++ b/stac_fastapi/extensions/stac_fastapi/extensions/version.py @@ -1,3 +1,3 @@ """Library version.""" -__version__ = "6.1.1" +__version__ = "6.1.3" diff --git a/stac_fastapi/types/stac_fastapi/types/extension.py b/stac_fastapi/types/stac_fastapi/types/extension.py index 22fed6068..cfa86a343 100644 --- a/stac_fastapi/types/stac_fastapi/types/extension.py +++ b/stac_fastapi/types/stac_fastapi/types/extension.py @@ -1,21 +1,25 @@ """Base api extension.""" import abc -from typing import List, Optional +from typing import List, Optional, Type, Union import attr from fastapi import FastAPI from pydantic import BaseModel +from stac_fastapi.types.search import APIRequest + @attr.s class ApiExtension(abc.ABC): """Abstract base class for defining API extensions.""" - GET = None - POST = None + GET: Optional[Type[APIRequest]] = None + POST: Optional[Type[BaseModel]] = None - def get_request_model(self, verb: str = "GET") -> Optional[BaseModel]: + def get_request_model( + self, verb: str = "GET" + ) -> Optional[Union[Type[BaseModel], Type[APIRequest]]]: """Return the request model for the extension.method. The model can differ based on HTTP verb diff --git a/stac_fastapi/types/stac_fastapi/types/search.py b/stac_fastapi/types/stac_fastapi/types/search.py index 01e622738..c30060746 100644 --- a/stac_fastapi/types/stac_fastapi/types/search.py +++ b/stac_fastapi/types/stac_fastapi/types/search.py @@ -23,7 +23,7 @@ def crop(v: PositiveInt) -> PositiveInt: return v -def str2list(x: str) -> Optional[List[str]]: +def str2list(x: Optional[str]) -> Optional[List[str]]: """Convert string to list base on , delimiter.""" if x: return x.split(",") @@ -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 + return t # type: ignore return None diff --git a/stac_fastapi/types/stac_fastapi/types/version.py b/stac_fastapi/types/stac_fastapi/types/version.py index 0911e1fa2..e725d696c 100644 --- a/stac_fastapi/types/stac_fastapi/types/version.py +++ b/stac_fastapi/types/stac_fastapi/types/version.py @@ -1,3 +1,3 @@ """Library version.""" -__version__ = "6.1.1" +__version__ = "6.1.3"