earthengine-api 1.6.11__py3-none-any.whl → 1.6.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {earthengine_api-1.6.11.dist-info → earthengine_api-1.6.12.dist-info}/METADATA +1 -1
  2. {earthengine_api-1.6.11.dist-info → earthengine_api-1.6.12.dist-info}/RECORD +48 -46
  3. ee/__init__.py +5 -5
  4. ee/_cloud_api_utils.py +33 -10
  5. ee/_state.py +105 -0
  6. ee/apifunction.py +1 -1
  7. ee/apitestcase.py +15 -21
  8. ee/batch.py +1 -1
  9. ee/cli/commands.py +153 -63
  10. ee/cli/eecli.py +1 -1
  11. ee/cli/utils.py +25 -15
  12. ee/collection.py +27 -18
  13. ee/computedobject.py +5 -5
  14. ee/customfunction.py +3 -3
  15. ee/data.py +104 -210
  16. ee/ee_array.py +4 -2
  17. ee/ee_number.py +1 -1
  18. ee/ee_string.py +18 -26
  19. ee/ee_types.py +2 -2
  20. ee/element.py +1 -1
  21. ee/featurecollection.py +10 -7
  22. ee/filter.py +2 -2
  23. ee/geometry.py +20 -21
  24. ee/image.py +7 -12
  25. ee/imagecollection.py +3 -3
  26. ee/mapclient.py +9 -9
  27. ee/oauth.py +13 -6
  28. ee/tests/_cloud_api_utils_test.py +16 -0
  29. ee/tests/_helpers_test.py +9 -9
  30. ee/tests/_state_test.py +49 -0
  31. ee/tests/apifunction_test.py +5 -5
  32. ee/tests/batch_test.py +61 -50
  33. ee/tests/collection_test.py +13 -13
  34. ee/tests/data_test.py +65 -60
  35. ee/tests/dictionary_test.py +9 -9
  36. ee/tests/ee_number_test.py +32 -26
  37. ee/tests/ee_string_test.py +8 -0
  38. ee/tests/ee_test.py +37 -19
  39. ee/tests/element_test.py +2 -2
  40. ee/tests/feature_test.py +6 -6
  41. ee/tests/function_test.py +5 -5
  42. ee/tests/geometry_test.py +73 -51
  43. ee/tests/oauth_test.py +21 -2
  44. ee/tests/serializer_test.py +8 -8
  45. {earthengine_api-1.6.11.dist-info → earthengine_api-1.6.12.dist-info}/WHEEL +0 -0
  46. {earthengine_api-1.6.11.dist-info → earthengine_api-1.6.12.dist-info}/entry_points.txt +0 -0
  47. {earthengine_api-1.6.11.dist-info → earthengine_api-1.6.12.dist-info}/licenses/LICENSE +0 -0
  48. {earthengine_api-1.6.11.dist-info → earthengine_api-1.6.12.dist-info}/top_level.txt +0 -0
ee/data.py CHANGED
@@ -3,6 +3,8 @@
3
3
  # Using lowercase function naming to match the JavaScript names.
4
4
  # pylint: disable=g-bad-name
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  from collections.abc import Iterator, Sequence
7
9
  import contextlib
8
10
  import json
@@ -23,6 +25,7 @@ import httplib2
23
25
  import requests
24
26
 
25
27
  from ee import _cloud_api_utils
28
+ from ee import _state
26
29
  from ee import _utils
27
30
  from ee import computedobject
28
31
  from ee import deprecation
@@ -93,52 +96,6 @@ _NOT_INITIALIZED_MESSAGE = (
93
96
  'Earth Engine client library not initialized. See http://goo.gle/ee-auth.'
94
97
  )
95
98
 
