eotdl 2025.4.22__tar.gz → 2025.4.22.post2__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.
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/PKG-INFO +1 -1
- eotdl-2025.4.22.post2/eotdl/__init__.py +1 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/commands/datasets.py +11 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/commands/models.py +12 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/commands/stac.py +2 -2
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/curation/stac/api.py +2 -2
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/datasets/__init__.py +1 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/datasets/update.py +8 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/models/__init__.py +1 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/models/update.py +7 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/APIRepo.py +2 -2
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/DatasetsAPIRepo.py +6 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/ModelsAPIRepo.py +5 -1
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/STACAPIRepo.py +2 -2
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/pyproject.toml +1 -1
- eotdl-2025.4.22.post2/tests/load/conftest.py +55 -0
- eotdl-2025.4.22.post2/tests/load/eotdl.tiers.json +34 -0
- eotdl-2025.4.22.post2/tests/load/test_upload_size.py +194 -0
- eotdl-2025.4.22.post2/tests/load/upload_times.log +6 -0
- eotdl-2025.4.22.post2/tests/load/upload_times_tifs.log +5 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/uv.lock +1 -1
- eotdl-2025.4.22/eotdl/__init__.py +0 -1
- eotdl-2025.4.22/pyproject.toml.bck +0 -35
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/.gitignore +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/README.md +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/airbus/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/airbus/client.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/airbus/parameters.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/airbus/utils.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/download.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/search.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/sentinelhub/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/sentinelhub/client.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/sentinelhub/evalscripts.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/sentinelhub/parameters.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/access/sentinelhub/utils.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/auth/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/auth/auth.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/auth/errors.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/auth/is_logged.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/auth/logout.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/cli.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/commands/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/commands/auth.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/curation/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/curation/stac/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/curation/stac/stac.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/datasets/ingest.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/datasets/retrieve.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/datasets/stage.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/files/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/files/ingest.bck +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/files/ingest.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/files/metadata.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/models/download.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/models/ingest.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/models/retrieve.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/models/stage.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/AuthAPIRepo.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/AuthRepo.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/FilesAPIRepo.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/repos/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/shared/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/shared/checksum.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/geo_utils.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/metadata.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/paths.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/stac.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/time_utils.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/tools/tools.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/wrappers/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl/wrappers/models.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/eotdl.png +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/main.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/_test_access.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/_test_hello.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/_test_auth.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/access/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/fixtures.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac/catalog.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac/sentinel-2-l2a/Jaca_1/Jaca_1.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac/sentinel-2-l2a/Jaca_2/Jaca_2.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac/sentinel-2-l2a/Jaca_3/Jaca_3.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac/sentinel-2-l2a/Jaca_4/Jaca_4.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac/sentinel-2-l2a/collection.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/catalog.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/labels/Jaca_1/Jaca_1.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/labels/Jaca_2/Jaca_2.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/labels/Jaca_3/Jaca_3.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/labels/Jaca_4/Jaca_4.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/labels/collection.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/sentinel-2-l2a/Jaca_1/Jaca_1.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/sentinel-2-l2a/Jaca_2/Jaca_2.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/sentinel-2-l2a/Jaca_3/Jaca_3.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/sentinel-2-l2a/Jaca_4/Jaca_4.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/jaca_dataset_stac_labels/sentinel-2-l2a/collection.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/labels_scaneo/Jaca_1_labels.geojson +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/labels_scaneo/Jaca_2_labels.geojson +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/labels_scaneo/Jaca_3_labels.geojson +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/labels_scaneo/Jaca_4_labels.geojson +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/labels_scaneo/labels.json +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/sentinel_2/Boadella_2020-01-13.tif +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/sentinel_2/Boadella_2020-01-13_labels.geojson +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/sentinel_2/Boadella_2020-01-28.tif +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_data/sentinel_2/Boadella_2020-02-02_labels.geojson +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_dataframe.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_extent.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_labels.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_ml_dataset.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/curation/stac/test_stac.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/datasets/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/datasets/_test_datasets.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/datasets/_test_download_dataset.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/datasets/_test_retrieve_datasets.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/tools/__init__.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/tools/test_geo_utils.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/tools/test_metadata.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/tools/test_paths.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/tools/test_time_utils.py +0 -0
- {eotdl-2025.4.22 → eotdl-2025.4.22.post2}/tests/unit/tools/test_tools.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "2025.04.22-2"
|
@@ -5,6 +5,7 @@ from ..datasets import (
|
|
5
5
|
retrieve_datasets,
|
6
6
|
ingest_dataset,
|
7
7
|
stage_dataset,
|
8
|
+
deactivate_dataset,
|
8
9
|
)
|
9
10
|
|
10
11
|
app = typer.Typer(help="Explore, ingest and download training datasets.")
|
@@ -141,5 +142,15 @@ def get(
|
|
141
142
|
typer.echo(e)
|
142
143
|
|
143
144
|
|
145
|
+
@app.command()
|
146
|
+
def deactivate(
|
147
|
+
dataset_id: str = typer.Argument(None, help="ID of the dataset to deactivate")
|
148
|
+
):
|
149
|
+
try:
|
150
|
+
deactivate_dataset(dataset_id)
|
151
|
+
typer.echo(f"Dataset {dataset_id} deactivated")
|
152
|
+
except Exception as e:
|
153
|
+
typer.echo(e)
|
154
|
+
|
144
155
|
if __name__ == "__main__":
|
145
156
|
app()
|
@@ -5,6 +5,7 @@ from ..models import (
|
|
5
5
|
retrieve_models,
|
6
6
|
ingest_model,
|
7
7
|
stage_model,
|
8
|
+
deactivate_model
|
8
9
|
)
|
9
10
|
|
10
11
|
app = typer.Typer(help="Explore, ingest and download ML models.")
|
@@ -132,5 +133,16 @@ def get(
|
|
132
133
|
typer.echo(e)
|
133
134
|
|
134
135
|
|
136
|
+
@app.command()
|
137
|
+
def deactivate(
|
138
|
+
model_id: str = typer.Argument(None, help="ID of the model to deactivate")
|
139
|
+
):
|
140
|
+
try:
|
141
|
+
deactivate_model(model_id)
|
142
|
+
typer.echo(f"Model {model_id} deactivated")
|
143
|
+
except Exception as e:
|
144
|
+
typer.echo(e)
|
145
|
+
|
146
|
+
|
135
147
|
if __name__ == "__main__":
|
136
148
|
app()
|
@@ -24,9 +24,9 @@ def collections():
|
|
24
24
|
raise typer.Abort()
|
25
25
|
|
26
26
|
@app.command()
|
27
|
-
def collection(
|
27
|
+
def collection(collection_name: str):
|
28
28
|
try:
|
29
|
-
data = retrieve_stac_collection(
|
29
|
+
data = retrieve_stac_collection(collection_name)
|
30
30
|
typer.echo(data)
|
31
31
|
except Exception as e:
|
32
32
|
typer.echo(e)
|
@@ -16,9 +16,9 @@ def retrieve_stac_collections():
|
|
16
16
|
raise Exception(error)
|
17
17
|
return data
|
18
18
|
|
19
|
-
def retrieve_stac_collection(
|
19
|
+
def retrieve_stac_collection(collection_name):
|
20
20
|
repo = STACAPIRepo()
|
21
|
-
data, error = repo.collection(
|
21
|
+
data, error = repo.collection(collection_name)
|
22
22
|
if error:
|
23
23
|
raise Exception(error)
|
24
24
|
return data
|
@@ -15,3 +15,11 @@ def update_dataset(dataset_id, metadata, content, user):
|
|
15
15
|
if error:
|
16
16
|
raise Exception(error)
|
17
17
|
return data
|
18
|
+
|
19
|
+
|
20
|
+
def deactivate_dataset(dataset_id):
|
21
|
+
repo = DatasetsAPIRepo()
|
22
|
+
data, error = repo.deactivate_dataset(dataset_id)
|
23
|
+
if error:
|
24
|
+
raise Exception(error)
|
25
|
+
return data
|
@@ -15,3 +15,10 @@ def update_model(model_id, metadata, content, user):
|
|
15
15
|
if error:
|
16
16
|
raise Exception(error)
|
17
17
|
return data
|
18
|
+
|
19
|
+
def deactivate_model(model_id):
|
20
|
+
repo = ModelsAPIRepo()
|
21
|
+
data, error = repo.deactivate_model(model_id)
|
22
|
+
if error:
|
23
|
+
raise Exception(error)
|
24
|
+
return data
|
@@ -4,8 +4,8 @@ import requests
|
|
4
4
|
|
5
5
|
class APIRepo:
|
6
6
|
def __init__(self, url=None):
|
7
|
-
default_url = "https://api.eotdl.com/"
|
8
|
-
|
7
|
+
# default_url = "https://api.eotdl.com/"
|
8
|
+
default_url = "http://localhost:8000/"
|
9
9
|
self.url = url if url else os.getenv("EOTDL_API_URL", default_url)
|
10
10
|
|
11
11
|
def format_response(self, response):
|
@@ -41,3 +41,9 @@ class DatasetsAPIRepo(APIRepo):
|
|
41
41
|
headers=self.generate_headers(user),
|
42
42
|
)
|
43
43
|
return self.format_response(response)
|
44
|
+
|
45
|
+
def deactivate_dataset(self, dataset_name):
|
46
|
+
response = requests.patch(
|
47
|
+
self.url + "datasets/deactivate/" + dataset_name
|
48
|
+
)
|
49
|
+
return self.format_response(response)
|
@@ -15,8 +15,8 @@ class STACAPIRepo(APIRepo):
|
|
15
15
|
response = requests.get(self.url + "stac/collections")
|
16
16
|
return self.format_response(response)
|
17
17
|
|
18
|
-
def collection(self,
|
19
|
-
response = requests.get(self.url + f"stac/collections/{
|
18
|
+
def collection(self, collection_name):
|
19
|
+
response = requests.get(self.url + f"stac/collections/{collection_name}")
|
20
20
|
return self.format_response(response)
|
21
21
|
|
22
22
|
def items(self, collection_id):
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import json
|
2
|
+
from bson import ObjectId
|
3
|
+
from minio import Minio
|
4
|
+
from pymongo import MongoClient
|
5
|
+
import pytest
|
6
|
+
import boto3
|
7
|
+
|
8
|
+
|
9
|
+
@pytest.fixture
|
10
|
+
def setup_mongo():
|
11
|
+
client = MongoClient("mongodb://localhost:27017/")
|
12
|
+
db = client["eotdl-test"]
|
13
|
+
|
14
|
+
client.drop_database("eotdl-test")
|
15
|
+
|
16
|
+
db = client["eotdl-test"]
|
17
|
+
tiers_collection = db["tiers"]
|
18
|
+
|
19
|
+
with open("eotdl/tests/load/eotdl.tiers.json", "r") as file:
|
20
|
+
json_data = json.load(file)
|
21
|
+
|
22
|
+
for item in json_data:
|
23
|
+
if "_id" in item:
|
24
|
+
item["_id"] = ObjectId(item["_id"])
|
25
|
+
|
26
|
+
tiers_collection.insert_many(json_data)
|
27
|
+
|
28
|
+
yield tiers_collection
|
29
|
+
|
30
|
+
client.drop_database("eotdl-test")
|
31
|
+
|
32
|
+
|
33
|
+
@pytest.fixture
|
34
|
+
def setup_minio():
|
35
|
+
minio_client = Minio(
|
36
|
+
"localhost:9000",
|
37
|
+
access_key="eotdl",
|
38
|
+
secret_key="12345678",
|
39
|
+
secure=False,
|
40
|
+
)
|
41
|
+
|
42
|
+
bucket_name = "eotdl-test"
|
43
|
+
|
44
|
+
if not minio_client.bucket_exists(bucket_name):
|
45
|
+
minio_client.make_bucket(bucket_name)
|
46
|
+
|
47
|
+
objects = minio_client.list_objects(bucket_name, recursive=True)
|
48
|
+
for obj in objects:
|
49
|
+
minio_client.remove_object(bucket_name, obj.object_name)
|
50
|
+
|
51
|
+
yield minio_client
|
52
|
+
|
53
|
+
objects = minio_client.list_objects(bucket_name, recursive=True)
|
54
|
+
for obj in objects:
|
55
|
+
minio_client.remove_object(bucket_name, obj.object_name)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"_id": "645242248456b2cc058e43bf",
|
4
|
+
"name": "free",
|
5
|
+
"limits": {
|
6
|
+
"datasets": {
|
7
|
+
"upload": 10,
|
8
|
+
"download": 3,
|
9
|
+
"count": 10
|
10
|
+
},
|
11
|
+
"models": {
|
12
|
+
"upload": 10,
|
13
|
+
"download": 10,
|
14
|
+
"count": 10
|
15
|
+
}
|
16
|
+
}
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"_id": "645242248456b2cc058e43c0",
|
20
|
+
"name": "dev",
|
21
|
+
"limits": {
|
22
|
+
"datasets": {
|
23
|
+
"upload": 100000,
|
24
|
+
"download": 100000,
|
25
|
+
"count": 100
|
26
|
+
},
|
27
|
+
"models": {
|
28
|
+
"upload": 100000,
|
29
|
+
"download": 100000,
|
30
|
+
"count": 100
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
]
|
@@ -0,0 +1,194 @@
|
|
1
|
+
from datetime import datetime, timezone
|
2
|
+
import io
|
3
|
+
import os
|
4
|
+
from pathlib import Path
|
5
|
+
import tempfile
|
6
|
+
import time
|
7
|
+
|
8
|
+
from eotdl.datasets.retrieve import retrieve_dataset_files
|
9
|
+
import numpy as np
|
10
|
+
import pytest
|
11
|
+
|
12
|
+
from eotdl.datasets import ingest_dataset, retrieve_dataset
|
13
|
+
import rasterio
|
14
|
+
|
15
|
+
|
16
|
+
os.environ["EOTDL_API_URL"] = "http://localhost:8000/"
|
17
|
+
|
18
|
+
|
19
|
+
def write_readme(path: Path, name: str):
|
20
|
+
readme_text = f"""---
|
21
|
+
name: {name}
|
22
|
+
authors:
|
23
|
+
- Derek van de Ven
|
24
|
+
license: free
|
25
|
+
source: https://github.com/earthpulse/eotdl/blob/main/tutorials/notebooks/02_ingesting.ipynb
|
26
|
+
---
|
27
|
+
|
28
|
+
# {name}
|
29
|
+
|
30
|
+
This file is nonsensical data used for load testing. It should not be stored on the web.
|
31
|
+
"""
|
32
|
+
|
33
|
+
with open(path / name / "README.md", "w") as outfile:
|
34
|
+
outfile.write(readme_text)
|
35
|
+
|
36
|
+
|
37
|
+
def generate_fake_tif_dataset(
|
38
|
+
path: Path, n_tifs: int = 10, tif_size: int = 256, name: str = "test_set"
|
39
|
+
):
|
40
|
+
files_to_upload = []
|
41
|
+
for count in range(n_tifs):
|
42
|
+
files_to_upload.append(f"{name}/FakeFolder/Fake_tif{count}.tif")
|
43
|
+
|
44
|
+
for rel_path in files_to_upload:
|
45
|
+
file_path = path / rel_path
|
46
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
47
|
+
|
48
|
+
width, height = tif_size, tif_size
|
49
|
+
data = np.full((height, width, 3), 256, dtype=np.uint32)
|
50
|
+
|
51
|
+
with rasterio.open(
|
52
|
+
file_path,
|
53
|
+
"w",
|
54
|
+
driver="GTiff",
|
55
|
+
height=height,
|
56
|
+
width=width,
|
57
|
+
count=3,
|
58
|
+
dtype="uint32",
|
59
|
+
crs="EPSG:4326",
|
60
|
+
transform=rasterio.transform.from_origin(0, height, 1, 1),
|
61
|
+
) as dst:
|
62
|
+
dst.write(data[:, :, 0], 1)
|
63
|
+
dst.write(data[:, :, 1], 2)
|
64
|
+
dst.write(data[:, :, 2], 3)
|
65
|
+
|
66
|
+
write_readme(path, name)
|
67
|
+
|
68
|
+
|
69
|
+
def generate_fake_dataset(
|
70
|
+
path: Path, size_mb: int = 10, n_files: int = 5, name: str = "test_set"
|
71
|
+
):
|
72
|
+
files_to_upload = []
|
73
|
+
for count in range(n_files):
|
74
|
+
files_to_upload.append(
|
75
|
+
f"{name}/FakeFolder/Fake_tif{count}.tif",
|
76
|
+
)
|
77
|
+
|
78
|
+
total_size_bytes = size_mb * 1024 * 1024
|
79
|
+
file_size = total_size_bytes // len(files_to_upload)
|
80
|
+
|
81
|
+
for rel_path in files_to_upload:
|
82
|
+
file_path = path / rel_path
|
83
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
84
|
+
|
85
|
+
# Write random binary data to simulate `.tif` files
|
86
|
+
with open(file_path, "wb") as f:
|
87
|
+
f.write(os.urandom(file_size)) # Random binary data
|
88
|
+
|
89
|
+
write_readme(path, name)
|
90
|
+
|
91
|
+
|
92
|
+
@pytest.mark.parametrize(
|
93
|
+
"total_size, n_files",
|
94
|
+
[
|
95
|
+
(1, 10),
|
96
|
+
# (1e1, 10),
|
97
|
+
# (1e3, 1), # 1 files amounting to 1 GB,
|
98
|
+
# (1e3, 20), # 20 files amounting to 1 GB
|
99
|
+
# (1e4, 100), # 100 10 MB files
|
100
|
+
# (3e4, 100), # 10 times 1 GB
|
101
|
+
],
|
102
|
+
)
|
103
|
+
def test_load(setup_mongo, setup_minio, total_size, n_files):
|
104
|
+
name = f"LoadTest-{int(total_size)}MB"
|
105
|
+
with tempfile.TemporaryDirectory(prefix="loadtest_") as tmpdir:
|
106
|
+
tmpdir = Path(tmpdir)
|
107
|
+
generate_fake_dataset(
|
108
|
+
path=tmpdir, size_mb=int(total_size), n_files=n_files, name=name
|
109
|
+
)
|
110
|
+
|
111
|
+
# upload
|
112
|
+
start_time = time.time()
|
113
|
+
ingest_dataset(path=str(tmpdir / name))
|
114
|
+
|
115
|
+
upload_duration = time.time() - start_time
|
116
|
+
print(f"Upload for {name} took {upload_duration:.2f} seconds.")
|
117
|
+
|
118
|
+
with open("eotdl/tests/load/upload_times.log", "a") as log_file:
|
119
|
+
log_file.write(
|
120
|
+
f"{total_size} MB made of {n_files} files took {upload_duration:.2f} seconds.\n"
|
121
|
+
)
|
122
|
+
|
123
|
+
# assert dataset ingested
|
124
|
+
dataset = retrieve_dataset(name=name)
|
125
|
+
assert dataset["name"] == name
|
126
|
+
assert round(dataset["versions"][0]["size"] / (1024 * 1024), 2) == total_size
|
127
|
+
|
128
|
+
# check files in minio
|
129
|
+
minio_files = []
|
130
|
+
minio_sizes = []
|
131
|
+
for obj in setup_minio.list_objects("eotdl-test", recursive=True):
|
132
|
+
minio_files.append(obj.object_name)
|
133
|
+
minio_sizes.append(obj.size)
|
134
|
+
assert obj.object_name.endswith(("tif", "md", "parquet"))
|
135
|
+
|
136
|
+
assert len(minio_files) == n_files + 2
|
137
|
+
assert round(sum(minio_sizes) / (1024 * 1024)) == total_size
|
138
|
+
|
139
|
+
|
140
|
+
@pytest.mark.parametrize(
|
141
|
+
"tif_size, n_tifs",
|
142
|
+
[
|
143
|
+
# (256, 100),
|
144
|
+
# (512, 100),
|
145
|
+
# (1024, 100),
|
146
|
+
(2048, 200),
|
147
|
+
],
|
148
|
+
)
|
149
|
+
def test_load_tifs(setup_mongo, setup_minio, tif_size, n_tifs):
|
150
|
+
name = f"LoadTest-{int(tif_size)}"
|
151
|
+
with tempfile.TemporaryDirectory(prefix="loadtest_") as tmpdir:
|
152
|
+
tmpdir = Path(tmpdir)
|
153
|
+
generate_fake_tif_dataset(
|
154
|
+
path=tmpdir, tif_size=tif_size, n_tifs=n_tifs, name=name
|
155
|
+
)
|
156
|
+
|
157
|
+
# upload
|
158
|
+
start_time = time.time()
|
159
|
+
ingest_dataset(path=str(tmpdir / name))
|
160
|
+
|
161
|
+
upload_duration = time.time() - start_time
|
162
|
+
print(f"Upload for {name} took {upload_duration:.2f} seconds.")
|
163
|
+
|
164
|
+
# assert dataset ingested
|
165
|
+
dataset = retrieve_dataset(name=name)
|
166
|
+
assert dataset["name"] == name
|
167
|
+
|
168
|
+
with open("eotdl/tests/load/upload_times_tifs.log", "a") as log_file:
|
169
|
+
log_file.write(
|
170
|
+
f"{tif_size}x {tif_size} made of {n_tifs} files took {upload_duration:.2f} seconds. ({round(dataset['versions'][0]['size'] / (1024 * 1024), 2)} mb)\n"
|
171
|
+
)
|
172
|
+
|
173
|
+
# check files in minio
|
174
|
+
minio_files = []
|
175
|
+
minio_sizes = []
|
176
|
+
for obj in setup_minio.list_objects("eotdl-test", recursive=True):
|
177
|
+
minio_files.append(obj.object_name)
|
178
|
+
minio_sizes.append(obj.size)
|
179
|
+
assert obj.object_name.endswith(("tif", "md", "parquet"))
|
180
|
+
|
181
|
+
if obj.object_name.endswith(".tif"):
|
182
|
+
file = setup_minio.get_object("eotdl-test", obj.object_name)
|
183
|
+
file_content = file.read()
|
184
|
+
with io.BytesIO(file_content) as byte_file:
|
185
|
+
with rasterio.open(byte_file) as src:
|
186
|
+
assert src.crs == "EPSG:4326"
|
187
|
+
assert src.width == src.height == tif_size
|
188
|
+
assert src.dtypes == ("uint32", "uint32", "uint32")
|
189
|
+
|
190
|
+
for band in range(1, 4):
|
191
|
+
colour = src.read(band)
|
192
|
+
assert set(colour.flatten()) == {np.uint32(256)}
|
193
|
+
|
194
|
+
assert len(minio_files) == n_tifs + 2
|
@@ -0,0 +1,6 @@
|
|
1
|
+
1 MB made of 10 files took 0.46 seconds.
|
2
|
+
10.0 MB made of 10 files took 0.44 seconds.
|
3
|
+
1000.0 MB made of 1 files took 9.78 seconds.
|
4
|
+
1000.0 MB made of 20 files took 10.35 seconds.
|
5
|
+
10000.0 MB made of 100 files took 120.89 seconds.
|
6
|
+
10000.0 MB made of 10 files took 133.24 seconds.
|
@@ -0,0 +1,5 @@
|
|
1
|
+
256x 256 made of 100 files took 5.89 seconds. (75.11 mb)
|
2
|
+
512x 512 made of 100 files took 8.48 seconds. (300.33 mb)
|
3
|
+
1024x 1024 made of 100 files took 23.38 seconds. (1200.62 mb)
|
4
|
+
2048x 2048 made of 100 files took 81.27 seconds. (4801.21 mb)
|
5
|
+
2048x 2048 made of 200 files took 202.64 seconds. (9602.42 mb)
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "2025.04.22"
|
@@ -1,35 +0,0 @@
|
|
1
|
-
[project]
|
2
|
-
name = "eotdl"
|
3
|
-
version = "2025.04.02"
|
4
|
-
description = "Earth Observation Training Data Lab"
|
5
|
-
authors = [
|
6
|
-
{name = "earthpulse", email = "it@earthpulse.es"},
|
7
|
-
]
|
8
|
-
license = "MIT"
|
9
|
-
readme = "README.md"
|
10
|
-
requires-python = ">=3.8"
|
11
|
-
dependencies = [
|
12
|
-
"geomet>=1.1.0",
|
13
|
-
"geopandas>=0.13.2",
|
14
|
-
"markdown>=3.7",
|
15
|
-
"pydantic>=2.10.6",
|
16
|
-
"pyjwt>=2.9.0",
|
17
|
-
"pystac>=1.8.4",
|
18
|
-
"python-frontmatter>=1.1.0",
|
19
|
-
"pyyaml>=6.0.2",
|
20
|
-
"rasterio>=1.3.11",
|
21
|
-
"requests>=2.32.3",
|
22
|
-
"sentinelhub>=3.11.1",
|
23
|
-
"tqdm>=4.67.1",
|
24
|
-
"typer>=0.15.1",
|
25
|
-
]
|
26
|
-
|
27
|
-
[project.scripts]
|
28
|
-
eotdl = "eotdl.cli:app"
|
29
|
-
|
30
|
-
[build-system]
|
31
|
-
requires = ["hatchling"]
|
32
|
-
build-backend = "hatchling.build"
|
33
|
-
|
34
|
-
[tool.hatch.build.targets.wheel]
|
35
|
-
packages = ["eotdl"]
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|