stac-fastapi.api 3.0.0a1__tar.gz → 3.0.0a3__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_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/PKG-INFO +1 -1
  2. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/app.py +0 -4
  3. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/config.py +1 -0
  4. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/routes.py +15 -1
  5. stac_fastapi_api-3.0.0a3/stac_fastapi/api/version.py +2 -0
  6. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi.api.egg-info/PKG-INFO +1 -1
  7. stac_fastapi_api-3.0.0a3/tests/test_api.py +447 -0
  8. stac_fastapi_api-3.0.0a1/stac_fastapi/api/version.py +0 -2
  9. stac_fastapi_api-3.0.0a1/tests/test_api.py +0 -172
  10. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/README.md +0 -0
  11. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/setup.cfg +0 -0
  12. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/setup.py +0 -0
  13. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/__init__.py +0 -0
  14. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/errors.py +0 -0
  15. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/middleware.py +0 -0
  16. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/models.py +0 -0
  17. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi/api/openapi.py +0 -0
  18. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi.api.egg-info/SOURCES.txt +0 -0
  19. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi.api.egg-info/dependency_links.txt +0 -0
  20. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi.api.egg-info/not-zip-safe +0 -0
  21. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi.api.egg-info/requires.txt +0 -0
  22. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/stac_fastapi.api.egg-info/top_level.txt +0 -0
  23. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/tests/test_app.py +0 -0
  24. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/tests/test_app_prefix.py +0 -0
  25. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/tests/test_middleware.py +0 -0
  26. {stac_fastapi_api-3.0.0a1 → stac_fastapi_api-3.0.0a3}/tests/test_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stac-fastapi.api
3
- Version: 3.0.0a1
3
+ Version: 3.0.0a3
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
@@ -458,10 +458,6 @@ class StacApi:
458
458
  self.client.title = self.title
459
459
  self.client.description = self.description
460
460
 
461
- fields_ext = self.get_extension(FieldsExtension)
462
- if fields_ext:
463
- self.settings.default_includes = fields_ext.default_includes
464
-
465
461
  Settings.set(self.settings)
466
462
  self.app.state.settings = self.settings
467
463
 
@@ -18,6 +18,7 @@ class ApiExtensions(enum.Enum):
18
18
  query = "query"
19
19
  sort = "sort"
20
20
  transaction = "transaction"
21
+ aggregation = "aggregation"
21
22
 
22
23
 
23
24
  class AddOns(enum.Enum):
@@ -1,5 +1,6 @@
1
1
  """Route factories."""
2
2
 
3
+ import copy
3
4
  import functools
4
5
  import inspect
5
6
  import warnings
