stac-fastapi.types 2.5.5__tar.gz → 3.0.0__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.
Files changed (26) hide show
  1. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/PKG-INFO +5 -6
  2. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/setup.py +4 -5
  3. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/config.py +4 -11
  4. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/conformance.py +1 -0
  5. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/core.py +123 -138
  6. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/extension.py +1 -0
  7. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/requests.py +1 -3
  8. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/rfc3339.py +37 -5
  9. stac_fastapi_types-3.0.0/stac_fastapi/types/search.py +190 -0
  10. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/stac.py +11 -18
  11. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/version.py +2 -1
  12. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi.types.egg-info/PKG-INFO +5 -6
  13. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi.types.egg-info/requires.txt +4 -5
  14. stac_fastapi_types-3.0.0/tests/test_limit.py +55 -0
  15. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/tests/test_rfc3339.py +30 -12
  16. stac_fastapi_types-2.5.5/stac_fastapi/types/search.py +0 -222
  17. stac_fastapi_types-2.5.5/tests/test_limit.py +0 -22
  18. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/README.md +0 -0
  19. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/setup.cfg +0 -0
  20. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/__init__.py +0 -0
  21. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/errors.py +0 -0
  22. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi/types/links.py +0 -0
  23. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi.types.egg-info/SOURCES.txt +0 -0
  24. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi.types.egg-info/dependency_links.txt +0 -0
  25. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi.types.egg-info/not-zip-safe +0 -0
  26. {stac_fastapi_types-2.5.5 → stac_fastapi_types-3.0.0}/stac_fastapi.types.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stac-fastapi.types
3
- Version: 2.5.5
3
+ Version: 3.0.0
4
4
  Summary: An implementation of STAC API based on the FastAPI framework.
5
5
  Home-page: https://github.com/stac-utils/stac-fastapi
6
6
  Author: Arturo Engineering
@@ -18,11 +18,10 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: License :: OSI Approved :: MIT License
19
19
  Requires-Python: >=3.8
20
20
  Description-Content-Type: text/markdown
21
- Requires-Dist: fastapi>=0.73.0
22
- Requires-Dist: attrs
23
- Requires-Dist: pydantic[dotenv]<2
24
- Requires-Dist: stac_pydantic==2.0.*
25
- Requires-Dist: pystac==1.*
21
+ Requires-Dist: fastapi-slim>=0.111.0
22
+ Requires-Dist: attrs>=23.2.0
23
+ Requires-Dist: pydantic-settings>=2
24
+ Requires-Dist: stac_pydantic~=3.1
26
25
  Requires-Dist: iso8601<2.2.0,>=1.0.2
27
26
  Provides-Extra: dev
28
27
  Requires-Dist: pytest; extra == "dev"
@@ -6,11 +6,10 @@ with open("README.md") as f:
6
6
  desc = f.read()
7
7
 
8
8
  install_requires = [
9
- "fastapi>=0.73.0",
10
- "attrs",
11
- "pydantic[dotenv]<2",
12
- "stac_pydantic==2.0.*",
13
- "pystac==1.*",
9
+ "fastapi-slim>=0.111.0",
10
+ "attrs>=23.2.0",
11
+ "pydantic-settings>=2",
12
+ "stac_pydantic~=3.1",
14
13
  "iso8601>=1.0.2,<2.2.0",
15
14
  ]
16
15
 
@@ -1,7 +1,8 @@
1
1
  """stac_fastapi.types.config module."""
2
- from typing import Optional, Set
3
2
 
4
- from pydantic import BaseSettings
3
+ from typing import Optional
4
+
5
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
6
 
6
7
 
7
8
  class ApiSettings(BaseSettings):
@@ -18,10 +19,6 @@ class ApiSettings(BaseSettings):
18
19
  as distinct columns in the database.
