eotdl 2025.2.10__py3-none-any.whl → 2025.3.25__py3-none-any.whl

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 (56) hide show
  1. eotdl/__init__.py +1 -1
  2. eotdl/access/download.py +2 -3
  3. eotdl/access/sentinelhub/client.py +2 -2
  4. eotdl/access/sentinelhub/utils.py +5 -1
  5. eotdl/cli.py +2 -2
  6. eotdl/commands/datasets.py +28 -31
  7. eotdl/commands/models.py +27 -30
  8. eotdl/commands/stac.py +57 -0
  9. eotdl/curation/__init__.py +0 -8
  10. eotdl/curation/stac/__init__.py +1 -8
  11. eotdl/curation/stac/api.py +58 -0
  12. eotdl/curation/stac/stac.py +31 -341
  13. eotdl/datasets/__init__.py +1 -1
  14. eotdl/datasets/ingest.py +28 -160
  15. eotdl/datasets/retrieve.py +0 -9
  16. eotdl/datasets/stage.py +64 -0
  17. eotdl/files/__init__.py +0 -2
  18. eotdl/files/ingest.bck +178 -0
  19. eotdl/files/ingest.py +229 -164
  20. eotdl/{datasets → files}/metadata.py +16 -17
  21. eotdl/models/__init__.py +1 -1
  22. eotdl/models/ingest.py +28 -159
  23. eotdl/models/stage.py +60 -0
  24. eotdl/repos/APIRepo.py +1 -1
  25. eotdl/repos/DatasetsAPIRepo.py +56 -43
  26. eotdl/repos/FilesAPIRepo.py +260 -167
  27. eotdl/repos/STACAPIRepo.py +40 -0
  28. eotdl/repos/__init__.py +1 -0
  29. {eotdl-2025.2.10.dist-info → eotdl-2025.3.25.dist-info}/METADATA +32 -19
  30. eotdl-2025.3.25.dist-info/RECORD +65 -0
  31. {eotdl-2025.2.10.dist-info → eotdl-2025.3.25.dist-info}/WHEEL +1 -1
  32. eotdl-2025.3.25.dist-info/entry_points.txt +3 -0
  33. eotdl/curation/stac/assets.py +0 -110
  34. eotdl/curation/stac/dataframe.py +0 -172
  35. eotdl/curation/stac/dataframe_bck.py +0 -253
  36. eotdl/curation/stac/dataframe_labeling.py +0 -63
  37. eotdl/curation/stac/extensions/__init__.py +0 -23
  38. eotdl/curation/stac/extensions/base.py +0 -30
  39. eotdl/curation/stac/extensions/dem.py +0 -18
  40. eotdl/curation/stac/extensions/eo.py +0 -117
  41. eotdl/curation/stac/extensions/label/__init__.py +0 -7
  42. eotdl/curation/stac/extensions/label/base.py +0 -136
  43. eotdl/curation/stac/extensions/label/image_name_labeler.py +0 -203
  44. eotdl/curation/stac/extensions/label/scaneo.py +0 -219
  45. eotdl/curation/stac/extensions/ml_dataset.py +0 -648
  46. eotdl/curation/stac/extensions/projection.py +0 -44
  47. eotdl/curation/stac/extensions/raster.py +0 -53
  48. eotdl/curation/stac/extensions/sar.py +0 -55
  49. eotdl/curation/stac/extent.py +0 -158
  50. eotdl/curation/stac/parsers.py +0 -61
  51. eotdl/datasets/download.py +0 -104
  52. eotdl/files/list_files.py +0 -13
  53. eotdl/models/download.py +0 -101
  54. eotdl/models/metadata.py +0 -43
  55. eotdl-2025.2.10.dist-info/RECORD +0 -81
  56. eotdl-2025.2.10.dist-info/entry_points.txt +0 -2
