ee-client 2.0.3__tar.gz → 2.1.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 (29) hide show
  1. {ee_client-2.0.3 → ee_client-2.1.0}/PKG-INFO +10 -3
  2. {ee_client-2.0.3 → ee_client-2.1.0}/README.rst +9 -2
  3. {ee_client-2.0.3 → ee_client-2.1.0}/ee_client.egg-info/PKG-INFO +10 -3
  4. {ee_client-2.0.3 → ee_client-2.1.0}/ee_client.egg-info/SOURCES.txt +1 -0
  5. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/__init__.py +1 -1
  6. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/client.py +15 -28
  7. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/export/image.py +20 -7
  8. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/export/table.py +19 -6
  9. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/helpers.py +11 -5
  10. ee_client-2.1.0/eeclient/sepal_credential_mixin.py +37 -0
  11. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/tasks.py +16 -5
  12. {ee_client-2.0.3 → ee_client-2.1.0}/pyproject.toml +2 -2
  13. {ee_client-2.0.3 → ee_client-2.1.0}/LICENSE +0 -0
  14. {ee_client-2.0.3 → ee_client-2.1.0}/ee_client.egg-info/dependency_links.txt +0 -0
  15. {ee_client-2.0.3 → ee_client-2.1.0}/ee_client.egg-info/requires.txt +0 -0
  16. {ee_client-2.0.3 → ee_client-2.1.0}/ee_client.egg-info/top_level.txt +0 -0
  17. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/data.py +0 -0
  18. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/exceptions.py +0 -0
  19. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/export/__init__.py +0 -0
  20. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/interfaces/__init__.py +0 -0
  21. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/interfaces/export.py +0 -0
  22. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/interfaces/operations.py +0 -0
  23. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/interfaces/tasks.py +0 -0
  24. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/models.py +0 -0
  25. {ee_client-2.0.3 → ee_client-2.1.0}/eeclient/oauth_app.py +0 -0
  26. {ee_client-2.0.3 → ee_client-2.1.0}/setup.cfg +0 -0
  27. {ee_client-2.0.3 → ee_client-2.1.0}/tests/test_client.py +0 -0
  28. {ee_client-2.0.3 → ee_client-2.1.0}/tests/test_data.py +0 -0
  29. {ee_client-2.0.3 → ee_client-2.1.0}/tests/test_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ee-client
3
- Version: 2.0.3
3
+ Version: 2.1.0
4
4
  Summary: extends the capabilities of the earthengine-api by providing custom session management and client interactions
5
5
  Author-email: Daniel Guerrero <dfgm2006@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/dfguerrerom/ee-client
@@ -32,15 +32,22 @@ Dynamic: license-file
32
32
  Earth Engine Client 🌎
33
33
  ==============================
34
34
 
35
- The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through a custom authentication. Unlike the standard GEE API—which relies on a global session object and does not support multi-user environments—this client ensures that each session is authenticated and managed independently.
35
+ The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through custom authentication.
36
+
37
+ **Why This Package?**
38
+
39
+ While Google Earth Engine applications can be created using a global service account, this approach has significant limitations: users cannot access their private GEE assets without making them public. This package solves this problem by handling custom authentication, allowing each user to access their own private assets securely.
40
+
41
+ Unlike the standard GEE API—which relies on a global session object and does not support multi-user environments—this client ensures that each session is authenticated and managed independently with user-specific credentials.
36
42
 
37
43
  Each session is instantiated via the ``EESession`` class, currently only accepts SEPAL headers as its only parameter. **A valid ``sepal-session-id`` cookie must be present in these headers**, as it is used to retrieve the corresponding GEE credentials. Once authenticated, the session exposes an ``operations`` property that provides easy access to key API methods.
38
44
 
39
45
  Key Features
40
46
  ------------
41
47
 
48
+ - **Custom User Authentication**: Enable users to access their private GEE assets without requiring them to be public, solving the limitation of global service account approaches.
42
49
  - **SEPAL-based Initialization**: Create sessions using SEPAL headers. The required ``sepal-session-id`` cookie is automatically used to retrieve GEE credentials.
43
- - **Custom Session Management**: Encapsulate user-specific credentials and project data in an ``EESession`` object.
50
+ - **Multi-User Session Management**: Encapsulate user-specific credentials and project data in independent ``EESession`` objects.
44
51
  - **Enhanced API Operations**: Access GEE functionalities via the ``operations`` property, which includes methods such as:
45
52
  - ``get_info``: Retrieve detailed information about an Earth Engine object.
46
53
  - ``get_map_id``: Generate a map ID for an Earth Engine image.
@@ -1,15 +1,22 @@
1
1
  Earth Engine Client 🌎
2
2
  ==============================
3
3
 
4
- The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through a custom authentication. Unlike the standard GEE API—which relies on a global session object and does not support multi-user environments—this client ensures that each session is authenticated and managed independently.
4
+ The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through custom authentication.
5
+
6
+ **Why This Package?**
7
+
8
+ While Google Earth Engine applications can be created using a global service account, this approach has significant limitations: users cannot access their private GEE assets without making them public. This package solves this problem by handling custom authentication, allowing each user to access their own private assets securely.
9
+
10
+ Unlike the standard GEE API—which relies on a global session object and does not support multi-user environments—this client ensures that each session is authenticated and managed independently with user-specific credentials.
5
11
 
6
12
  Each session is instantiated via the ``EESession`` class, currently only accepts SEPAL headers as its only parameter. **A valid ``sepal-session-id`` cookie must be present in these headers**, as it is used to retrieve the corresponding GEE credentials. Once authenticated, the session exposes an ``operations`` property that provides easy access to key API methods.
7
13
 
8
14
  Key Features
9
15
  ------------
10
16
 
17
+ - **Custom User Authentication**: Enable users to access their private GEE assets without requiring them to be public, solving the limitation of global service account approaches.
11
18
  - **SEPAL-based Initialization**: Create sessions using SEPAL headers. The required ``sepal-session-id`` cookie is automatically used to retrieve GEE credentials.
12
- - **Custom Session Management**: Encapsulate user-specific credentials and project data in an ``EESession`` object.
19
+ - **Multi-User Session Management**: Encapsulate user-specific credentials and project data in independent ``EESession`` objects.
13
20
  - **Enhanced API Operations**: Access GEE functionalities via the ``operations`` property, which includes methods such as:
14
21
  - ``get_info``: Retrieve detailed information about an Earth Engine object.
15
22
  - ``get_map_id``: Generate a map ID for an Earth Engine image.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ee-client
3
- Version: 2.0.3
3
+ Version: 2.1.0
4
4
  Summary: extends the capabilities of the earthengine-api by providing custom session management and client interactions
5
5
  Author-email: Daniel Guerrero <dfgm2006@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/dfguerrerom/ee-client
@@ -32,15 +32,22 @@ Dynamic: license-file
32
32
  Earth Engine Client 🌎
33
33
  ==============================
34
34
 
35
- The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through a custom authentication. Unlike the standard GEE API—which relies on a global session object and does not support multi-user environments—this client ensures that each session is authenticated and managed independently.
35
+ The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through custom authentication.
36
+
37
+ **Why This Package?**
38
+
39
+ While Google Earth Engine applications can be created using a global service account, this approach has significant limitations: users cannot access their private GEE assets without making them public. This package solves this problem by handling custom authentication, allowing each user to access their own private assets securely.
40
+
41
+ Unlike the standard GEE API—which relies on a global session object and does not support multi-user environments—this client ensures that each session is authenticated and managed independently with user-specific credentials.
36
42
 
37
43
  Each session is instantiated via the ``EESession`` class, currently only accepts SEPAL headers as its only parameter. **A valid ``sepal-session-id`` cookie must be present in these headers**, as it is used to retrieve the corresponding GEE credentials. Once authenticated, the session exposes an ``operations`` property that provides easy access to key API methods.
38
44
 
39
45
  Key Features
40
46
  ------------
41
47
 
48
+ - **Custom User Authentication**: Enable users to access their private GEE assets without requiring them to be public, solving the limitation of global service account approaches.
42
49
  - **SEPAL-based Initialization**: Create sessions using SEPAL headers. The required ``sepal-session-id`` cookie is automatically used to retrieve GEE credentials.
43
- - **Custom Session Management**: Encapsulate user-specific credentials and project data in an ``EESession`` object.
50
+ - **Multi-User Session Management**: Encapsulate user-specific credentials and project data in independent ``EESession`` objects.
44
51
  - **Enhanced API Operations**: Access GEE functionalities via the ``operations`` property, which includes methods such as:
45
52
  - ``get_info``: Retrieve detailed information about an Earth Engine object.
46
53
  - ``get_map_id``: Generate a map ID for an Earth Engine image.
@@ -13,6 +13,7 @@ eeclient/exceptions.py
13
13
  eeclient/helpers.py
14
14
  eeclient/models.py
15
15
  eeclient/oauth_app.py
16
+ eeclient/sepal_credential_mixin.py
16
17
  eeclient/tasks.py
17
18
  eeclient/export/__init__.py
18
19
  eeclient/export/image.py
@@ -1,6 +1,6 @@
1
1
  __title__ = "eeclient"
2
2
  __summary__ = "A client for Google Earth Engine"
3
- __version__ = "2.0.3"
3
+ __version__ = "2.1.0"
4
4
 
5
5
  __author__ = "Daniel Guerrero"
6
6
  __email__ = "dfgm2006@gmail.com"
@@ -9,6 +9,7 @@ from contextlib import asynccontextmanager
9
9
 
10
10
  from eeclient.exceptions import EEClientError, EERestException
11
11
  from eeclient.models import GEEHeaders, GoogleTokens, SepalHeaders
12
+ from eeclient.sepal_credential_mixin import SepalCredentialMixin
12
13
 
13
14
  import eeclient.export as _export_module
14
15
  import eeclient.data as _operations_module
@@ -33,7 +34,7 @@ SEPAL_API_DOWNLOAD_URL = None
33
34
  VERIFY_SSL = True
34
35
 
35
36
 
36
- class EESession:
37
+ class EESession(SepalCredentialMixin):
37
38
  def __init__(self, sepal_headers: SepalHeaders, enforce_project_id: bool = True):
38
39
  """Session that handles two scenarios to set the headers for Earth Engine API
39
40
 
@@ -48,38 +49,17 @@ class EESession:
48
49
  Raises:
49
50
  ValueError: If SEPAL_HOST environment variable is not set
50
51
  """
51
- # Get and validate environment variables that are required for the session
52
- self.sepal_host = os.getenv("SEPAL_HOST")
53
- if not self.sepal_host:
54
- raise ValueError("SEPAL_HOST environment variable not set")
55
-
56
- self.sepal_api_download_url = (
57
- f"https://{self.sepal_host}/api/user-files/download/"
58
- "?path=%2F.config%2Fearthengine%2Fcredentials"
59
- )
60
- self.verify_ssl = not (
61
- self.sepal_host == "host.docker.internal"
62
- or self.sepal_host == "danielg.sepal.io"
63
- )
52
+ super().__init__(sepal_headers)
64
53
 
65
- self.expiry_date = 0
66
54
  self.max_retries = 3
67
55
  self._credentials = None
68
-
69
56
  self.enforce_project_id = enforce_project_id
70
- self.sepal_headers = SepalHeaders.model_validate(sepal_headers)
71
- self.sepal_session_id = self.sepal_headers.cookies["SEPAL-SESSIONID"]
72
- self.sepal_user_data = self.sepal_headers.sepal_user
73
- self.user = self.sepal_user_data.username
74
57
 
75
58
  # Create user-specific logger
76
59
  self.logger = logging.getLogger(f"eeclient.{self.user}")
77
60
 
78
61
  # Initialize credentials from the initial tokens
79
- self._google_tokens = self.sepal_user_data.google_tokens
80
62
  if self._google_tokens:
81
- self.expiry_date = self._google_tokens.access_token_expiry_date
82
- self.project_id = self._google_tokens.project_id
83
63
  self._credentials = self._google_tokens
84
64
  else:
85
65
  self._credentials = None
@@ -118,7 +98,7 @@ class EESession:
118
98
  return await session.initialize()
119
99
 
120
100
  async def get_assets_folder(self) -> str:
121
- if self.is_expired():
101
+ if self.needs_credentials_refresh():
122
102
  await self.set_credentials()
123
103
  return f"projects/{self.project_id}/assets/"
124
104
 
@@ -126,6 +106,10 @@ class EESession:
126
106
  """Returns if a token is about to expire"""
127
107
  return (self.expiry_date / 1000) - time.time() < 60
128
108
 
109
+ def needs_credentials_refresh(self) -> bool:
110
+ """Returns if credentials need to be refreshed (missing or expired)"""
111
+ return not self._credentials or self.is_expired()
112
+
129
113
  def get_current_headers(self) -> GEEHeaders:
130
114
  """Get current headers without refreshing credentials"""
131
115
  if not self._credentials:
@@ -143,7 +127,7 @@ class EESession:
143
127
 
144
128
  async def get_headers(self) -> GEEHeaders:
145
129
  """Async method to get headers, refreshing credentials if needed"""
146
- if self.is_expired():
130
+ if self.needs_credentials_refresh():
147
131
  await self.set_credentials()
148
132
  return self.get_current_headers()
149
133
 
@@ -246,9 +230,12 @@ class EESession:
246
230
  try:
247
231
  async with self.get_client() as client:
248
232
  url_with_project = self.set_url_project(url)
249
- self.logger.debug(
250
- f"Making async (asdf) {method} request to {url_with_project}"
251
- )
233
+
234
+ if "assets" not in url_with_project:
235
+ # Do not log assets requests
236
+ self.logger.debug(
237
+ f"Making async {method} request to {url_with_project}"
238
+ )
252
239
  response = await client.request(
253
240
  method, url_with_project, json=data, params=params
254
241
  )
@@ -9,6 +9,7 @@ if TYPE_CHECKING:
9
9
  from ee import serializer
10
10
  import ee
11
11
  import logging
12
+ from eeclient.tasks import Task
12
13
 
13
14
  log = logging.getLogger("eeclient.export.image")
14
15
 
@@ -127,11 +128,14 @@ async def _export_image(
127
128
  scale: Optional[float] = None,
128
129
  crs: Optional[str] = None,
129
130
  crs_transform: Optional[AffineTransform] = None,
130
- ) -> dict:
131
+ ) -> Task:
131
132
  """
132
- Export a table to either Google Drive or Earth Engine Asset.
133
+ Export an image to either Google Drive or Earth Engine Asset.
133
134
 
134
135
  Exactly one of drive_options or asset_options must be provided.
136
+
137
+ Returns:
138
+ Task: The export task response from the API
135
139
  """