19
20
  """
20
21
 
21
- # TODO: Remove `default_includes` attribute so we can use
22
- # `pydantic.BaseSettings` instead
23
- default_includes: Optional[Set[str]] = None
24
-
25
22
  stac_fastapi_title: str = "stac-fastapi"
26
23
  stac_fastapi_description: str = "stac-fastapi"
27
24
  stac_fastapi_version: str = "0.1"
@@ -35,11 +32,7 @@ class ApiSettings(BaseSettings):
35
32
  openapi_url: str = "/api"
36
33
  docs_url: str = "/api.html"
37
34
 
38
- class Config:
39
- """Model config (https://pydantic-docs.helpmanual.io/usage/model_config/)."""
40
-
41
- extra = "allow"
42
- env_file = ".env"
35
+ model_config = SettingsConfigDict(env_file=".env", extra="allow")
43
36
 
44
37
 
45
38
  class Settings:
@@ -1,4 +1,5 @@
1
1
  """Conformance Classes."""
2
+
2
3
  from enum import Enum
3
4
 
4
5
 
@@ -6,19 +6,30 @@ from urllib.parse import urljoin
6
6
 
7
7
  import attr
8
8
  from fastapi import Request
9
+ from geojson_pydantic.geometries import Geometry
10
+ from stac_pydantic import Collection, Item, ItemCollection
11
+ from stac_pydantic.api.version import STAC_API_VERSION
9
12
  from stac_pydantic.links import Relations
10
13
  from stac_pydantic.shared import BBox, MimeTypes
11
- from stac_pydantic.version import STAC_VERSION
12
14
  from starlette.responses import Response
13
15
 
14
- from stac_fastapi.types import stac as stac_types
16
+ from stac_fastapi.types import stac
15
17
  from stac_fastapi.types.config import ApiSettings
16
18
  from stac_fastapi.types.conformance import BASE_CONFORMANCE_CLASSES
17
19
  from stac_fastapi.types.extension import ApiExtension
18
20
  from stac_fastapi.types.requests import get_base_url
19
21
  from stac_fastapi.types.rfc3339 import DateTimeType
20
22
  from stac_fastapi.types.search import BaseSearchPostRequest
21
- from stac_fastapi.types.stac import Conformance
23
+
24
+ __all__ = [
25
+ "NumType",
26
+ "StacType",
27
+ "BaseTransactionsClient",
28
+ "AsyncBaseTransactionsClient",
29
+ "LandingPageMixin",
30
+ "BaseCoreClient",
31
+ "AsyncBaseCoreClient",
32
+ ]
22
33
 
23
34
  NumType = Union[float, int]
24
35
  StacType = Dict[str, Any]
@@ -34,9 +45,9 @@ class BaseTransactionsClient(abc.ABC):
34
45
  def create_item(
35
46
  self,
36
47
  collection_id: str,
37
- item: Union[stac_types.Item, stac_types.ItemCollection],
48
+ item: Union[Item, ItemCollection],
38
49
  **kwargs,
39
- ) -> Optional[Union[stac_types.Item, Response, None]]:
50
+ ) -> Optional[Union[stac.Item, Response, None]]:
40
51
  """Create a new item.
41
52
 
42
53
  Called with `POST /collections/{collection_id}/items`.
@@ -52,8 +63,8 @@ class BaseTransactionsClient(abc.ABC):
52
63
 
53
64
  @abc.abstractmethod
54
65
  def update_item(
55
- self, collection_id: str, item_id: str, item: stac_types.Item, **kwargs
56
- ) -> Optional[Union[stac_types.Item, Response]]:
66
+ self, collection_id: str, item_id: str, item: Item, **kwargs
67
+ ) -> Optional[Union[stac.Item, Response]]:
57
68
  """Perform a complete update on an existing item.
58
69
 
59
70
  Called with `PUT /collections/{collection_id}/items`. It is expected
@@ -73,7 +84,7 @@ class BaseTransactionsClient(abc.ABC):
73
84
  @abc.abstractmethod
