stac-fastapi-elasticsearch 6.5.0__tar.gz → 6.6.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 (21) hide show
  1. stac_fastapi_elasticsearch-6.6.0/.gitignore +143 -0
  2. stac_fastapi_elasticsearch-6.6.0/PKG-INFO +58 -0
  3. stac_fastapi_elasticsearch-6.6.0/README.md +20 -0
  4. stac_fastapi_elasticsearch-6.6.0/pyproject.toml +71 -0
  5. stac_fastapi_elasticsearch-6.6.0/pytest.ini +4 -0
  6. {stac_fastapi_elasticsearch-6.5.0 → stac_fastapi_elasticsearch-6.6.0}/stac_fastapi/elasticsearch/database_logic.py +29 -73
  7. {stac_fastapi_elasticsearch-6.5.0 → stac_fastapi_elasticsearch-6.6.0}/stac_fastapi/elasticsearch/version.py +1 -1
  8. stac_fastapi_elasticsearch-6.5.0/PKG-INFO +0 -716
  9. stac_fastapi_elasticsearch-6.5.0/README.md +0 -695
  10. stac_fastapi_elasticsearch-6.5.0/setup.cfg +0 -7
  11. stac_fastapi_elasticsearch-6.5.0/setup.py +0 -58
  12. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/PKG-INFO +0 -716
  13. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/SOURCES.txt +0 -15
  14. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/dependency_links.txt +0 -1
  15. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/entry_points.txt +0 -2
  16. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/not-zip-safe +0 -1
  17. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/requires.txt +0 -21
  18. stac_fastapi_elasticsearch-6.5.0/stac_fastapi_elasticsearch.egg-info/top_level.txt +0 -1
  19. {stac_fastapi_elasticsearch-6.5.0 → stac_fastapi_elasticsearch-6.6.0}/stac_fastapi/elasticsearch/__init__.py +0 -0
  20. {stac_fastapi_elasticsearch-6.5.0 → stac_fastapi_elasticsearch-6.6.0}/stac_fastapi/elasticsearch/app.py +0 -0
  21. {stac_fastapi_elasticsearch-6.5.0 → stac_fastapi_elasticsearch-6.6.0}/stac_fastapi/elasticsearch/config.py +0 -0