96
- # OAuth2 credentials object. This may be set by ee.Initialize().
97
- _credentials: Optional[credentials_lib.Credentials] = None
98
-
99
- # The base URL for all data calls. This is set by ee.Initialize().
100
- _api_base_url: Optional[str] = None
101
-
102
- # The base URL for map tiles. This is set by ee.Initialize().
103
- _tile_base_url: Optional[str] = None
104
-
105
- # The base URL for all Cloud API calls. This is set by ee.Initialize().
106
- _cloud_api_base_url: Optional[str] = None
107
-
108
- # Google Cloud API key. This may be set by ee.Initialize().
109
- _cloud_api_key: Optional[str] = None
110
-
111
- # A Requests session. This is set by ee.Initialize()
112
- _requests_session: Optional[requests.Session] = None
113
-
114
- # A resource object for making Cloud API calls.
115
- _cloud_api_resource = None
116
-
117
- # A resource object for making Cloud API calls and receiving raw return types.
118
- _cloud_api_resource_raw = None
119
-
120
- # The default user project to use when making Cloud API calls.
121
- _cloud_api_user_project: str = DEFAULT_CLOUD_API_USER_PROJECT
122
-
123
- # The API client version number to send when making requests.
124
- _cloud_api_client_version: Optional[str] = None
125
-
126
- # The http_transport to use.
127
- _http_transport = None
128
-
129
- # Whether the module has been initialized.
130
- _initialized: bool = False
131
-
132
- # Sets the number of milliseconds to wait for a request before considering
133
- # it timed out. 0 means no limit.
134
- _deadline_ms: int = 0
135
-
136
- # Maximum number of times to retry a rate-limited request.
137
- _max_retries: int = 5
138
-
139
- # User agent to indicate which application is calling Earth Engine
140
- _user_agent: Optional[str] = None
141
-
142
99
 
143
100
  class _ThreadLocals(threading.local):
144
101
  """Storage for thread local variables."""
@@ -161,6 +118,11 @@ class _ThreadLocals(threading.local):
161
118
  _thread_locals = _ThreadLocals()
162
119
 
163
120
 