74
85
  def delete_item(
75
86
  self, item_id: str, collection_id: str, **kwargs
76
- ) -> Optional[Union[stac_types.Item, Response]]:
87
+ ) -> Optional[Union[stac.Item, Response]]:
77
88
  """Delete an item from a collection.
78
89
 
79
90
  Called with `DELETE /collections/{collection_id}/items/{item_id}`
@@ -89,8 +100,8 @@ class BaseTransactionsClient(abc.ABC):
89
100
 
90
101
  @abc.abstractmethod
91
102
  def create_collection(
92
- self, collection: stac_types.Collection, **kwargs
93
- ) -> Optional[Union[stac_types.Collection, Response]]:
103
+ self, collection: Collection, **kwargs
104
+ ) -> Optional[Union[stac.Collection, Response]]:
94
105
  """Create a new collection.
95
106
 
96
107
  Called with `POST /collections`.
@@ -105,8 +116,8 @@ class BaseTransactionsClient(abc.ABC):
105
116
 
106
117
  @abc.abstractmethod
107
118
  def update_collection(
108
- self, collection_id: str, collection: stac_types.Collection, **kwargs
109
- ) -> Optional[Union[stac_types.Collection, Response]]:
119
+ self, collection_id: str, collection: Collection, **kwargs
120
+ ) -> Optional[Union[stac.Collection, Response]]:
110
121
  """Perform a complete update on an existing collection.
111
122
 
112
123
  Called with `PUT /collections/{collection_id}`. It is expected that this
@@ -126,7 +137,7 @@ class BaseTransactionsClient(abc.ABC):
126
137
  @abc.abstractmethod
127
138
  def delete_collection(
128
139
  self, collection_id: str, **kwargs
129
- ) -> Optional[Union[stac_types.Collection, Response]]:
140
+ ) -> Optional[Union[stac.Collection, Response]]:
130
141
  """Delete a collection.
131
142
 
132
143
  Called with `DELETE /collections/{collection_id}`
@@ -148,9 +159,9 @@ class AsyncBaseTransactionsClient(abc.ABC):
148
159
  async def create_item(
149
160
  self,
150
161
  collection_id: str,
151
- item: Union[stac_types.Item, stac_types.ItemCollection],
162
+ item: Union[Item, ItemCollection],
152
163
  **kwargs,
153
- ) -> Optional[Union[stac_types.Item, Response, None]]:
164
+ ) -> Optional[Union[stac.Item, Response, None]]:
154
165
  """Create a new item.
155
166
 
156
167
  Called with `POST /collections/{collection_id}/items`.
@@ -166,8 +177,8 @@ class AsyncBaseTransactionsClient(abc.ABC):
166
177
 
167
178
  @abc.abstractmethod
168
179
  async def update_item(
169
- self, collection_id: str, item_id: str, item: stac_types.Item, **kwargs
170
- ) -> Optional[Union[stac_types.Item, Response]]:
180
+ self, collection_id: str, item_id: str, item: Item, **kwargs
181
+ ) -> Optional[Union[stac.Item, Response]]:
171
182
  """Perform a complete update on an existing item.
172
183
 
173
184
  Called with `PUT /collections/{collection_id}/items`. It is expected
@@ -186,7 +197,7 @@ class AsyncBaseTransactionsClient(abc.ABC):
186
197
  @abc.abstractmethod
187
198
  async def delete_item(
188
199
  self, item_id: str, collection_id: str, **kwargs
189
- ) -> Optional[Union[stac_types.Item, Response]]:
200
+ ) -> Optional[Union[stac.Item, Response]]:
190
201
  """Delete an item from a collection.
191
202
 
192
203
  Called with `DELETE /collections/{collection_id}/items/{item_id}`
@@ -202,8 +213,8 @@ class AsyncBaseTransactionsClient(abc.ABC):
202
213
 
203
214
  @abc.abstractmethod
204
215
  async def create_collection(
205
- self, collection: stac_types.Collection, **kwargs
206
- ) -> Optional[Union[stac_types.Collection, Response]]:
216
+ self, collection: Collection, **kwargs
217
+ ) -> Optional[Union[stac.Collection, Response]]:
207
218
  """Create a new collection.
