earthengine-api 1.6.14__py3-none-any.whl → 1.6.15rc0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: earthengine-api
3
- Version: 1.6.14
3
+ Version: 1.6.15rc0
4
4
  Summary: Earth Engine Python API
5
5
  Author-email: Google LLC <noreply@google.com>
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
- earthengine_api-1.6.14.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
2
- ee/__init__.py,sha256=AEeWgOZjwLgqC8n8K1Az1SYMdSBWLXxVPeNWnH359qg,16804
1
+ earthengine_api-1.6.15rc0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
2
+ ee/__init__.py,sha256=3iMYhYua5h_2KgfiuQb7XCszK6IvMOgBmB3OPAomzxo,16807
3
3
  ee/_arg_types.py,sha256=nrJrnPFnAS8fzMxAGmG3TbUOi_yFVrnSGW5IP8ATzDQ,2662
4
4
  ee/_cloud_api_utils.py,sha256=06xr56VvGeQHl6DTeoC9_YE0hKVtE11tMnDCv98TKSA,32998
5
5
  ee/_helpers.py,sha256=71xYDbCO_1usY3SnedoA9zi7j6dnPBijru1eUh4o25g,4859
@@ -18,7 +18,7 @@ ee/customfunction.py,sha256=ONDKyd5dldQLMX7diYZJK5wc8ty_-cI8K421Jumo9SM,7381
18
18
  ee/data.py,sha256=eI6-JLKqw4RNsa_zOWAb2j8NgXCrVSKm9SjniGiZRPQ,85497
19
19
  ee/daterange.py,sha256=nrRYkR2M2aVU0ZJyG7yiZStFt-W2TvYVuazoZK_WZqM,4948
20
20
  ee/deprecation.py,sha256=J6eTNrKE3pQodyE8Pig8ixPRT3C4pTxFqrraE8R_cOo,6226
21
- ee/deserializer.py,sha256=Xz9Dis85JgZeLvpF-4yw3ZRv39rjvCTBYHjio8DE1kM,8424
21
+ ee/deserializer.py,sha256=8LeCq113UQgBn9wl7h2A9IOhk9m6A1p56-H5Q8Gm-MM,8386
22
22
  ee/dictionary.py,sha256=b0t46vaeVMsFGI2icdGNspmedRtVVxfiIcFLWcmL2v8,10508
23
23
  ee/ee_array.py,sha256=EJmQ-zku1x0e6z44SlVD-F7mafmvRS0DoByKFyeDCuc,36368
24
24
  ee/ee_date.py,sha256=ixmLMrrGjq30DX9QY92HTeUgFZhWdn485cyaJkksh6U,10757
@@ -46,15 +46,15 @@ ee/oauth.py,sha256=7rqMxdYHPuNcoHv_SswuiJa2taEBjyh2sX1iszjLnO0,22247
46
46
  ee/pixeltype.py,sha256=ucUwJ5SvcOT849Ap4mlJL9z11IAbcT1w9ii8-zOoqdI,5196
47
47
  ee/projection.py,sha256=n7WvMeYEG9zksGN1tIX7RGweC4IyCrXAKsvPY0e2b8k,5868
48
48
  ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- ee/reducer.py,sha256=80LyfpjpyJj3FO36fviZIK5YcnDxssMZgrRK-Y3whSs,33740
49
+ ee/reducer.py,sha256=zO-bhNOQPoWlzjvXiHC40hwg3KFmA52eQb1uutUW1MQ,33813
50
50
  ee/serializer.py,sha256=OldyytHpwmUVt28TEjlSS7J-3CE7GBZhyyXhvyMQIGs,22806
51
51
  ee/table_converter.py,sha256=6ARbOLq1VPU1_wXY2pyv0PuzY4XyEBwM3npMt6Hp__U,2088
52
52
  ee/terrain.py,sha256=TIbeQiVGv4okTTsHCnaP6TxSvaRF-GX_06asVIFN8dY,4873
53
53
  ee/cli/__init__.py,sha256=YjzBDuYi6fiOv77Xfl-Qib2O6gRZj9z7Sx2Zz6teTXU,33
