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.

Files changed (44) hide show
  1. {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/METADATA +2 -3
  2. {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/RECORD +44 -44
  3. ee/__init__.py +13 -13
  4. ee/_cloud_api_utils.py +29 -28
  5. ee/_helpers.py +6 -6
  6. ee/_utils.py +2 -1
  7. ee/apitestcase.py +10 -10
  8. ee/batch.py +7 -0
  9. ee/cli/commands.py +6 -10
  10. ee/cli/utils.py +28 -23
  11. ee/collection.py +3 -2
  12. ee/computedobject.py +4 -1
  13. ee/customfunction.py +2 -1
  14. ee/data.py +32 -31
  15. ee/deprecation.py +8 -2
  16. ee/deserializer.py +10 -10
  17. ee/ee_number.py +6 -16
  18. ee/encodable.py +2 -1
  19. ee/image_converter.py +3 -3
  20. ee/imagecollection.py +2 -2
  21. ee/model.py +29 -31
  22. ee/oauth.py +37 -37
  23. ee/reducer.py +2 -0
  24. ee/serializer.py +6 -6
  25. ee/table_converter.py +3 -3
  26. ee/terrain.py +1 -1
  27. ee/tests/batch_test.py +67 -3
  28. ee/tests/collection_test.py +35 -0
  29. ee/tests/data_test.py +300 -4
  30. ee/tests/deprecation_test.py +4 -2
  31. ee/tests/deserializer_test.py +47 -0
  32. ee/tests/ee_number_test.py +40 -1
  33. ee/tests/image_converter_test.py +1 -3
  34. ee/tests/kernel_test.py +4 -0
  35. ee/tests/model_test.py +12 -0
  36. ee/tests/oauth_test.py +170 -7
  37. ee/tests/reducer_test.py +13 -0
  38. ee/tests/serializer_test.py +29 -2
  39. ee/tests/table_converter_test.py +49 -5
  40. ee/tests/terrain_test.py +8 -0
  41. {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/WHEEL +0 -0
  42. {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/entry_points.txt +0 -0
  43. {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/licenses/LICENSE +0 -0
  44. {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/top_level.txt +0 -0
ee/model.py CHANGED
@@ -1,7 +1,5 @@
1
1
  """A wrapper for Models."""
2
2
 
3
- from typing import Optional
4
-
5
3
  from ee import _arg_types
6
4
  from ee import apifunction
7
5
  from ee import computedobject
@@ -66,26 +64,26 @@ class Model(computedobject.ComputedObject):
66
64
  @deprecation.Deprecated('Migrate to Vertex AI')
67
65
  def fromAiPlatformPredictor(
68
66
  # pylint: disable=invalid-name
69
- projectName: Optional[_arg_types.Any] = None,
70
- projectId: Optional[_arg_types.String] = None,
71
- modelName: Optional[_arg_types.String] = None,
67
+ projectName: _arg_types.Any | None = None,
68
+ projectId: _arg_types.String | None = None,
69
+ modelName: _arg_types.String | None = None,
72
70
  # pylint: enable=invalid-name
73
- version: Optional[_arg_types.String] = None,
74
- region: Optional[_arg_types.String] = None,
71
+ version: _arg_types.String | None = None,
72
+ region: _arg_types.String | None = None,
75
73
  # pylint: disable=invalid-name
76
- inputProperties: Optional[_arg_types.List] = None,
77
- inputTypeOverride: Optional[_arg_types.Dictionary] = None,
78
- inputShapes: Optional[_arg_types.Dictionary] = None,
74
+ inputProperties: _arg_types.List | None = None,
75
+ inputTypeOverride: _arg_types.Dictionary | None = None,
76
+ inputShapes: _arg_types.Dictionary | None = None,
79
77
  # pylint: enable=invalid-name
80
- proj: Optional[_arg_types.Projection] = None,
78
+ proj: _arg_types.Projection | None = None,
81
79
  # pylint: disable=invalid-name
82
- fixInputProj: Optional[_arg_types.Bool] = None,
83
- inputTileSize: Optional[_arg_types.List] = None,
84
- inputOverlapSize: Optional[_arg_types.List] = None,
85
- outputTileSize: Optional[_arg_types.List] = None,
86
- outputBands: Optional[_arg_types.Dictionary] = None,
87
- outputProperties: Optional[_arg_types.Dictionary] = None,
88
- outputMultiplier: Optional[_arg_types.Number] = None,
80
+ fixInputProj: _arg_types.Bool | None = None,
81
+ inputTileSize: _arg_types.List | None = None,
82
+ inputOverlapSize: _arg_types.List | None = None,
83
+ outputTileSize: _arg_types.List | None = None,
84
+ outputBands: _arg_types.Dictionary | None = None,
85
+ outputProperties: _arg_types.Dictionary | None = None,
86
+ outputMultiplier: _arg_types.Number | None = None,
89
87
  # pylint: enable=invalid-name
90
88
  ) -> 'Model':
91
89
  """Returns an ee.Model from a description of an AI Platform prediction model.
@@ -168,21 +166,21 @@ class Model(computedobject.ComputedObject):
168
166
  def fromVertexAi(
169
167
  endpoint: _arg_types.String,
170
168
  # pylint: disable=invalid-name
171
- inputProperties: Optional[_arg_types.List] = None,
172
- inputTypeOverride: Optional[_arg_types.Dictionary] = None,
173
- inputShapes: Optional[_arg_types.Dictionary] = None,
169
+ inputProperties: _arg_types.List | None = None,
170
+ inputTypeOverride: _arg_types.Dictionary | None = None,
171
+ inputShapes: _arg_types.Dictionary | None = None,
174
172
  # pylint: enable=invalid-name
175
- proj: Optional[_arg_types.Projection] = None,
173
+ proj: _arg_types.Projection | None = None,
176
174
  # pylint: disable=invalid-name
177
- fixInputProj: Optional[_arg_types.Bool] = None,
178
- inputTileSize: Optional[_arg_types.List] = None,
179
- inputOverlapSize: Optional[_arg_types.List] = None,
180
- outputTileSize: Optional[_arg_types.List] = None,
181
- outputBands: Optional[_arg_types.Dictionary] = None,
182
- outputProperties: Optional[_arg_types.Dictionary] = None,
183
- outputMultiplier: Optional[_arg_types.Number] = None,
184
- maxPayloadBytes: Optional[_arg_types.Integer] = None,
185
- payloadFormat: Optional[_arg_types.String] = None,
175
+ fixInputProj: _arg_types.Bool | None = None,
176
+ inputTileSize: _arg_types.List | None = None,
177
+ inputOverlapSize: _arg_types.List | None = None,
178
+ outputTileSize: _arg_types.List | None = None,
179
+ outputBands: _arg_types.Dictionary | None = None,
180
+ outputProperties: _arg_types.Dictionary | None = None,
181
+ outputMultiplier: _arg_types.Number | None = None,
182
+ maxPayloadBytes: _arg_types.Integer | None = None,
183
+ payloadFormat: _arg_types.String | None = None,
186
184
  # pylint: enable=invalid-name
187
185
  ) -> 'Model':
188
186
  """Returns an ee.Model from a description of a Vertex AI model endpoint.
ee/oauth.py CHANGED
@@ -9,6 +9,7 @@ Typical use-case consists of:
9
9
  """
10
10
 
11
11
  import base64
12
+ from collections.abc import Sequence
12
13
  import errno
13
14
  import hashlib
14
15
  import http.server
@@ -17,8 +18,7 @@ import os
17
18
  import shutil
18
19
  import subprocess
19
20
  import sys
20
- from typing import Any, Optional, Union
21
- from collections.abc import Sequence
21
+ from typing import Any
22
22
  import urllib.error
23
23
  import urllib.parse
24
24
  import urllib.request
@@ -101,13 +101,13 @@ def get_credentials_arguments() -> dict[str, Any]:
101
101
  return args
102
102
 
103
103
 
104
- def is_sdk_credentials(credentials: Optional[Any]) -> bool:
104
+ def is_sdk_credentials(credentials: Any | None) -> bool:
105
105
  return is_sdk_project(project_number_from_credentials(credentials))
106
106
 
107
107
 
108
108
  def project_number_from_credentials(
109
- credentials: Optional[Any],
110
- ) -> Optional[str]:
109
+ credentials: Any | None,
110
+ ) -> str | None:
111
111
  client_id = credentials and getattr(credentials, 'client_id', None)
112
112
  return _project_number_from_client_id(client_id)
113
113
 
@@ -116,7 +116,7 @@ def is_sdk_project(project: str) -> bool:
116
116
  return project in SDK_PROJECTS
117
117
 
118
118
 
119
- def get_appdefault_project() -> Optional[str]:
119
+ def get_appdefault_project() -> str | None:
120
120
  try:
121
121
  adc_path = _cloud_sdk.get_application_default_credentials_path()
122
122
  with open(adc_path) as adc_json:
@@ -134,7 +134,7 @@ def _valid_credentials_exist() -> bool:
134
134
  return False
135
135
 
136
136
 
137
- def is_valid_credentials(credentials: Optional[Any]) -> bool:
137
+ def is_valid_credentials(credentials: Any | None) -> bool:
138
138
  if credentials is None:
139
139
  return False
140
140
  try:
@@ -146,8 +146,8 @@ def is_valid_credentials(credentials: Optional[Any]) -> bool:
146
146
 
147
147
  def get_authorization_url(
148
148
  code_challenge: str,
149
- scopes: Optional[Sequence[str]] = None,
150
- redirect_uri: Optional[str] = None,
149
+ scopes: Sequence[str] | None = None,
150
+ redirect_uri: str | None = None,
151
151
  ) -> str:
152
152
  """Returns a URL to generate an auth code."""
153
153
 
@@ -164,9 +164,9 @@ def get_authorization_url(
164
164
  def request_token(
165
165
  auth_code: str,
166
166
  code_verifier: str,
167
- client_id: Optional[str] = None,
168
- client_secret: Optional[str] = None,
169
- redirect_uri: Optional[str] = None,
167
+ client_id: str | None = None,
168
+ client_secret: str | None = None,
169
+ redirect_uri: str | None = None,
170
170
  ) -> str:
171
171
  """Uses authorization code to request tokens."""
172
172
 
@@ -201,7 +201,7 @@ def write_private_json(json_path: str, info_dict: dict[str, Any]) -> None:
201
201
  except OSError as e:
202
202
  if e.errno != errno.EEXIST:
203
203
  # pylint:disable=broad-exception-raised,raise-missing-from
204
- raise Exception('Error creating directory {}: {}'.format(dirname, e))
204
+ raise Exception(f'Error creating directory {dirname}: {e}')
205
205
  # pylint:enable=broad-exception-raised,raise-missing-from
206
206
 
207
207
  file_content = json.dumps(info_dict)
@@ -226,7 +226,7 @@ def _in_jupyter_shell() -> bool:
226
226
  """Tests if the code is being executed within Jupyter."""
227
227
  try:
228
228
  import ipykernel.zmqshell
229
- return isinstance(IPython.get_ipython(),
229
+ return isinstance(IPython.get_ipython(), # pylint: disable=undefined-variable
230
230
  ipykernel.zmqshell.ZMQInteractiveShell)
231
231
  except ImportError:
232
232
  return False
@@ -234,7 +234,7 @@ def _in_jupyter_shell() -> bool:
234
234
  return False
235
235
 
236
236
 
237
- def _project_number_from_client_id(client_id: Optional[str]) -> Optional[str]:
237
+ def _project_number_from_client_id(client_id: str | None) -> str | None:
238
238
  """Returns the project number associated with the given OAuth client ID."""
239
239
  # Client IDs are of the form:
240
240
  # PROJECTNUMBER-BASE32STUFF.apps.googleusercontent.com.
@@ -243,10 +243,10 @@ def _project_number_from_client_id(client_id: Optional[str]) -> Optional[str]:
243
243
 
244
244
 
245
245
  def _obtain_and_write_token(
246
- auth_code: Optional[str] = None,
247
- code_verifier: Optional[str] = None,
248
- scopes: Optional[Sequence[str]] = None,
249
- redirect_uri: Optional[str] = None,
246
+ auth_code: str | None = None,
247
+ code_verifier: str | None = None,
248
+ scopes: Sequence[str] | None = None,
249
+ redirect_uri: str | None = None,
250
250
  ) -> None:
251
251
  """Obtains and writes credentials token based on an authorization code."""
252
252
  fetch_data = {}
@@ -283,7 +283,7 @@ def _obtain_and_write_token(
283
283
 
284
284
 
285
285
  def _display_auth_instructions_for_noninteractive(
286
- auth_url: str, code_verifier: Union[bytes, str]
286
+ auth_url: str, code_verifier: bytes | str
287
287
  ) -> None:
288
288
  """Displays instructions for authenticating without blocking for user input."""
289
289
  # Python 3 `bytes` should be decoded to `str` if used as an argument of
@@ -310,7 +310,7 @@ def _display_auth_instructions_for_noninteractive(
310
310
 
311
311
 
312
312
  def _display_auth_instructions_with_print(
313
- auth_url: str, coda: Optional[str] = None
313
+ auth_url: str, coda: str | None = None
314
314
  ) -> None:
315
315
  """Displays instructions for authenticating using a print statement."""
316
316
  print(
@@ -325,11 +325,11 @@ def _display_auth_instructions_with_print(
325
325
 
326
326
 
327
327
  def _display_auth_instructions_with_html(
328
- auth_url: str, coda: Optional[str] = None
328
+ auth_url: str, coda: str | None = None
329
329
  ) -> None:
330
330
  """Displays instructions for authenticating using HTML code."""
331
331
  try:
332
- IPython.display.display(IPython.display.HTML(
332
+ IPython.display.display(IPython.display.HTML( # pylint: disable=undefined-variable
333
333
  """<p>To authorize access needed by Earth Engine, open the following
334
334
  URL in a web browser and follow the instructions:</p>
335
335
  <p><a href={0}>{0}</a></p>
@@ -382,8 +382,8 @@ def _no_gcloud() -> bool:
382
382
 
383
383
 
384
384
  def _load_gcloud_credentials(
385
- scopes: Optional[Sequence[str]] = None,
386
- quiet: Optional[bool] = None,
385
+ scopes: Sequence[str] | None = None,
386
+ quiet: bool | None = None,
387
387
  run_gcloud_legacy: bool = False,
388
388
  ) -> None:
389
389
  """Initializes credentials by running gcloud flows."""
@@ -435,7 +435,7 @@ def _start_server(port: int):
435
435
  class Handler(http.server.BaseHTTPRequestHandler):
436
436
  """Handles the OAuth callback and reports a success page."""
437
437
 
438
- code: Optional[str] = None
438
+ code: str | None = None
439
439
 
440
440
  def do_GET(self) -> None: # pylint: disable=invalid-name
441
441
  Handler.code = urllib.parse.parse_qs(
@@ -460,7 +460,7 @@ def _start_server(port: int):
460
460
  self.server = http.server.HTTPServer(('localhost', port), Handler)
461
461
  self.url = 'http://localhost:%s' % self.server.server_address[1]
462
462
 
463
- def fetch_code(self) -> Optional[str]:
463
+ def fetch_code(self) -> str | None:
464
464
  self.server.handle_request() # Blocks until a single request arrives.
465
465
  self.server.server_close()
466
466
  return Handler.code
@@ -469,13 +469,13 @@ def _start_server(port: int):
469
469
 
470
470
 
471
471
  def authenticate(
472
- cli_authorization_code: Optional[str] = None,
473
- quiet: Optional[bool] = None,
474
- cli_code_verifier: Optional[str] = None,
475
- auth_mode: Optional[str] = None,
476
- scopes: Optional[Sequence[str]] = None,
472
+ cli_authorization_code: str | None = None,
473
+ quiet: bool | None = None,
474
+ cli_code_verifier: str | None = None,
475
+ auth_mode: str | None = None,
476
+ scopes: Sequence[str] | None = None,
477
477
  force: bool = False,
478
- ) -> Optional[bool]:
478
+ ) -> bool | None:
479
479
  """Prompts the user to authorize access to Earth Engine via OAuth2.
480
480
 
481
481
  Args:
@@ -564,11 +564,11 @@ class Flow:
564
564
  """Holds state for auth flows."""
565
565
  code_verifier: str
566
566
  scopes: Sequence[str]
567
- server: Optional[Any]
567
+ server: Any | None
568
568
  auth_url: str
569
569
 
570
570
  def __init__(
571
- self, auth_mode: str = 'notebook', scopes: Optional[Sequence[str]] = None
571
+ self, auth_mode: str = 'notebook', scopes: Sequence[str] | None = None
572
572
  ):
573
573
  """Initializes auth URL and PKCE verifier, for use in save_code().
574
574
 
@@ -601,7 +601,7 @@ class Flow:
601
601
  # pylint:disable-next=broad-exception-raised
602
602
  raise ee_exception.EEException('Unknown auth_mode "%s"' % auth_mode)
603
603
 
604
- def save_code(self, code: Optional[str] = None) -> None:
604
+ def save_code(self, code: str | None = None) -> None:
605
605
  """Fetches auth code if not given, and saves the generated credentials."""
606
606
  redirect_uri = None
607
607
  if self.server and not code:
@@ -609,7 +609,7 @@ class Flow:
609
609
  code = self.server.fetch_code() # Waits for oauth callback
610
610
  _obtain_and_write_token(code, self.code_verifier, self.scopes, redirect_uri)
611
611
 
612
- def display_instructions(self, quiet: Optional[bool] = None) -> bool:
612
+ def display_instructions(self, quiet: bool | None = None) -> bool:
613
613
  """Prints to stdout, and returns True if a browser should be opened."""
614
614
 
615
615
  if quiet:
ee/reducer.py CHANGED
@@ -465,8 +465,10 @@ class Reducer(computedobject.ComputedObject):
465
465
 
466
466
  def group(
467
467
  self,
468
+ # pylint: disable=invalid-name
468
469
  groupField: _arg_types.Integer | None = None,
469
470
  groupName: _arg_types.String | None = None,
471
+ # pylint: enable=invalid-name
470
472
  ) -> Reducer:
471
473
  """Returns a reducer groups reducer records by the value of a given input.
472
474
 
ee/serializer.py CHANGED
@@ -4,7 +4,7 @@ import collections
4
4
  import datetime
5
5
  import hashlib
6
6
  import json
7
- from typing import Any, Optional
7
+ from typing import Any
8
8
 
9
9
  from ee import _cloud_api_utils
10
10
  from ee import _utils
@@ -32,7 +32,7 @@ def DatetimeToMicroseconds(date: datetime.datetime) -> int:
32
32
 
33
33
  class Serializer:
34
34
  """A serializer for EE object trees."""
35
- unbound_name: Optional[str]
35
+ unbound_name: str | None
36
36
 
37
37
  # Whether the encoding should factor out shared subtrees.
38
38
  _is_compound: bool
@@ -48,7 +48,7 @@ class Serializer:
48
48
  self,
49
49
  is_compound: bool = True,
50
50
  for_cloud_api: bool = False,
51
- unbound_name: Optional[str] = None,
51
+ unbound_name: str | None = None,
52
52
  ):
53
53
  """Constructs a serializer.
54
54
 
@@ -280,7 +280,7 @@ def encode(
280
280
  obj: Any,
281
281
  is_compound: bool = True,
282
282
  for_cloud_api: bool = True,
283
- unbound_name: Optional[str] = None,
283
+ unbound_name: str | None = None,
284
284
  ) -> Any:
285
285
  """Serialize an object to a JSON-compatible structure for API calls.
286
286
 
@@ -358,7 +358,7 @@ class _ExpressionOptimizer:
358
358
  - Collapse dicts and arrays of constants to constant dicts/arrays.
359
359
  """
360
360
 
361
- def __init__(self, result: Any, values: Optional[Any] = None):
361
+ def __init__(self, result: Any, values: Any | None = None):
362
362
  """Builds an ExpressionOptimizer.
363
363
 
364
364
  Args:
@@ -385,7 +385,7 @@ class _ExpressionOptimizer:
385
385
  reference_counts = collections.defaultdict(int)
386
386
  reference_counts[self._result] += 1
387
387
 
388
- def _contained_reference(value: Any) -> Optional[Any]:
388
+ def _contained_reference(value: Any) -> Any | None:
389
389
  """Gets a contained reference from a ValueNode, if there is one."""
390
390
  if 'functionDefinitionValue' in value:
391
391
  return value['functionDefinitionValue']['body']
ee/table_converter.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Converters used in the table data fetching methods."""
2
2
 
3
3
  from collections.abc import Iterator
4
- from typing import Any, Optional, Union
4
+ from typing import Any
5
5
 
6
6
 
7
7
  class TableConverter:
@@ -59,8 +59,8 @@ _TABLE_DATA_CONVERTERS: dict[str, type[TableConverter]] = {
59
59
 
60
60
 
61
61
  def from_file_format(
62
- file_format: Union[str, TableConverter]
63
- ) -> Optional[TableConverter]:
62
+ file_format: str | TableConverter
63
+ ) -> TableConverter | None:
64
64
  if isinstance(file_format, TableConverter):
65
65
  return file_format
66
66
  if file_format in _TABLE_DATA_CONVERTERS:
ee/terrain.py CHANGED
@@ -13,7 +13,7 @@ class Terrain:
13
13
 
14
14
  def __init__(self):
15
15
  raise RuntimeError(
16
- self.__name__
16
+ self.__class__.__name__
17
17
  + ' should not be used as an object. Only direct usage of Terrain'
18
18
  ' static methods is allowed. For example, use this: '
19
19
  ' `ee.Terrain.aspect(...)`'
ee/tests/batch_test.py CHANGED
@@ -2,7 +2,7 @@
2
2
  """Test for the ee.batch module."""
3
3
 
4
4
  import json
5
- from typing import Any, Optional
5
+ from typing import Any
6
6
  import unittest
7
7
  from unittest import mock
8
8
 
@@ -138,6 +138,14 @@ class TaskTest(unittest.TestCase):
138
138
  ):
139
139
  self.assertFalse(task.active())
140
140
 
141
+ def test_success(self):
142
+ self.assertTrue(batch.Task.State.success(batch.Task.State.COMPLETED))
143
+ self.assertTrue(batch.Task.State.success('COMPLETED'))
144
+ for state in batch.Task.State:
145
+ if state != batch.Task.State.COMPLETED:
146
+ self.assertFalse(batch.Task.State.success(state))
147
+ self.assertFalse(batch.Task.State.success(state.value))
148
+
141
149
  def test_repr_without_config(self):
142
150
  task = batch.Task('an id', 'a task type', 'a state')
143
151
  self.assertEqual('<Task "an id">', task.__repr__())
@@ -193,8 +201,8 @@ class ExportTest(unittest.TestCase):
193
201
  class BatchTestCase(apitestcase.ApiTestCase):
194
202
  """A test case for batch functionality."""
195
203
 
196
- start_call_params: Optional[Any]
197
- update_call_params: Optional[Any]
204
+ start_call_params: Any | None
205
+ update_call_params: Any | None
198
206
 
199
207
  def setUp(self):
200
208
  super().setUp()
@@ -266,6 +274,7 @@ class BatchTestCase(apitestcase.ApiTestCase):
266
274
  'name': (
267
275
  'projects/earthengine-legacy/assets/users/foo/bar'
268
276
  ),
277
+ 'overwrite': False,
269
278
  }
270
279
  },
271
280
  'description': 'myExportImageTask',
@@ -417,6 +426,7 @@ class BatchTestCase(apitestcase.ApiTestCase):
417
426
  'name': (
418
427
  'projects/earthengine-legacy/assets/users/foo/bar'
419
428
  ),
429
+ 'overwrite': False,
420
430
  },
421
431
  'pyramidingPolicyOverrides': {'B1': 'MIN'},
422
432
  },
@@ -443,6 +453,7 @@ class BatchTestCase(apitestcase.ApiTestCase):
443
453
  'name': (
444
454
  'projects/earthengine-legacy/assets/users/foo/bar'
445
455
  ),
456
+ 'overwrite': False,
446
457
  },
447
458
  'tileSize': {'value': 4},
448
459
  },
