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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stac-fastapi-api
3
- Version: 6.2.0
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 CORSMiddleware, ProxyHeaderMiddleware
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(CORSMiddleware),
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 scope in scopes:
100
- _scope = copy.deepcopy(scope)
101
- for route in routes:
102
- if scope["path"] == "*":
103
- # NOTE: ignore type, because BaseRoute has no "path" attribute
104
- # but APIRoute does.
105
- _scope["path"] = route.path # type: ignore
106
-
107
- # NOTE: ignore type, because BaseRoute has no "method" attribute
108
- # but APIRoute does.
109
- if scope["method"] == "*":
110
- _scope["method"] = list(route.methods)[0] # type: ignore
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:
@@ -1,3 +1,3 @@
1
1
  """Library version."""
2
2
 
3
- __version__ = "6.2.0"
3
+ __version__ = "6.3.0"