208
219
 
209
220
  Called with `POST /collections`.
@@ -218,8 +229,8 @@ class AsyncBaseTransactionsClient(abc.ABC):
218
229
 
219
230
  @abc.abstractmethod
220
231
  async def update_collection(
221
- self, collection_id: str, collection: stac_types.Collection, **kwargs
222
- ) -> Optional[Union[stac_types.Collection, Response]]:
232
+ self, collection_id: str, collection: Collection, **kwargs
233
+ ) -> Optional[Union[stac.Collection, Response]]:
223
234
  """Perform a complete update on an existing collection.
224
235
 
225
236
  Called with `PUT /collections/{collection_id}`. It is expected that this item
@@ -239,7 +250,7 @@ class AsyncBaseTransactionsClient(abc.ABC):
239
250
  @abc.abstractmethod
240
251
  async def delete_collection(
241
252
  self, collection_id: str, **kwargs
242
- ) -> Optional[Union[stac_types.Collection, Response]]:
253
+ ) -> Optional[Union[stac.Collection, Response]]:
243
254
  """Delete a collection.
244
255
 
245
256
  Called with `DELETE /collections/{collection_id}`
@@ -257,7 +268,7 @@ class AsyncBaseTransactionsClient(abc.ABC):
257
268
  class LandingPageMixin(abc.ABC):
258
269
  """Create a STAC landing page (GET /)."""
259
270
 
260
- stac_version: str = attr.ib(default=STAC_VERSION)
271
+ stac_version: str = attr.ib(default=STAC_API_VERSION)
261
272
  landing_page_id: str = attr.ib(default=api_settings.stac_fastapi_landing_id)
262
273
  title: str = attr.ib(default=api_settings.stac_fastapi_title)
263
274
  description: str = attr.ib(default=api_settings.stac_fastapi_description)
@@ -267,8 +278,8 @@ class LandingPageMixin(abc.ABC):
267
278
  base_url: str,
268
279
  conformance_classes: List[str],
269
280
  extension_schemas: List[str],