121
+ def _get_state() -> _state.EEState:
122
+ """Returns the current state, or a default state if not initialized."""
123
+ return _state.get_state()
124
+
125
+
164
126
  def initialize(
165
127
  credentials: Any = None,
166
128
  api_base_url: Optional[str] = None,
@@ -188,57 +150,51 @@ def initialize(
188
150
  project: The client project ID or number to use when making API calls.
189
151
  http_transport: The http transport to use
190
152
  """
191
- global _api_base_url, _tile_base_url, _credentials, _initialized
192
- global _requests_session
193
- global _cloud_api_base_url
194
- global _cloud_api_key
195
- global _cloud_api_user_project, _http_transport
196
- global _cloud_api_client_version
197
-
153
+ state = _get_state()
198
154
  # If already initialized, only replace the explicitly specified parts.
199
155
 
200
156
  if credentials is not None:
201
- _credentials = credentials
157
+ state.credentials = credentials
202
158
 
203
159
  if api_base_url is not None:
204
- _api_base_url = api_base_url
205
- elif not _initialized:
206
- _api_base_url = DEFAULT_API_BASE_URL
160
+ state.api_base_url = api_base_url
161
+ elif not state.initialized:
162
+ state.api_base_url = DEFAULT_API_BASE_URL
207
163
 
208
164
  if tile_base_url is not None:
209
- _tile_base_url = tile_base_url
210
- elif not _initialized:
211
- _tile_base_url = DEFAULT_TILE_BASE_URL
165
+ state.tile_base_url = tile_base_url
166
+ elif not state.initialized:
167
+ state.tile_base_url = DEFAULT_TILE_BASE_URL
212
168
 
213
169
  if cloud_api_key is not None:
214
- _cloud_api_key = cloud_api_key
170
+ state.cloud_api_key = cloud_api_key
215
171
 
216
172
  if cloud_api_base_url is not None:
217
- _cloud_api_base_url = cloud_api_base_url
218
- elif not _initialized:
219
- _cloud_api_base_url = DEFAULT_CLOUD_API_BASE_URL
173
+ state.cloud_api_base_url = cloud_api_base_url
174
+ elif not state.initialized:
175
+ state.cloud_api_base_url = DEFAULT_CLOUD_API_BASE_URL
220
176
 
221
177
  if __version__ is not None:
222
178
  version = __version__
223
- _cloud_api_client_version = version
179
+ state.cloud_api_client_version = version
224
180
 
225
- _http_transport = http_transport
181
+ state.http_transport = http_transport
226
182
 
227
- if _requests_session is None:
228
- _requests_session = requests.Session()
183
+ if state.requests_session is None:
184
+ state.requests_session = requests.Session()
229
185
 
230
186
  _install_cloud_api_resource()
231
187
 
232
188
  if project is not None:
233
- _cloud_api_user_project = project
189
+ state.cloud_api_user_project = project
234
190
  else:
235
- _cloud_api_user_project = DEFAULT_CLOUD_API_USER_PROJECT
191
+ state.cloud_api_user_project = DEFAULT_CLOUD_API_USER_PROJECT
236
192
 
237
- _initialized = True
193
+ state.initialized = True
238
194
 
239
195
 
240
196
  def is_initialized() -> bool:
241
- return _initialized
197
+ return _get_state().initialized
242
198
 
243
199
 
244
200
  def get_persistent_credentials() -> credentials_lib.Credentials:
@@ -286,89 +242,78 @@ def get_persistent_credentials() -> credentials_lib.Credentials:
286
242
 
287
243
 
288
244
  def reset() -> None:
289
- """Resets the data module, clearing credentials and custom base URLs."""
290
- global _api_base_url, _tile_base_url, _credentials, _initialized
291
- global _requests_session, _cloud_api_resource, _cloud_api_resource_raw
292
- global _cloud_api_base_url, _cloud_api_user_project
293
- global _cloud_api_key, _http_transport
294
- _credentials = None
295
- _api_base_url = None
296
- _tile_base_url = None
297
- if _requests_session is not None:
298
- _requests_session.close()
299
- _requests_session = None
300
- _cloud_api_base_url = None
301
- _cloud_api_key = None
302
- _cloud_api_resource = None
303
- _cloud_api_resource_raw = None
304
- _cloud_api_user_project = DEFAULT_CLOUD_API_USER_PROJECT
305
- _http_transport = None
306
- _initialized = False
245
+ """Resets the EE state, clearing credentials and custom base URLs."""
246
+ _state.reset_state()
307
247
 
308
248
 
309
249
  def _get_projects_path() -> str:
310
250
  """Returns the projects path to use for constructing a request."""
311
- return f'projects/{_cloud_api_user_project}'
251
+ return f'projects/{_get_state().cloud_api_user_project}'
312
252
 
313
253
 
314
254
  def _install_cloud_api_resource() -> None:
315
255
  """Builds or rebuilds the Cloud API resource object, if needed."""
316
- global _cloud_api_resource, _cloud_api_resource_raw
317
-
318
- timeout = (_deadline_ms / 1000.0) or None
319
- assert _requests_session is not None
320
- _cloud_api_resource = _cloud_api_utils.build_cloud_resource(
321
- _cloud_api_base_url,
322
- _requests_session,
323
- credentials=_credentials,
324
- api_key=_cloud_api_key,
256
+ state = _get_state()
257
+
258
+ timeout = (state.deadline_ms / 1000.0) or None
259
+ assert state.requests_session is not None
260
+ state.cloud_api_resource = _cloud_api_utils.build_cloud_resource(
261
+ state.cloud_api_base_url,
262
+ state.requests_session,
263
+ credentials=state.credentials,
264
+ api_key=state.cloud_api_key,
325
265
  timeout=timeout,
326
- num_retries=_max_retries,
266
+ num_retries=state.max_retries,
327
267
  headers_supplier=_make_request_headers,
328
268
  response_inspector=_handle_profiling_response,
329
- http_transport=_http_transport,
269
+ http_transport=state.http_transport,
330
270
  )
331
271
 
332
- _cloud_api_resource_raw = _cloud_api_utils.build_cloud_resource(
333
- _cloud_api_base_url,
334
- _requests_session,
335
- credentials=_credentials,
336
- api_key=_cloud_api_key,
272
+ state.cloud_api_resource_raw = _cloud_api_utils.build_cloud_resource(
273
+ state.cloud_api_base_url,
274
+ state.requests_session,
275
+ credentials=state.credentials,
276
+ api_key=state.cloud_api_key,
337
277
  timeout=timeout,
338
- num_retries=_max_retries,
278
+ num_retries=state.max_retries,
339
279
  headers_supplier=_make_request_headers,
340
280
  response_inspector=_handle_profiling_response,
341
- http_transport=_http_transport,
281
+ http_transport=state.http_transport,
342
282
  raw=True,
343
283
  )
344
284
 
345
285
 
346
286
  def _get_cloud_projects() -> Any:
347
- if _cloud_api_resource is None:
287
+ state = _get_state()
288
+ if state.cloud_api_resource is None:
348
289
  raise ee_exception.EEException(_NOT_INITIALIZED_MESSAGE)
349
- return _cloud_api_resource.projects()
290
+ return state.cloud_api_resource.projects()
350
291
 
351
292
 
352
293
  def _get_cloud_projects_raw() -> Any:
353
- if _cloud_api_resource_raw is None:
294
+ state = _get_state()
295
+ if state.cloud_api_resource_raw is None:
354
296
  raise ee_exception.EEException(_NOT_INITIALIZED_MESSAGE)
355
- return _cloud_api_resource_raw.projects()
297
+ return state.cloud_api_resource_raw.projects()
356
298
 
357
299
 
358
300
  def _make_request_headers() -> Optional[dict[str, Any]]:
359
301
  """Adds headers based on client context."""
302
+ state = _get_state()
360
303
  headers: dict[str, Any] = {}
361
304
  client_version_header_values: list[Any] = []
362
- if _cloud_api_client_version is not None:
363
- client_version_header_values.append('ee-py/' + _cloud_api_client_version)
364
- if _user_agent is not None:
365
- headers[_USER_AGENT_HEADER] = _user_agent
305
+ if state.cloud_api_client_version is not None:
306
+ client_version_header_values.append(
307
+ f'ee-py/{state.cloud_api_client_version}'
308
+ )
309
+ if state.user_agent is not None:
310
+ headers[_USER_AGENT_HEADER] = state.user_agent
366
311
  client_version_header_values.append('python/' + platform.python_version())
367
312
  headers[_API_CLIENT_VERSION_HEADER] = ' '.join(client_version_header_values)
368
313
  if _thread_locals.profile_hook:
369
314
  headers[_PROFILE_REQUEST_HEADER] = '1'
370
- if _cloud_api_user_project is not DEFAULT_CLOUD_API_USER_PROJECT:
371
- headers[_USER_PROJECT_OVERRIDE_HEADER] = _cloud_api_user_project
315
+ if state.cloud_api_user_project is not DEFAULT_CLOUD_API_USER_PROJECT:
316
+ headers[_USER_PROJECT_OVERRIDE_HEADER] = state.cloud_api_user_project
372
317
  if headers:
373
318
  return headers
374
319
  return None
@@ -399,7 +344,7 @@ def _execute_cloud_call(
399
344
  Raises:
400
345
  EEException if the call fails.
401
346
  """
402
- num_retries = _max_retries if num_retries is None else num_retries
347
+ num_retries = _get_state().max_retries if num_retries is None else num_retries
403
348
  try:
404
349
  return call.execute(num_retries=num_retries)
405
350
  except googleapiclient.errors.HttpError as e:
@@ -442,23 +387,20 @@ def _maybe_populate_workload_tag(body: dict[str, Any]) -> None:
442
387
 
443
388
  def setCloudApiKey(cloud_api_key: str) -> None:
444
389
  """Sets the Cloud API key parameter ("api_key") for all requests."""
445
- global _cloud_api_key
446
- _cloud_api_key = cloud_api_key
390
+ _get_state().cloud_api_key = cloud_api_key
447
391
  _install_cloud_api_resource()
448
392
 
449
393
 
450
394
  def setCloudApiUserProject(cloud_api_user_project: str) -> None:
451
- global _cloud_api_user_project
452
- _cloud_api_user_project = cloud_api_user_project
395
+ _get_state().cloud_api_user_project = cloud_api_user_project
453
396
 
454
397
 
455
398
  def setUserAgent(user_agent: str) -> None:
456
- global _user_agent
457
- _user_agent = user_agent
399
+ _get_state().user_agent = user_agent
458
400
 
459
401
 
460
402
  def getUserAgent() -> Optional[str]:
461
- return _user_agent
403
+ return _get_state().user_agent
462
404
 
463
405
 
464
406
  def setDeadline(milliseconds: float) -> None:
@@ -468,8 +410,7 @@ def setDeadline(milliseconds: float) -> None:
468
410
  milliseconds: The number of milliseconds to wait for a request
469
411
  before considering it timed out. 0 means no limit.
470
412
  """
471
- global _deadline_ms
472
- _deadline_ms = milliseconds
413
+ _get_state().deadline_ms = milliseconds
473
414
  _install_cloud_api_resource()
474
415
 
475
416
 
@@ -483,8 +424,7 @@ def setMaxRetries(max_retries: int) -> None:
483
424
  raise ValueError('max_retries must be non-negative')
484
425
  if max_retries >= 100:
485
426
  raise ValueError('Too many retries')
486
- global _max_retries
487
- _max_retries = max_retries
427
+ _get_state().max_retries = max_retries
488
428
 
489
429
 
490
430
  @contextlib.contextmanager
@@ -526,7 +466,7 @@ def getInfo(asset_id: str) -> Optional[Any]:
526
466
  _get_cloud_projects()
527
467
  .assets()
528
468
  .get(name=name, prettyPrint=False)
529
- .execute(num_retries=_max_retries)
469
+ .execute(num_retries=_get_state().max_retries)
530
470
  )
531
471
  except googleapiclient.errors.HttpError as e:
532
472
  if e.resp.status == 404:
@@ -747,11 +687,12 @@ def getMapId(params: dict[str, Any]) -> dict[str, Any]:
747
687
  .maps()
748
688
  .create(parent=_get_projects_path(), **queryParams)
749
689
  )
690
+ state = _get_state()
750
691
  map_name = result['name']
751
692
  url_format = '%s/%s/%s/tiles/{z}/{x}/{y}' % (
752
- _tile_base_url, _cloud_api_utils.VERSION, map_name)
753
- if _cloud_api_key:
754
- url_format += '?key=%s' % _cloud_api_key
693
+ state.tile_base_url, _cloud_api_utils.VERSION, map_name)
694
+ if state.cloud_api_key:
695
+ url_format += f'?key={state.cloud_api_key}'
755
696
 
756
697
  return {'mapid': map_name, 'token': '',
757
698
  'tile_fetcher': TileFetcher(url_format, map_name=map_name)}
@@ -787,8 +728,9 @@ def getFeatureViewTilesKey(params: dict[str, Any]) -> dict[str, Any]:
787
728
  )
788
729
  name = result['name']
789
730
  version = _cloud_api_utils.VERSION
790
- format_tile_url = (
791
- lambda x, y, z: f'{_tile_base_url}/{version}/{name}/tiles/{z}/{x}/{y}')
731
+ format_tile_url = lambda x, y, z: (
732
+ f'{_get_state().tile_base_url}/{version}/{name}/tiles/{z}/{x}/{y}'
733
+ )
792
734
  token = name.rsplit('/', 1).pop()
793
735
  return {
794
736
  'token': token,
@@ -1256,11 +1198,12 @@ def makeThumbUrl(thumbId: dict[str, str]) -> str:
1256
1198
  Returns:
1257
1199
  A URL from which the thumbnail can be obtained.
1258
1200
  """
1201
+ state = _get_state()
1259
1202
  url = '{}/{}/{}:getPixels'.format(
1260
- _tile_base_url, _cloud_api_utils.VERSION, thumbId['thumbid']
1203
+ state.tile_base_url, _cloud_api_utils.VERSION, thumbId['thumbid']
1261
1204
  )
1262
- if _cloud_api_key:
1263
- url += '?key=%s' % _cloud_api_key
1205
+ if state.cloud_api_key:
1206
+ url += f'?key={state.cloud_api_key}'
1264
1207
  return url
1265
1208
 
1266
1209
 
@@ -1390,7 +1333,7 @@ def makeDownloadUrl(downloadId: dict[str, str]) -> str:
1390
1333
  A URL from which the download can be obtained.
1391
1334
  """
1392
1335
  return '{}/{}/{}:getPixels'.format(
1393
- _tile_base_url, _cloud_api_utils.VERSION, downloadId['docid']
1336
+ _get_state().tile_base_url, _cloud_api_utils.VERSION, downloadId['docid']
1394
1337
  )
1395
1338
 
1396
1339
 
@@ -1453,7 +1396,7 @@ def makeTableDownloadUrl(downloadId: dict[str, str]) -> str:
1453
1396
  A Url from which the download can be obtained.
1454
1397
  """
1455
1398
  return '{}/{}/{}:getFeatures'.format(
1456
- _tile_base_url, _cloud_api_utils.VERSION, downloadId['docid']
1399
+ _get_state().tile_base_url, _cloud_api_utils.VERSION, downloadId['docid']
1457
1400
  )
1458
1401
 
1459
1402
 
@@ -1461,11 +1404,11 @@ def getAlgorithms() -> Any:
1461
1404
  """Get the list of algorithms.
1462
1405
 
1463
1406
  Returns:
1464
- The dictionary of algorithms. Each algorithm is a dictionary containing
1407
+ The dictionary of algorithms. Each algorithm is a dictionary containing
1465
1408
  the following fields:
1466
1409
  "description" - (string) A text description of the algorithm.
1467
1410
  "returns" - (string) The return type of the algorithm.
1468
- "args" - An array of arguments. Each argument specifies the following:
1411
+ "args" - An array of arguments. Each argument specifies the following:
1469
1412
  "name" - (string) The name of the argument.
1470
1413
  "description" - (string) A text description of the argument.
1471
1414
  "type" - (string) The type of the argument.
@@ -1691,19 +1634,20 @@ def getTaskStatus(taskId: Union[list[str], str]) -> list[Any]:
1691
1634
  """
1692
1635
  if isinstance(taskId, str):
1693
1636
  taskId = [taskId]
1637
+ state = _get_state()
1694
1638
  result = []
1695
1639
  for one_id in taskId:
1696
1640
  # Don't use getOperation as it will translate the exception, and we need
1697
1641
  # to handle 404s specially.
1698
1642
  name = _cloud_api_utils.convert_task_id_to_operation_name(
1699
- _cloud_api_user_project, one_id
1643
+ state.cloud_api_user_project, one_id
1700
1644
  )
1701
1645
  try:
1702
1646
  operation = (
1703
1647
  _get_cloud_projects()
1704
1648
  .operations()
1705
1649
  .get(name=name)
1706
- .execute(num_retries=_max_retries)
1650
+ .execute(num_retries=state.max_retries)
1707
1651
  )
1708
1652
  result.append(_cloud_api_utils.convert_operation_to_task(operation))
1709
1653
  except googleapiclient.errors.HttpError as e:
@@ -1734,7 +1678,7 @@ def cancelTask(taskId: str) -> None:
1734
1678
  """Cancels a batch task."""
1735
1679
  cancelOperation(
1736
1680
  _cloud_api_utils.convert_task_id_to_operation_name(
1737
- _cloud_api_user_project, taskId
1681
+ _get_state().cloud_api_user_project, taskId
1738
1682
  )
1739
1683
  )
1740
1684
 
@@ -1910,7 +1854,7 @@ def _prepare_and_run_export(
1910
1854
  if isinstance(params['expression'], encodable.Encodable):
1911
1855
  params['expression'] = serializer.encode(
1912
1856
  params['expression'], for_cloud_api=True)
1913
- num_retries = _max_retries if request_id else 0
1857
+ num_retries = _get_state().max_retries if request_id else 0
1914
1858
  return _execute_cloud_call(
1915
1859
  export_endpoint(project=_get_projects_path(), body=params),
1916
1860
  num_retries=num_retries)
@@ -1936,7 +1880,7 @@ def _startIngestion(
1936
1880
 
1937
1881
  # It's only safe to retry the request if there's a unique ID to make it
1938
1882
  # idempotent.
1939
- num_retries = _max_retries if request_id else 0
1883
+ num_retries = _get_state().max_retries if request_id else 0
1940
1884
 
1941
1885
  image = _get_cloud_projects().image()
1942
1886
  if import_mode == _INTERNAL_IMPORT:
@@ -2071,7 +2015,7 @@ def startTableIngestion(
2071
2015
  }
2072
2016
  # It's only safe to retry the request if there's a unique ID to make it
2073
2017
  # idempotent.
2074
- num_retries = _max_retries if request_id else 0
2018
+ num_retries = _get_state().max_retries if request_id else 0
2075
2019
  operation = _execute_cloud_call(
2076
2020
  _get_cloud_projects()
2077
2021
  .table()
@@ -2324,8 +2268,8 @@ def updateProjectConfig(
2324
2268
 
2325
2269
 
2326
2270
  def authorizeHttp(http: Any) -> Any:
2327
- if _credentials:
2328
- return google_auth_httplib2.AuthorizedHttp(_credentials)
2271
+ if credentials := _get_state().credentials:
2272
+ return google_auth_httplib2.AuthorizedHttp(credentials)
2329
2273
  else:
2330
2274
  return http
2331
2275
 
@@ -2369,7 +2313,7 @@ def convert_asset_id_to_asset_name(asset_id: str) -> str:
2369
2313
 
2370
2314
  def getWorkloadTag() -> Optional[Union[int, str]]:
2371
2315
  """Returns the currently set workload tag."""
2372
- return _workloadTag.get()
2316
+ return _get_state().workload_tag.get()
2373
2317
 
2374
2318
 
2375
2319
  def setWorkloadTag(tag: Optional[Union[int, str]]) -> None:
@@ -2382,7 +2326,7 @@ def setWorkloadTag(tag: Optional[Union[int, str]]) -> None:
2382
2326
  Args:
2383
2327
  tag: The tag to set.
2384
2328
  """
2385
- _workloadTag.set(tag)
2329
+ _get_state().workload_tag.set(tag)
2386
2330
 
2387
2331
 
2388
2332
  @contextlib.contextmanager
@@ -2421,8 +2365,9 @@ def setDefaultWorkloadTag(tag: Optional[Union[int, str]]) -> None:
2421
2365
  Args:
2422
2366
  tag: The tag to set.
2423
2367
  """
2424
- _workloadTag.setDefault(tag)
2425
- _workloadTag.set(tag)
2368
+ state = _get_state()
2369
+ state.workload_tag.set_default(tag)
2370
+ state.workload_tag.set(tag)
2426
2371
 
2427
2372
 
2428
2373
  @_utils.accept_opt_prefix('opt_resetDefault')
@@ -2435,58 +2380,7 @@ def resetWorkloadTag(resetDefault: bool = False) -> None:
2435
2380
  Args:
2436
2381
  resetDefault: Whether to reset the default back to empty.
2437
2382
  """
2383
+ state = _get_state()
2438
2384
  if resetDefault:
2439
- _workloadTag.setDefault('')
2440
- _workloadTag.reset()
2441
-
2442
-
2443
- # TODO(user): Consider only returning str even for ints.
2444
- class _WorkloadTag:
2445
- """A helper class to manage the workload tag."""
2446
- _tag: Optional[Union[int, str]]
2447
- _default: Optional[Union[int, str]]
2448
-
2449
- def __init__(self):
2450
- # TODO(user): Consider using None as default and setting them above.
2451
- self._tag = ''
2452
- self._default = ''
2453
-
2454
- def get(self) -> Union[int, str, None]:
2455
- return self._tag
2456
-
2457
- def set(self, tag: Optional[Union[int, str]]) -> None:
2458
- self._tag = self.validate(tag)
2459
-
2460
- def setDefault(self, newDefault: Optional[Union[int, str]]) -> None:
2461
- self._default = self.validate(newDefault)
2462
-
2463
- def reset(self) -> None:
2464
- self._tag = self._default
2465
-
2466
- def validate(self, tag: Optional[Union[int, str]]) -> str:
2467
- """Throws an error if setting an invalid tag.
2468
-
2469
- Args:
2470
- tag: the tag to validate.
2471
-
2472
- Returns:
2473
- The validated tag.
2474
-
2475
- Raises:
2476
- ValueError if the tag does not match the expected format.
2477
- """
2478
- if not tag and tag != 0:
2479
- return ''
2480
- tag = str(tag)
2481
- if not re.fullmatch(r'([a-z0-9]|[a-z0-9][-_a-z0-9]{0,61}[a-z0-9])', tag):
2482
- validationMessage = (
2483
- 'Tags must be 1-63 characters, '
2484
- 'beginning and ending with a lowercase alphanumeric character '
2485
- '([a-z0-9]) with dashes (-), underscores (_), '
2486
- 'and lowercase alphanumerics between.')
2487
- raise ValueError(f'Invalid tag, "{tag}". {validationMessage}')
2488
- return tag
2489
-
2490
-
2491
- # Tracks the currently set workload tag.
2492
- _workloadTag = _WorkloadTag()
2385
+ state.workload_tag.set_default('')
2386
+ state.workload_tag.reset()
ee/ee_array.py CHANGED
@@ -189,6 +189,8 @@ class Array(computedobject.ComputedObject):
189
189
 
190
190
  return apifunction.ApiFunction.call_(self.name() + '.bitCount', self)
191
191
 
192
+ @staticmethod
193
+ # pylint: disable-next=redefined-builtin
192
194
  def bitsToArray(input: _arg_types.Integer) -> Array:
193
195
  """Returns an Array from the bits of an integer.
194
196
 
@@ -1041,7 +1043,7 @@ class Array(computedobject.ComputedObject):
1041
1043
  start: The coordinate of the first slice (inclusive) along 'axis'.
1042
1044
  Negative numbers are used to position the start of slicing relative to
1043
1045
  the end of the array, where -1 starts at the last position on the axis,
1044
- -2 starts at the next to last position, etc. Defaults to 0.
1046
+ -2 starts at the next to last position, etc. Defaults to 0.
1045
1047
  end: The coordinate (exclusive) at which to stop taking slices. By default
1046
1048
  this will be the length of the given axis. Negative numbers are used to
1047
1049
  position the end of slicing relative to the end of the array, where -1
@@ -1049,7 +1051,7 @@ class Array(computedobject.ComputedObject):
1049
1051
  etc.
1050
1052
  step: The separation between slices along 'axis'; a slice will be taken at
1051
1053
  each whole multiple of 'step' from 'start' (inclusive) to 'end'
1052
- (exclusive). Must be positive. Defaults to 1.
1054
+ (exclusive). Must be positive. Defaults to 1.
1053
1055
 
1054
1056
  Returns:
1055
1057
  An ee.Array.
ee/ee_number.py CHANGED
@@ -781,7 +781,7 @@ class Number(computedobject.ComputedObject):
781
781
  ) -> Number:
782
782
  """Scales the input so that [min, max] becomes [0, 1].
783
783
 
784
- Values outside the range are NOT clamped. If min == max, 0 is returned.
784
+ Values outside the range are NOT clamped. If min == max, 0 is returned.
785
785
 
786
786
  Args:
787
787
  min: Minimum value of the input to be scaled to 0.