earthengine-api 1.6.13__py3-none-any.whl → 1.7.4__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.
Potentially problematic release.
This version of earthengine-api might be problematic. Click here for more details.
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/METADATA +2 -3
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/RECORD +44 -44
- ee/__init__.py +13 -13
- ee/_cloud_api_utils.py +29 -28
- ee/_helpers.py +6 -6
- ee/_utils.py +2 -1
- ee/apitestcase.py +10 -10
- ee/batch.py +7 -0
- ee/cli/commands.py +6 -10
- ee/cli/utils.py +28 -23
- ee/collection.py +3 -2
- ee/computedobject.py +4 -1
- ee/customfunction.py +2 -1
- ee/data.py +32 -31
- ee/deprecation.py +8 -2
- ee/deserializer.py +10 -10
- ee/ee_number.py +6 -16
- ee/encodable.py +2 -1
- ee/image_converter.py +3 -3
- ee/imagecollection.py +2 -2
- ee/model.py +29 -31
- ee/oauth.py +37 -37
- ee/reducer.py +2 -0
- ee/serializer.py +6 -6
- ee/table_converter.py +3 -3
- ee/terrain.py +1 -1
- ee/tests/batch_test.py +67 -3
- ee/tests/collection_test.py +35 -0
- ee/tests/data_test.py +300 -4
- ee/tests/deprecation_test.py +4 -2
- ee/tests/deserializer_test.py +47 -0
- ee/tests/ee_number_test.py +40 -1
- ee/tests/image_converter_test.py +1 -3
- ee/tests/kernel_test.py +4 -0
- ee/tests/model_test.py +12 -0
- ee/tests/oauth_test.py +170 -7
- ee/tests/reducer_test.py +13 -0
- ee/tests/serializer_test.py +29 -2
- ee/tests/table_converter_test.py +49 -5
- ee/tests/terrain_test.py +8 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/WHEEL +0 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/entry_points.txt +0 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/licenses/LICENSE +0 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/top_level.txt +0 -0
ee/cli/utils.py
CHANGED
|
@@ -14,7 +14,7 @@ import re
|
|
|
14
14
|
import tempfile
|
|
15
15
|
import threading
|
|
16
16
|
import time
|
|
17
|
-
from typing import Any, AnyStr
|
|
17
|
+
from typing import Any, AnyStr
|
|
18
18
|
import urllib.parse
|
|
19
19
|
|
|
20
20
|
from google.cloud import storage
|
|
@@ -32,7 +32,7 @@ DEFAULT_EE_CONFIG_FILE_RELATIVE = os.path.join(
|
|
|
32
32
|
DEFAULT_EE_CONFIG_FILE = os.path.join(
|
|
33
33
|
HOMEDIR, DEFAULT_EE_CONFIG_FILE_RELATIVE)
|
|
34
34
|
|
|
35
|
-
CONFIG_PARAMS: dict[str,
|
|
35
|
+
CONFIG_PARAMS: dict[str, str | list[str] | None] = {
|
|
36
36
|
'account': None,
|
|
37
37
|
'cloud_api_key': None,
|
|
38
38
|
'private_key': None,
|
|
@@ -145,7 +145,10 @@ class CommandLineConfig:
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
def _split_gcs_path(path):
|
|
148
|
-
|
|
148
|
+
# This only catches some troubles. For complete details on naming, see:
|
|
149
|
+
# https://cloud.google.com/storage/docs/buckets
|
|
150
|
+
# https://cloud.google.com/storage/docs/objects#naming
|
|
151
|
+
m = re.search('gs://([a-z0-9][a-z0-9-_.]*)/(.*)', path, re.IGNORECASE)
|
|
149
152
|
if not m:
|
|
150
153
|
raise ValueError(f"'{path}' is not a valid GCS path")
|
|
151
154
|
|
|
@@ -197,7 +200,7 @@ class GcsHelper:
|
|
|
197
200
|
if not os.path.exists(dir_path):
|
|
198
201
|
os.makedirs(dir_path)
|
|
199
202
|
|
|
200
|
-
if output_path
|
|
203
|
+
if not output_path.endswith('/'):
|
|
201
204
|
blob.download_to_filename(output_path)
|
|
202
205
|
|
|
203
206
|
return temp_dir
|
|
@@ -206,7 +209,7 @@ class GcsHelper:
|
|
|
206
209
|
"""Uploads a directory to cloud storage."""
|
|
207
210
|
canonical_path = _canonicalize_dir_path(source_path)
|
|
208
211
|
|
|
209
|
-
files =
|
|
212
|
+
files = []
|
|
210
213
|
for dirpath, _, filenames in os.walk(canonical_path):
|
|
211
214
|
files += [os.path.join(dirpath, f) for f in filenames]
|
|
212
215
|
|
|
@@ -224,7 +227,7 @@ def is_gcs_path(path: str) -> bool:
|
|
|
224
227
|
|
|
225
228
|
|
|
226
229
|
def query_yes_no(msg: str) -> bool:
|
|
227
|
-
print('
|
|
230
|
+
print(f'{msg} (y/n)')
|
|
228
231
|
while True:
|
|
229
232
|
confirm = input().lower()
|
|
230
233
|
if confirm == 'y':
|
|
@@ -264,10 +267,9 @@ def wait_for_task(
|
|
|
264
267
|
state = status['metadata']['state']
|
|
265
268
|
if status.get('done', False):
|
|
266
269
|
error_message = status.get('error', {}).get('message')
|
|
267
|
-
print('Task
|
|
268
|
-
% (task_id, state, elapsed))
|
|
270
|
+
print(f'Task {task_id} ended at state: {state} after {elapsed:.2f} seconds')
|
|
269
271
|
if error_message:
|
|
270
|
-
raise ee.ee_exception.EEException('Error:
|
|
272
|
+
raise ee.ee_exception.EEException(f'Error: {error_message}')
|
|
271
273
|
return
|
|
272
274
|
if log_progress and elapsed - last_check >= 30:
|
|
273
275
|
print('[{:%H:%M:%S}] Current state for task {}: {}'
|
|
@@ -309,17 +311,20 @@ def wait_for_tasks(
|
|
|
309
311
|
status_counts = collections.defaultdict(int)
|
|
310
312
|
for status in status_list:
|
|
311
313
|
status_counts[status] += 1
|
|
314
|
+
succeeded = status_counts['SUCCEEDED']
|
|
315
|
+
failed = status_counts['FAILED']
|
|
316
|
+
cancelled = status_counts['CANCELLED']
|
|
312
317
|
num_incomplete = (
|
|
313
318
|
len(status_list)
|
|
314
|
-
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
319
|
+
- succeeded
|
|
320
|
+
- failed
|
|
321
|
+
- cancelled
|
|
317
322
|
)
|
|
318
323
|
print('Finished waiting for tasks.\n Status summary:')
|
|
319
|
-
print('
|
|
320
|
-
print('
|
|
321
|
-
print('
|
|
322
|
-
print('
|
|
324
|
+
print(f' {succeeded} tasks completed successfully.')
|
|
325
|
+
print(f' {failed} tasks failed.')
|
|
326
|
+
print(f' {cancelled} tasks cancelled.')
|
|
327
|
+
print(f' {num_incomplete} tasks are still incomplete (timed-out)')
|
|
323
328
|
|
|
324
329
|
|
|
325
330
|
def expand_gcs_wildcards(source_files: list[str]) -> Iterable[str]:
|
|
@@ -351,7 +356,7 @@ def expand_gcs_wildcards(source_files: list[str]) -> Iterable[str]:
|
|
|
351
356
|
bucket, rest = bucket_match.group(1, 2)
|
|
352
357
|
else:
|
|
353
358
|
raise ee.ee_exception.EEException(
|
|
354
|
-
'Badly formatted source file or bucket:
|
|
359
|
+
f'Badly formatted source file or bucket: {source}')
|
|
355
360
|
prefix = rest[:rest.find('*')] # Everything before the first wildcard
|
|
356
361
|
|
|
357
362
|
bucket_files = _gcs_ls(bucket, prefix)
|
|
@@ -395,23 +400,23 @@ def _gcs_ls(bucket: str, prefix: str = '') -> Iterable[str]:
|
|
|
395
400
|
try:
|
|
396
401
|
response, content = http.request(url, method=method)
|
|
397
402
|
except httplib2.HttpLib2Error as e:
|
|
398
|
-
raise ee.ee_exception.EEException('Unexpected HTTP error:
|
|
403
|
+
raise ee.ee_exception.EEException(f'Unexpected HTTP error: {e}') from e
|
|
399
404
|
|
|
400
405
|
if response.status < 100 or response.status >= 300:
|
|
401
406
|
raise ee.ee_exception.EEException(
|
|
402
|
-
'Error retrieving bucket
|
|
403
|
-
|
|
407
|
+
f'Error retrieving bucket {bucket}; '
|
|
408
|
+
f'Server returned HTTP code: {response.status}'
|
|
404
409
|
)
|
|
405
410
|
|
|
406
411
|
json_content = json.loads(content)
|
|
407
412
|
if 'error' in json_content:
|
|
408
413
|
json_error = json_content['error']['message']
|
|
409
|
-
raise ee.ee_exception.EEException(
|
|
410
|
-
|
|
414
|
+
raise ee.ee_exception.EEException(
|
|
415
|
+
f'Error retrieving bucket {bucket}: {json_error}')
|
|
411
416
|
|
|
412
417
|
if 'items' not in json_content:
|
|
413
418
|
raise ee.ee_exception.EEException(
|
|
414
|
-
'Cannot find items list in the response from GCS:
|
|
419
|
+
f'Cannot find items list in the response from GCS: {json_content}')
|
|
415
420
|
objects = json_content['items']
|
|
416
421
|
object_names = [str(gc_object['name']) for gc_object in objects]
|
|
417
422
|
|
ee/collection.py
CHANGED
|
@@ -5,8 +5,9 @@ This class is never intended to be instantiated by the user.
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
from collections.abc import Callable
|
|
8
9
|
import datetime
|
|
9
|
-
from typing import Any,
|
|
10
|
+
from typing import Any, Generic, TypeVar
|
|
10
11
|
|
|
11
12
|
from ee import _arg_types
|
|
12
13
|
from ee import _utils
|
|
@@ -204,7 +205,7 @@ class Collection(Generic[ElementType], element.Element):
|
|
|
204
205
|
|
|
205
206
|
# pylint: disable-next=redefined-builtin
|
|
206
207
|
def aggregate_product(self, property: _arg_types.String) -> ee_number.Number:
|
|
207
|
-
"""Returns the product of the values
|
|
208
|
+
"""Returns the product of the values of the selected property.
|
|
208
209
|
|
|
209
210
|
Aggregates over a given property of the objects in a collection, calculating
|
|
210
211
|
the product of the values of the selected property.
|
ee/computedobject.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from ee import _utils
|
|
8
9
|
from ee import data
|
|
@@ -233,9 +234,11 @@ class ComputedObject(encodable.Encodable, metaclass=ComputedObjectMetaclass):
|
|
|
233
234
|
return obj
|
|
234
235
|
else:
|
|
235
236
|
result = cls.__new__(cls) # pylint: disable=no-value-for-parameter
|
|
237
|
+
# pylint: disable=attribute-error
|
|
236
238
|
result.func = obj.func
|
|
237
239
|
result.args = obj.args
|
|
238
240
|
result.varName = obj.varName
|
|
241
|
+
# pylint: enable=attribute-error
|
|
239
242
|
return result
|
|
240
243
|
|
|
241
244
|
@staticmethod
|
ee/customfunction.py
CHANGED
ee/data.py
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
-
from collections.abc import Iterator, Sequence
|
|
8
|
+
from collections.abc import Callable, Iterator, Sequence
|
|
9
9
|
import contextlib
|
|
10
10
|
import json
|
|
11
11
|
import platform
|
|
12
12
|
import re
|
|
13
13
|
import sys
|
|
14
14
|
import threading
|
|
15
|
-
from typing import Any
|
|
15
|
+
from typing import Any
|
|
16
16
|
import uuid
|
|
17
17
|
import warnings
|
|
18
18
|
|
|
@@ -112,7 +112,7 @@ class _ThreadLocals(threading.local):
|
|
|
112
112
|
# and the user would have to modify each call to profile, rather than
|
|
113
113
|
# enabling profiling as a wrapper around the entire program (with
|
|
114
114
|
# ee.data.profiling, defined below).
|
|
115
|
-
self.profile_hook:
|
|
115
|
+
self.profile_hook: Callable[[str], None] | None = None
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
_thread_locals = _ThreadLocals()
|
|
@@ -125,11 +125,11 @@ def _get_state() -> _state.EEState:
|
|
|
125
125
|
|
|
126
126
|
def initialize(
|
|
127
127
|
credentials: Any = None,
|
|
128
|
-
api_base_url:
|
|
129
|
-
tile_base_url:
|
|
130
|
-
cloud_api_base_url:
|
|
131
|
-
cloud_api_key:
|
|
132
|
-
project:
|
|
128
|
+
api_base_url: str | None = None,
|
|
129
|
+
tile_base_url: str | None = None,
|
|
130
|
+
cloud_api_base_url: str | None = None,
|
|
131
|
+
cloud_api_key: str | None = None,
|
|
132
|
+
project: str | None = None,
|
|
133
133
|
http_transport: Any = None,
|
|
134
134
|
) -> None:
|
|
135
135
|
"""Initializes the data module, setting credentials and base URLs.
|
|
@@ -297,7 +297,7 @@ def _get_cloud_projects_raw() -> Any:
|
|
|
297
297
|
return state.cloud_api_resource_raw.projects()
|
|
298
298
|
|
|
299
299
|
|
|
300
|
-
def _make_request_headers() ->
|
|
300
|
+
def _make_request_headers() -> dict[str, Any] | None:
|
|
301
301
|
"""Adds headers based on client context."""
|
|
302
302
|
state = _get_state()
|
|
303
303
|
headers: dict[str, Any] = {}
|
|
@@ -329,7 +329,7 @@ def _handle_profiling_response(response: httplib2.Response) -> None:
|
|
|
329
329
|
|
|
330
330
|
|
|
331
331
|
def _execute_cloud_call(
|
|
332
|
-
call: googleapiclient.http.HttpRequest, num_retries:
|
|
332
|
+
call: googleapiclient.http.HttpRequest, num_retries: int | None = None
|
|
333
333
|
) -> Any:
|
|
334
334
|
"""Executes a Cloud API call and translates errors to EEExceptions.
|
|
335
335
|
|
|
@@ -399,7 +399,7 @@ def setUserAgent(user_agent: str) -> None:
|
|
|
399
399
|
_get_state().user_agent = user_agent
|
|
400
400
|
|
|
401
401
|
|
|
402
|
-
def getUserAgent() ->
|
|
402
|
+
def getUserAgent() -> str | None:
|
|
403
403
|
return _get_state().user_agent
|
|
404
404
|
|
|
405
405
|
|
|
@@ -449,7 +449,7 @@ def profiling(hook: Any) -> Iterator[None]:
|
|
|
449
449
|
|
|
450
450
|
|
|
451
451
|
@deprecation.Deprecated('Use getAsset')
|
|
452
|
-
def getInfo(asset_id: str) ->
|
|
452
|
+
def getInfo(asset_id: str) -> Any | None:
|
|
453
453
|
"""Load info for an asset, given an asset id.
|
|
454
454
|
|
|
455
455
|
Args:
|
|
@@ -512,8 +512,8 @@ def getList(params: dict[str, Any]) -> Any:
|
|
|
512
512
|
|
|
513
513
|
|
|
514
514
|
def listImages(
|
|
515
|
-
params:
|
|
516
|
-
) -> dict[str,
|
|
515
|
+
params: str | dict[str, Any],
|
|
516
|
+
) -> dict[str, list[Any] | None]:
|
|
517
517
|
"""Returns the images in an image collection or folder.
|
|
518
518
|
|
|
519
519
|
Args:
|
|
@@ -550,7 +550,7 @@ def listImages(
|
|
|
550
550
|
return images
|
|
551
551
|
|
|
552
552
|
|
|
553
|
-
def listAssets(params:
|
|
553
|
+
def listAssets(params: str | dict[str, Any]) -> dict[str, list[Any]]:
|
|
554
554
|
"""Returns the assets in a folder.
|
|
555
555
|
|
|
556
556
|
Args:
|
|
@@ -603,7 +603,7 @@ def listAssets(params: Union[str, dict[str, Any]]) -> dict[str, list[Any]]:
|
|
|
603
603
|
return assets
|
|
604
604
|
|
|
605
605
|
|
|
606
|
-
def listBuckets(project:
|
|
606
|
+
def listBuckets(project: str | None = None) -> Any:
|
|
607
607
|
"""Returns top-level assets and folders for the Cloud Project or user.
|
|
608
608
|
|
|
609
609
|
Args:
|
|
@@ -689,7 +689,7 @@ def getMapId(params: dict[str, Any]) -> dict[str, Any]:
|
|
|
689
689
|
)
|
|
690
690
|
state = _get_state()
|
|
691
691
|
map_name = result['name']
|
|
692
|
-
url_format = '
|
|
692
|
+
url_format = '{}/{}/{}/tiles/{{z}}/{{x}}/{{y}}'.format(
|
|
693
693
|
state.tile_base_url, _cloud_api_utils.VERSION, map_name)
|
|
694
694
|
if state.cloud_api_key:
|
|
695
695
|
url_format += f'?key={state.cloud_api_key}'
|
|
@@ -738,7 +738,7 @@ def getFeatureViewTilesKey(params: dict[str, Any]) -> dict[str, Any]:
|
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
|
|
741
|
-
def _extract_table_converter(params: dict[str, Any]) ->
|
|
741
|
+
def _extract_table_converter(params: dict[str, Any]) -> Any | None:
|
|
742
742
|
if 'fileFormat' in params:
|
|
743
743
|
file_format = params.get('fileFormat')
|
|
744
744
|
converter = table_converter.from_file_format(file_format)
|
|
@@ -1070,7 +1070,7 @@ def computeValue(obj: computedobject.ComputedObject) -> Any:
|
|
|
1070
1070
|
|
|
1071
1071
|
@deprecation.Deprecated('Use getThumbId and makeThumbUrl')
|
|
1072
1072
|
def getThumbnail(
|
|
1073
|
-
params: dict[str, Any], thumbType:
|
|
1073
|
+
params: dict[str, Any], thumbType: str | None = None
|
|
1074
1074
|
) -> Any:
|
|
1075
1075
|
"""Get a Thumbnail for a given asset.
|
|
1076
1076
|
|
|
@@ -1105,7 +1105,7 @@ def getThumbnail(
|
|
|
1105
1105
|
|
|
1106
1106
|
|
|
1107
1107
|
def getThumbId(
|
|
1108
|
-
params: dict[str, Any], thumbType:
|
|
1108
|
+
params: dict[str, Any], thumbType: str | None = None
|
|
1109
1109
|
) -> dict[str, str]:
|
|
1110
1110
|
"""Get a Thumbnail ID for a given asset.
|
|
1111
1111
|
|
|
@@ -1442,8 +1442,8 @@ def getAlgorithms() -> Any:
|
|
|
1442
1442
|
@_utils.accept_opt_prefix('opt_path', 'opt_force', 'opt_properties')
|
|
1443
1443
|
def createAsset(
|
|
1444
1444
|
value: dict[str, Any],
|
|
1445
|
-
path:
|
|
1446
|
-
properties:
|
|
1445
|
+
path: str | None = None,
|
|
1446
|
+
properties: dict[str, Any] | None = None,
|
|
1447
1447
|
) -> dict[str, Any]:
|
|
1448
1448
|
"""Creates an asset from a JSON value.
|
|
1449
1449
|
|
|
@@ -1589,7 +1589,7 @@ def getTaskList() -> list[Any]:
|
|
|
1589
1589
|
for o in listOperations()]
|
|
1590
1590
|
|
|
1591
1591
|
|
|
1592
|
-
def listOperations(project:
|
|
1592
|
+
def listOperations(project: str | None = None) -> list[Any]:
|
|
1593
1593
|
"""Retrieves a list of the user's tasks.
|
|
1594
1594
|
|
|
1595
1595
|
Args:
|
|
@@ -1616,7 +1616,7 @@ def listOperations(project: Optional[str] = None) -> list[Any]:
|
|
|
1616
1616
|
|
|
1617
1617
|
|
|
1618
1618
|
@deprecation.Deprecated('Use getOperation')
|
|
1619
|
-
def getTaskStatus(taskId:
|
|
1619
|
+
def getTaskStatus(taskId: list[str] | str) -> list[Any]:
|
|
1620
1620
|
"""Retrieve status of one or more long-running tasks.
|
|
1621
1621
|
|
|
1622
1622
|
Args:
|
|
@@ -1868,7 +1868,7 @@ def _startIngestion(
|
|
|
1868
1868
|
request_id: Any,
|
|
1869
1869
|
params: dict[str, Any],
|
|
1870
1870
|
allow_overwrite: bool = False,
|
|
1871
|
-
import_mode:
|
|
1871
|
+
import_mode: str | None = _INTERNAL_IMPORT,
|
|
1872
1872
|
) -> dict[str, Any]:
|
|
1873
1873
|
"""Starts an ingestion task or creates an external image."""
|
|
1874
1874
|
request = {
|
|
@@ -2126,7 +2126,7 @@ def getIamPolicy(asset_id: str) -> Any:
|
|
|
2126
2126
|
|
|
2127
2127
|
|
|
2128
2128
|
@deprecation.Deprecated('Use setIamPolicy')
|
|
2129
|
-
def setAssetAcl(assetId: str, aclUpdate:
|
|
2129
|
+
def setAssetAcl(assetId: str, aclUpdate: str | dict[str, Any]) -> None:
|
|
2130
2130
|
"""Sets the access control list of the asset with the given ID.
|
|
2131
2131
|
|
|
2132
2132
|
The owner ACL cannot be changed, and the final ACL of the asset
|
|
@@ -2161,6 +2161,7 @@ def setIamPolicy(asset_id: str, policy: Any) -> None:
|
|
|
2161
2161
|
.setIamPolicy(resource=name, body={'policy': policy}, prettyPrint=False)
|
|
2162
2162
|
)
|
|
2163
2163
|
|
|
2164
|
+
|
|
2164
2165
|
@deprecation.Deprecated('Use ee.data.updateAsset().')
|
|
2165
2166
|
def setAssetProperties(assetId: str, properties: dict[str, Any]) -> None:
|
|
2166
2167
|
"""Sets metadata properties of the asset with the given ID.
|
|
@@ -2239,7 +2240,7 @@ def getProjectConfig() -> dict[str, Any]:
|
|
|
2239
2240
|
|
|
2240
2241
|
|
|
2241
2242
|
def updateProjectConfig(
|
|
2242
|
-
project_config: dict[str, Any], update_mask:
|
|
2243
|
+
project_config: dict[str, Any], update_mask: Sequence[str] | None = None
|
|
2243
2244
|
) -> dict[str, Any]:
|
|
2244
2245
|
"""Updates the project config for the current project.
|
|
2245
2246
|
|
|
@@ -2311,12 +2312,12 @@ def convert_asset_id_to_asset_name(asset_id: str) -> str:
|
|
|
2311
2312
|
return _cloud_api_utils.convert_asset_id_to_asset_name(asset_id)
|
|
2312
2313
|
|
|
2313
2314
|
|
|
2314
|
-
def getWorkloadTag() ->
|
|
2315
|
+
def getWorkloadTag() -> int | str | None:
|
|
2315
2316
|
"""Returns the currently set workload tag."""
|
|
2316
2317
|
return _get_state().workload_tag.get()
|
|
2317
2318
|
|
|
2318
2319
|
|
|
2319
|
-
def setWorkloadTag(tag:
|
|
2320
|
+
def setWorkloadTag(tag: int | str | None) -> None:
|
|
2320
2321
|
"""Sets the workload tag, used to label computation and exports.
|
|
2321
2322
|
|
|
2322
2323
|
Workload tag must be 1 - 63 characters, beginning and ending with an
|
|
@@ -2330,7 +2331,7 @@ def setWorkloadTag(tag: Optional[Union[int, str]]) -> None:
|
|
|
2330
2331
|
|
|
2331
2332
|
|
|
2332
2333
|
@contextlib.contextmanager
|
|
2333
|
-
def workloadTagContext(tag:
|
|
2334
|
+
def workloadTagContext(tag: int | str | None) -> Iterator[None]:
|
|
2334
2335
|
"""Produces a context manager which sets the workload tag, then resets it.
|
|
2335
2336
|
|
|
2336
2337
|
Workload tag must be 1 - 63 characters, beginning and ending with an
|
|
@@ -2350,7 +2351,7 @@ def workloadTagContext(tag: Optional[Union[int, str]]) -> Iterator[None]:
|
|
|
2350
2351
|
resetWorkloadTag()
|
|
2351
2352
|
|
|
2352
2353
|
|
|
2353
|
-
def setDefaultWorkloadTag(tag:
|
|
2354
|
+
def setDefaultWorkloadTag(tag: int | str | None) -> None:
|
|
2354
2355
|
"""Sets the workload tag, and as the default for which to reset back to.
|
|
2355
2356
|
|
|
2356
2357
|
For example, calling `ee.data.resetWorkloadTag()` will reset the workload tag
|
ee/deprecation.py
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from collections.abc import Callable
|
|
5
6
|
import dataclasses
|
|
6
7
|
import datetime
|
|
7
8
|
import functools
|
|
8
9
|
import inspect
|
|
9
10
|
import json
|
|
10
|
-
from typing import Any
|
|
11
|
+
from typing import Any
|
|
11
12
|
import urllib
|
|
12
13
|
import warnings
|
|
13
14
|
|
|
@@ -36,7 +37,7 @@ def Deprecated(message: str):
|
|
|
36
37
|
@functools.wraps(func)
|
|
37
38
|
def Wrapper(*args, **kwargs):
|
|
38
39
|
warnings.warn_explicit(
|
|
39
|
-
'{}() is deprecated: {}'
|
|
40
|
+
f'{func.__name__}() is deprecated: {message}',
|
|
40
41
|
category=DeprecationWarning,
|
|
41
42
|
filename=func.__code__.co_filename,
|
|
42
43
|
lineno=func.__code__.co_firstlineno + 1,
|
|
@@ -204,6 +205,11 @@ def _IssueAssetDeprecationWarning(asset: DeprecatedAsset) -> None:
|
|
|
204
205
|
formatted_date = removal_date.strftime('%B %d, %Y').replace(' 0', ' ')
|
|
205
206
|
warning += f' by {formatted_date}'
|
|
206
207
|
warning += '.'
|
|
208
|
+
if asset.replacement_id:
|
|
209
|
+
warning = (
|
|
210
|
+
warning
|
|
211
|
+
+ f'\nThis dataset has been superseded by {asset.replacement_id}\n'
|
|
212
|
+
)
|
|
207
213
|
if asset.learn_more_url:
|
|
208
214
|
warning = warning + f'\nLearn more: {asset.learn_more_url}\n'
|
|
209
215
|
warnings.warn(warning, category=DeprecationWarning)
|
ee/deserializer.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""A deserializer that decodes EE object trees from JSON DAGs."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
from ee import apifunction
|
|
7
7
|
from ee import computedobject
|
|
@@ -13,7 +13,7 @@ from ee import function
|
|
|
13
13
|
from ee import geometry
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def fromJSON(json_obj:
|
|
16
|
+
def fromJSON(json_obj: bytes | str) -> Any: # pylint: disable=g-bad-name
|
|
17
17
|
"""Deserialize an object from a JSON string appropriate for API calls.
|
|
18
18
|
|
|
19
19
|
Args:
|
|
@@ -76,7 +76,7 @@ def _decodeValue(json_obj: Any, named_values: dict[str, Any]) -> Any:
|
|
|
76
76
|
|
|
77
77
|
# Ensure that we've got a proper object at this point.
|
|
78
78
|
if not isinstance(json_obj, dict):
|
|
79
|
-
raise ee_exception.EEException('Cannot decode object: '
|
|
79
|
+
raise ee_exception.EEException(f'Cannot decode object: {json_obj}')
|
|
80
80
|
|
|
81
81
|
# Check for explicitly typed values.
|
|
82
82
|
type_name = json_obj['type']
|
|
@@ -88,12 +88,12 @@ def _decodeValue(json_obj: Any, named_values: dict[str, Any]) -> Any:
|
|
|
88
88
|
elif type_name == 'ArgumentRef':
|
|
89
89
|
var_name = json_obj['value']
|
|
90
90
|
if not isinstance(var_name, str):
|
|
91
|
-
raise ee_exception.EEException('Invalid variable name: '
|
|
92
|
-
return customfunction.CustomFunction.variable(None, var_name)
|
|
91
|
+
raise ee_exception.EEException(f'Invalid variable name: {var_name}')
|
|
92
|
+
return customfunction.CustomFunction.variable(None, var_name)
|
|
93
93
|
elif type_name == 'Date':
|
|
94
94
|
microseconds = json_obj['value']
|
|
95
95
|
if not isinstance(microseconds, (float, int)):
|
|
96
|
-
raise ee_exception.EEException('Invalid date value: '
|
|
96
|
+
raise ee_exception.EEException(f'Invalid date value: {microseconds}')
|
|
97
97
|
return ee_date.Date(microseconds / 1e3)
|
|
98
98
|
elif type_name == 'Bytes':
|
|
99
99
|
result = encodable.Encodable()
|
|
@@ -131,7 +131,7 @@ def _decodeValue(json_obj: Any, named_values: dict[str, Any]) -> Any:
|
|
|
131
131
|
elif type_name == 'CompoundValue':
|
|
132
132
|
raise ee_exception.EEException('Nested CompoundValues are disallowed.')
|
|
133
133
|
else:
|
|
134
|
-
raise ee_exception.EEException('Unknown encoded object type: '
|
|
134
|
+
raise ee_exception.EEException(f'Unknown encoded object type: {type_name}')
|
|
135
135
|
|
|
136
136
|
|
|
137
137
|
def _invocation(func: Any, args: dict[str, Any]) -> Any:
|
|
@@ -150,10 +150,10 @@ def _invocation(func: Any, args: dict[str, Any]) -> Any:
|
|
|
150
150
|
'returns': 'ComputedObject'
|
|
151
151
|
}
|
|
152
152
|
return function.SecondOrderFunction(func, signature).apply(args)
|
|
153
|
-
raise ee_exception.EEException('Invalid function value:
|
|
153
|
+
raise ee_exception.EEException(f'Invalid function value: {func}')
|
|
154
154
|
|
|
155
155
|
|
|
156
|
-
def fromCloudApiJSON(json_obj:
|
|
156
|
+
def fromCloudApiJSON(json_obj: str | bytes) -> Any: # pylint: disable=g-bad-name
|
|
157
157
|
"""Deserializes an object from the JSON string used in Cloud API calls.
|
|
158
158
|
|
|
159
159
|
Args:
|
|
@@ -180,7 +180,7 @@ def decodeCloudApi(json_obj: dict[str, Any]) -> Any:
|
|
|
180
180
|
def lookup(reference, kind):
|
|
181
181
|
if reference not in decoded:
|
|
182
182
|
if reference not in json_obj['values']:
|
|
183
|
-
raise ee_exception.EEException('Cannot find {} {}'
|
|
183
|
+
raise ee_exception.EEException(f'Cannot find {reference} {kind}')
|
|
184
184
|
decoded[reference] = decode_node(json_obj['values'][reference])
|
|
185
185
|
return decoded[reference]
|
|
186
186
|
|
ee/ee_number.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""A wrapper for numbers."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
from ee import _arg_types
|
|
7
7
|
from ee import _cloud_api_utils
|
|
@@ -586,9 +586,9 @@ class Number(computedobject.ComputedObject):
|
|
|
586
586
|
|
|
587
587
|
return apifunction.ApiFunction.call_(self.name() + '.or', self, right)
|
|
588
588
|
|
|
589
|
+
@staticmethod
|
|
589
590
|
def parse(
|
|
590
|
-
# pylint: disable=redefined-builtin
|
|
591
|
-
input: _arg_types.String,
|
|
591
|
+
input: _arg_types.String, # pylint: disable=redefined-builtin
|
|
592
592
|
radix: _arg_types.Integer | None = None,
|
|
593
593
|
) -> Number:
|
|
594
594
|
"""Returns a number from a string.
|
|
@@ -772,27 +772,17 @@ class Number(computedobject.ComputedObject):
|
|
|
772
772
|
|
|
773
773
|
return apifunction.ApiFunction.call_(self.name() + '.uint8', self)
|
|
774
774
|
|
|
775
|
-
# pylint: disable=redefined-builtin
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
self,
|
|
779
|
-
min: Union[int, float, computedobject.ComputedObject],
|
|
780
|
-
max: Union[int, float, computedobject.ComputedObject],
|
|
781
|
-
) -> Number:
|
|
782
|
-
"""Scales the input so that [min, max] becomes [0, 1].
|
|
775
|
+
# pylint: disable-next=redefined-builtin
|
|
776
|
+
def unitScale(self, min: _arg_types.Number, max: _arg_types.Number) -> Number:
|
|
777
|
+
"""Returns the input scaled so that [min, max] becomes [0, 1].
|
|
783
778
|
|
|
784
779
|
Values outside the range are NOT clamped. If min == max, 0 is returned.
|
|
785
780
|
|
|
786
781
|
Args:
|
|
787
782
|
min: Minimum value of the input to be scaled to 0.
|
|
788
783
|
max: Maximum value of the input to be scaled to 1.
|
|
789
|
-
|
|
790
|
-
Returns:
|
|
791
|
-
An ee.Number.
|
|
792
784
|
"""
|
|
793
785
|
|
|
794
786
|
return apifunction.ApiFunction.call_(
|
|
795
787
|
self.name() + '.unitScale', self, min, max
|
|
796
788
|
)
|
|
797
|
-
# pytype: enable=invalid-annotation
|
|
798
|
-
# pylint: enable=redefined-builtin
|
ee/encodable.py
CHANGED
ee/image_converter.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Converters used in the image data fetching methods."""
|
|
2
2
|
|
|
3
3
|
import io
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class ImageConverter:
|
|
@@ -49,8 +49,8 @@ _PIXEL_DATA_CONVERTERS: dict[str, type[ImageConverter]] = {
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def from_file_format(
|
|
52
|
-
file_format:
|
|
53
|
-
) ->
|
|
52
|
+
file_format: str | ImageConverter,
|
|
53
|
+
) -> ImageConverter | None:
|
|
54
54
|
if isinstance(file_format, ImageConverter):
|
|
55
55
|
return file_format
|
|
56
56
|
if file_format in _PIXEL_DATA_CONVERTERS:
|
ee/imagecollection.py
CHANGED