270
- ) -> stac_types.LandingPage:
271
- landing_page = stac_types.LandingPage(
281
+ ) -> stac.LandingPage:
282
+ landing_page = stac.LandingPage(
272
283
  type="Catalog",
273
284
  id=self.landing_page_id,
274
285
  title=self.title,
@@ -278,35 +289,35 @@ class LandingPageMixin(abc.ABC):
278
289
  links=[
279
290
  {
280
291
  "rel": Relations.self.value,
281
- "type": MimeTypes.json,
292
+ "type": MimeTypes.json.value,
282
293
  "href": base_url,
283
294
  },
284
295
  {
285
296
  "rel": Relations.root.value,
286
- "type": MimeTypes.json,
297
+ "type": MimeTypes.json.value,
287
298
  "href": base_url,
288
299
  },
289
300
  {
290
- "rel": "data",
291
- "type": MimeTypes.json,
301
+ "rel": Relations.data.value,
302
+ "type": MimeTypes.json.value,
292
303
  "href": urljoin(base_url, "collections"),
293
304
  },
294
305
  {
295
306
  "rel": Relations.conformance.value,
296
- "type": MimeTypes.json,
307
+ "type": MimeTypes.json.value,
297
308
  "title": "STAC/OGC conformance classes implemented by this server",
298
309
  "href": urljoin(base_url, "conformance"),
299
310
  },
300
311
  {
301
312
  "rel": Relations.search.value,
302
- "type": MimeTypes.geojson,
313
+ "type": MimeTypes.geojson.value,
303
314
  "title": "STAC search",
304
315
  "href": urljoin(base_url, "search"),
305
316
  "method": "GET",
306
317
  },
307
318
  {
308
319
  "rel": Relations.search.value,
309
- "type": MimeTypes.geojson,
320
+ "type": MimeTypes.geojson.value,
310
321
  "title": "STAC search",
311
322
  "href": urljoin(base_url, "search"),
312
323
  "method": "POST",
@@ -314,6 +325,7 @@ class LandingPageMixin(abc.ABC):
314
325
  ],
315
326
  stac_extensions=extension_schemas,
316
327
  )
328
+
317
329
  return landing_page
318
330
 
319
331
 
@@ -356,7 +368,7 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
356
368
 
357
369
  return base_conformance
358
370
 
359
- def landing_page(self, **kwargs) -> stac_types.LandingPage:
371
+ def landing_page(self, **kwargs) -> stac.LandingPage:
360
372
  """Landing page.
361
373
 
362
374
  Called with `GET /`.
@@ -366,6 +378,7 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
366
378
  """
367
379
  request: Request = kwargs["request"]
368
380
  base_url = get_base_url(request)
381
+
369
382
  landing_page = self._landing_page(
370
383
  base_url=base_url,
371
384
  conformance_classes=self.conformance_classes(),
@@ -376,18 +389,35 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
376
389
  if self.extension_is_enabled("FilterExtension"):
377
390
  landing_page["links"].append(
378
391
  {
379
- # TODO: replace this with Relations.queryables.value,
380
- "rel": "http://www.opengis.net/def/rel/ogc/1.0/queryables",
381
- # TODO: replace this with MimeTypes.jsonschema,
382
- "type": "application/schema+json",
392
+ "rel": Relations.queryables.value,
393
+ "type": MimeTypes.jsonschema.value,
383
394
  "title": "Queryables",
384
395
  "href": urljoin(base_url, "queryables"),
385
- "method": "GET",
386
396
  }
387
397
  )
388
398
 
399
+ # Add Aggregation links
400
+ if self.extension_is_enabled("AggregationExtension"):
401
+ landing_page["links"].extend(
402
+ [
403
+ {
404
+ "rel": "aggregate",
405
+ "type": "application/json",
406
+ "title": "Aggregate",
407
+ "href": urljoin(base_url, "aggregate"),
408
+ },
409
+ {
410
+ "rel": "aggregations",
411
+ "type": "application/json",
412
+ "title": "Aggregations",
413
+ "href": urljoin(base_url, "aggregations"),
414
+ },
415
+ ]
416
+ )
417
+
389
418
  # Add Collections links
390
419
  collections = self.all_collections(request=kwargs["request"])
420
+
391
421
  for collection in collections["collections"]:
392
422
  landing_page["links"].append(
393
423
  {
@@ -401,8 +431,8 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
401
431
  # Add OpenAPI URL
402
432
  landing_page["links"].append(
403
433
  {
404
- "rel": "service-desc",
405
- "type": "application/vnd.oai.openapi+json;version=3.0",
434
+ "rel": Relations.service_desc.value,
435
+ "type": MimeTypes.openapi.value,
406
436
  "title": "OpenAPI service description",
407
437
  "href": str(request.url_for("openapi")),
408
438
  }
@@ -411,16 +441,16 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
411
441
  # Add human readable service-doc
412
442
  landing_page["links"].append(
413
443
  {
414
- "rel": "service-doc",
415
- "type": "text/html",
444
+ "rel": Relations.service_doc.value,
445
+ "type": MimeTypes.html.value,
416
446
  "title": "OpenAPI service documentation",
417
447
  "href": str(request.url_for("swagger_ui_html")),
418
448
  }
419
449
  )
420
450
 
421
- return landing_page
451
+ return stac.LandingPage(**landing_page)
422
452
 
423
- def conformance(self, **kwargs) -> stac_types.Conformance:
453
+ def conformance(self, **kwargs) -> stac.Conformance:
424
454
  """Conformance classes.
425
455
 
426
456
  Called with `GET /conformance`.
@@ -428,12 +458,12 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
428
458
  Returns:
429
459
  Conformance classes which the server conforms to.
430
460
  """
431
- return Conformance(conformsTo=self.conformance_classes())
461
+ return stac.Conformance(conformsTo=self.conformance_classes())
432
462
 
433
463
  @abc.abstractmethod
434
464
  def post_search(
435
465
  self, search_request: BaseSearchPostRequest, **kwargs
436
- ) -> stac_types.ItemCollection:
466
+ ) -> stac.ItemCollection:
437
467
  """Cross catalog search (POST).
438
468
 
439
469
  Called with `POST /search`.
@@ -452,15 +482,11 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
452
482
  collections: Optional[List[str]] = None,
453
483
  ids: Optional[List[str]] = None,
454
484
  bbox: Optional[BBox] = None,
485
+ intersects: Optional[Geometry] = None,
455
486
  datetime: Optional[DateTimeType] = None,
456
487
  limit: Optional[int] = 10,
457
- query: Optional[str] = None,
458
- token: Optional[str] = None,
459
- fields: Optional[List[str]] = None,
460
- sortby: Optional[str] = None,
461
- intersects: Optional[str] = None,
462
488
  **kwargs,
463
- ) -> stac_types.ItemCollection:
489
+ ) -> stac.ItemCollection:
464
490
  """Cross catalog search (GET).
465
491
 
466
492
  Called with `GET /search`.
@@ -471,7 +497,7 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
471
497
  ...
472
498
 
473
499
  @abc.abstractmethod
474
- def get_item(self, item_id: str, collection_id: str, **kwargs) -> stac_types.Item:
500
+ def get_item(self, item_id: str, collection_id: str, **kwargs) -> stac.Item:
475
501
  """Get item by id.
476
502
 
477
503
  Called with `GET /collections/{collection_id}/items/{item_id}`.
@@ -486,7 +512,7 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
486
512
  ...
487
513
 
488
514
  @abc.abstractmethod
489
- def all_collections(self, **kwargs) -> stac_types.Collections:
515
+ def all_collections(self, **kwargs) -> stac.Collections:
490
516
  """Get all available collections.
491
517
 
492
518
  Called with `GET /collections`.
@@ -497,7 +523,7 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
497
523
  ...
498
524
 
499
525
  @abc.abstractmethod
500
- def get_collection(self, collection_id: str, **kwargs) -> stac_types.Collection:
526
+ def get_collection(self, collection_id: str, **kwargs) -> stac.Collection:
501
527
  """Get collection by id.
502
528
 
503
529
  Called with `GET /collections/{collection_id}`.
@@ -519,7 +545,7 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
519
545
  limit: int = 10,
520
546
  token: str = None,
521
547
  **kwargs,
522
- ) -> stac_types.ItemCollection:
548
+ ) -> stac.ItemCollection:
523
549
  """Get all items from a specific collection.
524
550
 
525
551
  Called with `GET /collections/{collection_id}/items`
@@ -564,7 +590,7 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
564
590
  """Check if an api extension is enabled."""
565
591
  return any([type(ext).__name__ == extension for ext in self.extensions])
566
592
 
567
- async def landing_page(self, **kwargs) -> stac_types.LandingPage:
593
+ async def landing_page(self, **kwargs) -> stac.LandingPage:
568
594
  """Landing page.
569
595
 
570
596
  Called with `GET /`.
@@ -574,6 +600,7 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
574
600
  """
575
601
  request: Request = kwargs["request"]
576
602
  base_url = get_base_url(request)
603
+
577
604
  landing_page = self._landing_page(
578
605
  base_url=base_url,
579
606
  conformance_classes=self.conformance_classes(),
@@ -584,18 +611,36 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
584
611
  if self.extension_is_enabled("FilterExtension"):
585
612
  landing_page["links"].append(
586
613
  {
587
- # TODO: replace this with Relations.queryables.value,
588
- "rel": "http://www.opengis.net/def/rel/ogc/1.0/queryables",
589
- # TODO: replace this with MimeTypes.jsonschema,
590
- "type": "application/schema+json",
614
+ "rel": Relations.queryables.value,
615
+ "type": MimeTypes.jsonschema.value,
591
616
  "title": "Queryables",
592
617
  "href": urljoin(base_url, "queryables"),
593
618
  "method": "GET",
594
619
  }
595
620
  )
596
621
 
622
+ # Add Aggregation links
623
+ if self.extension_is_enabled("AggregationExtension"):
624
+ landing_page["links"].extend(
625
+ [
626
+ {
627
+ "rel": "aggregate",
628
+ "type": "application/json",
629
+ "title": "Aggregate",
630
+ "href": urljoin(base_url, "aggregate"),
631
+ },
632
+ {
633
+ "rel": "aggregations",
634
+ "type": "application/json",
635
+ "title": "Aggregations",
636
+ "href": urljoin(base_url, "aggregations"),
637
+ },
638
+ ]
639
+ )
640
+
597
641
  # Add Collections links
598
642
  collections = await self.all_collections(request=kwargs["request"])
643
+
599
644
  for collection in collections["collections"]:
600
645
  landing_page["links"].append(
601
646
  {
@@ -609,26 +654,26 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
609
654
  # Add OpenAPI URL
610
655
  landing_page["links"].append(
611
656
  {
612
- "rel": "service-desc",
613
- "type": "application/vnd.oai.openapi+json;version=3.0",
657
+ "rel": Relations.service_desc.value,
658
+ "type": MimeTypes.openapi.value,
614
659
  "title": "OpenAPI service description",
615
- "href": urljoin(base_url, request.app.openapi_url.lstrip("/")),
660
+ "href": str(request.url_for("openapi")),
616
661
  }
617
662
  )
618
663
 
619
664
  # Add human readable service-doc
620
665
  landing_page["links"].append(
621
666
  {
622
- "rel": "service-doc",
623
- "type": "text/html",
667
+ "rel": Relations.service_doc.value,
668
+ "type": MimeTypes.html.value,
624
669
  "title": "OpenAPI service documentation",
625
- "href": urljoin(base_url, request.app.docs_url.lstrip("/")),
670
+ "href": str(request.url_for("swagger_ui_html")),
626
671
  }
627
672
  )
628
673
 
629
- return landing_page
674
+ return stac.LandingPage(**landing_page)
630
675
 
631
- async def conformance(self, **kwargs) -> stac_types.Conformance:
676
+ async def conformance(self, **kwargs) -> stac.Conformance:
632
677
  """Conformance classes.
633
678
 
634
679
  Called with `GET /conformance`.
@@ -636,12 +681,12 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
636
681
  Returns:
637
682
  Conformance classes which the server conforms to.
638
683
  """
639
- return Conformance(conformsTo=self.conformance_classes())
684
+ return stac.Conformance(conformsTo=self.conformance_classes())
640
685
 
641
686
  @abc.abstractmethod
642
687
  async def post_search(
643
688
  self, search_request: BaseSearchPostRequest, **kwargs
644
- ) -> stac_types.ItemCollection:
689
+ ) -> stac.ItemCollection:
645
690
  """Cross catalog search (POST).
646
691
 
647
692
  Called with `POST /search`.
@@ -660,15 +705,11 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
660
705
  collections: Optional[List[str]] = None,
661
706
  ids: Optional[List[str]] = None,
662
707
  bbox: Optional[BBox] = None,
708
+ intersects: Optional[Geometry] = None,
663
709
  datetime: Optional[DateTimeType] = None,
664
710
  limit: Optional[int] = 10,
665
- query: Optional[str] = None,
666
- token: Optional[str] = None,
667
- fields: Optional[List[str]] = None,
668
- sortby: Optional[str] = None,
669
- intersects: Optional[str] = None,
670
711
  **kwargs,
671
- ) -> stac_types.ItemCollection:
712
+ ) -> stac.ItemCollection:
672
713
  """Cross catalog search (GET).
673
714
 
674
715
  Called with `GET /search`.
@@ -679,9 +720,7 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
679
720
  ...
680
721
 
681
722
  @abc.abstractmethod
682
- async def get_item(
683
- self, item_id: str, collection_id: str, **kwargs
684
- ) -> stac_types.Item:
723
+ async def get_item(self, item_id: str, collection_id: str, **kwargs) -> stac.Item:
685
724
  """Get item by id.
686
725
 
687
726
  Called with `GET /collections/{collection_id}/items/{item_id}`.
@@ -696,7 +735,7 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
696
735
  ...
697
736
 
698
737
  @abc.abstractmethod
699
- async def all_collections(self, **kwargs) -> stac_types.Collections:
738
+ async def all_collections(self, **kwargs) -> stac.Collections:
700
739
  """Get all available collections.
701
740
 
702
741
  Called with `GET /collections`.
@@ -707,9 +746,7 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
707
746
  ...
708
747
 
709
748
  @abc.abstractmethod
710
- async def get_collection(
711
- self, collection_id: str, **kwargs
712
- ) -> stac_types.Collection:
749
+ async def get_collection(self, collection_id: str, **kwargs) -> stac.Collection:
713
750
  """Get collection by id.
714
751
 
715
752
  Called with `GET /collections/{collection_id}`.
@@ -731,7 +768,7 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
731
768
  limit: int = 10,
732
769
  token: str = None,
733
770
  **kwargs,
734
- ) -> stac_types.ItemCollection:
771
+ ) -> stac.ItemCollection:
735
772
  """Get all items from a specific collection.
736
773
 
737
774
  Called with `GET /collections/{collection_id}/items`
@@ -745,55 +782,3 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
745
782
  An ItemCollection.
746
783
  """
747
784
  ...
748
-
749
-
750
- @attr.s
751
- class AsyncBaseFiltersClient(abc.ABC):
752
- """Defines a pattern for implementing the STAC filter extension."""
753
-
754
- async def get_queryables(
755
- self, collection_id: Optional[str] = None, **kwargs
756
- ) -> Dict[str, Any]:
757
- """Get the queryables available for the given collection_id.
758
-
759
- If collection_id is None, returns the intersection of all queryables over all
760
- collections.
761
-
762
- This base implementation returns a blank queryable schema. This is not allowed
763
- under OGC CQL but it is allowed by the STAC API Filter Extension
764
- https://github.com/radiantearth/stac-api-spec/tree/master/fragments/filter#queryables
765
- """
766
- return {
767
- "$schema": "https://json-schema.org/draft/2019-09/schema",
768
- "$id": "https://example.org/queryables",
769
- "type": "object",
770
- "title": "Queryables for Example STAC API",
771
- "description": "Queryable names for the example STAC API Item Search filter.",
772
- "properties": {},
773
- }
774
-
775
-
776
- @attr.s
777
- class BaseFiltersClient(abc.ABC):
778
- """Defines a pattern for implementing the STAC filter extension."""
779
-
780
- def get_queryables(
781
- self, collection_id: Optional[str] = None, **kwargs
782
- ) -> Dict[str, Any]:
783
- """Get the queryables available for the given collection_id.
784
-
785
- If collection_id is None, returns the intersection of all queryables over all
786
- collections.
787
-
788
- This base implementation returns a blank queryable schema. This is not allowed
789
- under OGC CQL but it is allowed by the STAC API Filter Extension
790
- https://github.com/stac-api-extensions/filter#queryables
791
- """
792
- return {
793
- "$schema": "https://json-schema.org/draft/2019-09/schema",
794
- "$id": "https://example.org/queryables",
795
- "type": "object",
796
- "title": "Queryables for Example STAC API",
797
- "description": "Queryable names for the example STAC API Item Search filter.",
798
- "properties": {},
799
- }