stac-fastapi.extensions 6.3.0__tar.gz → 6.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/PKG-INFO +1 -1
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/aggregation/aggregation.py +6 -7
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/aggregation/client.py +11 -12
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/aggregation/request.py +5 -6
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/aggregation/types.py +9 -9
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/bulk_transactions/bulk_transactions.py +10 -9
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/collection_search/collection_search.py +21 -21
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/collection_search/request.py +14 -17
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/fields/fields.py +6 -7
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/fields/request.py +8 -9
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/filter/client.py +5 -5
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/filter/filter.py +10 -12
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/filter/request.py +7 -8
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/free_text/free_text.py +10 -11
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/free_text/request.py +7 -8
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/pagination/offset_pagination.py +4 -6
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/pagination/pagination.py +4 -6
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/pagination/request.py +7 -8
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/pagination/token_pagination.py +4 -6
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/query/query.py +6 -7
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/query/request.py +3 -4
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/sort/request.py +5 -6
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/sort/sort.py +6 -7
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/transaction/client.py +22 -23
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/transaction/request.py +28 -28
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/transaction/transaction.py +16 -16
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/version.py +1 -1
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/.gitignore +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/README.md +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/pyproject.toml +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/aggregation/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/bulk_transactions/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/collection_search/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/collection_search/client.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/core/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/fields/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/filter/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/free_text/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/pagination/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/py.typed +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/query/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/sort/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/third_party/__init__.py +0 -0
- {stac_fastapi_extensions-6.3.0 → stac_fastapi_extensions-6.3.2}/stac_fastapi/extensions/transaction/__init__.py +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Aggregation Extension."""
|
|
2
2
|
|
|
3
|
-
from enum import
|
|
4
|
-
from typing import List, Type, Union
|
|
3
|
+
from enum import StrEnum
|
|
5
4
|
|
|
6
5
|
import attr
|
|
7
6
|
from fastapi import APIRouter, FastAPI
|
|
@@ -16,7 +15,7 @@ from .client import AsyncBaseAggregationClient, BaseAggregationClient
|
|
|
16
15
|
from .request import AggregationExtensionGetRequest, AggregationExtensionPostRequest
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
class AggregationConformanceClasses(
|
|
18
|
+
class AggregationConformanceClasses(StrEnum):
|
|
20
19
|
"""Conformance classes for the Aggregation extension.
|
|
21
20
|
|
|
22
21
|
See
|
|
@@ -53,14 +52,14 @@ class AggregationExtension(ApiExtension):
|
|
|
53
52
|
conformance_classes: Conformance classes provided by the extension
|
|
54
53
|
"""
|
|
55
54
|
|
|
56
|
-
GET:
|
|
57
|
-
POST:
|
|
55
|
+
GET: type[APIRequest] = AggregationExtensionGetRequest
|
|
56
|
+
POST: type[BaseModel] = AggregationExtensionPostRequest
|
|
58
57
|
|
|
59
|
-
client:
|
|
58
|
+
client: AsyncBaseAggregationClient | BaseAggregationClient = attr.ib(
|
|
60
59
|
factory=BaseAggregationClient
|
|
61
60
|
)
|
|
62
61
|
|
|
63
|
-
conformance_classes:
|
|
62
|
+
conformance_classes: list[str] = attr.ib(
|
|
64
63
|
default=[AggregationConformanceClasses.AGGREGATION]
|
|
65
64
|
)
|
|
66
65
|
router: APIRouter = attr.ib(factory=APIRouter)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Aggregation extensions clients."""
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
-
from typing import List, Optional, Union
|
|
5
4
|
|
|
6
5
|
import attr
|
|
7
6
|
from geojson_pydantic.geometries import Geometry
|
|
@@ -21,7 +20,7 @@ class BaseAggregationClient(abc.ABC):
|
|
|
21
20
|
# AGGREGATION_COLLECTION = AggregationCollection
|
|
22
21
|
|
|
23
22
|
def get_aggregations(
|
|
24
|
-
self, collection_id:
|
|
23
|
+
self, collection_id: str | None = None, **kwargs
|
|
25
24
|
) -> AggregationCollection:
|
|
26
25
|
"""Get the aggregations available for the given collection_id.
|
|
27
26
|
|
|
@@ -46,7 +45,7 @@ class BaseAggregationClient(abc.ABC):
|
|
|
46
45
|
)
|
|
47
46
|
|
|
48
47
|
def aggregate(
|
|
49
|
-
self, collection_id:
|
|
48
|
+
self, collection_id: str | None = None, **kwargs
|
|
50
49
|
) -> AggregationCollection:
|
|
51
50
|
"""Return the aggregation buckets for a given search result"""
|
|
52
51
|
return AggregationCollection(
|
|
@@ -76,7 +75,7 @@ class AsyncBaseAggregationClient(abc.ABC):
|
|
|
76
75
|
# AGGREGATION_COLLECTION = AggregationCollection
|
|
77
76
|
|
|
78
77
|
async def get_aggregations(
|
|
79
|
-
self, collection_id:
|
|
78
|
+
self, collection_id: str | None = None, **kwargs
|
|
80
79
|
) -> AggregationCollection:
|
|
81
80
|
"""Get the aggregations available for the given collection_id.
|
|
82
81
|
|
|
@@ -102,14 +101,14 @@ class AsyncBaseAggregationClient(abc.ABC):
|
|
|
102
101
|
|
|
103
102
|
async def aggregate(
|
|
104
103
|
self,
|
|
105
|
-
collection_id:
|
|
106
|
-
aggregations:
|
|
107
|
-
collections:
|
|
108
|
-
ids:
|
|
109
|
-
bbox:
|
|
110
|
-
intersects:
|
|
111
|
-
datetime:
|
|
112
|
-
limit:
|
|
104
|
+
collection_id: str | None = None,
|
|
105
|
+
aggregations: str | list[str] | None = None,
|
|
106
|
+
collections: list[str] | None = None,
|
|
107
|
+
ids: list[str] | None = None,
|
|
108
|
+
bbox: BBox | None = None,
|
|
109
|
+
intersects: Geometry | None = None,
|
|
110
|
+
datetime: DateTimeType | None = None,
|
|
111
|
+
limit: int | None = 10,
|
|
113
112
|
**kwargs,
|
|
114
113
|
) -> AggregationCollection:
|
|
115
114
|
"""Return the aggregation buckets for a given search result"""
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"""Request model for the Aggregation extension."""
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Annotated
|
|
4
4
|
|
|
5
5
|
import attr
|
|
6
6
|
from fastapi import Query
|
|
7
7
|
from pydantic import Field
|
|
8
|
-
from typing_extensions import Annotated
|
|
9
8
|
|
|
10
9
|
from stac_fastapi.types.search import (
|
|
11
10
|
BaseSearchGetRequest,
|
|
@@ -16,10 +15,10 @@ from stac_fastapi.types.search import (
|
|
|
16
15
|
|
|
17
16
|
def _agg_converter(
|
|
18
17
|
val: Annotated[
|
|
19
|
-
|
|
18
|
+
str | None,
|
|
20
19
|
Query(description="A list of aggregations to compute and return."),
|
|
21
20
|
] = None,
|
|
22
|
-
) ->
|
|
21
|
+
) -> list[str] | None:
|
|
23
22
|
return str2list(val)
|
|
24
23
|
|
|
25
24
|
|
|
@@ -27,13 +26,13 @@ def _agg_converter(
|
|
|
27
26
|
class AggregationExtensionGetRequest(BaseSearchGetRequest):
|
|
28
27
|
"""Aggregation Extension GET request model."""
|
|
29
28
|
|
|
30
|
-
aggregations:
|
|
29
|
+
aggregations: list[str] | None = attr.ib(default=None, converter=_agg_converter)
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
class AggregationExtensionPostRequest(BaseSearchPostRequest):
|
|
34
33
|
"""Aggregation Extension POST request model."""
|
|
35
34
|
|
|
36
|
-
aggregations:
|
|
35
|
+
aggregations: list[str] | None = Field(
|
|
37
36
|
default=None,
|
|
38
37
|
description="A list of aggregations to compute and return.",
|
|
39
38
|
)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Aggregation Extension types."""
|
|
2
2
|
|
|
3
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, Literal, NotRequired
|
|
4
4
|
|
|
5
|
-
from typing_extensions import
|
|
5
|
+
from typing_extensions import TypedDict
|
|
6
6
|
|
|
7
7
|
from stac_fastapi.types.rfc3339 import DateTimeType
|
|
8
8
|
|
|
@@ -11,10 +11,10 @@ Bucket = TypedDict(
|
|
|
11
11
|
{
|
|
12
12
|
"key": str,
|
|
13
13
|
"data_type": str,
|
|
14
|
-
"frequency": NotRequired[
|
|
14
|
+
"frequency": NotRequired[dict],
|
|
15
15
|
# we can't use the `class Bucket` notation because `from` is a reserved key
|
|
16
|
-
"from": NotRequired[
|
|
17
|
-
"to": NotRequired[
|
|
16
|
+
"from": NotRequired[int | float],
|
|
17
|
+
"to": NotRequired[int | float | None],
|
|
18
18
|
},
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -24,14 +24,14 @@ class Aggregation(TypedDict):
|
|
|
24
24
|
|
|
25
25
|
name: str
|
|
26
26
|
data_type: str
|
|
27
|
-
buckets: NotRequired[
|
|
27
|
+
buckets: NotRequired[list[Bucket]]
|
|
28
28
|
overflow: NotRequired[int]
|
|
29
|
-
value: NotRequired[
|
|
29
|
+
value: NotRequired[str | int | DateTimeType]
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class AggregationCollection(TypedDict):
|
|
33
33
|
"""STAC Item Aggregation Collection."""
|
|
34
34
|
|
|
35
35
|
type: Literal["AggregationCollection"]
|
|
36
|
-
aggregations:
|
|
37
|
-
links:
|
|
36
|
+
aggregations: list[Aggregation]
|
|
37
|
+
links: list[dict[str, Any]]
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""Bulk transactions extension."""
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
-
from
|
|
5
|
-
from
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
import attr
|
|
8
9
|
from fastapi import APIRouter, FastAPI
|
|
@@ -14,7 +15,7 @@ from stac_fastapi.api.routes import create_async_endpoint
|
|
|
14
15
|
from stac_fastapi.types.extension import ApiExtension
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
class BulkTransactionMethod(
|
|
18
|
+
class BulkTransactionMethod(StrEnum):
|
|
18
19
|
"""Bulk Transaction Methods."""
|
|
19
20
|
|
|
20
21
|
INSERT = "insert"
|
|
@@ -24,7 +25,7 @@ class BulkTransactionMethod(str, Enum):
|
|
|
24
25
|
class Items(BaseModel):
|
|
25
26
|
"""A group of STAC Item objects, in the form of a dictionary from Item.id -> Item."""
|
|
26
27
|
|
|
27
|
-
items:
|
|
28
|
+
items: dict[str, Any]
|
|
28
29
|
method: BulkTransactionMethod = BulkTransactionMethod.INSERT
|
|
29
30
|
|
|
30
31
|
def __iter__(self):
|
|
@@ -49,7 +50,7 @@ class BaseBulkTransactionsClient(abc.ABC):
|
|
|
49
50
|
def bulk_item_insert(
|
|
50
51
|
self,
|
|
51
52
|
items: Items,
|
|
52
|
-
chunk_size:
|
|
53
|
+
chunk_size: int | None = None,
|
|
53
54
|
**kwargs,
|
|
54
55
|
) -> str:
|
|
55
56
|
"""Bulk creation of items.
|
|
@@ -111,10 +112,10 @@ class BulkTransactionExtension(ApiExtension):
|
|
|
111
112
|
}
|
|
112
113
|
"""
|
|
113
114
|
|
|
114
|
-
client:
|
|
115
|
-
conformance_classes:
|
|
116
|
-
schema_href:
|
|
117
|
-
route_dependencies:
|
|
115
|
+
client: AsyncBaseBulkTransactionsClient | BaseBulkTransactionsClient = attr.ib()
|
|
116
|
+
conformance_classes: list[str] = attr.ib(default=list())
|
|
117
|
+
schema_href: str | None = attr.ib(default=None)
|
|
118
|
+
route_dependencies: Sequence[Depends] | None = attr.ib(default=None)
|
|
118
119
|
|
|
119
120
|
def register(self, app: FastAPI) -> None:
|
|
120
121
|
"""Register the extension with a FastAPI application.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Collection-Search extension."""
|
|
2
2
|
|
|
3
|
-
from enum import
|
|
4
|
-
from typing import
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from typing import cast
|
|
5
5
|
|
|
6
6
|
import attr
|
|
7
7
|
from fastapi import APIRouter, FastAPI
|
|
@@ -19,7 +19,7 @@ from .client import AsyncBaseCollectionSearchClient, BaseCollectionSearchClient
|
|
|
19
19
|
from .request import BaseCollectionSearchGetRequest, BaseCollectionSearchPostRequest
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
class CollectionSearchConformanceClasses(
|
|
22
|
+
class CollectionSearchConformanceClasses(StrEnum):
|
|
23
23
|
"""Conformance classes for the Collection-Search extension.
|
|
24
24
|
|
|
25
25
|
See
|
|
@@ -49,16 +49,16 @@ class CollectionSearchExtension(ApiExtension):
|
|
|
49
49
|
the extension
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
|
-
GET:
|
|
53
|
-
POST:
|
|
52
|
+
GET: type[APIRequest] = attr.ib(default=BaseCollectionSearchGetRequest)
|
|
53
|
+
POST: type[BaseModel] | None = attr.ib(init=False)
|
|
54
54
|
|
|
55
|
-
conformance_classes:
|
|
55
|
+
conformance_classes: list[str] = attr.ib(
|
|
56
56
|
default=[
|
|
57
57
|
CollectionSearchConformanceClasses.COLLECTIONSEARCH.value,
|
|
58
58
|
CollectionSearchConformanceClasses.BASIS.value,
|
|
59
59
|
]
|
|
60
60
|
)
|
|
61
|
-
schema_href:
|
|
61
|
+
schema_href: str | None = attr.ib(default=None)
|
|
62
62
|
|
|
63
63
|
def register(self, app: FastAPI) -> None:
|
|
64
64
|
"""Register the extension with a FastAPI application.
|
|
@@ -74,9 +74,9 @@ class CollectionSearchExtension(ApiExtension):
|
|
|
74
74
|
@classmethod
|
|
75
75
|
def from_extensions(
|
|
76
76
|
cls,
|
|
77
|
-
extensions:
|
|
77
|
+
extensions: list[ApiExtension],
|
|
78
78
|
*,
|
|
79
|
-
schema_href:
|
|
79
|
+
schema_href: str | None = None,
|
|
80
80
|
) -> "CollectionSearchExtension":
|
|
81
81
|
"""Create CollectionSearchExtension object from extensions."""
|
|
82
82
|
|
|
@@ -88,7 +88,7 @@ class CollectionSearchExtension(ApiExtension):
|
|
|
88
88
|
conformance_classes.extend(ext.conformance_classes)
|
|
89
89
|
|
|
90
90
|
get_request_model = cast(
|
|
91
|
-
|
|
91
|
+
type[APIRequest],
|
|
92
92
|
create_request_model(
|
|
93
93
|
model_name="CollectionsGetRequest",
|
|
94
94
|
base_model=BaseCollectionSearchGetRequest,
|
|
@@ -121,19 +121,19 @@ class CollectionSearchPostExtension(CollectionSearchExtension):
|
|
|
121
121
|
the extension
|
|
122
122
|
"""
|
|
123
123
|
|
|
124
|
-
client:
|
|
124
|
+
client: AsyncBaseCollectionSearchClient | BaseCollectionSearchClient = attr.ib()
|
|
125
125
|
settings: ApiSettings = attr.ib()
|
|
126
|
-
conformance_classes:
|
|
126
|
+
conformance_classes: list[str] = attr.ib(
|
|
127
127
|
default=[
|
|
128
128
|
CollectionSearchConformanceClasses.COLLECTIONSEARCH.value,
|
|
129
129
|
CollectionSearchConformanceClasses.BASIS.value,
|
|
130
130
|
]
|
|
131
131
|
)
|
|
132
|
-
schema_href:
|
|
132
|
+
schema_href: str | None = attr.ib(default=None)
|
|
133
133
|
router: APIRouter = attr.ib(factory=APIRouter)
|
|
134
134
|
|
|
135
|
-
GET:
|
|
136
|
-
POST:
|
|
135
|
+
GET: type[APIRequest] = attr.ib(default=BaseCollectionSearchGetRequest)
|
|
136
|
+
POST: type[BaseModel] = attr.ib(default=BaseCollectionSearchPostRequest)
|
|
137
137
|
|
|
138
138
|
def register(self, app: FastAPI) -> None:
|
|
139
139
|
"""Register the extension with a FastAPI application.
|
|
@@ -169,12 +169,12 @@ class CollectionSearchPostExtension(CollectionSearchExtension):
|
|
|
169
169
|
@classmethod
|
|
170
170
|
def from_extensions( # type: ignore [override]
|
|
171
171
|
cls,
|
|
172
|
-
extensions:
|
|
172
|
+
extensions: list[ApiExtension],
|
|
173
173
|
*,
|
|
174
|
-
schema_href:
|
|
175
|
-
client:
|
|
174
|
+
schema_href: str | None = None,
|
|
175
|
+
client: AsyncBaseCollectionSearchClient | BaseCollectionSearchClient,
|
|
176
176
|
settings: ApiSettings,
|
|
177
|
-
router:
|
|
177
|
+
router: APIRouter | None = None,
|
|
178
178
|
) -> "CollectionSearchPostExtension":
|
|
179
179
|
"""Create CollectionSearchPostExtension object from extensions."""
|
|
180
180
|
conformance_classes = [
|
|
@@ -185,7 +185,7 @@ class CollectionSearchPostExtension(CollectionSearchExtension):
|
|
|
185
185
|
conformance_classes.extend(ext.conformance_classes)
|
|
186
186
|
|
|
187
187
|
get_request_model = cast(
|
|
188
|
-
|
|
188
|
+
type[APIRequest],
|
|
189
189
|
create_request_model(
|
|
190
190
|
model_name="CollectionsGetRequest",
|
|
191
191
|
base_model=BaseCollectionSearchGetRequest,
|
|
@@ -195,7 +195,7 @@ class CollectionSearchPostExtension(CollectionSearchExtension):
|
|
|
195
195
|
)
|
|
196
196
|
|
|
197
197
|
post_request_model = cast(
|
|
198
|
-
|
|
198
|
+
type[BaseModel],
|
|
199
199
|
create_request_model(
|
|
200
200
|
model_name="CollectionsPostRequest",
|
|
201
201
|
base_model=BaseCollectionSearchPostRequest,
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"""Request models for the Collection-Search extension."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime as dt
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Annotated, cast
|
|
5
5
|
|
|
6
6
|
import attr
|
|
7
7
|
from fastapi import Query
|
|
8
8
|
from pydantic import BaseModel, Field, PrivateAttr, ValidationInfo, field_validator
|
|
9
9
|
from stac_pydantic.shared import BBox, SearchDatetime
|
|
10
|
-
from typing_extensions import Annotated
|
|
11
10
|
|
|
12
11
|
from stac_fastapi.types.search import (
|
|
13
12
|
APIRequest,
|
|
@@ -23,10 +22,10 @@ from stac_fastapi.types.search import (
|
|
|
23
22
|
class BaseCollectionSearchGetRequest(APIRequest, DatetimeMixin):
|
|
24
23
|
"""Basics additional Collection-Search parameters for the GET request."""
|
|
25
24
|
|
|
26
|
-
bbox:
|
|
25
|
+
bbox: BBox | None = attr.ib(default=None, converter=_bbox_converter) # type: ignore
|
|
27
26
|
datetime: DateTimeQueryType = attr.ib(default=None, validator=_validate_datetime)
|
|
28
27
|
limit: Annotated[
|
|
29
|
-
|
|
28
|
+
Limit | None,
|
|
30
29
|
Query(
|
|
31
30
|
description="Limits the number of results that are included in each page of the response." # noqa: E501
|
|
32
31
|
),
|
|
@@ -36,7 +35,7 @@ class BaseCollectionSearchGetRequest(APIRequest, DatetimeMixin):
|
|
|
36
35
|
class BaseCollectionSearchPostRequest(BaseModel):
|
|
37
36
|
"""Collection-Search POST model."""
|
|
38
37
|
|
|
39
|
-
bbox:
|
|
38
|
+
bbox: BBox | None = Field(
|
|
40
39
|
default=None,
|
|
41
40
|
description="Only return items intersecting this bounding box. Mutually exclusive with **intersects**.", # noqa: E501
|
|
42
41
|
json_schema_extra={
|
|
@@ -48,7 +47,7 @@ class BaseCollectionSearchPostRequest(BaseModel):
|
|
|
48
47
|
],
|
|
49
48
|
},
|
|
50
49
|
)
|
|
51
|
-
datetime:
|
|
50
|
+
datetime: str | None = Field(
|
|
52
51
|
default=None,
|
|
53
52
|
description="""Only return items that have a temporal property that intersects this value.\n
|
|
54
53
|
Either a date-time or an interval, open or closed. Date and time expressions adhere to RFC 3339. Open intervals are expressed using double-dots.""", # noqa: E501
|
|
@@ -67,24 +66,24 @@ Either a date-time or an interval, open or closed. Date and time expressions adh
|
|
|
67
66
|
],
|
|
68
67
|
},
|
|
69
68
|
)
|
|
70
|
-
limit:
|
|
69
|
+
limit: Limit | None = Field(
|
|
71
70
|
10,
|
|
72
71
|
description="Limits the number of results that are included in each page of the response (capped to 10_000).", # noqa: E501
|
|
73
72
|
)
|
|
74
73
|
|
|
75
74
|
# Private properties to store the parsed datetime values.
|
|
76
75
|
# Not part of the model schema.
|
|
77
|
-
_start_date:
|
|
78
|
-
_end_date:
|
|
76
|
+
_start_date: dt | None = PrivateAttr(default=None)
|
|
77
|
+
_end_date: dt | None = PrivateAttr(default=None)
|
|
79
78
|
|
|
80
79
|
# Properties to return the private values
|
|
81
80
|
@property
|
|
82
|
-
def start_date(self) ->
|
|
81
|
+
def start_date(self) -> dt | None:
|
|
83
82
|
"""start date."""
|
|
84
83
|
return self._start_date
|
|
85
84
|
|
|
86
85
|
@property
|
|
87
|
-
def end_date(self) ->
|
|
86
|
+
def end_date(self) -> dt | None:
|
|
88
87
|
"""end date."""
|
|
89
88
|
return self._end_date
|
|
90
89
|
|
|
@@ -95,10 +94,10 @@ Either a date-time or an interval, open or closed. Date and time expressions adh
|
|
|
95
94
|
if v:
|
|
96
95
|
# Validate order
|
|
97
96
|
if len(v) == 4:
|
|
98
|
-
xmin, ymin, xmax, ymax = cast(
|
|
97
|
+
xmin, ymin, xmax, ymax = cast(tuple[int, int, int, int], v)
|
|
99
98
|
else:
|
|
100
99
|
xmin, ymin, min_elev, xmax, ymax, max_elev = cast(
|
|
101
|
-
|
|
100
|
+
tuple[int, int, int, int, int, int], v
|
|
102
101
|
)
|
|
103
102
|
if max_elev < min_elev:
|
|
104
103
|
raise ValueError(
|
|
@@ -117,9 +116,7 @@ Either a date-time or an interval, open or closed. Date and time expressions adh
|
|
|
117
116
|
|
|
118
117
|
@field_validator("datetime", mode="after")
|
|
119
118
|
@classmethod
|
|
120
|
-
def validate_datetime(
|
|
121
|
-
cls, value: Optional[str], info: ValidationInfo
|
|
122
|
-
) -> Optional[str]:
|
|
119
|
+
def validate_datetime(cls, value: str | None, info: ValidationInfo) -> str | None:
|
|
123
120
|
"""validate datetime."""
|
|
124
121
|
# Split on "/" and replace no value or ".." with None
|
|
125
122
|
if value is None:
|
|
@@ -139,7 +136,7 @@ Either a date-time or an interval, open or closed. Date and time expressions adh
|
|
|
139
136
|
|
|
140
137
|
# Cast because pylance gets confused by the type adapter and annotated type
|
|
141
138
|
dates = cast(
|
|
142
|
-
|
|
139
|
+
list[dt | None],
|
|
143
140
|
[
|
|
144
141
|
# Use the type adapter to validate the datetime strings,
|
|
145
142
|
# strict is necessary due to pydantic issues #8736 and #8762
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Fields extension."""
|
|
2
2
|
|
|
3
|
-
from enum import
|
|
4
|
-
from typing import List, Optional, Type
|
|
3
|
+
from enum import StrEnum
|
|
5
4
|
|
|
6
5
|
import attr
|
|
7
6
|
from fastapi import FastAPI
|
|
@@ -13,7 +12,7 @@ from stac_fastapi.types.search import APIRequest
|
|
|
13
12
|
from .request import FieldsExtensionGetRequest, FieldsExtensionPostRequest
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
class FieldsConformanceClasses(
|
|
15
|
+
class FieldsConformanceClasses(StrEnum):
|
|
17
16
|
"""Conformance classes for the Fields extension.
|
|
18
17
|
|
|
19
18
|
See https://github.com/stac-api-extensions/fields
|
|
@@ -44,15 +43,15 @@ class FieldsExtension(ApiExtension):
|
|
|
44
43
|
the extension
|
|
45
44
|
"""
|
|
46
45
|
|
|
47
|
-
GET:
|
|
48
|
-
POST:
|
|
46
|
+
GET: type[APIRequest] = FieldsExtensionGetRequest
|
|
47
|
+
POST: type[BaseModel] = FieldsExtensionPostRequest
|
|
49
48
|
|
|
50
|
-
conformance_classes:
|
|
49
|
+
conformance_classes: list[str] = attr.ib(
|
|
51
50
|
factory=lambda: [
|
|
52
51
|
FieldsConformanceClasses.SEARCH,
|
|
53
52
|
]
|
|
54
53
|
)
|
|
55
|
-
schema_href:
|
|
54
|
+
schema_href: str | None = attr.ib(default=None)
|
|
56
55
|
|
|
57
56
|
def register(self, app: FastAPI) -> None:
|
|
58
57
|
"""Register the extension with a FastAPI application.
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"""Request models for the fields extension."""
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Annotated
|
|
4
4
|
|
|
5
5
|
import attr
|
|
6
6
|
from fastapi import Query
|
|
7
7
|
from pydantic import BaseModel, Field
|
|
8
|
-
from typing_extensions import Annotated
|
|
9
8
|
|
|
10
9
|
from stac_fastapi.types.search import APIRequest, str2list
|
|
11
10
|
|
|
@@ -18,11 +17,11 @@ class PostFieldsExtension(BaseModel):
|
|
|
18
17
|
exclude: set of fields to exclude.
|
|
19
18
|
"""
|
|
20
19
|
|
|
21
|
-
include:
|
|
22
|
-
exclude:
|
|
20
|
+
include: set[str] | None = set()
|
|
21
|
+
exclude: set[str] | None = set()
|
|
23
22
|
|
|
24
23
|
@staticmethod
|
|
25
|
-
def _get_field_dict(fields:
|
|
24
|
+
def _get_field_dict(fields: set[str] | None) -> dict:
|
|
26
25
|
"""Pydantic include/excludes notation.
|
|
27
26
|
|
|
28
27
|
Internal method to create a dictionary for advanced include or exclude
|
|
@@ -46,7 +45,7 @@ class PostFieldsExtension(BaseModel):
|
|
|
46
45
|
|
|
47
46
|
def _fields_converter(
|
|
48
47
|
val: Annotated[
|
|
49
|
-
|
|
48
|
+
str | None,
|
|
50
49
|
Query(
|
|
51
50
|
description="Include or exclude fields from items body.",
|
|
52
51
|
openapi_examples={
|
|
@@ -55,7 +54,7 @@ def _fields_converter(
|
|
|
55
54
|
},
|
|
56
55
|
),
|
|
57
56
|
] = None,
|
|
58
|
-
) ->
|
|
57
|
+
) -> list[str] | None:
|
|
59
58
|
return str2list(val)
|
|
60
59
|
|
|
61
60
|
|
|
@@ -63,13 +62,13 @@ def _fields_converter(
|
|
|
63
62
|
class FieldsExtensionGetRequest(APIRequest):
|
|
64
63
|
"""Additional fields for the GET request."""
|
|
65
64
|
|
|
66
|
-
fields:
|
|
65
|
+
fields: list[str] | None = attr.ib(default=None, converter=_fields_converter)
|
|
67
66
|
|
|
68
67
|
|
|
69
68
|
class FieldsExtensionPostRequest(BaseModel):
|
|
70
69
|
"""Additional fields and schema for the POST request."""
|
|
71
70
|
|
|
72
|
-
fields:
|
|
71
|
+
fields: PostFieldsExtension | None = Field(
|
|
73
72
|
PostFieldsExtension(),
|
|
74
73
|
description="Include or exclude fields from items body.",
|
|
75
74
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Filter extensions clients."""
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
import attr
|
|
7
7
|
|
|
@@ -11,8 +11,8 @@ class AsyncBaseFiltersClient(abc.ABC):
|
|
|
11
11
|
"""Defines a pattern for implementing the STAC filter extension."""
|
|
12
12
|
|
|
13
13
|
async def get_queryables(
|
|
14
|
-
self, collection_id:
|
|
15
|
-
) ->
|
|
14
|
+
self, collection_id: str | None = None, **kwargs
|
|
15
|
+
) -> dict[str, Any]:
|
|
16
16
|
"""Get the queryables available for the given collection_id.
|
|
17
17
|
|
|
18
18
|
If collection_id is None, returns the intersection of all queryables over all
|
|
@@ -37,8 +37,8 @@ class BaseFiltersClient(abc.ABC):
|
|
|
37
37
|
"""Defines a pattern for implementing the STAC filter extension."""
|
|
38
38
|
|
|
39
39
|
def get_queryables(
|
|
40
|
-
self, collection_id:
|
|
41
|
-
) ->
|
|
40
|
+
self, collection_id: str | None = None, **kwargs
|
|
41
|
+
) -> dict[str, Any]:
|
|
42
42
|
"""Get the queryables available for the given collection_id.
|
|
43
43
|
|
|
44
44
|
If collection_id is None, returns the intersection of all queryables over all
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
"""Filter Extension."""
|
|
3
2
|
|
|
4
|
-
from enum import
|
|
5
|
-
from typing import List, Type, Union
|
|
3
|
+
from enum import StrEnum
|
|
6
4
|
|
|
7
5
|
import attr
|
|
8
6
|
from fastapi import APIRouter, FastAPI
|
|
@@ -18,7 +16,7 @@ from .client import AsyncBaseFiltersClient, BaseFiltersClient
|
|
|
18
16
|
from .request import FilterExtensionGetRequest, FilterExtensionPostRequest
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
class FilterConformanceClasses(
|
|
19
|
+
class FilterConformanceClasses(StrEnum):
|
|
22
20
|
"""Conformance classes for the Filter extension.
|
|
23
21
|
|
|
24
22
|
See
|
|
@@ -74,13 +72,13 @@ class FilterExtension(ApiExtension):
|
|
|
74
72
|
conformance_classes: Conformance classes provided by the extension
|
|
75
73
|
"""
|
|
76
74
|
|
|
77
|
-
GET:
|
|
78
|
-
POST:
|
|
75
|
+
GET: type[APIRequest] = FilterExtensionGetRequest
|
|
76
|
+
POST: type[BaseModel] = FilterExtensionPostRequest
|
|
79
77
|
|
|
80
|
-
client:
|
|
78
|
+
client: AsyncBaseFiltersClient | BaseFiltersClient = attr.ib(
|
|
81
79
|
factory=BaseFiltersClient
|
|
82
80
|
)
|
|
83
|
-
conformance_classes:
|
|
81
|
+
conformance_classes: list[str] = attr.ib(
|
|
84
82
|
default=[
|
|
85
83
|
FilterConformanceClasses.FILTER,
|
|
86
84
|
FilterConformanceClasses.SEARCH,
|
|
@@ -91,7 +89,7 @@ class FilterExtension(ApiExtension):
|
|
|
91
89
|
]
|
|
92
90
|
)
|
|
93
91
|
router: APIRouter = attr.ib(factory=APIRouter)
|
|
94
|
-
response_class:
|
|
92
|
+
response_class: type[Response] = attr.ib(default=JSONSchemaResponse)
|
|
95
93
|
|
|
96
94
|
def register(self, app: FastAPI) -> None:
|
|
97
95
|
"""Register the extension with a FastAPI application.
|
|
@@ -140,7 +138,7 @@ class FilterExtension(ApiExtension):
|
|
|
140
138
|
class SearchFilterExtension(FilterExtension):
|
|
141
139
|
"""Item Search Filter Extension."""
|
|
142
140
|
|
|
143
|
-
conformance_classes:
|
|
141
|
+
conformance_classes: list[str] = attr.ib(
|
|
144
142
|
default=[
|
|
145
143
|
FilterConformanceClasses.FILTER,
|
|
146
144
|
FilterConformanceClasses.SEARCH,
|
|
@@ -182,7 +180,7 @@ class SearchFilterExtension(FilterExtension):
|
|
|
182
180
|
class ItemCollectionFilterExtension(FilterExtension):
|
|
183
181
|
"""Item Collection Filter Extension."""
|
|
184
182
|
|
|
185
|
-
conformance_classes:
|
|
183
|
+
conformance_classes: list[str] = attr.ib(
|
|
186
184
|
default=[
|
|
187
185
|
FilterConformanceClasses.FILTER,
|
|
188
186
|
FilterConformanceClasses.ITEMS,
|
|
@@ -224,7 +222,7 @@ class ItemCollectionFilterExtension(FilterExtension):
|
|
|
224
222
|
class CollectionSearchFilterExtension(FilterExtension):
|
|
225
223
|
"""Collection Search Filter Extension."""
|
|
226
224
|
|
|
227
|
-
conformance_classes:
|
|
225
|
+
conformance_classes: list[str] = attr.ib(
|
|
228
226
|
default=[
|
|
229
227
|
FilterConformanceClasses.FILTER,
|
|
230
228
|
FilterConformanceClasses.COLLECTIONS,
|