136
140
  if (drive_options is None and asset_options is None) or (
137
141
  drive_options is not None and asset_options is not None
@@ -177,7 +181,8 @@ async def _export_image(
177
181
  log.debug(f"Exporting image with params: {request_params}")
178
182
 
179
183
  url = "{earth_engine_api_url}/projects/{project}/image:export"
180
- return await client.rest_call("POST", url, data=request_params)
184
+ response_data = await client.rest_call("POST", url, data=request_params)
185
+ return Task.model_validate(response_data)
181
186
 
182
187
 
183
188
  async def image_to_drive_async(
@@ -198,8 +203,12 @@ async def image_to_drive_async(
198
203
  scale: Optional[float] = None,
199
204
  crs: Optional[str] = None,
200
205
  crs_transform: Optional[AffineTransform] = None,
201
- ) -> dict:
202
- """Abstracts the export of an image to Google Drive."""
206
+ ) -> Task:
207
+ """Abstracts the export of an image to Google Drive.
208
+
209
+ Returns:
210
+ Task: The export task response from the API
211
+ """
203
212
  drive_options = DriveOptions(
204
213
  file_format=file_format,
205
214
  drive_destination=DriveDestination(
@@ -240,8 +249,12 @@ async def image_to_asset_async(
240
249
  scale: Optional[float] = None,
241
250
  crs: Optional[str] = None,
242
251
  crs_transform: Optional[AffineTransform] = None,
243
- ) -> dict:
244
- """Abstracts the export of an image to Earth Engine Asset."""
252
+ ) -> Task:
253
+ """Abstracts the export of an image to Earth Engine Asset.
254
+
255
+ Returns:
256
+ Task: The export task response from the API
257
+ """
245
258
  asset_options = AssetOptions(
246
259
  earth_engine_destination=EarthEngineDestination(name=asset_id),
247
260
  )
@@ -7,6 +7,7 @@ if TYPE_CHECKING:
7
7
  from eeclient.client import EESession
8
8
 
9
9
  from ee import serializer, encodable
10
+ from eeclient.tasks import Task
10
11
 
11
12
 
12
13
  class TableFileFormat(str, Enum):
@@ -75,11 +76,14 @@ async def _export_table(
75
76
  max_vertices: Optional[int] = None,
76
77
  workload_tag: Optional[str] = None,
77
78
  priority: Optional[int] = None,
78
- ) -> dict:
79
+ ) -> Task:
79
80
  """
80
81
  Export a table to either Google Drive or Earth Engine Asset.
81
82
 
82
83
  Exactly one of drive_options or asset_options must be provided.
84
+
85
+ Returns:
86
+ Task: The export task response from the API
83
87
  """
84
88
  if (drive_options is None and asset_options is None) or (
85
89
  drive_options is not None and asset_options is not None
@@ -107,24 +111,30 @@ async def _export_table(
107
111
  params = export_options.model_dump(by_alias=True, exclude_none=True)
108
112
 
109
113
  url = "{earth_engine_api_url}/projects/{project}/table:export"
110
- return await client.rest_call("POST", url, data=params)
114
+ response_data = await client.rest_call("POST", url, data=params)
115
+ return Task.model_validate(response_data)
111
116
 
112
117
 
113
118
  async def table_to_drive_async(
114
119
  client: "EESession",
115
120
  collection,
116
- filename_prefix: str,
117
121
  file_format: TableFileFormat,
122
+ filename_prefix: str = "",
118
123
  folder: Optional[str] = None,
119
124
  description: str = "myExportTableTask",
120
125
  selectors: Optional[list] = None,
121
126
  max_vertices: Optional[int] = None,
122
127
  priority: Optional[int] = None,
123
- ) -> dict:
128
+ ) -> Task:
124
129
  """
125
130
  Export a table to Google Drive.
131
+
132
+ Returns:
133
+ Task: The export task response from the API
126
134
  """
127
- drive_destination = DriveDestination(filename_prefix=filename_prefix, folder=folder)
135
+ drive_destination = DriveDestination(
136
+ filename_prefix=filename_prefix or description, folder=folder
137
+ )
128
138
  drive_options = DriveOptions(
129
139
  file_format=file_format, drive_destination=drive_destination
130
140
  )
@@ -148,9 +158,12 @@ async def table_to_asset_async(
148
158
  selectors: Optional[list] = None,
149
159
  max_vertices: Optional[int] = None,
150
160
  priority: Optional[int] = None,
151
- ) -> dict:
161
+ ) -> Task:
152
162
  """
153
163
  Export a table to Earth Engine Asset.
164
+
165
+ Returns:
166
+ Task: The export task response from the API
154
167
  """
155
168
  asset_options = AssetOptions(
156
169
  earth_engine_destination=EarthEngineDestination(name=asset_id)
@@ -2,7 +2,7 @@ import os
2
2
  import requests
3
3
  import logging
4
4
  from eeclient.models import SepalHeaders, SepalUser
5
- from typing import Union
5
+ from typing import Optional, Union
6
6
 
7
7
  from ee.imagecollection import ImageCollection
8
8
  from ee.feature import Feature
@@ -59,11 +59,17 @@ def parse_cookie_string(cookie_string):
59
59
  return cookies
60
60
 
61
61
 
62
- def get_sepal_headers_from_auth():
62
+ def get_sepal_headers_from_auth(
63
+ sepal_user: Optional[str] = None,
64
+ sepal_password: Optional[str] = None,
65
+ sepal_host: Optional[str] = None,
66
+ ) -> SepalHeaders:
67
+
63
68
  log.debug("Getting SEPAL headers from authentication")
64
- sepal_user = os.getenv("LOCAL_SEPAL_USER")
65
- sepal_password = os.getenv("LOCAL_SEPAL_PASSWORD")
66
- sepal_host = os.getenv("SEPAL_HOST")
69
+
70
+ sepal_user = sepal_user or os.getenv("LOCAL_SEPAL_USER")
71
+ sepal_password = sepal_password or os.getenv("LOCAL_SEPAL_PASSWORD")
72
+ sepal_host = sepal_host or os.getenv("SEPAL_HOST")
67
73
 
68
74
  if not sepal_user or not sepal_password or not sepal_host:
69
75
  raise ValueError(
@@ -0,0 +1,37 @@
1
+ from eeclient.models import SepalHeaders
2
+ import os
3
+ import logging
4
+
5
+ log = logging.getLogger("eeclient")
6
+
7
+
8
+ class SepalCredentialMixin:
9
+ def __init__(self, sepal_headers: SepalHeaders):
10
+ log.debug("Initializing GDriveInterface with SEPAL headers")
11
+ self.sepal_host = os.getenv("SEPAL_HOST")
12
+ if not self.sepal_host:
13
+ raise ValueError("SEPAL_HOST environment variable not set")
14
+
15
+ self.sepal_headers = SepalHeaders.model_validate(sepal_headers)
16
+ self.sepal_session_id = self.sepal_headers.cookies["SEPAL-SESSIONID"]
17
+ self.sepal_user_data = self.sepal_headers.sepal_user
18
+ self.user = self.sepal_user_data.username
19
+
20
+ self.sepal_api_download_url = (
21
+ f"https://{self.sepal_host}/api/user-files/download/"
22
+ "?path=%2F.config%2Fearthengine%2Fcredentials"
23
+ )
24
+ self.verify_ssl = not (
25
+ self.sepal_host == "host.docker.internal"
26
+ or self.sepal_host == "danielg.sepal.io"
27
+ )
28
+
29
+ self._google_tokens = self.sepal_user_data.google_tokens
30
+ if self._google_tokens:
31
+ self.access_token = self._google_tokens.access_token
32
+ self.project_id = self._google_tokens.project_id
33
+ self.expiry_date = self._google_tokens.access_token_expiry_date
34
+ else:
35
+ self.access_token = None
36
+ self.project_id = None
37
+ self.expiry_date = 0
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
3
3
 
4
4
  if TYPE_CHECKING:
5
5
  from eeclient.client import EESession
6
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, Field, computed_field
7
7
  from typing import List, Optional, Any
8
8
  from datetime import datetime
9
9
 
@@ -31,7 +31,7 @@ class Stage(CamelCaseModel):
31
31
 
32
32
  class TaskMetadata(CamelCaseModel):
33
33
  type_info: str = Field(alias="@type")
34
- state: str
34
+ state: Optional[str] = None
35
35
  description: str
36
36
  priority: int
37
37
  create_time: datetime
@@ -40,7 +40,7 @@ class TaskMetadata(CamelCaseModel):
40
40
  end_time: Optional[datetime] = None
41
41
  type: str
42
42
  destination_uris: Optional[List[str]] = None
43
- attempt: int
43
+ attempt: Optional[int] = None
44
44
  progress: Optional[float] = None
45
45
  stages: Optional[List[Stage]] = None
46
46
  batch_eecu_usage_seconds: Optional[float] = None
@@ -55,9 +55,20 @@ class Task(CamelCaseModel):
55
55
  metadata: TaskMetadata
56
56
  done: Optional[bool] = None
57
57
  response: Optional[Response] = None
58
- # Add error field which might be present instead of response
59
58
  error: Optional[Any] = None
60
59
 
60
+ @computed_field
61
+ @property
62
+ def id(self) -> str:
63
+ """Extract the task ID from the name field.
64
+
65
+ The name field has format: 'projects/{project}/operations/{task_id}'
66
+ This property extracts just the {task_id} part.
67
+ """
68
+ if "/operations/" in self.name:
69
+ return self.name.split("/operations/")[-1]
70
+ return self.name
71
+
61
72
 
62
73
  class TasksResponse(CamelCaseModel):
63
74
  operations: List[Task]
@@ -79,7 +90,7 @@ async def get_tasks_async(client: "EESession") -> TasksResponse:
79
90
  return operations_response
80
91
 
81
92
 
82
- async def get_task_async(client: "EESession", task_id: str):
93
+ async def get_task_async(client: "EESession", task_id: str) -> Optional[Task]:
83
94
  """Search for the described task in the user Task list return None if
84
95
  nothing is found.
85
96
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ee-client"
7
- version = "2.0.3"
7
+ version = "2.1.0"
8
8
  description = "extends the capabilities of the earthengine-api by providing custom session management and client interactions"
9
9
  readme = { file = "README.rst", content-type = "text/x-rst" }
10
10
  authors = [
@@ -66,7 +66,7 @@ branch = true
66
66
  [tool.commitizen]
67
67
  tag_format = "v$major.$minor.$patch$prerelease"
68
68
  update_changelog_on_bump = false
69
- version = "2.0.3"
69
+ version = "2.1.0"
70
70
  version_files = [
71
71
  "pyproject.toml:version",
72
72
  "eeclient/__init__.py:__version__",
File without changes
File without changes
File without changes
File without changes
File without changes