@@ -452,6 +463,43 @@ class BatchTestCase(apitestcase.ApiTestCase):
452
463
  task_ordered.config,
453
464
  )
454
465
 
466
+ task_with_overwrite = ee.batch.Export.image.toAsset(
467
+ image=config['image'],
468
+ assetId=config['assetId'],
469
+ overwrite=True,
470
+ )
471
+ self.assertTrue(
472
+ task_with_overwrite.config['assetExportOptions'][
473
+ 'earthEngineDestination'
474
+ ]['overwrite']
475
+ )
476
+
477
+ task_with_priority = ee.batch.Export.image.toAsset(
478
+ image=config['image'],
479
+ assetId=config['assetId'],
480
+ priority=999,
481
+ )
482
+ self.assertIsNone(task_with_priority.id)
483
+ self.assertIsNone(task_with_priority.name)
484
+ self.assertEqual('EXPORT_IMAGE', task_with_priority.task_type)
485
+ self.assertEqual('UNSUBMITTED', task_with_priority.state)
486
+ self.assertEqual(
487
+ {
488
+ 'expression': expected_expression,
489
+ 'description': 'myExportImageTask',
490
+ 'assetExportOptions': {
491
+ 'earthEngineDestination': {
492
+ 'name': (
493
+ 'projects/earthengine-legacy/assets/users/foo/bar'
494
+ ),
495
+ 'overwrite': False,
496
+ }
497
+ },
498
+ 'priority': {'value': 999},
499
+ },
500
+ task_with_priority.config,
501
+ )
502
+
455
503
  def test_export_image_to_asset_cloud_api_with_tile_size(self):