eotdl/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.02.10"
1
+ __version__ = "2025.03.25"
eotdl/access/download.py CHANGED
@@ -42,9 +42,8 @@ def download_sentinel_imagery(
42
42
  bulk = False
43
43
  else:
44
44
  bulk = True
45
-
46
- data = client.download_data(requests_list)
47
- imagery_from_tmp_to_dir(output, client.tmp_dir, name=name, bulk=bulk)
45
+ client.download_data(requests_list)
46
+ imagery_from_tmp_to_dir(output, name=name, bulk=bulk)
48
47
 
49
48
 
50
49
  def search_and_download_sentinel_imagery(
@@ -15,7 +15,6 @@ from sentinelhub import (
15
15
  SentinelHubDownloadClient,
16
16
  MimeType,
17
17
  )
18
- import uuid
19
18
 
20
19
  from ...repos.AuthRepo import AuthRepo
21
20
  from .parameters import SHParameters
@@ -58,7 +57,7 @@ class SHClient:
58
57
  self.config.sh_client_id = creds["SH_CLIENT_ID"]
59
58
  self.config.sh_client_secret = creds["SH_CLIENT_SECRET"]
60
59
  self.catalog = SentinelHubCatalog(config=self.config)
61
- self.tmp_dir = "/tmp/sentinelhub/" + str(uuid.uuid4())
60
+ self.tmp_dir = "/tmp/sentinelhub"
62
61
 
63
62
  def search_data(
64
63
  self, bounding_box: list, time_interval: list, parameters: SHParameters
@@ -110,4 +109,5 @@ class SHClient:
110
109
  requests = [requests]
111
110
  download_requests = [request.download_list[0] for request in requests]
112
111
  data = download_client.download(download_requests)
112
+
113
113
  return data
@@ -50,7 +50,7 @@ def evaluate_sentinel_parameters(
50
50
 
51
51
  def imagery_from_tmp_to_dir(
52
52
  output_dir: str,
53
- tmp_dir: Optional[str],
53
+ tmp_dir: Optional[str] = "/tmp/sentinelhub",
54
54
  name: Optional[str] = None,
55
55
  bulk: Optional[bool] = False,
56
56
  ) -> None:
@@ -60,7 +60,9 @@ def imagery_from_tmp_to_dir(
60
60
  downloaded_files = glob(f"{tmp_dir}/**/response.tiff")
61
61
  if len(downloaded_files) == 0:
62
62
  return
63
+
63
64
  makedirs(output_dir, exist_ok=True)
65
+
64
66
  for downloaded_file in downloaded_files:
65
67
  request_json = downloaded_file.replace("response.tiff", "request.json")
66
68
  metadata = generate_raster_metadata(downloaded_file, request_json)
@@ -73,9 +75,11 @@ def imagery_from_tmp_to_dir(
73
75
  output_filename = f"{metadata['type']}_{metadata['acquisition-date']}"
74
76
  else:
75
77
  output_filename = metadata["type"]
78
+
76
79
  copyfile(downloaded_file, f"{output_dir}/{output_filename}.tif")
77
80
  with open(f"{output_dir}/{output_filename}.json", "w", encoding="utf-8") as f:
78
81
  json.dump(metadata, f)
82
+
79
83
  rmtree(tmp_dir)
80
84
 
81
85
 
eotdl/cli.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import typer
2
2
  import os
3
3
 
4
- from .commands import auth, datasets, models
4
+ from .commands import auth, datasets, models, stac
5
5
  from .repos import APIRepo
6
6
  from . import __version__
7
7
 
@@ -10,7 +10,7 @@ app = typer.Typer(help="Welcome to EOTDL. Learn more at https://www.eotdl.com/")
10
10
  app.add_typer(auth.app, name="auth")
11
11
  app.add_typer(datasets.app, name="datasets")
12
12
  app.add_typer(models.app, name="models")
13
-
13
+ app.add_typer(stac.app, name="stac")
14
14
 
15
15
  @app.command()
16
16
  def version():
@@ -4,39 +4,11 @@ from pathlib import Path
4
4
  from ..datasets import (
5
5
  retrieve_datasets,
6
6
  ingest_dataset,
7
- download_dataset,
7
+ stage_dataset,
8
8
  )
9
9
 
10
10
  app = typer.Typer(help="Explore, ingest and download training datasets.")
11
11
 
12
-
13
- @app.command()
14
- def list(
15
- name: str = typer.Option(
16
- None, "--name", "-n", help="Filter the returned datasets by name"
17
- ),
18
- limit: int = typer.Option(
19
- None, "--limit", "-l", help="Limit the number of returned results"
20
- ),
21
- ):
22
- """
23
- Retrieve a list with all the datasets in the EOTDL.
24
-
25
- If using --name, it will filter the results by name. If no name is provided, it will return all the datasets.\n
26
- If using --limit, it will limit the number of results. If no limit is provided, it will return all the datasets.
27
- \n\n
28
- Examples\n
29
- --------\n
30
- $ eotdl datasets list\n
31
- $ eotdl datasets list --name YourModel --limit 5
32
- """
33
- try:
34
- datasets = retrieve_datasets(name, limit)
35
- typer.echo(datasets)
36
- except Exception as e:
37
- typer.echo(e)
38
-
39
-
40
12
  @app.command()
41
13
  def ingest(
42
14
  path: Path = typer.Option(
@@ -62,7 +34,7 @@ def ingest(
62
34
  ),
63
35
  ):
64
36
  """
65
- Ingest a dataset to the EOTDL.
37
+ Ingest a dataset to the EOTDL.asdf
66
38
 
67
39
  This command ingests the dataset to the EOTDL. The dataset must be a folder with the dataset files,
68
40
  and at least a README.md file (and a catalog.json file for Q1+). If these files are missing, the ingestion
@@ -90,7 +62,32 @@ def ingest(
90
62
  ingest_dataset(path, verbose, typer.echo, foce_metadata_update, sync_metadata)
91
63
  except Exception as e:
92
64
  typer.echo(e)
65
+
66
+ @app.command()
67
+ def list(
68
+ name: str = typer.Option(
69
+ None, "--name", "-n", help="Filter the returned datasets by name"
70
+ ),
71
+ limit: int = typer.Option(
72
+ None, "--limit", "-l", help="Limit the number of returned results"
73
+ ),
74
+ ):
75
+ """
76
+ Retrieve a list with all the datasets in the EOTDL.
93
77
 
78
+ If using --name, it will filter the results by name. If no name is provided, it will return all the datasets.\n
79
+ If using --limit, it will limit the number of results. If no limit is provided, it will return all the datasets.
80
+ \n\n
81
+ Examples\n
82
+ --------\n
83
+ $ eotdl datasets list\n
84
+ $ eotdl datasets list --name YourModel --limit 5
85
+ """
86
+ try:
87
+ datasets = retrieve_datasets(name, limit)
88
+ typer.echo(datasets)
89
+ except Exception as e:
90
+ typer.echo(e)
94
91
 
95
92
  @app.command()
96
93
  def get(
@@ -130,7 +127,7 @@ def get(
130
127
  $ eotdl dataset get YourDataset --path /path/to/download --file dataset.zip --version 1 --assets True --force True --verbose True
131
128
  """
132
129
  try:
133
- dst_path = download_dataset(
130
+ dst_path = stage_dataset(
134
131
  dataset,
135
132
  version,
136
133
  path,
eotdl/commands/models.py CHANGED
@@ -4,39 +4,11 @@ from pathlib import Path
4
4
  from ..models import (
5
5
  retrieve_models,
6
6
  ingest_model,
7
- download_model,
7
+ stage_model,
8
8
  )
9
9
 
10
10
  app = typer.Typer(help="Explore, ingest and download ML models.")
11
11
 
12
-
13
- @app.command()
14
- def list(
15
- name: str = typer.Option(
16
- None, "--name", "-n", help="Filter the returned models by name"
17
- ),
18
- limit: int = typer.Option(
19
- None, "--limit", "-l", help="Limit the number of returned results"
20
- ),
21
- ):
22
- """
23
- Retrieve a list with all the models in the EOTDL.
24
-
25
- If using --name, it will filter the results by name. If no name is provided, it will return all the models.\n
26
- If using --limit, it will limit the number of results. If no limit is provided, it will return all the models.
27
- \n\n
28
- Examples\n
29
- --------\n
30
- $ eotdl models list\n
31
- $ eotdl models list --name YourModel --limit 5
32
- """
33
- try:
34
- models = retrieve_models(name, limit)
35
- typer.echo(models)
36
- except Exception as e:
37
- typer.echo(e)
38
-
39
-
40
12
  @app.command()
41
13
  def ingest(
42
14
  path: Path = typer.Option(..., "--path", "-p", help="Path to the model to ingest"),
@@ -88,6 +60,31 @@ def ingest(
88
60
  except Exception as e:
89
61
  typer.echo(e)
90
62
 
63
+ @app.command()
64
+ def list(
65
+ name: str = typer.Option(
66
+ None, "--name", "-n", help="Filter the returned models by name"
67
+ ),
68
+ limit: int = typer.Option(
69
+ None, "--limit", "-l", help="Limit the number of returned results"
70
+ ),
71
+ ):
72
+ """
73
+ Retrieve a list with all the models in the EOTDL.
74
+
75
+ If using --name, it will filter the results by name. If no name is provided, it will return all the models.\n
76
+ If using --limit, it will limit the number of results. If no limit is provided, it will return all the models.
77
+ \n\n
78
+ Examples\n
79
+ --------\n
80
+ $ eotdl models list\n
81
+ $ eotdl models list --name YourModel --limit 5
82
+ """
83
+ try:
84
+ models = retrieve_models(name, limit)
85
+ typer.echo(models)
86
+ except Exception as e:
87
+ typer.echo(e)
91
88
 
92
89
  @app.command()
93
90
  def get(
@@ -127,7 +124,7 @@ def get(
127
124
  $ eotdl models get YourModel --path /path/to/download --file model.zip --version 1 --assets True --force True --verbose True
128
125
  """
129
126
  try:
130
- dst_path = download_model(
127
+ dst_path = stage_model(
131
128
  model, version, path, typer.echo, assets, force, verbose
132
129
  )
133
130
  typer.echo(f"Data available at {dst_path}")
eotdl/commands/stac.py ADDED
@@ -0,0 +1,57 @@
1
+ import typer
2
+ from typing import Optional
3
+
4
+ from ..curation.stac.api import api_status, search_stac_columns, retrieve_stac_collections, retrieve_stac_collection, retrieve_stac_items, retrieve_stac_item, search_stac_items
5
+
6
+ app = typer.Typer(help="EOTDL STAC API")
7
+
8
+ @app.command()
9
+ def status():
10
+ try:
11
+ data = api_status()
12
+ typer.echo(data)
13
+ except Exception as e:
14
+ typer.echo(e)
15
+ raise typer.Abort()
16
+
17
+ @app.command()
18
+ def collections():
19
+ try:
20
+ data = retrieve_stac_collections()
21
+ typer.echo(data)
22
+ except Exception as e:
23
+ typer.echo(e)
24
+ raise typer.Abort()
25
+
26
+ @app.command()
27
+ def collection(collection_id: str):
28
+ try:
29
+ data = retrieve_stac_collection(collection_id)
30
+ typer.echo(data)
31
+ except Exception as e:
32
+ typer.echo(e)
33
+ raise typer.Abort()
34
+
35
+ @app.command()
36
+ def items(collection_id: str):
37
+ try:
38
+ data = retrieve_stac_items(collection_id)
39
+ typer.echo(data)
40
+ except Exception as e:
41
+ typer.echo(e)
42
+
43
+ @app.command()
44
+ def item(collection_id: str, item_id: str):
45
+ try:
46
+ data = retrieve_stac_item(collection_id, item_id)
47
+ typer.echo(data)
48
+ except Exception as e:
49
+ typer.echo(e)
50
+
51
+ @app.command()
52
+ def search(collection_id: str, query: Optional[str] = None):
53
+ try:
54
+ data = search_stac_items(collection_id, query)
55
+ typer.echo(data)
56
+ except Exception as e:
57
+ typer.echo(e)
@@ -1,8 +0,0 @@
1
- """
2
- Curation module
3
- """
4
-
5
- from .stac.dataframe import STACDataFrame # , read_stac
6
- from .stac.stac import STACGenerator
7
- from .stac.parsers import STACIdParser, StructuredParser, UnestructuredParser
8
- from .stac.dataframe_labeling import UnlabeledStrategy, LabeledStrategy
@@ -1,8 +1 @@
1
- """
2
- STAC module
3
- """
4
-
5
- # from .stac import STACGenerator
6
- # from .utils import format_time_acquired
7
- # from .parsers import STACIdParser, StructuredParser, UnestructuredParser
8
- from .dataframe import STACDataFrame, read_stac
1
+ from .stac import create_stac_catalog
@@ -0,0 +1,58 @@
1
+ import json
2
+
3
+ from ...repos import STACAPIRepo
4
+
5
+ def api_status():
6
+ repo = STACAPIRepo()
7
+ data, error = repo.status()
8
+ if error:
9
+ raise Exception(error)
10
+ return data
11
+
12
+ def retrieve_stac_collections():
13
+ repo = STACAPIRepo()
14
+ data, error = repo.collections()
15
+ if error:
16
+ raise Exception(error)
17
+ return data
18
+
19
+ def retrieve_stac_collection(collection_id):
20
+ repo = STACAPIRepo()
21
+ data, error = repo.collection(collection_id)
22
+ if error:
23
+ raise Exception(error)
24
+ return data
25
+
26
+ def retrieve_stac_items(collection_id):
27
+ repo = STACAPIRepo()
28
+ data, error = repo.items(collection_id)
29
+ if error:
30
+ raise Exception(error)
31
+ return data
32
+
33
+ def retrieve_stac_item(collection_id, item_id):
34
+ repo = STACAPIRepo()
35
+ data, error = repo.item(collection_id, item_id)
36
+ if error:
37
+ raise Exception(error)
38
+ return data
39
+
40
+ def search_stac_items(collection_id, query = None):
41
+ repo = STACAPIRepo()
42
+ if query is None:
43
+ data, error = repo.search_columns(collection_id)
44
+ if error:
45
+ raise Exception(error)
46
+ return data
47
+ data, error = repo.search(collection_id, str(query))
48
+ if error:
49
+ raise Exception(error)
50
+ return json.loads(data)
51
+
52
+
53
+ def search_stac_columns(collection_id):
54
+ repo = STACAPIRepo()
55
+ data, error = repo.search_columns(collection_id)
56
+ if error:
57
+ raise Exception(error)
58
+ return data