54
- ee/cli/commands.py,sha256=8OeaoMIjseD7Eah9HoaeYzQFN6i6T9rUPYPh-9S9rZc,73544
54
+ ee/cli/commands.py,sha256=RQhs16sE2TBDXto094utFOghpgtnxYfIhUOPXBtkg54,73456
55
55
  ee/cli/eecli.py,sha256=1yDyingkwurai13F_PF91RYsBev6jGJ9WEoZaT2Dgy8,3043
56
56
  ee/cli/eecli_wrapper.py,sha256=Z7R3IJcht2uG1h57oY7BSrkPiwQzNmmYlyCSX1_7L7c,1089
57
- ee/cli/utils.py,sha256=Y6z2Qd7qyFwe_Qc-OVlbOw-BSWxLr7ytuhxEgcYAKwI,14116
57
+ ee/cli/utils.py,sha256=wxAtAHtAmNZsCTbXh-9l-om9tH0sD-P4O7Fl8n3qfR0,14255
58
58
  ee/tests/_cloud_api_utils_test.py,sha256=p8kwehArlj_j4HWsx6vNEk2Dw17MlxYw0XtzupsDWdY,19493
59
59
  ee/tests/_helpers_test.py,sha256=vyhbY9hE_zcSI692eAdjtM36P2vVXScDj_ENA-0tces,3991
60
60
  ee/tests/_state_test.py,sha256=AKe5Vopzt24FJPiPcEce_oOT861gOkd6mUOAWZr6C0g,1175
@@ -72,7 +72,7 @@ ee/tests/confusionmatrix_test.py,sha256=46JJh1-91AiYISXWZ6-2lvY5_Njvc8ompO9kmwql
72
72
  ee/tests/data_test.py,sha256=-_TcPdCdqqfeCNA_hGU9mpjKHl1GxBnb9tCWDWsFrrc,40394
73
73
  ee/tests/daterange_test.py,sha256=a5fpg2lko3kCJzxQPCoAc_vjXkKy2zYcXbeSZKAFovI,8583
74
74
  ee/tests/deprecation_test.py,sha256=CoVug7J9YdB2utZ-BikyJcjitYPQLz49JL_z89xuQSQ,8484
75
- ee/tests/deserializer_test.py,sha256=-tbrL0cjrXdSLF7M3wl-QQuj6TjXJdkjp7RZvVErUy4,3427
75
+ ee/tests/deserializer_test.py,sha256=i_tlyzKgCo1-VpWPAQnTWNcr2klourcMcBbFZJN6Ivw,5050
76
76
  ee/tests/dictionary_test.py,sha256=IRaXMr3GzZFQ5BiHdB35Iio2TckIK67Cnp6KH0h8Aa8,11818
77
77
  ee/tests/ee_array_test.py,sha256=JVXShdbOVOjlfSpNgYc_NVrknQatuPOZ19fG0Ii5yVU,50268
78
78
  ee/tests/ee_date_test.py,sha256=8rLUXfjyiW3LiBOCSneA7ZGgmoFgN5oZr58x5THtKGY,11106
@@ -93,17 +93,17 @@ ee/tests/image_converter_test.py,sha256=uRXYOCU3a0ZaRTHw-ovVP8FJC2mVE9wbHd3JzoEx
93
93
  ee/tests/image_test.py,sha256=_SJmee7orPot26vbxKEZcNZ6OsrNrxv3ToInWYLNZLM,150917
94
94
  ee/tests/imagecollection_test.py,sha256=qosRZXCbhwFuy8qR7DbA-FMl4ktW7Y2cUJHeXLcszpg,38444
95
95
  ee/tests/join_test.py,sha256=pFILq3qM27rO64WYbBC1A_Gs8_pabRv68X7MU_EM_cw,7630