456
504
  """Verifies the Asset export task created by Export.image.toAsset()."""
457
505
  with apitestcase.UsingCloudApi():
@@ -481,6 +529,7 @@ class BatchTestCase(apitestcase.ApiTestCase):
481
529
  'name': (
482
530
  'projects/earthengine-legacy/assets/users/foo/bar'
483
531
  ),
532
+ 'overwrite': False,
484
533
  },
485
534
  'tileSize': {'value': 4},
486
535
  },
@@ -1125,11 +1174,25 @@ class BatchTestCase(apitestcase.ApiTestCase):
1125
1174
  'name': (
1126
1175
  'projects/earthengine-legacy/assets/users/foo/bar'
1127
1176
  ),
1177
+ 'overwrite': False,
1128
1178
  }
1129
1179
  },
1130
1180
  },
1131
1181
  task.config,
1132
1182
  )
1183
+
1184
+ task_with_overwrite = ee.batch.Export.table.toAsset(
1185
+ collection=ee.FeatureCollection('foo'),
1186
+ description='foo',
1187
+ assetId='users/foo/bar',
1188
+ overwrite=True,
1189
+ )
1190
+ self.assertTrue(
1191
+ task_with_overwrite.config['assetExportOptions'][
1192
+ 'earthEngineDestination'
1193
+ ]['overwrite']
1194
+ )
1195
+
1133
1196
  task_with_priority = ee.batch.Export.table.toAsset(
1134
1197
  collection=ee.FeatureCollection('foo'),
1135
1198
  description='foo',
@@ -1145,6 +1208,7 @@ class BatchTestCase(apitestcase.ApiTestCase):
1145
1208
  'name': (
1146
1209
  'projects/earthengine-legacy/assets/users/foo/bar'
1147
1210
  ),
1211
+ 'overwrite': False,
1148
1212
  }
