stac-fastapi.api 6.2.0__tar.gz → 6.3.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-6.2.0 → stac_fastapi_api-6.3.0}/PKG-INFO +1 -1
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/app.py +10 -3
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/middleware.py +16 -7
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/routes.py +52 -42
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/version.py +1 -1
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/.gitignore +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/README.md +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/pyproject.toml +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/__init__.py +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/config.py +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/errors.py +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/models.py +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/openapi.py +0 -0
- {stac_fastapi_api-6.2.0 → stac_fastapi_api-6.3.0}/stac_fastapi/api/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stac-fastapi-api
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.3.0
|
|
4
4
|
Summary: An implementation of STAC API based on the FastAPI framework.
|
|
5
5
|
Project-URL: Homepage, https://github.com/stac-utils/stac-fastapi
|
|
6
6
|
Author-email: ArturoAI <engineering@arturo.ai>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Fastapi app creation."""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import inspect
|
|
5
4
|
from typing import Awaitable, Callable, Dict, List, Optional, Tuple, Type, Union
|
|
6
5
|
|
|
@@ -13,10 +12,11 @@ from stac_pydantic import api
|
|
|
13
12
|
from stac_pydantic.shared import MimeTypes
|
|
14
13
|
from stac_pydantic.version import STAC_VERSION
|
|
15
14
|
from starlette.middleware import Middleware
|
|
15
|
+
from starlette.middleware.cors import CORSMiddleware
|
|
16
16
|
from starlette.responses import Response
|
|
17
17
|
|
|
18
18
|
from stac_fastapi.api.errors import DEFAULT_STATUS_CODES, add_exception_handlers
|
|
19
|
-
from stac_fastapi.api.middleware import
|
|
19
|
+
from stac_fastapi.api.middleware import ProxyHeaderMiddleware
|
|
20
20
|
from stac_fastapi.api.models import (
|
|
21
21
|
APIRequest,
|
|
22
22
|
CollectionUri,
|
|
@@ -126,7 +126,14 @@ class StacApi:
|
|
|
126
126
|
default=attr.Factory(
|
|
127
127
|
lambda: [
|
|
128
128
|
Middleware(BrotliMiddleware),
|
|
129
|
-
Middleware(
|
|
129
|
+
Middleware(
|
|
130
|
+
CORSMiddleware,
|
|
131
|
+
# Set CORS defaults to those recommended by the STAC API spec
|
|
132
|
+
allow_origins=["*"],
|
|
133
|
+
allow_methods=["OPTIONS", "POST", "GET"],
|
|
134
|
+
allow_headers=["Content-Type"],
|
|
135
|
+
max_age=600,
|
|
136
|
+
),
|
|
130
137
|
Middleware(ProxyHeaderMiddleware),
|
|
131
138
|
]
|
|
132
139
|
)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import contextlib
|
|
4
4
|
import re
|
|
5
5
|
import typing
|
|
6
|
+
import warnings
|
|
6
7
|
from http.client import HTTP_PORT, HTTPS_PORT
|
|
7
8
|
from typing import List, Optional, Tuple
|
|
8
9
|
|
|
@@ -31,17 +32,25 @@ class CORSMiddleware(_CORSMiddleware):
|
|
|
31
32
|
allow_origin_regex: typing.Optional[str] = None,
|
|
32
33
|
expose_headers: typing.Sequence[str] = (),
|
|
33
34
|
max_age: int = 600,
|
|
35
|
+
**kwargs: typing.Any,
|
|
34
36
|
) -> None:
|
|
35
37
|
"""Create CORS middleware."""
|
|
38
|
+
warnings.warn(
|
|
39
|
+
"""stac_fastapi.api.middleware.CORSMiddleware is deprecated and
|
|
40
|
+
will be removed in a future release.
|
|
41
|
+
Please use starlette.middleware.cors.CORSMiddleware instead.""",
|
|
42
|
+
DeprecationWarning,
|
|
43
|
+
)
|
|
36
44
|
super().__init__(
|
|
37
45
|
app,
|
|
38
|
-
allow_origins,
|
|
39
|
-
allow_methods,
|
|
40
|
-
allow_headers,
|
|
41
|
-
allow_credentials,
|
|
42
|
-
allow_origin_regex,
|
|
43
|
-
expose_headers,
|
|
44
|
-
max_age,
|
|
46
|
+
allow_origins=allow_origins,
|
|
47
|
+
allow_methods=allow_methods,
|
|
48
|
+
allow_headers=allow_headers,
|
|
49
|
+
allow_credentials=allow_credentials,
|
|
50
|
+
allow_origin_regex=allow_origin_regex,
|
|
51
|
+
expose_headers=expose_headers,
|
|
52
|
+
max_age=max_age,
|
|
53
|
+
**kwargs,
|
|
45
54
|
)
|
|
46
55
|
|
|
47
56
|
|
|
@@ -83,6 +83,45 @@ class Scope(TypedDict, total=False):
|
|
|
83
83
|
type: Optional[str]
|
|
84
84
|
|
|
85
85
|
|
|
86
|
+
def _is_endpoint_route(route: BaseRoute) -> bool:
|
|
87
|
+
"""Check if route is a standard endpoint (not a mount or sub-router)."""
|
|
88
|
+
return (
|
|
89
|
+
hasattr(route, "path") and hasattr(route, "methods") and route.methods is not None
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _apply_dependencies_to_route(
|
|
94
|
+
route: BaseRoute, scopes: List[Scope], dependencies: List[params.Depends]
|
|
95
|
+
) -> None:
|
|
96
|
+
"""Apply dependencies to a single route matching the given scopes."""
|
|
97
|
+
for scope in scopes:
|
|
98
|
+
_scope = copy.deepcopy(scope)
|
|
99
|
+
|
|
100
|
+
if scope["path"] == "*":
|
|
101
|
+
_scope["path"] = route.path # type: ignore
|
|
102
|
+
|
|
103
|
+
if scope["method"] == "*":
|
|
104
|
+
_scope["method"] = list(route.methods)[0] # type: ignore
|
|
105
|
+
|
|
106
|
+
match, _ = route.matches({"type": "http", **_scope})
|
|
107
|
+
if match != Match.FULL:
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
if not hasattr(route, "dependant"):
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
for depends in dependencies[::-1]:
|
|
114
|
+
route.dependant.dependencies.insert(
|
|
115
|
+
0,
|
|
116
|
+
get_parameterless_sub_dependant(
|
|
117
|
+
depends=depends,
|
|
118
|
+
path=route.path_format, # type: ignore
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
route.dependencies.extend(dependencies) # type: ignore
|
|
123
|
+
|
|
124
|
+
|
|
86
125
|
def add_route_dependencies(
|
|
87
126
|
routes: List[BaseRoute], scopes: List[Scope], dependencies: List[params.Depends]
|
|
88
127
|
) -> None:
|
|
@@ -96,48 +135,19 @@ def add_route_dependencies(
|
|
|
96
135
|
Returns:
|
|
97
136
|
None
|
|
98
137
|
"""
|
|
99
|
-
for
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
match, _ = route.matches({"type": "http", **_scope})
|
|
113
|
-
if match != Match.FULL:
|
|
114
|
-
continue
|
|
115
|
-
|
|
116
|
-
# Ignore paths without dependants, e.g. /api, /api.html, /docs/oauth2-redirect
|
|
117
|
-
if not hasattr(route, "dependant"):
|
|
118
|
-
continue
|
|
119
|
-
|
|
120
|
-
# Mimicking how APIRoute handles dependencies:
|
|
121
|
-
# https://github.com/tiangolo/fastapi/blob/1760da0efa55585c19835d81afa8ca386036c325/fastapi/routing.py#L408-L412
|
|
122
|
-
for depends in dependencies[::-1]:
|
|
123
|
-
route.dependant.dependencies.insert(
|
|
124
|
-
0,
|
|
125
|
-
get_parameterless_sub_dependant(
|
|
126
|
-
# NOTE: ignore type, because BaseRoute has no "path_format"
|
|
127
|
-
# attribute but APIRoute does.
|
|
128
|
-
depends=depends,
|
|
129
|
-
path=route.path_format, # type: ignore
|
|
130
|
-
),
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
# Register dependencies directly on route so that they aren't ignored if
|
|
134
|
-
# the routes are later associated with an app (e.g.
|
|
135
|
-
# app.include_router(router))
|
|
136
|
-
# https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/applications.py#L337-L360
|
|
137
|
-
# https://github.com/tiangolo/fastapi/blob/58ab733f19846b4875c5b79bfb1f4d1cb7f4823f/fastapi/routing.py#L677-L678
|
|
138
|
-
# NOTE: ignore type, because BaseRoute has no "dependencies" attribute
|
|
139
|
-
# but APIRoute does.
|
|
140
|
-
route.dependencies.extend(dependencies) # type: ignore
|
|
138
|
+
for route in routes:
|
|
139
|
+
if hasattr(route, "original_router"):
|
|
140
|
+
add_route_dependencies(route.original_router.routes, scopes, dependencies)
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
if hasattr(route, "routes") and route.routes:
|
|
144
|
+
add_route_dependencies(route.routes, scopes, dependencies)
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
if not _is_endpoint_route(route):
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
_apply_dependencies_to_route(route, scopes, dependencies)
|
|
141
151
|
|
|
142
152
|
|
|
143
153
|
def add_direct_response(app: FastAPI) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|