96
- ee/tests/kernel_test.py,sha256=ZblWHqgleJ-7C4lnL7awxfR1mcYtcxpXkkKUziKG2cA,19249
97
- ee/tests/model_test.py,sha256=f2oLaDaAEr23QjkIAhBKY1Mt8CSRmo5N1-fyYRGd5j8,12053
96
+ ee/tests/kernel_test.py,sha256=-0nZVNSxE1IGs4y60oijISh2Hi1V7NCjrmUnEMDd0nQ,19378
97
+ ee/tests/model_test.py,sha256=dgnWfqR4R4MIUljMBL1TOcztzA-lWEl7cT5f2Y0k2ck,12483
98
98
  ee/tests/oauth_test.py,sha256=jYFw8GWPFmLR0jh2NvbcrMizQo_qR_bRDBVRdIZ44g0,3067
99
99
  ee/tests/pixeltype_test.py,sha256=00IWKnZ7xxkVwSSCuWOlCwlTsHAb3XPyKp1Arc4S12U,10024
100
100
  ee/tests/projection_test.py,sha256=fKXXxQPBvWdlMNtNsJze2pbsT0yHHlL7ON8Pdjm1Z7E,6871
101
- ee/tests/reducer_test.py,sha256=NYJTmX6AmBZyXGjOkgUh4t3tB6E8_vGlPYQIxJQbV9Q,31518
101
+ ee/tests/reducer_test.py,sha256=vqXpgLZ7fPyfZ12srpREgMpfrKYLcFQod3Qn1Niv7VM,31979
102
102
  ee/tests/serializer_test.py,sha256=6pPUZODnhvXa8oIIK9i5q1EDJ8Y4gw9HJ2aHwb1-2I4,9819
103
103
  ee/tests/table_converter_test.py,sha256=2F7DyEj-iHVbt9-W1iwAHDl-K1GA_2QHalTXzac2ot8,3373
104
104
  ee/tests/terrain_test.py,sha256=inZ2sy807nDG_HMutzGHaqcTUaLnZQOMdWyf0NrQzV0,4561
105
- earthengine_api-1.6.14.dist-info/METADATA,sha256=zqlGWeeZfZSQnDsgAZvvtkwp_jHaZORkSO_2gNiS8JI,2194
106
- earthengine_api-1.6.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
107
- earthengine_api-1.6.14.dist-info/entry_points.txt,sha256=-Ax4SCU-S474r8OD2LIxata6PRmkZoDrppQ4fP_exNc,50
108
- earthengine_api-1.6.14.dist-info/top_level.txt,sha256=go5zOwCgm5lIS3yTR-Vsxp1gNI4qdS-MP5eY-7zMxVY,3
109
- earthengine_api-1.6.14.dist-info/RECORD,,
105
+ earthengine_api-1.6.15rc0.dist-info/METADATA,sha256=09dxu8SpKEAZTF2mHVChCUdddfJ9adaDB1N1niDp8s4,2197
106
+ earthengine_api-1.6.15rc0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
107
+ earthengine_api-1.6.15rc0.dist-info/entry_points.txt,sha256=-Ax4SCU-S474r8OD2LIxata6PRmkZoDrppQ4fP_exNc,50
108
+ earthengine_api-1.6.15rc0.dist-info/top_level.txt,sha256=go5zOwCgm5lIS3yTR-Vsxp1gNI4qdS-MP5eY-7zMxVY,3
109
+ earthengine_api-1.6.15rc0.dist-info/RECORD,,
ee/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """The EE Python library."""
2
2
 
3
- __version__ = '1.6.14'
3
+ __version__ = '1.6.15rc0'
4
4
 
5
5
  # Using lowercase function naming to match the JavaScript names.
6
6
  # pylint: disable=g-bad-name
ee/cli/commands.py CHANGED
@@ -128,7 +128,7 @@ def _comma_separated_strings(string: str) -> list[str]:
128
128
  """Parses an input consisting of comma-separated strings."""
129
129
  error_msg = 'Argument should be a comma-separated list of strings: {}'
130
130
  values = string.split(',')
131
- if not values:
131
+ if not all(values):
132
132
  raise argparse.ArgumentTypeError(error_msg.format(string))
133
133
  return values
134
134
 
@@ -137,7 +137,7 @@ def _comma_separated_numbers(string: str) -> list[float]:
137
137
  """Parses an input consisting of comma-separated numbers."""