1149
1213
  },
1150
1214
  'priority': {'value': 999},
@@ -47,6 +47,10 @@ class CollectionTestCase(apitestcase.ApiTestCase):
47
47
 
48
48
  # We don't allow empty filters.
49
49
  self.assertRaises(Exception, collection.filter)
50
+ with self.assertRaisesRegex(ee.EEException, 'Empty filters.'):
51
+ collection.filter(None) # pytype: disable=wrong-arg-types
52
+ with self.assertRaisesRegex(ee.EEException, 'Empty filters.'):
53
+ collection.filter('')
50
54
 
51
55
  filtered = collection.filter(ee.Filter.eq('foo', 1))
52
56
  self.assertEqual(ee.ApiFunction.lookup('Collection.filter'), filtered.func)
@@ -75,6 +79,37 @@ class CollectionTestCase(apitestcase.ApiTestCase):
75
79
  collection.filter(ee.Filter.eq('foo', 13)),
76
80
  collection.filterMetadata('foo', 'equals', 13))
77
81
 
82
+ def test_load_table(self):
83
+ """Verifies Collection.loadTable()."""
84
+ table_id = 'a/table/id'
85
+ geometry_column = 'geom'
86
+ version = 123
87
+ result = ee.Collection.loadTable(
88
+ tableId=table_id, geometryColumn=geometry_column, version=version
89
+ )
90
+ self.assertEqual(ee.ApiFunction.lookup('Collection.loadTable'), result.func)
91
+ self.assertEqual(
92
+ {
93
+ 'tableId': ee.String(table_id),
94
+ 'geometryColumn': ee.String(geometry_column),
95
+ 'version': ee.Number(version),
96
+ },
97
+ result.args,
98
+ )
99
+ self.assertIsInstance(result, ee.FeatureCollection)
100
+
101
+ result2 = ee.Collection.loadTable(tableId=table_id)
102
+ self.assertEqual(ee.ApiFunction.lookup('Collection.loadTable'), result2.func)
103
+ self.assertEqual(
104
+ {
105
+ 'tableId': ee.String(table_id),
106
+ 'geometryColumn': None,
107
+ 'version': None,
108
+ },
109
+ result2.args,
110
+ )
111
+ self.assertIsInstance(result2, ee.FeatureCollection)
112
+
78
113
  def test_mapping(self):
79
114
  """Verifies the behavior of the map() method."""
80
115
  collection = ee.ImageCollection('foo')