@@ -0,0 +1,143 @@
1
+ elasticsearch/snapshots/
2
+
3
+ # Byte-compiled / optimized / DLL files
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ pip-wheel-metadata/
26
+ share/python-wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .nox/
46
+ .coverage
47
+ .coverage.*
48
+ .cache
49
+ nosetests.xml
50
+ coverage.xml
51
+ *.cover
52
+ *.py,cover
53
+ .hypothesis/
54
+ .pytest_cache/
55
+
56
+ # Translations
57
+ *.mo
58
+ *.pot
59
+
60
+ # Django stuff:
61
+ *.log
62
+ local_settings.py
63
+ db.sqlite3
64
+ db.sqlite3-journal
65
+
66
+ # Flask stuff:
67
+ instance/
68
+ .webassets-cache
69
+
70
+ # Scrapy stuff:
71
+ .scrapy
72
+
73
+ # Sphinx documentation
74
+ docs/_build/
75
+
76
+ # PyBuilder
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ .python-version
88
+
89
+ # pipenv
90
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
91
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
92
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
93
+ # install all needed dependencies.
94
+ #Pipfile.lock
95
+
96
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
97
+ __pypackages__/
98
+
99
+ # Celery stuff
100
+ celerybeat-schedule
101
+ celerybeat.pid
102
+
103
+ # SageMath parsed files
104
+ *.sage.py
105
+
106
+ # Environments
107
+ .env
108
+ .venv
109
+ env/
110
+ venv/
111
+ ENV/
112
+ env.bak/
113
+ venv.bak/
114
+
115
+ # Spyder project settings
116
+ .spyderproject
117
+ .spyproject
118
+
119
+ # Rope project settings
120
+ .ropeproject
121
+
122
+ # mkdocs documentation
123
+ /site
124
+
125
+ # mypy
126
+ .mypy_cache/
127
+ .dmypy.json
128
+ dmypy.json
129
+
130
+ # Pyre type checker
131
+ .pyre/
132
+
133
+ /esdata
134
+
135
+ # Virtualenv
136
+ venv
137
+
138
+ # VSCode folder
139
+ .vscode
140
+
141
+ /docs/src/api/*
142
+
143
+ .DS_Store
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.4
2
+ Name: stac_fastapi_elasticsearch
3
+ Version: 6.6.0
4
+ Summary: An implementation of STAC API based on the FastAPI framework with Elasticsearch.
5
+ Project-URL: Homepage, https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
6
+ License: MIT
7
+ Keywords: Elasticsearch,FastAPI,STAC,STAC-API,stac-fastapi
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Intended Audience :: Information Technology
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: >=3.9
19
+ Requires-Dist: elasticsearch[async]~=8.19.1
20
+ Requires-Dist: sfeos-helpers==6.6.0
21
+ Requires-Dist: stac-fastapi-core==6.6.0
22
+ Requires-Dist: starlette<0.36.0,>=0.35.0
23
+ Requires-Dist: uvicorn~=0.23.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: ciso8601~=2.3.0; extra == 'dev'
26
+ Requires-Dist: httpx<0.28.0,>=0.24.0; extra == 'dev'
27
+ Requires-Dist: pre-commit~=3.0.0; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio~=0.21.0; extra == 'dev'
29
+ Requires-Dist: pytest-cov~=4.0.0; extra == 'dev'
30
+ Requires-Dist: pytest~=8.0; extra == 'dev'
31
+ Provides-Extra: docs
32
+ Requires-Dist: mkdocs-material~=9.0.0; extra == 'docs'
33
+ Requires-Dist: mkdocs~=1.4.0; extra == 'docs'
34
+ Requires-Dist: pdocs~=1.2.0; extra == 'docs'
35
+ Provides-Extra: server
36
+ Requires-Dist: uvicorn[standard]~=0.23.0; extra == 'server'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # stac-fastapi-elasticsearch
40
+
41
+ This is the Elasticsearch backend for stac-fastapi. For full documentation, please see the [main README](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/blob/main/README.md).
42
+
43
+ ## Package Information
44
+
45
+ - **Package name**: stac-fastapi-elasticsearch
46
+ - **Description**: An implementation of STAC API based on the FastAPI framework with Elasticsearch.
47
+ - **Documentation**: [https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/)
48
+ - **Source**: [GitHub Repository](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/)
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install stac-fastapi-elasticsearch
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ For detailed usage and examples, please refer to the [main documentation](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/).
@@ -0,0 +1,20 @@
1
+ # stac-fastapi-elasticsearch
2
+
3
+ This is the Elasticsearch backend for stac-fastapi. For full documentation, please see the [main README](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/blob/main/README.md).
4
+
5
+ ## Package Information
6
+
7
+ - **Package name**: stac-fastapi-elasticsearch
8
+ - **Description**: An implementation of STAC API based on the FastAPI framework with Elasticsearch.
9
+ - **Documentation**: [https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/)
10
+ - **Source**: [GitHub Repository](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/)
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install stac-fastapi-elasticsearch
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ For detailed usage and examples, please refer to the [main documentation](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/).
@@ -0,0 +1,71 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "stac_fastapi_elasticsearch"
7
+ description = "An implementation of STAC API based on the FastAPI framework with Elasticsearch."
8
+ readme = "README.md"
9
+ requires-python = ">=3.9"
10
+ license = {text = "MIT"}
11
+ authors = []
12
+ classifiers = [
13
+ "Intended Audience :: Developers",
14
+ "Intended Audience :: Information Technology",
15
+ "Intended Audience :: Science/Research",
16
+ "Programming Language :: Python :: 3.9",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
22
+ "License :: OSI Approved :: MIT License",
23
+ ]
24
+ keywords = [
25
+ "STAC",
26
+ "STAC-API",
27
+ "FastAPI",
28
+ "Elasticsearch",
29
+ "stac-fastapi",
30
+ ]
31
+ dynamic = ["version"]
32
+ dependencies = [
33
+ "stac-fastapi-core==6.6.0",
34
+ "sfeos-helpers==6.6.0",
35
+ "elasticsearch[async]~=8.19.1",
36
+ "uvicorn~=0.23.0",
37
+ "starlette>=0.35.0,<0.36.0",
38
+ ]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch"
42
+
43
+ [project.optional-dependencies]
44
+ dev = [
45
+ "pytest~=8.0",
46
+ "pytest-cov~=4.0.0",
47
+ "pytest-asyncio~=0.21.0",
48
+ "pre-commit~=3.0.0",
49
+ "ciso8601~=2.3.0",
50
+ "httpx>=0.24.0,<0.28.0",
51
+ ]
52
+ docs = [
53
+ "mkdocs~=1.4.0",
54
+ "mkdocs-material~=9.0.0",
55
+ "pdocs~=1.2.0",
56
+ ]
57
+ server = [
58
+ "uvicorn[standard]~=0.23.0",
59
+ ]
60
+
61
+ [project.scripts]
62
+ stac-fastapi-elasticsearch = "stac_fastapi.elasticsearch.app:run"
63
+
64
+ [tool.hatch.version]
65
+ path = "stac_fastapi/elasticsearch/version.py"
66
+
67
+ [tool.hatch.build.targets.sdist]
68
+ exclude = ["alembic", "tests", "scripts"]
69
+
70
+ [tool.hatch.build.targets.wheel]
71
+ only-include = ["stac_fastapi"]
@@ -0,0 +1,4 @@
1
+ [pytest]
2
+ testpaths = tests
3
+ addopts = -sv
4
+ asyncio_mode = auto
@@ -17,7 +17,7 @@ from starlette.requests import Request
17
17
 
18
18
  from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
19
19
  from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
20
- from stac_fastapi.core.utilities import bbox2polygon, get_bool_env, get_max_limit
20
+ from stac_fastapi.core.utilities import MAX_LIMIT, bbox2polygon, get_bool_env
21
21
  from stac_fastapi.elasticsearch.config import AsyncElasticsearchSettings
22
22
  from stac_fastapi.elasticsearch.config import (
23
23
  ElasticsearchSettings as SyncElasticsearchSettings,
@@ -29,13 +29,15 @@ from stac_fastapi.extensions.core.transaction.request import (
29
29
  )
30
30
  from stac_fastapi.sfeos_helpers import filter as filter_module
31
31
  from stac_fastapi.sfeos_helpers.database import (
32
+ add_bbox_shape_to_collection,
33
+ apply_collections_bbox_filter_shared,
34
+ apply_collections_datetime_filter_shared,
32
35
  apply_free_text_filter_shared,
33
36
  apply_intersects_filter_shared,
34
37
  create_index_templates_shared,
35
38
  delete_item_index_shared,
36
39
  get_queryables_mapping_shared,
37
40
  index_alias_by_collection_id,
38
- index_by_collection_id,
39
41
  mk_actions,
40
42
  mk_item_id,
41
43
  populate_sort_shared,
@@ -99,26 +101,6 @@ async def create_collection_index() -> None:
99
101
  await client.close()
100
102
 
101
103
 
102
- async def create_item_index(collection_id: str):
103
- """
104
- Create the index for Items. The settings of the index template will be used implicitly.
105
-
106
- Args:
107
- collection_id (str): Collection identifier.
108
-
109
- Returns:
110
- None
111
-
112
- """
113
- client = AsyncElasticsearchSettings().create_client
114
-
115
- await client.options(ignore_status=400).indices.create(
116
- index=f"{index_by_collection_id(collection_id)}-000001",
117
- body={"aliases": {index_alias_by_collection_id(collection_id): {}}},
118
- )
119
- await client.close()
120
-
121
-
122
104
  async def delete_item_index(collection_id: str):
123
105
  """Delete the index for items in a collection.
124
106
 
@@ -175,6 +157,7 @@ class DatabaseLogic(BaseDatabaseLogic):
175
157
  limit: int,
176
158
  request: Request,
177
159
  sort: Optional[List[Dict[str, Any]]] = None,
160
+ bbox: Optional[List[float]] = None,
178
161
  q: Optional[List[str]] = None,
179
162
  filter: Optional[Dict[str, Any]] = None,
180
163
  query: Optional[Dict[str, Dict[str, Any]]] = None,
@@ -187,6 +170,7 @@ class DatabaseLogic(BaseDatabaseLogic):
187
170
  limit (int): The number of results to return.
188
171
  request (Request): The FastAPI request object.
189
172
  sort (Optional[List[Dict[str, Any]]]): Optional sort parameter from the request.
173
+ bbox (Optional[List[float]]): Bounding box to filter collections by spatial extent.
190
174
  q (Optional[List[str]]): Free text search terms.
191
175
  query (Optional[Dict[str, Dict[str, Any]]]): Query extension parameters.
192
176
  filter (Optional[Dict[str, Any]]): Structured query in CQL2 format.
@@ -309,18 +293,20 @@ class DatabaseLogic(BaseDatabaseLogic):
309
293
  query_parts.append(search_dict["query"])
310
294
 
311
295
  except Exception as e:
312
- logger = logging.getLogger(__name__)
313
296
  logger.error(f"Error converting query to Elasticsearch: {e}")
314
297
  # If there's an error, add a query that matches nothing
315
298
  query_parts.append({"bool": {"must_not": {"match_all": {}}}})
316
299
  raise
317
300
 
318
- # Combine all query parts with AND logic if there are multiple
319
- datetime_filter = None
320
- if datetime:
321
- datetime_filter = self._apply_collection_datetime_filter(datetime)
322
- if datetime_filter:
323
- query_parts.append(datetime_filter)
301
+ # Apply bbox filter if provided
302
+ bbox_filter = apply_collections_bbox_filter_shared(bbox)
303
+ if bbox_filter:
304
+ query_parts.append(bbox_filter)
305
+
306
+ # Apply datetime filter if provided
307
+ datetime_filter = apply_collections_datetime_filter_shared(datetime)
308
+ if datetime_filter:
309
+ query_parts.append(datetime_filter)
324
310
 
325
311
  # Combine all query parts with AND logic
326
312
  if query_parts:
@@ -330,12 +316,6 @@ class DatabaseLogic(BaseDatabaseLogic):
330
316
  else {"bool": {"must": query_parts}}
331
317
  )
332
318
 
333
- # Create a copy of the body for count query (without pagination and sorting)
334
- count_body = body.copy()
335
- if "search_after" in count_body:
336
- del count_body["search_after"]
337
- count_body["size"] = 0
338
-
339
319
  # Create async tasks for both search and count
340
320
  search_task = asyncio.create_task(
341
321
  self.client.search(
@@ -381,46 +361,10 @@ class DatabaseLogic(BaseDatabaseLogic):
381
361
  try:
382
362
  matched = count_task.result().get("count")
383
363
  except Exception as e:
384
- logger = logging.getLogger(__name__)
385
364
  logger.error(f"Count task failed: {e}")
386
365
 
387
366
  return collections, next_token, matched
388
367
 
389
- @staticmethod
390
- def _apply_collection_datetime_filter(
391
- datetime_str: Optional[str],
392
- ) -> Optional[Dict[str, Any]]:
393
- """Create a temporal filter for collections based on their extent."""
394
- if not datetime_str:
395
- return None
396
-
397
- # Parse the datetime string into start and end
398
- if "/" in datetime_str:
399
- start, end = datetime_str.split("/")
400
- # Replace open-ended ranges with concrete dates
401
- if start == "..":
402
- # For open-ended start, use a very early date
403
- start = "1800-01-01T00:00:00Z"
404
- if end == "..":
405
- # For open-ended end, use a far future date
406
- end = "2999-12-31T23:59:59Z"
407
- else:
408
- # If it's just a single date, use it for both start and end
409
- start = end = datetime_str
410
-
411
- return {
412
- "bool": {
413
- "must": [
414
- # Check if any date in the array is less than or equal to the query end date
415
- # This will match if the collection's start date is before or equal to the query end date
416
- {"range": {"extent.temporal.interval": {"lte": end}}},
417
- # Check if any date in the array is greater than or equal to the query start date
418
- # This will match if the collection's end date is after or equal to the query start date
419
- {"range": {"extent.temporal.interval": {"gte": start}}},
420
- ]
421
- }
422
- }
423
-
424
368
  async def get_one_item(self, collection_id: str, item_id: str) -> Dict:
425
369
  """Retrieve a single item from the database.
426
370
 
@@ -818,7 +762,7 @@ class DatabaseLogic(BaseDatabaseLogic):
818
762
  index_param = ITEM_INDICES
819
763
  query = add_collections_to_body(collection_ids, query)
820
764
 
821
- max_result_window = get_max_limit()
765
+ max_result_window = MAX_LIMIT
822
766
 
823
767
  size_limit = min(limit + 1, max_result_window)
824
768
 
@@ -1388,7 +1332,7 @@ class DatabaseLogic(BaseDatabaseLogic):
1388
1332
  None
1389
1333
 
1390
1334
  Notes:
1391
- A new index is created for the items in the Collection using the `create_item_index` function.
1335
+ A new index is created for the items in the Collection if the index insertion strategy requires it.
1392
1336
  """
1393
1337
  collection_id = collection["id"]
1394
1338
 
@@ -1406,6 +1350,12 @@ class DatabaseLogic(BaseDatabaseLogic):
1406
1350
  if await self.client.exists(index=COLLECTIONS_INDEX, id=collection_id):
1407
1351
  raise ConflictError(f"Collection {collection_id} already exists")
1408
1352
 
1353
+ if get_bool_env("ENABLE_COLLECTIONS_SEARCH") or get_bool_env(
1354
+ "ENABLE_COLLECTIONS_SEARCH_ROUTE"
1355
+ ):
1356
+ # Convert bbox to bbox_shape for geospatial queries (ES/OS specific)
1357
+ add_bbox_shape_to_collection(collection)
1358
+
1409
1359
  # Index the collection in the database
1410
1360
  await self.client.index(
1411
1361
  index=COLLECTIONS_INDEX,
@@ -1509,6 +1459,12 @@ class DatabaseLogic(BaseDatabaseLogic):
1509
1459
  await self.delete_collection(collection_id)
1510
1460
 
1511
1461
  else:
1462
+ if get_bool_env("ENABLE_COLLECTIONS_SEARCH") or get_bool_env(
1463
+ "ENABLE_COLLECTIONS_SEARCH_ROUTE"
1464
+ ):
1465
+ # Convert bbox to bbox_shape for geospatial queries (ES/OS specific)
1466
+ add_bbox_shape_to_collection(collection)
1467
+
1512
1468
  # Update the existing collection
1513
1469
  await self.client.index(
1514
1470
  index=COLLECTIONS_INDEX,
@@ -1,2 +1,2 @@
1
1
  """library version."""
2
- __version__ = "6.5.0"
2
+ __version__ = "6.6.0"