@@ -100,15 +101,28 @@ def add_route_dependencies(
100
101
  Allows a developer to add dependencies to a route after the route has been
101
102
  defined.
102
103
 
104
+ "*" can be used for path or method to match all allowed routes.
105
+
103
106
  Returns:
104
107
  None
105
108
  """
106
109
  for scope in scopes:
110
+ _scope = copy.deepcopy(scope)
107
111
  for route in routes:
108
- match, _ = route.matches({"type": "http", **scope})
112
+ if scope["path"] == "*":
113
+ _scope["path"] = route.path
114
+
115
+ if scope["method"] == "*":
116
+ _scope["method"] = list(route.methods)[0]
117
+
118
+ match, _ = route.matches({"type": "http", **_scope})
109
119
  if match != Match.FULL:
110
120
  continue
111
121
 
122
+ # Ignore paths without dependants, e.g. /api, /api.html, /docs/oauth2-redirect
123
+ if not hasattr(route, "dependant"):
124
+ continue
125
+
112
126
  # Mimicking how APIRoute handles dependencies:
113
127
  # https://github.com/tiangolo/fastapi/blob/1760da0efa55585c19835d81afa8ca386036c325/fastapi/routing.py#L408-L412
114
128
  for depends in dependencies[::-1]:
@@ -0,0 +1,2 @@
1
+ """Library version."""
2
+ __version__ = "3.0.0a3"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stac-fastapi.api
3
- Version: 3.0.0a1
3
+ Version: 3.0.0a3
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
@@ -0,0 +1,447 @@
1
+ from fastapi import Depends, HTTPException, security, status
2
+ from starlette.testclient import TestClient
3
+
4
+ from stac_fastapi.api.app import StacApi
5
+ from stac_fastapi.extensions.core import (
6
+ TokenPaginationExtension,
7
+ TransactionExtension,
8
+ )
9
+ from stac_fastapi.types import config, core
10
+
11
+
12
+ class TestRouteDependencies:
13
+ @staticmethod
14
+ def _build_api(**overrides):
15
+ settings = config.ApiSettings()
16
+ return StacApi(
17
+ **{
18
+ "settings": settings,
19
+ "client": DummyCoreClient(),
20
+ "extensions": [
21
+ TransactionExtension(
22
+ client=DummyTransactionsClient(), settings=settings
23
+ ),
24
+ TokenPaginationExtension(),
25
+ ],
26
+ **overrides,
27
+ }
28
+ )
29
+
30
+ @staticmethod
31
+ def _assert_dependency_applied(api, routes):
32
+ with TestClient(api.app) as client:
33
+ for route in routes:
34
+ response = getattr(client, route["method"].lower())(route["path"])
35
+ assert (
36
+ response.status_code == 401
37
+ ), "Unauthenticated requests should be rejected"
38
+ assert response.json() == {"detail": "Not authenticated"}
39
+
40
+ path = route["path"].format(
41
+ collectionId="test_collection", itemId="test_item"
42
+ )
43
+ response = client.request(
44
+ method=route["method"].lower(),
45
+ url=path,
46
+ auth=("bob", "dobbs"),
47
+ content=route["payload"],
48
+ headers={"content-type": "application/json"},
49
+ )
50
+ assert (
51
+ 200 <= response.status_code < 300
52
+ ), "Authenticated requests should be accepted"
53
+ assert response.json() == "dummy response"
54
+
55
+ @staticmethod
56
+ def _assert_dependency_not_applied(api, routes):
57
+ with TestClient(api.app) as client:
58
+ for route in routes:
59
+ path = route["path"].format(
60
+ collectionId="test_collection", itemId="test_item"
61
+ )
62
+ response = client.request(
63
+ method=route["method"].lower(),
64
+ url=path,
65
+ content=route["payload"],
66
+ headers={"content-type": "application/json"},
67
+ )
68
+ assert (
69
+ 200 <= response.status_code < 300
70
+ ), "Authenticated requests should be accepted"
71
+ assert response.json() == "dummy response"
72
+
73
+ def test_openapi_content_type(self):
74
+ api = self._build_api()
75
+ with TestClient(api.app) as client:
76
+ response = client.get(api.settings.openapi_url)
77
+ assert (
78
+ response.headers["content-type"]
79
+ == "application/vnd.oai.openapi+json;version=3.0"
80
+ )
81
+
82
+ def test_build_api_with_route_dependencies(self, collection, item):
83
+ routes = [
84
+ {"path": "/collections", "method": "POST", "payload": collection},
85
+ {
86
+ "path": "/collections/{collectionId}",
87
+ "method": "PUT",
88
+ "payload": collection,
89
+ },
90
+ {"path": "/collections/{collectionId}", "method": "DELETE", "payload": ""},
91
+ {
92
+ "path": "/collections/{collectionId}/items",
93
+ "method": "POST",
94
+ "payload": item,
95
+ },
96
+ {
97
+ "path": "/collections/{collectionId}/items/{itemId}",
98
+ "method": "PUT",
99
+ "payload": item,
100
+ },
101
+ {
102
+ "path": "/collections/{collectionId}/items/{itemId}",
103
+ "method": "DELETE",
104
+ "payload": "",
105
+ },
106
+ ]
107
+ dependencies = [Depends(must_be_bob)]
108
+ api = self._build_api(route_dependencies=[(routes, dependencies)])
109
+ self._assert_dependency_applied(api, routes)
110
+
111
+ def test_add_route_dependencies_after_building_api(self, collection, item):
112
+ routes = [
113
+ {"path": "/collections", "method": "POST", "payload": collection},
114
+ {
115
+ "path": "/collections/{collectionId}",
116
+ "method": "PUT",
117
+ "payload": collection,
118
+ },
119
+ {"path": "/collections/{collectionId}", "method": "DELETE", "payload": ""},
120
+ {
121
+ "path": "/collections/{collectionId}/items",
122
+ "method": "POST",
123
+ "payload": item,
124
+ },
125
+ {
126
+ "path": "/collections/{collectionId}/items/{itemId}",
127
+ "method": "PUT",
128
+ "payload": item,
129
+ },
130
+ {
131
+ "path": "/collections/{collectionId}/items/{itemId}",
132
+ "method": "DELETE",
133
+ "payload": "",
134
+ },
135
+ ]
136
+ api = self._build_api()
137
+ api.add_route_dependencies(scopes=routes, dependencies=[Depends(must_be_bob)])
138
+ self._assert_dependency_applied(api, routes)
139
+
140
+ def test_build_api_with_default_route_dependencies(self, collection, item):
141
+ routes = [{"path": "*", "method": "*"}]
142
+ test_routes = [
143
+ {"path": "/collections", "method": "POST", "payload": collection},
144
+ {
145
+ "path": "/collections/{collectionId}",
146
+ "method": "PUT",
147
+ "payload": collection,
148
+ },
149
+ {"path": "/collections/{collectionId}", "method": "DELETE", "payload": ""},
150
+ {
151
+ "path": "/collections/{collectionId}/items",
152
+ "method": "POST",
153
+ "payload": item,
154
+ },
155
+ {
156
+ "path": "/collections/{collectionId}/items/{itemId}",
157
+ "method": "PUT",
158
+ "payload": item,
159
+ },
160
+ {
161
+ "path": "/collections/{collectionId}/items/{itemId}",
162
+ "method": "DELETE",
163
+ "payload": "",
164
+ },
165
+ ]
166
+ dependencies = [Depends(must_be_bob)]
167
+ api = self._build_api(route_dependencies=[(routes, dependencies)])
168
+ self._assert_dependency_applied(api, test_routes)
169
+
170
+ def test_build_api_with_default_path_route_dependencies(self, collection, item):
171
+ routes = [{"path": "*", "method": "POST"}]
172
+ test_routes = [
173
+ {
174
+ "path": "/collections",
175
+ "method": "POST",
176
+ "payload": collection,
177
+ },
178
+ {
179
+ "path": "/collections/{collectionId}/items",
180
+ "method": "POST",
181
+ "payload": item,
182
+ },
183
+ ]
184
+ test_not_routes = [
185
+ {
186
+ "path": "/collections/{collectionId}",
187
+ "method": "PUT",
188
+ "payload": collection,
189
+ },
190
+ {
191
+ "path": "/collections/{collectionId}",
192
+ "method": "DELETE",
193
+ "payload": "",
194
+ },
195
+ {
196
+ "path": "/collections/{collectionId}/items/{itemId}",
197
+ "method": "PUT",
198
+ "payload": item,
199
+ },
200
+ {
201
+ "path": "/collections/{collectionId}/items/{itemId}",
202
+ "method": "DELETE",
203
+ "payload": "",
204
+ },
205
+ ]
206
+ dependencies = [Depends(must_be_bob)]
207
+ api = self._build_api(route_dependencies=[(routes, dependencies)])
208
+ self._assert_dependency_applied(api, test_routes)
209
+ self._assert_dependency_not_applied(api, test_not_routes)
210
+
211
+ def test_build_api_with_default_method_route_dependencies(self, collection, item):
212
+ routes = [
213
+ {
214
+ "path": "/collections/{collectionId}",
215
+ "method": "*",
216
+ },
217
+ {
218
+ "path": "/collections/{collectionId}/items/{itemId}",
219
+ "method": "*",
220
+ },
221
+ ]
222
+ test_routes = [
223
+ {
224
+ "path": "/collections/{collectionId}",
225
+ "method": "PUT",
226
+ "payload": collection,
227
+ },
228
+ {
229
+ "path": "/collections/{collectionId}",
230
+ "method": "DELETE",
231
+ "payload": "",
232
+ },
233
+ {
234
+ "path": "/collections/{collectionId}/items/{itemId}",
235
+ "method": "PUT",
236
+ "payload": item,
237
+ },
238
+ {
239
+ "path": "/collections/{collectionId}/items/{itemId}",
240
+ "method": "DELETE",
241
+ "payload": "",
242
+ },
243
+ ]
244
+ test_not_routes = [
245
+ {
246
+ "path": "/collections",
247
+ "method": "POST",
248
+ "payload": collection,
249
+ },
250
+ {
251
+ "path": "/collections/{collectionId}/items",
252
+ "method": "POST",
253
+ "payload": item,
254
+ },
255
+ ]
256
+ dependencies = [Depends(must_be_bob)]
257
+ api = self._build_api(route_dependencies=[(routes, dependencies)])
258
+ self._assert_dependency_applied(api, test_routes)
259
+ self._assert_dependency_not_applied(api, test_not_routes)
260
+
261
+ def test_add_default_route_dependencies_after_building_api(self, collection, item):
262
+ routes = [{"path": "*", "method": "*"}]
263
+ test_routes = [
264
+ {
265
+ "path": "/collections",
266
+ "method": "POST",
267
+ "payload": collection,
268
+ },
269
+ {
270
+ "path": "/collections/{collectionId}",
271
+ "method": "PUT",
272
+ "payload": collection,
273
+ },
274
+ {
275
+ "path": "/collections/{collectionId}",
276
+ "method": "DELETE",
277
+ "payload": "",
278
+ },
279
+ {
280
+ "path": "/collections/{collectionId}/items",
281
+ "method": "POST",
282
+ "payload": item,
283
+ },
284
+ {
285
+ "path": "/collections/{collectionId}/items/{itemId}",
286
+ "method": "PUT",
287
+ "payload": item,
288
+ },
289
+ {
290
+ "path": "/collections/{collectionId}/items/{itemId}",
291
+ "method": "DELETE",
292
+ "payload": "",
293
+ },
294
+ ]
295
+ api = self._build_api()
296
+ api.add_route_dependencies(scopes=routes, dependencies=[Depends(must_be_bob)])
297
+ self._assert_dependency_applied(api, test_routes)
298
+
299
+ def test_add_default_path_route_dependencies_after_building_api(
300
+ self, collection, item
301
+ ):
302
+ routes = [{"path": "*", "method": "POST"}]
303
+ test_routes = [
304
+ {
305
+ "path": "/collections",
306
+ "method": "POST",
307
+ "payload": collection,
308
+ },
309
+ {
310
+ "path": "/collections/{collectionId}/items",
311
+ "method": "POST",
312
+ "payload": item,
313
+ },
314
+ ]
315
+ test_not_routes = [
316
+ {
317
+ "path": "/collections/{collectionId}",
318
+ "method": "PUT",
319
+ "payload": collection,
320
+ },
321
+ {
322
+ "path": "/collections/{collectionId}",
323
+ "method": "DELETE",
324
+ "payload": "",
325
+ },
326
+ {
327
+ "path": "/collections/{collectionId}/items/{itemId}",
328
+ "method": "PUT",
329
+ "payload": item,
330
+ },
331
+ {
332
+ "path": "/collections/{collectionId}/items/{itemId}",
333
+ "method": "DELETE",
334
+ "payload": "",
335
+ },
336
+ ]
337
+ api = self._build_api()
338
+ api.add_route_dependencies(scopes=routes, dependencies=[Depends(must_be_bob)])
339
+ self._assert_dependency_applied(api, test_routes)
340
+ self._assert_dependency_not_applied(api, test_not_routes)
341
+
342
+ def test_add_default_method_route_dependencies_after_building_api(
343
+ self, collection, item
344
+ ):
345
+ routes = [
346
+ {
347
+ "path": "/collections/{collectionId}",
348
+ "method": "*",
349
+ },
350
+ {
351
+ "path": "/collections/{collectionId}/items/{itemId}",
352
+ "method": "*",
353
+ },
354
+ ]
355
+ test_routes = [
356
+ {
357
+ "path": "/collections/{collectionId}",
358
+ "method": "PUT",
359
+ "payload": collection,
360
+ },
361
+ {
362
+ "path": "/collections/{collectionId}",
363
+ "method": "DELETE",
364
+ "payload": "",
365
+ },
366
+ {
367
+ "path": "/collections/{collectionId}/items/{itemId}",
368
+ "method": "PUT",
369
+ "payload": item,
370
+ },
371
+ {
372
+ "path": "/collections/{collectionId}/items/{itemId}",
373
+ "method": "DELETE",
374
+ "payload": "",
375
+ },
376
+ ]
377
+ test_not_routes = [
378
+ {
379
+ "path": "/collections",
380
+ "method": "POST",
381
+ "payload": collection,
382
+ },
383
+ {
384
+ "path": "/collections/{collectionId}/items",
385
+ "method": "POST",
386
+ "payload": item,
387
+ },
388
+ ]
389
+ api = self._build_api()
390
+ api.add_route_dependencies(scopes=routes, dependencies=[Depends(must_be_bob)])
391
+ self._assert_dependency_applied(api, test_routes)
392
+ self._assert_dependency_not_applied(api, test_not_routes)
393
+
394
+
395
+ class DummyCoreClient(core.BaseCoreClient):
396
+ def all_collections(self, *args, **kwargs):
397
+ ...
398
+
399
+ def get_collection(self, *args, **kwargs):
400
+ ...
401
+
402
+ def get_item(self, *args, **kwargs):
403
+ ...
404
+
405
+ def get_search(self, *args, **kwargs):
406
+ ...
407
+
408
+ def post_search(self, *args, **kwargs):
409
+ ...
410
+
411
+ def item_collection(self, *args, **kwargs):
412
+ ...
413
+
414
+
415
+ class DummyTransactionsClient(core.BaseTransactionsClient):
416
+ """Defines a pattern for implementing the STAC transaction extension."""
417
+
418
+ def create_item(self, *args, **kwargs):
419
+ return "dummy response"
420
+
421
+ def update_item(self, *args, **kwargs):
422
+ return "dummy response"
423
+
424
+ def delete_item(self, *args, **kwargs):
425
+ return "dummy response"
426
+
427
+ def create_collection(self, *args, **kwargs):
428
+ return "dummy response"
429
+
430
+ def update_collection(self, *args, **kwargs):
431
+ return "dummy response"
432
+
433
+ def delete_collection(self, *args, **kwargs):
434
+ return "dummy response"
435
+
436
+
437
+ def must_be_bob(
438
+ credentials: security.HTTPBasicCredentials = Depends(security.HTTPBasic()),
439
+ ):
440
+ if credentials.username == "bob":
441
+ return True
442
+
443
+ raise HTTPException(
444
+ status_code=status.HTTP_401_UNAUTHORIZED,
445
+ detail="You're not Bob",
446
+ headers={"WWW-Authenticate": "Basic"},
447
+ )
@@ -1,2 +0,0 @@
1
- """Library version."""
2
- __version__ = "3.0.0a1"
@@ -1,172 +0,0 @@
1
- from fastapi import Depends, HTTPException, security, status
2
- from starlette.testclient import TestClient
3
-
4
- from stac_fastapi.api.app import StacApi
5
- from stac_fastapi.extensions.core import TokenPaginationExtension, TransactionExtension
6
- from stac_fastapi.types import config, core
7
-
8
-
9
- class TestRouteDependencies:
10
- @staticmethod
11
- def _build_api(**overrides):
12
- settings = config.ApiSettings()
13
- return StacApi(
14
- **{
15
- "settings": settings,
16
- "client": DummyCoreClient(),
17
- "extensions": [
18
- TransactionExtension(
19
- client=DummyTransactionsClient(), settings=settings
20
- ),
21
- TokenPaginationExtension(),
22
- ],
23
- **overrides,
24
- }
25
- )
26
-
27
- @staticmethod
28
- def _assert_dependency_applied(api, routes):
29
- with TestClient(api.app) as client:
30
- for route in routes:
31
- response = getattr(client, route["method"].lower())(route["path"])
32
- assert (
33
- response.status_code == 401
34
- ), "Unauthenticated requests should be rejected"
35
- assert response.json() == {"detail": "Not authenticated"}
36
-
37
- path = route["path"].format(
38
- collectionId="test_collection", itemId="test_item"
39
- )
40
- response = client.request(
41
- method=route["method"].lower(),
42
- url=path,
43
- auth=("bob", "dobbs"),
44
- content=route["payload"],
45
- headers={"content-type": "application/json"},
46
- )
47
- assert (
48
- 200 <= response.status_code < 300
49
- ), "Authenticated requests should be accepted"
50
- assert response.json() == "dummy response"
51
-
52
- def test_openapi_content_type(self):
53
- api = self._build_api()
54
- with TestClient(api.app) as client:
55
- response = client.get(api.settings.openapi_url)
56
- assert (
57
- response.headers["content-type"]
58
- == "application/vnd.oai.openapi+json;version=3.0"
59
- )
60
-
61
- def test_build_api_with_route_dependencies(self, collection, item):
62
- routes = [
63
- {"path": "/collections", "method": "POST", "payload": collection},
64
- {
65
- "path": "/collections/{collectionId}",
66
- "method": "PUT",
67
- "payload": collection,
68
- },
69
- {"path": "/collections/{collectionId}", "method": "DELETE", "payload": ""},
70
- {
71
- "path": "/collections/{collectionId}/items",
72
- "method": "POST",
73
- "payload": item,
74
- },
75
- {
76
- "path": "/collections/{collectionId}/items/{itemId}",
77
- "method": "PUT",
78
- "payload": item,
79
- },
80
- {
81
- "path": "/collections/{collectionId}/items/{itemId}",
82
- "method": "DELETE",
83
- "payload": "",
84
- },
85
- ]
86
- dependencies = [Depends(must_be_bob)]
87
- api = self._build_api(route_dependencies=[(routes, dependencies)])
88
- self._assert_dependency_applied(api, routes)
89
-
90
- def test_add_route_dependencies_after_building_api(self, collection, item):
91
- routes = [
92
- {"path": "/collections", "method": "POST", "payload": collection},
93
- {
94
- "path": "/collections/{collectionId}",
95
- "method": "PUT",
96
- "payload": collection,
97
- },
98
- {"path": "/collections/{collectionId}", "method": "DELETE", "payload": ""},
99
- {
100
- "path": "/collections/{collectionId}/items",
101
- "method": "POST",
102
- "payload": item,
103
- },
104
- {
105
- "path": "/collections/{collectionId}/items/{itemId}",
106
- "method": "PUT",
107
- "payload": item,
108
- },
109
- {
110
- "path": "/collections/{collectionId}/items/{itemId}",
111
- "method": "DELETE",
112
- "payload": "",
113
- },
114
- ]
115
- api = self._build_api()
116
- api.add_route_dependencies(scopes=routes, dependencies=[Depends(must_be_bob)])
117
- self._assert_dependency_applied(api, routes)
118
-
119
-
120
- class DummyCoreClient(core.BaseCoreClient):
121
- def all_collections(self, *args, **kwargs):
122
- ...
123
-
124
- def get_collection(self, *args, **kwargs):
125
- ...
126
-
127
- def get_item(self, *args, **kwargs):
128
- ...
129
-
130
- def get_search(self, *args, **kwargs):
131
- ...
132
-
133
- def post_search(self, *args, **kwargs):
134
- ...
135
-
136
- def item_collection(self, *args, **kwargs):
137
- ...
138
-
139
-
140
- class DummyTransactionsClient(core.BaseTransactionsClient):
141
- """Defines a pattern for implementing the STAC transaction extension."""
142
-
143
- def create_item(self, *args, **kwargs):
144
- return "dummy response"
145
-
146
- def update_item(self, *args, **kwargs):
147
- return "dummy response"
148
-
149
- def delete_item(self, *args, **kwargs):
150
- return "dummy response"
151
-
152
- def create_collection(self, *args, **kwargs):
153
- return "dummy response"
154
-
155
- def update_collection(self, *args, **kwargs):
156
- return "dummy response"
157
-
158
- def delete_collection(self, *args, **kwargs):
159
- return "dummy response"
160
-
161
-
162
- def must_be_bob(
163
- credentials: security.HTTPBasicCredentials = Depends(security.HTTPBasic()),
164
- ):
165
- if credentials.username == "bob":
166
- return True
167
-
168
- raise HTTPException(
169
- status_code=status.HTTP_401_UNAUTHORIZED,
170
- detail="You're not Bob",
171
- headers={"WWW-Authenticate": "Basic"},
172
- )