138
138
  error_msg = 'Argument should be a comma-separated list of numbers: {}'
139
139
  values = string.split(',')
140
- if not values:
140
+ if not all(values):
141
141
  raise argparse.ArgumentTypeError(error_msg.format(string))
142
142
  numbervalues = []
143
143
  for value in values:
@@ -155,9 +155,9 @@ def _comma_separated_numbers(string: str) -> list[float]:
155
155
  def _comma_separated_pyramiding_policies(string: str) -> list[str]:
156
156
  """Parses an input consisting of comma-separated pyramiding policies."""
157
157
  error_msg = ('Argument should be a comma-separated list of: '
158
- '{{"mean", "sample", "min", "max", "mode"}}: {}')
158
+ '{{"mean", "median", "sample", "min", "max", "mode"}}: {}')
159
159
  values = string.split(',')
160
- if not values:
160
+ if not all(values):
161
161
  raise argparse.ArgumentTypeError(error_msg.format(string))
162
162
  redvalues = []
163
163
  for value in values:
@@ -226,10 +226,6 @@ def _format_cloud_timestamp(timestamp: str | None) -> str:
226
226
  return _datetime_from_cloud_timestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
227
227
 
228
228
 
229
- def _parse_millis(millis: float) -> datetime.datetime:
230
- return datetime.datetime.fromtimestamp(millis / 1000)
231
-
232
-
233
229
  def _decode_date(string: str) -> Union[float, str]:
234
230
  """Decodes a date from a command line argument, returning msec since epoch".
235
231
 
ee/cli/utils.py CHANGED
@@ -145,7 +145,10 @@ class CommandLineConfig:
145
145
 
146
146
 
147
147
  def _split_gcs_path(path):
148
- m = re.search('gs://([a-z0-9-_.]*)/(.*)', path, re.IGNORECASE)
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[-1:] != '/':
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 = list()
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('%s (y/n)' % msg)
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 %s ended at state: %s after %.2f seconds'
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: %s' % error_message)
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
- - status_counts['SUCCEEDED']
315
- - status_counts['FAILED']
316
- - status_counts['CANCELLED']
319
+ - succeeded
320
+ - failed
321
+ - cancelled
317
322
  )
318
323
  print('Finished waiting for tasks.\n Status summary:')
319
- print(' %d tasks completed successfully.' % status_counts['SUCCEEDED'])
320
- print(' %d tasks failed.' % status_counts['FAILED'])
321
- print(' %d tasks cancelled.' % status_counts['CANCELLED'])
322
- print(' %d tasks are still incomplete (timed-out)' % num_incomplete)
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: %s' % source)
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: %s' % str(e))
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 %s; Server returned HTTP code: %d'
403
- % (bucket, response.status)
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('Error retrieving bucket %s: %s' %
410
- (bucket, json_error))
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: %s' % json_content)
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/deserializer.py CHANGED
@@ -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: ' + json_obj)
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: ' + var_name)
92
- return customfunction.CustomFunction.variable(None, var_name) # pylint: disable=protected-access
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: ' + microseconds)
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: ' + type_name)
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,7 +150,7 @@ 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: %s' % func)
153
+ raise ee_exception.EEException(f'Invalid function value: {func}')
154
154
 
155
155
 
156
156
  def fromCloudApiJSON(json_obj: Union[str, bytes]) -> Any: # pylint: disable=g-bad-name
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
 
@@ -80,6 +80,53 @@ class DeserializerTest(apitestcase.ApiTestCase):
80
80
  ):
81
81
  deserializer.decode(encoded)
82
82
 
83
+ def test_duplicate_scope_key(self):
84
+ """Verifies raising duplicate scope key in decode()."""
85
+ encoded = {
86
+ 'type': 'CompoundValue',
87
+ 'scope': [['a', 1], ['a', 2]],
88
+ 'value': 3,
89
+ }
90
+ with self.assertRaisesRegex(
91
+ ee.EEException, 'Duplicate scope key "a" in scope #1.'
92
+ ):
93
+ deserializer.decode(encoded)
94
+
95
+ def test_cannot_decode_object(self):
96
+ """Verifies raising EEException for non-dict objects in _decodeValue()."""
97
+ with self.assertRaisesRegex(
98
+ ee.EEException, r'Cannot decode object: \(1\+1j\)'
99
+ ):
100
+ deserializer.decode([1 + 1j])
101
+
102
+ def test_invalid_date_value(self):
103
+ """Verifies EEException for invalid date values in _decodeValue()."""
104
+ with self.assertRaisesRegex(
105
+ ee.EEException, r'Invalid date value: not-a-number'
106
+ ):
107
+ deserializer.decode({'type': 'Date', 'value': 'not-a-number'})
108
+
109
+ def test_invocation_of_custom_function(self):
110
+ """Verifies decoding of an Invocation of a CustomFunction."""
111
+ encoded = {
112
+ 'type': 'Invocation',
113
+ 'function': {
114
+ 'type': 'Function',
115
+ 'argumentNames': ['foo'],
116
+ 'body': {'type': 'ArgumentRef', 'value': 'foo'},
117
+ },
118
+ 'arguments': {'foo': 1},
119
+ }
120
+ decoded = deserializer.decode(encoded)
121
+ self.assertIsInstance(decoded, ee.ComputedObject)
122
+
123
+ def test_date_decode(self):
124
+ """Verifies decoding of a Date."""
125
+ encoded = {'type': 'Date', 'value': 1609459200000000}
126
+ decoded = deserializer.decode(encoded)
127
+ self.assertIsInstance(decoded, ee.Date)
128
+ self.assertEqual({'value': 1609459200000}, decoded.args)
129
+
83
130
 
84
131
  if __name__ == '__main__':
85
132
  unittest.main()
ee/tests/kernel_test.py CHANGED
@@ -287,6 +287,10 @@ class KernelTest(apitestcase.ApiTestCase):
287
287
  result = json.loads(expression.serialize())
288
288
  self.assertEqual(expect, result)
289
289
 
290
+ def test_fixed_no_weights(self):
291
+ with self.assertRaisesRegex(ValueError, 'weights is required.'):
292
+ ee.Kernel.fixed()
293
+
290
294
  def test_gaussian(self):
291
295
  radius = 1.1
292
296
  sigma = 2.2
ee/tests/model_test.py CHANGED
@@ -115,6 +115,18 @@ class ModelTest(apitestcase.ApiTestCase):
115
115
  }
116
116
  self.assertEqual(expect, result)
117
117
 
118
+ def test_model_constructor_invalid(self):
119
+ with self.assertRaisesRegex(
120
+ TypeError, 'Model constructor can only cast to Model.'
121
+ ):
122
+ ee.Model('not a computed object') # pytype: disable=wrong-arg-types
123
+
124
+ def test_model_constructor_invalid_int(self):
125
+ with self.assertRaisesRegex(
126
+ TypeError, 'Model constructor can only cast to Model.'
127
+ ):
128
+ ee.Model(123) # pytype: disable=wrong-arg-types
129
+
118
130
  def test_from_ai_platform_predictor(self):
119
131
  project_name = 'some project'
120
132
  project_id = 'a project id'
ee/tests/reducer_test.py CHANGED
@@ -809,6 +809,19 @@ class ReducerTest(apitestcase.ApiTestCase):
809
809
  result = json.loads(expression.serialize())
810
810
  self.assertEqual(expect, result)
811
811
 
812
+ def test_ridge_regression_kwargs_with_lambda(self):
813
+ with self.assertRaisesRegex(
814
+ ValueError, 'lambda_ cannot be set when providing kwargs.'
815
+ ):
816
+ ee.Reducer.ridgeRegression(1, lambda_=3, **{'lambda': 4})
817
+
818
+ def test_ridge_regression_unexpected_kwargs(self):
819
+ with self.assertRaisesRegex(
820
+ ValueError,
821
+ r"Unexpected arguments: \['unexpected'\]\. Expected: lambda.",
822
+ ):
823
+ ee.Reducer.ridgeRegression(1, unexpected=4)
824
+
812
825
  def test_robust_linear_regression(self):
813
826
  num_x = 1
814
827
  num_y = 2