stac-fastapi.api 5.1.1__tar.gz → 5.2.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.
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/PKG-INFO +9 -6
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/setup.py +9 -2
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/app.py +74 -66
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/middleware.py +2 -2
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/routes.py +36 -4
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/version.py +1 -1
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi.api.egg-info/PKG-INFO +9 -6
- stac_fastapi_api-5.2.0/stac_fastapi.api.egg-info/requires.txt +21 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/tests/test_app.py +74 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/tests/test_app_prefix.py +3 -0
- stac_fastapi_api-5.1.1/stac_fastapi.api.egg-info/requires.txt +0 -18
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/README.md +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/setup.cfg +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/__init__.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/config.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/errors.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/models.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi/api/openapi.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi.api.egg-info/SOURCES.txt +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi.api.egg-info/dependency_links.txt +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi.api.egg-info/not-zip-safe +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi.api.egg-info/top_level.txt +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/tests/test_api.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/tests/test_middleware.py +0 -0
- {stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/tests/test_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: stac-fastapi.api
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2.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
|
|
@@ -19,7 +19,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
Requires-Dist: brotli_asgi
|
|
22
|
-
Requires-Dist: stac-fastapi.types~=5.
|
|
22
|
+
Requires-Dist: stac-fastapi.types~=5.2
|
|
23
23
|
Provides-Extra: dev
|
|
24
24
|
Requires-Dist: httpx; extra == "dev"
|
|
25
25
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -30,9 +30,12 @@ Requires-Dist: requests; extra == "dev"
|
|
|
30
30
|
Provides-Extra: benchmark
|
|
31
31
|
Requires-Dist: pytest-benchmark; extra == "benchmark"
|
|
32
32
|
Provides-Extra: docs
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist: mkdocs
|
|
35
|
-
Requires-Dist:
|
|
33
|
+
Requires-Dist: black>=23.10.1; extra == "docs"
|
|
34
|
+
Requires-Dist: mkdocs>=1.4.3; extra == "docs"
|
|
35
|
+
Requires-Dist: mkdocs-jupyter>=0.24.5; extra == "docs"
|
|
36
|
+
Requires-Dist: mkdocs-material[imaging]>=9.5; extra == "docs"
|
|
37
|
+
Requires-Dist: griffe-inherited-docstrings>=1.0.0; extra == "docs"
|
|
38
|
+
Requires-Dist: mkdocstrings[python]>=0.25.1; extra == "docs"
|
|
36
39
|
Dynamic: author
|
|
37
40
|
Dynamic: author-email
|
|
38
41
|
Dynamic: classifier
|
|
@@ -7,7 +7,7 @@ with open("README.md") as f:
|
|
|
7
7
|
|
|
8
8
|
install_requires = [
|
|
9
9
|
"brotli_asgi",
|
|
10
|
-
"stac-fastapi.types~=5.
|
|
10
|
+
"stac-fastapi.types~=5.2",
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
extra_reqs = {
|
|
@@ -22,7 +22,14 @@ extra_reqs = {
|
|
|
22
22
|
"benchmark": [
|
|
23
23
|
"pytest-benchmark",
|
|
24
24
|
],
|
|
25
|
-
"docs": [
|
|
25
|
+
"docs": [
|
|
26
|
+
"black>=23.10.1",
|
|
27
|
+
"mkdocs>=1.4.3",
|
|
28
|
+
"mkdocs-jupyter>=0.24.5",
|
|
29
|
+
"mkdocs-material[imaging]>=9.5",
|
|
30
|
+
"griffe-inherited-docstrings>=1.0.0",
|
|
31
|
+
"mkdocstrings[python]>=0.25.1",
|
|
32
|
+
],
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Fastapi app creation."""
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
from typing import Dict, List, Optional, Tuple, Type, Union
|
|
4
|
+
from typing import Awaitable, Callable, Dict, List, Optional, Tuple, Type, Union
|
|
5
5
|
|
|
6
6
|
import attr
|
|
7
7
|
from brotli_asgi import BrotliMiddleware
|
|
@@ -25,7 +25,12 @@ from stac_fastapi.api.models import (
|
|
|
25
25
|
ItemUri,
|
|
26
26
|
)
|
|
27
27
|
from stac_fastapi.api.openapi import update_openapi
|
|
28
|
-
from stac_fastapi.api.routes import
|
|
28
|
+
from stac_fastapi.api.routes import (
|
|
29
|
+
Scope,
|
|
30
|
+
add_direct_response,
|
|
31
|
+
add_route_dependencies,
|
|
32
|
+
create_async_endpoint,
|
|
33
|
+
)
|
|
29
34
|
from stac_fastapi.types.config import ApiSettings, Settings
|
|
30
35
|
from stac_fastapi.types.core import AsyncBaseCoreClient, BaseCoreClient
|
|
31
36
|
from stac_fastapi.types.extension import ApiExtension
|
|
@@ -62,6 +67,10 @@ class StacApi:
|
|
|
62
67
|
specified routes. This is useful
|
|
63
68
|
for applying custom auth requirements to routes defined elsewhere in
|
|
64
69
|
the application.
|
|
70
|
+
health_check:
|
|
71
|
+
A Callable which return application's `health` information.
|
|
72
|
+
Defaults to `def health: return {"status": "UP"}`
|
|
73
|
+
|
|
65
74
|
"""
|
|
66
75
|
|
|
67
76
|
settings: ApiSettings = attr.ib()
|
|
@@ -123,6 +132,9 @@ class StacApi:
|
|
|
123
132
|
)
|
|
124
133
|
)
|
|
125
134
|
route_dependencies: List[Tuple[List[Scope], List[Depends]]] = attr.ib(default=[])
|
|
135
|
+
health_check: Union[Callable[[], Dict], Callable[[], Awaitable[Dict]]] = attr.ib(
|
|
136
|
+
default=lambda: {"status": "UP"}
|
|
137
|
+
)
|
|
126
138
|
|
|
127
139
|
def get_extension(self, extension: Type[ApiExtension]) -> Optional[ApiExtension]:
|
|
128
140
|
"""Get an extension.
|
|
@@ -138,12 +150,8 @@ class StacApi:
|
|
|
138
150
|
return ext
|
|
139
151
|
return None
|
|
140
152
|
|
|
141
|
-
def register_landing_page(self):
|
|
142
|
-
"""Register landing page (GET /).
|
|
143
|
-
|
|
144
|
-
Returns:
|
|
145
|
-
None
|
|
146
|
-
"""
|
|
153
|
+
def register_landing_page(self) -> None:
|
|
154
|
+
"""Register landing page (GET /)."""
|
|
147
155
|
self.router.add_api_route(
|
|
148
156
|
name="Landing Page",
|
|
149
157
|
path="/",
|
|
@@ -165,12 +173,8 @@ class StacApi:
|
|
|
165
173
|
endpoint=create_async_endpoint(self.client.landing_page, EmptyRequest),
|
|
166
174
|
)
|
|
167
175
|
|
|
168
|
-
def register_conformance_classes(self):
|
|
169
|
-
"""Register conformance classes (GET /conformance).
|
|
170
|
-
|
|
171
|
-
Returns:
|
|
172
|
-
None
|
|
173
|
-
"""
|
|
176
|
+
def register_conformance_classes(self) -> None:
|
|
177
|
+
"""Register conformance classes (GET /conformance)."""
|
|
174
178
|
self.router.add_api_route(
|
|
175
179
|
name="Conformance Classes",
|
|
176
180
|
path="/conformance",
|
|
@@ -192,12 +196,8 @@ class StacApi:
|
|
|
192
196
|
endpoint=create_async_endpoint(self.client.conformance, EmptyRequest),
|
|
193
197
|
)
|
|
194
198
|
|
|
195
|
-
def register_get_item(self):
|
|
196
|
-
"""Register get item endpoint (GET /collections/{collection_id}/items/{item_id}).
|
|
197
|
-
|
|
198
|
-
Returns:
|
|
199
|
-
None
|
|
200
|
-
"""
|
|
199
|
+
def register_get_item(self) -> None:
|
|
200
|
+
"""Register get item endpoint (GET /collections/{collection_id}/items/{item_id}).""" # noqa: E501
|
|
201
201
|
self.router.add_api_route(
|
|
202
202
|
name="Get Item",
|
|
203
203
|
path="/collections/{collection_id}/items/{item_id}",
|
|
@@ -219,12 +219,8 @@ class StacApi:
|
|
|
219
219
|
),
|
|
220
220
|
)
|
|
221
221
|
|
|
222
|
-
def register_post_search(self):
|
|
223
|
-
"""Register search endpoint (POST /search).
|
|
224
|
-
|
|
225
|
-
Returns:
|
|
226
|
-
None
|
|
227
|
-
"""
|
|
222
|
+
def register_post_search(self) -> None:
|
|
223
|
+
"""Register search endpoint (POST /search)."""
|
|
228
224
|
self.router.add_api_route(
|
|
229
225
|
name="Search",
|
|
230
226
|
path="/search",
|
|
@@ -248,12 +244,8 @@ class StacApi:
|
|
|
248
244
|
),
|
|
249
245
|
)
|
|
250
246
|
|
|
251
|
-
def register_get_search(self):
|
|
252
|
-
"""Register search endpoint (GET /search).
|
|
253
|
-
|
|
254
|
-
Returns:
|
|
255
|
-
None
|
|
256
|
-
"""
|
|
247
|
+
def register_get_search(self) -> None:
|
|
248
|
+
"""Register search endpoint (GET /search)."""
|
|
257
249
|
self.router.add_api_route(
|
|
258
250
|
name="Search",
|
|
259
251
|
path="/search",
|
|
@@ -277,12 +269,8 @@ class StacApi:
|
|
|
277
269
|
),
|
|
278
270
|
)
|
|
279
271
|
|
|
280
|
-
def register_get_collections(self):
|
|
281
|
-
"""Register get collections endpoint (GET /collections).
|
|
282
|
-
|
|
283
|
-
Returns:
|
|
284
|
-
None
|
|
285
|
-
"""
|
|
272
|
+
def register_get_collections(self) -> None:
|
|
273
|
+
"""Register get collections endpoint (GET /collections)."""
|
|
286
274
|
self.router.add_api_route(
|
|
287
275
|
name="Get Collections",
|
|
288
276
|
path="/collections",
|
|
@@ -306,12 +294,8 @@ class StacApi:
|
|
|
306
294
|
),
|
|
307
295
|
)
|
|
308
296
|
|
|
309
|
-
def register_get_collection(self):
|
|
310
|
-
"""Register get collection endpoint (GET /collection/{collection_id}).
|
|
311
|
-
|
|
312
|
-
Returns:
|
|
313
|
-
None
|
|
314
|
-
"""
|
|
297
|
+
def register_get_collection(self) -> None:
|
|
298
|
+
"""Register get collection endpoint (GET /collection/{collection_id})."""
|
|
315
299
|
self.router.add_api_route(
|
|
316
300
|
name="Get Collection",
|
|
317
301
|
path="/collections/{collection_id}",
|
|
@@ -335,12 +319,8 @@ class StacApi:
|
|
|
335
319
|
),
|
|
336
320
|
)
|
|
337
321
|
|
|
338
|
-
def register_get_item_collection(self):
|
|
339
|
-
"""Register get item collection endpoint (GET /collection/{collection_id}/items).
|
|
340
|
-
|
|
341
|
-
Returns:
|
|
342
|
-
None
|
|
343
|
-
"""
|
|
322
|
+
def register_get_item_collection(self) -> None:
|
|
323
|
+
"""Register get item collection endpoint (GET /collection/{collection_id}/items).""" # noqa: E501
|
|
344
324
|
self.router.add_api_route(
|
|
345
325
|
name="Get ItemCollection",
|
|
346
326
|
path="/collections/{collection_id}/items",
|
|
@@ -364,7 +344,7 @@ class StacApi:
|
|
|
364
344
|
),
|
|
365
345
|
)
|
|
366
346
|
|
|
367
|
-
def register_core(self):
|
|
347
|
+
def register_core(self) -> None:
|
|
368
348
|
"""Register core STAC endpoints.
|
|
369
349
|
|
|
370
350
|
GET /
|
|
@@ -378,8 +358,6 @@ class StacApi:
|
|
|
378
358
|
|
|
379
359
|
Injects application logic (StacApi.client) into the API layer.
|
|
380
360
|
|
|
381
|
-
Returns:
|
|
382
|
-
None
|
|
383
361
|
"""
|
|
384
362
|
self.register_landing_page()
|
|
385
363
|
self.register_conformance_classes()
|
|
@@ -390,41 +368,68 @@ class StacApi:
|
|
|
390
368
|
self.register_get_collection()
|
|
391
369
|
self.register_get_item_collection()
|
|
392
370
|
|
|
393
|
-
def add_health_check(self):
|
|
371
|
+
def add_health_check(self) -> None:
|
|
394
372
|
"""Add a health check."""
|
|
373
|
+
|
|
395
374
|
mgmt_router = APIRouter(prefix=self.app.state.router_prefix)
|
|
396
375
|
|
|
397
|
-
@mgmt_router.get("/_mgmt/ping")
|
|
398
376
|
async def ping():
|
|
399
|
-
"""Liveliness
|
|
377
|
+
"""Liveliness probe."""
|
|
400
378
|
return {"message": "PONG"}
|
|
401
379
|
|
|
380
|
+
mgmt_router.add_api_route(
|
|
381
|
+
name="Ping",
|
|
382
|
+
path="/_mgmt/ping",
|
|
383
|
+
response_model=Dict,
|
|
384
|
+
responses={
|
|
385
|
+
200: {
|
|
386
|
+
"content": {
|
|
387
|
+
MimeTypes.json.value: {},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
response_class=self.response_class,
|
|
392
|
+
methods=["GET"],
|
|
393
|
+
endpoint=ping,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
mgmt_router.add_api_route(
|
|
397
|
+
name="Health",
|
|
398
|
+
path="/_mgmt/health",
|
|
399
|
+
response_model=Dict,
|
|
400
|
+
responses={
|
|
401
|
+
200: {
|
|
402
|
+
"content": {
|
|
403
|
+
MimeTypes.json.value: {},
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
response_class=self.response_class,
|
|
408
|
+
methods=["GET"],
|
|
409
|
+
endpoint=self.health_check,
|
|
410
|
+
)
|
|
402
411
|
self.app.include_router(mgmt_router, tags=["Liveliness/Readiness"])
|
|
403
412
|
|
|
404
413
|
def add_route_dependencies(
|
|
405
|
-
self, scopes: List[Scope], dependencies
|
|
414
|
+
self, scopes: List[Scope], dependencies: List[Depends]
|
|
406
415
|
) -> None:
|
|
407
416
|
"""Add custom dependencies to routes.
|
|
408
417
|
|
|
409
418
|
Args:
|
|
410
|
-
scopes: list of
|
|
411
|
-
and `method` property.
|
|
412
|
-
dependencies: list of
|
|
413
|
-
dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/)
|
|
419
|
+
scopes: list of Scope.
|
|
420
|
+
Each scope should be a dict with a `path` and `method` property.
|
|
421
|
+
dependencies: list of fastapi.Depends
|
|
422
|
+
[FastAPI dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/)
|
|
414
423
|
to apply to each scope.
|
|
415
424
|
|
|
416
|
-
Returns:
|
|
417
|
-
None
|
|
418
425
|
"""
|
|
419
426
|
return add_route_dependencies(self.app.router.routes, scopes, dependencies)
|
|
420
427
|
|
|
421
|
-
def __attrs_post_init__(self):
|
|
428
|
+
def __attrs_post_init__(self) -> None:
|
|
422
429
|
"""Post-init hook.
|
|
423
430
|
|
|
424
431
|
Responsible for setting up the application upon instantiation of the class.
|
|
425
432
|
|
|
426
|
-
Returns:
|
|
427
|
-
None
|
|
428
433
|
"""
|
|
429
434
|
# inject settings
|
|
430
435
|
self.client.extensions = self.extensions
|
|
@@ -463,3 +468,6 @@ class StacApi:
|
|
|
463
468
|
# customize route dependencies
|
|
464
469
|
for scopes, dependencies in self.route_dependencies:
|
|
465
470
|
self.add_route_dependencies(scopes=scopes, dependencies=dependencies)
|
|
471
|
+
|
|
472
|
+
if self.app.state.settings.enable_direct_response:
|
|
473
|
+
add_direct_response(self.app)
|
|
@@ -82,7 +82,7 @@ class ProxyHeaderMiddleware:
|
|
|
82
82
|
|
|
83
83
|
await self.app(scope, receive, send)
|
|
84
84
|
|
|
85
|
-
def _get_forwarded_url_parts(self, scope: Scope) -> Tuple[str]:
|
|
85
|
+
def _get_forwarded_url_parts(self, scope: Scope) -> Tuple[str, str, str]:
|
|
86
86
|
proto = scope.get("scheme", "http")
|
|
87
87
|
header_host = self._get_header_value_by_name(scope, "host")
|
|
88
88
|
if header_host is None:
|
|
@@ -127,7 +127,7 @@ class ProxyHeaderMiddleware:
|
|
|
127
127
|
@staticmethod
|
|
128
128
|
def _replace_header_value_by_name(
|
|
129
129
|
scope: Scope, header_name: str, new_value: str
|
|
130
|
-
) -> List[Tuple[str]]:
|
|
130
|
+
) -> List[Tuple[str, str]]:
|
|
131
131
|
return [
|
|
132
132
|
(name, value)
|
|
133
133
|
for name, value in scope["headers"]
|
|
@@ -5,13 +5,15 @@ import functools
|
|
|
5
5
|
import inspect
|
|
6
6
|
from typing import Any, Callable, Dict, List, Optional, Type, TypedDict, Union
|
|
7
7
|
|
|
8
|
-
from fastapi import Depends, params
|
|
9
|
-
from fastapi.
|
|
8
|
+
from fastapi import Depends, FastAPI, params
|
|
9
|
+
from fastapi.datastructures import DefaultPlaceholder
|
|
10
|
+
from fastapi.dependencies.utils import get_dependant, get_parameterless_sub_dependant
|
|
11
|
+
from fastapi.routing import APIRoute
|
|
10
12
|
from pydantic import BaseModel
|
|
11
13
|
from starlette.concurrency import run_in_threadpool
|
|
12
14
|
from starlette.requests import Request
|
|
13
15
|
from starlette.responses import Response
|
|
14
|
-
from starlette.routing import BaseRoute, Match
|
|
16
|
+
from starlette.routing import BaseRoute, Match, request_response
|
|
15
17
|
from starlette.status import HTTP_204_NO_CONTENT
|
|
16
18
|
|
|
17
19
|
from stac_fastapi.api.models import APIRequest
|
|
@@ -86,7 +88,7 @@ class Scope(TypedDict, total=False):
|
|
|
86
88
|
|
|
87
89
|
|
|
88
90
|
def add_route_dependencies(
|
|
89
|
-
routes: List[BaseRoute], scopes: List[Scope], dependencies
|
|
91
|
+
routes: List[BaseRoute], scopes: List[Scope], dependencies: List[params.Depends]
|
|
90
92
|
) -> None:
|
|
91
93
|
"""Add dependencies to routes.
|
|
92
94
|
|
|
@@ -131,3 +133,33 @@ def add_route_dependencies(
|
|
|
131
133
|
# https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/applications.py#L337-L360
|
|
132
134
|
# https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/routing.py#L677-L678
|
|
133
135
|
route.dependencies.extend(dependencies)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def add_direct_response(app: FastAPI) -> None:
|
|
139
|
+
"""
|
|
140
|
+
Setup FastAPI application's endpoints to return Response Object directly, avoiding
|
|
141
|
+
Pydantic validation and FastAPI (slow) serialization.
|
|
142
|
+
|
|
143
|
+
ref: https://gist.github.com/Zaczero/00f3a2679ebc0a25eb938ed82bc63553
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
def wrap_endpoint(endpoint: Callable, cls: Type[Response]):
|
|
147
|
+
@functools.wraps(endpoint)
|
|
148
|
+
async def wrapper(*args, **kwargs):
|
|
149
|
+
content = await endpoint(*args, **kwargs)
|
|
150
|
+
return content if isinstance(content, Response) else cls(content)
|
|
151
|
+
|
|
152
|
+
return wrapper
|
|
153
|
+
|
|
154
|
+
for route in app.routes:
|
|
155
|
+
if not isinstance(route, APIRoute):
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
response_class = route.response_class
|
|
159
|
+
if isinstance(response_class, DefaultPlaceholder):
|
|
160
|
+
response_class = response_class.value
|
|
161
|
+
|
|
162
|
+
if issubclass(response_class, Response):
|
|
163
|
+
route.endpoint = wrap_endpoint(route.endpoint, response_class)
|
|
164
|
+
route.dependant = get_dependant(path=route.path_format, call=route.endpoint)
|
|
165
|
+
route.app = request_response(route.get_route_handler())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: stac-fastapi.api
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2.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
|
|
@@ -19,7 +19,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
Requires-Dist: brotli_asgi
|
|
22
|
-
Requires-Dist: stac-fastapi.types~=5.
|
|
22
|
+
Requires-Dist: stac-fastapi.types~=5.2
|
|
23
23
|
Provides-Extra: dev
|
|
24
24
|
Requires-Dist: httpx; extra == "dev"
|
|
25
25
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -30,9 +30,12 @@ Requires-Dist: requests; extra == "dev"
|
|
|
30
30
|
Provides-Extra: benchmark
|
|
31
31
|
Requires-Dist: pytest-benchmark; extra == "benchmark"
|
|
32
32
|
Provides-Extra: docs
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist: mkdocs
|
|
35
|
-
Requires-Dist:
|
|
33
|
+
Requires-Dist: black>=23.10.1; extra == "docs"
|
|
34
|
+
Requires-Dist: mkdocs>=1.4.3; extra == "docs"
|
|
35
|
+
Requires-Dist: mkdocs-jupyter>=0.24.5; extra == "docs"
|
|
36
|
+
Requires-Dist: mkdocs-material[imaging]>=9.5; extra == "docs"
|
|
37
|
+
Requires-Dist: griffe-inherited-docstrings>=1.0.0; extra == "docs"
|
|
38
|
+
Requires-Dist: mkdocstrings[python]>=0.25.1; extra == "docs"
|
|
36
39
|
Dynamic: author
|
|
37
40
|
Dynamic: author-email
|
|
38
41
|
Dynamic: classifier
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
brotli_asgi
|
|
2
|
+
stac-fastapi.types~=5.2
|
|
3
|
+
|
|
4
|
+
[benchmark]
|
|
5
|
+
pytest-benchmark
|
|
6
|
+
|
|
7
|
+
[dev]
|
|
8
|
+
httpx
|
|
9
|
+
pytest
|
|
10
|
+
pytest-cov
|
|
11
|
+
pytest-asyncio
|
|
12
|
+
pre-commit
|
|
13
|
+
requests
|
|
14
|
+
|
|
15
|
+
[docs]
|
|
16
|
+
black>=23.10.1
|
|
17
|
+
mkdocs>=1.4.3
|
|
18
|
+
mkdocs-jupyter>=0.24.5
|
|
19
|
+
mkdocs-material[imaging]>=9.5
|
|
20
|
+
griffe-inherited-docstrings>=1.0.0
|
|
21
|
+
mkdocstrings[python]>=0.25.1
|
|
@@ -6,6 +6,7 @@ from fastapi import Path, Query
|
|
|
6
6
|
from fastapi.testclient import TestClient
|
|
7
7
|
from pydantic import ValidationError
|
|
8
8
|
from stac_pydantic import api
|
|
9
|
+
from starlette.requests import Request
|
|
9
10
|
from typing_extensions import Annotated
|
|
10
11
|
|
|
11
12
|
from stac_fastapi.api import app
|
|
@@ -108,6 +109,31 @@ def test_client_invalid_response_type(validate, TestCoreClient, item_dict):
|
|
|
108
109
|
assert item.status_code == 200, item.text
|
|
109
110
|
|
|
110
111
|
|
|
112
|
+
def test_client_response_by_pass(TestCoreClient, item_dict):
|
|
113
|
+
"""Check with `enable_direct_response` option."""
|
|
114
|
+
|
|
115
|
+
class InValidResponseClient(TestCoreClient):
|
|
116
|
+
def get_item(self, item_id: str, collection_id: str, **kwargs) -> stac.Item:
|
|
117
|
+
item_dict.pop("bbox", None)
|
|
118
|
+
item_dict.pop("geometry", None)
|
|
119
|
+
return item_dict
|
|
120
|
+
|
|
121
|
+
test_app = app.StacApi(
|
|
122
|
+
settings=ApiSettings(
|
|
123
|
+
enable_response_models=False,
|
|
124
|
+
enable_direct_response=True,
|
|
125
|
+
),
|
|
126
|
+
client=InValidResponseClient(),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
with TestClient(test_app.app) as client:
|
|
130
|
+
item = client.get("/collections/test/items/test")
|
|
131
|
+
|
|
132
|
+
assert item.json()
|
|
133
|
+
assert item.status_code == 200
|
|
134
|
+
assert item.headers["content-type"] == "application/geo+json"
|
|
135
|
+
|
|
136
|
+
|
|
111
137
|
def test_client_openapi(TestCoreClient):
|
|
112
138
|
"""Test if response models are all documented with OpenAPI."""
|
|
113
139
|
|
|
@@ -504,3 +530,51 @@ def test_client_datetime_input_params():
|
|
|
504
530
|
assert post_search.json() == "2020-01-01T00:00:00.00001Z"
|
|
505
531
|
assert post_search_zero.status_code == 200, post_search_zero.text
|
|
506
532
|
assert post_search_zero.json() == "2020-01-01T00:00:00.0000Z"
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def test_mgmt_endpoints(AsyncTestCoreClient):
|
|
536
|
+
"""Test ping/health endpoints."""
|
|
537
|
+
|
|
538
|
+
test_app = app.StacApi(
|
|
539
|
+
settings=ApiSettings(),
|
|
540
|
+
client=AsyncTestCoreClient(),
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
with TestClient(test_app.app) as client:
|
|
544
|
+
resp = client.get("/_mgmt/ping")
|
|
545
|
+
assert resp.status_code == 200
|
|
546
|
+
assert resp.json() == {"message": "PONG"}
|
|
547
|
+
|
|
548
|
+
resp = client.get("/_mgmt/health")
|
|
549
|
+
assert resp.status_code == 200
|
|
550
|
+
assert resp.json() == {"status": "UP"}
|
|
551
|
+
|
|
552
|
+
def health_check(request: Request):
|
|
553
|
+
return {
|
|
554
|
+
"status": "UP",
|
|
555
|
+
"database": {
|
|
556
|
+
"status": "UP",
|
|
557
|
+
"version": "0.1.0",
|
|
558
|
+
},
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
test_app = app.StacApi(
|
|
562
|
+
settings=ApiSettings(),
|
|
563
|
+
client=AsyncTestCoreClient(),
|
|
564
|
+
health_check=health_check,
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
with TestClient(test_app.app) as client:
|
|
568
|
+
resp = client.get("/_mgmt/ping")
|
|
569
|
+
assert resp.status_code == 200
|
|
570
|
+
assert resp.json() == {"message": "PONG"}
|
|
571
|
+
|
|
572
|
+
resp = client.get("/_mgmt/health")
|
|
573
|
+
assert resp.status_code == 200
|
|
574
|
+
assert resp.json() == {
|
|
575
|
+
"status": "UP",
|
|
576
|
+
"database": {
|
|
577
|
+
"status": "UP",
|
|
578
|
+
"version": "0.1.0",
|
|
579
|
+
},
|
|
580
|
+
}
|
|
@@ -34,6 +34,9 @@ def test_api_prefix(TestCoreClient, prefix):
|
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
with TestClient(api.app, base_url="http://stac.io") as client:
|
|
37
|
+
ping = client.get(f"{prefix}/_mgmt/ping")
|
|
38
|
+
assert ping.status_code == 200, ping.json() == {"message": "PONG"}
|
|
39
|
+
|
|
37
40
|
landing = client.get(f"{prefix}/")
|
|
38
41
|
assert landing.status_code == 200, landing.json()
|
|
39
42
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stac_fastapi_api-5.1.1 → stac_fastapi_api-5.2.0}/stac_fastapi.api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|