earthengine-api 1.5.13rc0__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.5.13rc0.dist-info → earthengine_api-1.7.4.dist-info}/METADATA +3 -3
- earthengine_api-1.7.4.dist-info/RECORD +109 -0
- {earthengine_api-1.5.13rc0.dist-info → earthengine_api-1.7.4.dist-info}/WHEEL +1 -1
- ee/__init__.py +29 -28
- ee/_arg_types.py +7 -6
- ee/_cloud_api_utils.py +95 -78
- ee/_helpers.py +17 -13
- ee/_state.py +105 -0
- ee/_utils.py +2 -1
- ee/apifunction.py +21 -19
- ee/apitestcase.py +33 -38
- ee/batch.py +87 -77
- ee/blob.py +10 -12
- ee/classifier.py +57 -59
- ee/cli/commands.py +178 -114
- ee/cli/eecli.py +1 -1
- ee/cli/utils.py +61 -42
- ee/clusterer.py +39 -41
- ee/collection.py +64 -54
- ee/computedobject.py +19 -16
- ee/confusionmatrix.py +9 -9
- ee/customfunction.py +13 -12
- ee/data.py +220 -322
- ee/daterange.py +10 -10
- ee/deprecation.py +21 -13
- ee/deserializer.py +25 -20
- ee/dictionary.py +11 -11
- ee/ee_array.py +22 -20
- ee/ee_date.py +23 -23
- ee/ee_list.py +15 -16
- ee/ee_number.py +11 -21
- ee/ee_string.py +24 -32
- ee/ee_types.py +4 -4
- ee/element.py +15 -15
- ee/encodable.py +7 -4
- ee/errormargin.py +4 -4
- ee/feature.py +68 -71
- ee/featurecollection.py +41 -40
- ee/filter.py +90 -92
- ee/function.py +8 -8
- ee/geometry.py +95 -93
- ee/image.py +238 -236
- ee/image_converter.py +4 -4
- ee/imagecollection.py +30 -27
- ee/join.py +13 -15
- ee/kernel.py +55 -57
- ee/mapclient.py +9 -9
- ee/model.py +29 -31
- ee/oauth.py +76 -63
- ee/pixeltype.py +6 -6
- ee/projection.py +5 -4
- ee/reducer.py +41 -41
- ee/serializer.py +14 -14
- ee/table_converter.py +7 -6
- ee/terrain.py +7 -9
- ee/tests/_cloud_api_utils_test.py +21 -6
- ee/tests/_helpers_test.py +57 -4
- ee/tests/_state_test.py +49 -0
- ee/tests/algorithms.json +85 -2
- ee/tests/apifunction_test.py +5 -5
- ee/tests/batch_test.py +135 -57
- ee/tests/blob_test.py +5 -5
- ee/tests/classifier_test.py +3 -3
- ee/tests/clusterer_test.py +3 -3
- ee/tests/collection_test.py +48 -13
- ee/tests/confusionmatrix_test.py +3 -3
- ee/tests/data_test.py +484 -55
- ee/tests/daterange_test.py +4 -4
- ee/tests/deprecation_test.py +6 -4
- ee/tests/deserializer_test.py +64 -5
- ee/tests/dictionary_test.py +12 -12
- ee/tests/ee_array_test.py +3 -3
- ee/tests/ee_date_test.py +4 -4
- ee/tests/ee_list_test.py +3 -3
- ee/tests/ee_number_test.py +75 -30
- ee/tests/ee_string_test.py +11 -3
- ee/tests/ee_test.py +40 -22
- ee/tests/element_test.py +2 -2
- ee/tests/errormargin_test.py +1 -1
- ee/tests/feature_test.py +10 -10
- ee/tests/featurecollection_test.py +3 -3
- ee/tests/filter_test.py +4 -4
- ee/tests/function_test.py +5 -5
- ee/tests/geometry_point_test.py +3 -3
- ee/tests/geometry_test.py +93 -52
- ee/tests/image_converter_test.py +1 -3
- ee/tests/image_test.py +3 -3
- ee/tests/imagecollection_test.py +3 -3
- ee/tests/join_test.py +3 -3
- ee/tests/kernel_test.py +7 -3
- ee/tests/model_test.py +17 -5
- ee/tests/oauth_test.py +189 -7
- ee/tests/pixeltype_test.py +6 -7
- ee/tests/projection_test.py +5 -6
- ee/tests/reducer_test.py +16 -3
- ee/tests/serializer_test.py +39 -12
- ee/tests/table_converter_test.py +51 -7
- ee/tests/terrain_test.py +11 -3
- earthengine_api-1.5.13rc0.dist-info/RECORD +0 -107
- {earthengine_api-1.5.13rc0.dist-info → earthengine_api-1.7.4.dist-info}/entry_points.txt +0 -0
- {earthengine_api-1.5.13rc0.dist-info → earthengine_api-1.7.4.dist-info}/licenses/LICENSE +0 -0
- {earthengine_api-1.5.13rc0.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:
|
|
70
|
-
projectId:
|
|
71
|
-
modelName:
|
|
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:
|
|
74
|
-
region:
|
|
71
|
+
version: _arg_types.String | None = None,
|
|
72
|
+
region: _arg_types.String | None = None,
|
|
75
73
|
# pylint: disable=invalid-name
|
|
76
|
-
inputProperties:
|
|
77
|
-
inputTypeOverride:
|
|
78
|
-
inputShapes:
|
|
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:
|
|
78
|
+
proj: _arg_types.Projection | None = None,
|
|
81
79
|
# pylint: disable=invalid-name
|
|
82
|
-
fixInputProj:
|
|
83
|
-
inputTileSize:
|
|
84
|
-
inputOverlapSize:
|
|
85
|
-
outputTileSize:
|
|
86
|
-
outputBands:
|
|
87
|
-
outputProperties:
|
|
88
|
-
outputMultiplier:
|
|
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:
|
|
172
|
-
inputTypeOverride:
|
|
173
|
-
inputShapes:
|
|
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:
|
|
173
|
+
proj: _arg_types.Projection | None = None,
|
|
176
174
|
# pylint: disable=invalid-name
|
|
177
|
-
fixInputProj:
|
|
178
|
-
inputTileSize:
|
|
179
|
-
inputOverlapSize:
|
|
180
|
-
outputTileSize:
|
|
181
|
-
outputBands:
|
|
182
|
-
outputProperties:
|
|
183
|
-
outputMultiplier:
|
|
184
|
-
maxPayloadBytes:
|
|
185
|
-
payloadFormat:
|
|
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,7 +18,7 @@ import os
|
|
|
17
18
|
import shutil
|
|
18
19
|
import subprocess
|
|
19
20
|
import sys
|
|
20
|
-
from typing import Any
|
|
21
|
+
from typing import Any
|
|
21
22
|
import urllib.error
|
|
22
23
|
import urllib.parse
|
|
23
24
|
import urllib.request
|
|
@@ -87,7 +88,7 @@ def get_credentials_path() -> str:
|
|
|
87
88
|
return cred_path
|
|
88
89
|
|
|
89
90
|
|
|
90
|
-
def get_credentials_arguments() ->
|
|
91
|
+
def get_credentials_arguments() -> dict[str, Any]:
|
|
91
92
|
with open(get_credentials_path()) as creds:
|
|
92
93
|
stored = json.load(creds)
|
|
93
94
|
args = {}
|
|
@@ -100,13 +101,13 @@ def get_credentials_arguments() -> Dict[str, Any]:
|
|
|
100
101
|
return args
|
|
101
102
|
|
|
102
103
|
|
|
103
|
-
def is_sdk_credentials(credentials:
|
|
104
|
+
def is_sdk_credentials(credentials: Any | None) -> bool:
|
|
104
105
|
return is_sdk_project(project_number_from_credentials(credentials))
|
|
105
106
|
|
|
106
107
|
|
|
107
108
|
def project_number_from_credentials(
|
|
108
|
-
credentials:
|
|
109
|
-
) ->
|
|
109
|
+
credentials: Any | None,
|
|
110
|
+
) -> str | None:
|
|
110
111
|
client_id = credentials and getattr(credentials, 'client_id', None)
|
|
111
112
|
return _project_number_from_client_id(client_id)
|
|
112
113
|
|
|
@@ -115,7 +116,7 @@ def is_sdk_project(project: str) -> bool:
|
|
|
115
116
|
return project in SDK_PROJECTS
|
|
116
117
|
|
|
117
118
|
|
|
118
|
-
def get_appdefault_project() ->
|
|
119
|
+
def get_appdefault_project() -> str | None:
|
|
119
120
|
try:
|
|
120
121
|
adc_path = _cloud_sdk.get_application_default_credentials_path()
|
|
121
122
|
with open(adc_path) as adc_json:
|
|
@@ -133,7 +134,7 @@ def _valid_credentials_exist() -> bool:
|
|
|
133
134
|
return False
|
|
134
135
|
|
|
135
136
|
|
|
136
|
-
def is_valid_credentials(credentials:
|
|
137
|
+
def is_valid_credentials(credentials: Any | None) -> bool:
|
|
137
138
|
if credentials is None:
|
|
138
139
|
return False
|
|
139
140
|
try:
|
|
@@ -145,8 +146,8 @@ def is_valid_credentials(credentials: Optional[Any]) -> bool:
|
|
|
145
146
|
|
|
146
147
|
def get_authorization_url(
|
|
147
148
|
code_challenge: str,
|
|
148
|
-
scopes:
|
|
149
|
-
redirect_uri:
|
|
149
|
+
scopes: Sequence[str] | None = None,
|
|
150
|
+
redirect_uri: str | None = None,
|
|
150
151
|
) -> str:
|
|
151
152
|
"""Returns a URL to generate an auth code."""
|
|
152
153
|
|
|
@@ -163,9 +164,9 @@ def get_authorization_url(
|
|
|
163
164
|
def request_token(
|
|
164
165
|
auth_code: str,
|
|
165
166
|
code_verifier: str,
|
|
166
|
-
client_id:
|
|
167
|
-
client_secret:
|
|
168
|
-
redirect_uri:
|
|
167
|
+
client_id: str | None = None,
|
|
168
|
+
client_secret: str | None = None,
|
|
169
|
+
redirect_uri: str | None = None,
|
|
169
170
|
) -> str:
|
|
170
171
|
"""Uses authorization code to request tokens."""
|
|
171
172
|
|
|
@@ -184,14 +185,14 @@ def request_token(
|
|
|
184
185
|
urllib.parse.urlencode(request_args).encode()).read().decode()
|
|
185
186
|
except urllib.error.HTTPError as e:
|
|
186
187
|
# pylint:disable=broad-exception-raised,raise-missing-from
|
|
187
|
-
raise Exception('Problem requesting tokens. Please try again.
|
|
188
|
+
raise Exception('Problem requesting tokens. Please try again. %s %s' %
|
|
188
189
|
(e, e.read()))
|
|
189
190
|
# pylint:enable=broad-exception-raised,raise-missing-from
|
|
190
191
|
|
|
191
192
|
return json.loads(response)['refresh_token']
|
|
192
193
|
|
|
193
194
|
|
|
194
|
-
def write_private_json(json_path: str, info_dict:
|
|
195
|
+
def write_private_json(json_path: str, info_dict: dict[str, Any]) -> None:
|
|
195
196
|
"""Attempts to write the passed token to the given user directory."""
|
|
196
197
|
|
|
197
198
|
dirname = os.path.dirname(json_path)
|
|
@@ -200,7 +201,7 @@ def write_private_json(json_path: str, info_dict: Dict[str, Any]) -> None:
|
|
|
200
201
|
except OSError as e:
|
|
201
202
|
if e.errno != errno.EEXIST:
|
|
202
203
|
# pylint:disable=broad-exception-raised,raise-missing-from
|
|
203
|
-
raise Exception('Error creating directory
|
|
204
|
+
raise Exception(f'Error creating directory {dirname}: {e}')
|
|
204
205
|
# pylint:enable=broad-exception-raised,raise-missing-from
|
|
205
206
|
|
|
206
207
|
file_content = json.dumps(info_dict)
|
|
@@ -225,7 +226,7 @@ def _in_jupyter_shell() -> bool:
|
|
|
225
226
|
"""Tests if the code is being executed within Jupyter."""
|
|
226
227
|
try:
|
|
227
228
|
import ipykernel.zmqshell
|
|
228
|
-
return isinstance(IPython.get_ipython(),
|
|
229
|
+
return isinstance(IPython.get_ipython(), # pylint: disable=undefined-variable
|
|
229
230
|
ipykernel.zmqshell.ZMQInteractiveShell)
|
|
230
231
|
except ImportError:
|
|
231
232
|
return False
|
|
@@ -233,7 +234,7 @@ def _in_jupyter_shell() -> bool:
|
|
|
233
234
|
return False
|
|
234
235
|
|
|
235
236
|
|
|
236
|
-
def _project_number_from_client_id(client_id:
|
|
237
|
+
def _project_number_from_client_id(client_id: str | None) -> str | None:
|
|
237
238
|
"""Returns the project number associated with the given OAuth client ID."""
|
|
238
239
|
# Client IDs are of the form:
|
|
239
240
|
# PROJECTNUMBER-BASE32STUFF.apps.googleusercontent.com.
|
|
@@ -242,10 +243,10 @@ def _project_number_from_client_id(client_id: Optional[str]) -> Optional[str]:
|
|
|
242
243
|
|
|
243
244
|
|
|
244
245
|
def _obtain_and_write_token(
|
|
245
|
-
auth_code:
|
|
246
|
-
code_verifier:
|
|
247
|
-
scopes:
|
|
248
|
-
redirect_uri:
|
|
246
|
+
auth_code: str | None = None,
|
|
247
|
+
code_verifier: str | None = None,
|
|
248
|
+
scopes: Sequence[str] | None = None,
|
|
249
|
+
redirect_uri: str | None = None,
|
|
249
250
|
) -> None:
|
|
250
251
|
"""Obtains and writes credentials token based on an authorization code."""
|
|
251
252
|
fetch_data = {}
|
|
@@ -282,7 +283,7 @@ def _obtain_and_write_token(
|
|
|
282
283
|
|
|
283
284
|
|
|
284
285
|
def _display_auth_instructions_for_noninteractive(
|
|
285
|
-
auth_url: str, code_verifier:
|
|
286
|
+
auth_url: str, code_verifier: bytes | str
|
|
286
287
|
) -> None:
|
|
287
288
|
"""Displays instructions for authenticating without blocking for user input."""
|
|
288
289
|
# Python 3 `bytes` should be decoded to `str` if used as an argument of
|
|
@@ -292,38 +293,43 @@ def _display_auth_instructions_for_noninteractive(
|
|
|
292
293
|
else:
|
|
293
294
|
code_verifier_str = code_verifier
|
|
294
295
|
|
|
295
|
-
print(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
296
|
+
print(
|
|
297
|
+
'Paste the following address into a web browser:\n'
|
|
298
|
+
'\n'
|
|
299
|
+
' {}\n'
|
|
300
|
+
'\n'
|
|
301
|
+
'On the web page, please authorize access to your '
|
|
302
|
+
'Earth Engine account and copy the authentication code. '
|
|
303
|
+
'Next authenticate with the following command:\n'
|
|
304
|
+
'\n'
|
|
305
|
+
' earthengine authenticate --code-verifier={} '
|
|
306
|
+
'--authorization-code=PLACE_AUTH_CODE_HERE\n'.format(
|
|
307
|
+
auth_url, code_verifier_str
|
|
308
|
+
)
|
|
309
|
+
)
|
|
306
310
|
|
|
307
311
|
|
|
308
312
|
def _display_auth_instructions_with_print(
|
|
309
|
-
auth_url: str, coda:
|
|
313
|
+
auth_url: str, coda: str | None = None
|
|
310
314
|
) -> None:
|
|
311
315
|
"""Displays instructions for authenticating using a print statement."""
|
|
312
|
-
print(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
print(
|
|
317
|
+
'To authorize access needed by Earth Engine, open the following '
|
|
318
|
+
'URL in a web browser and follow the instructions. If the web '
|
|
319
|
+
'browser does not start automatically, please manually browse the '
|
|
320
|
+
'URL below.\n'
|
|
321
|
+
'\n'
|
|
322
|
+
' {}\n'
|
|
323
|
+
'\n{}'.format(auth_url, coda or PASTE_CODA)
|
|
324
|
+
)
|
|
319
325
|
|
|
320
326
|
|
|
321
327
|
def _display_auth_instructions_with_html(
|
|
322
|
-
auth_url: str, coda:
|
|
328
|
+
auth_url: str, coda: str | None = None
|
|
323
329
|
) -> None:
|
|
324
330
|
"""Displays instructions for authenticating using HTML code."""
|
|
325
331
|
try:
|
|
326
|
-
IPython.display.display(IPython.display.HTML(
|
|
332
|
+
IPython.display.display(IPython.display.HTML( # pylint: disable=undefined-variable
|
|
327
333
|
"""<p>To authorize access needed by Earth Engine, open the following
|
|
328
334
|
URL in a web browser and follow the instructions:</p>
|
|
329
335
|
<p><a href={0}>{0}</a></p>
|
|
@@ -339,14 +345,14 @@ def _base64param(byte_string: bytes) -> bytes:
|
|
|
339
345
|
return base64.urlsafe_b64encode(byte_string).rstrip(b'=')
|
|
340
346
|
|
|
341
347
|
|
|
342
|
-
def _nonce_table(*nonce_keys: str) ->
|
|
348
|
+
def _nonce_table(*nonce_keys: str) -> dict[str, str]:
|
|
343
349
|
"""Makes random nonces, and adds PKCE challenges for each _verifier nonce."""
|
|
344
350
|
table = {}
|
|
345
351
|
for key in nonce_keys:
|
|
346
352
|
table[key] = _base64param(os.urandom(32))
|
|
347
353
|
if key.endswith('_verifier'):
|
|
348
354
|
# Generate a challenge that the server will use to ensure that requests
|
|
349
|
-
# only work with our verifiers.
|
|
355
|
+
# only work with our verifiers. https://tools.ietf.org/html/rfc7636
|
|
350
356
|
pkce_challenge = _base64param(hashlib.sha256(table[key]).digest())
|
|
351
357
|
table[key.replace('_verifier', '_challenge')] = pkce_challenge
|
|
352
358
|
return {k: v.decode() for k, v in table.items()}
|
|
@@ -376,8 +382,8 @@ def _no_gcloud() -> bool:
|
|
|
376
382
|
|
|
377
383
|
|
|
378
384
|
def _load_gcloud_credentials(
|
|
379
|
-
scopes:
|
|
380
|
-
quiet:
|
|
385
|
+
scopes: Sequence[str] | None = None,
|
|
386
|
+
quiet: bool | None = None,
|
|
381
387
|
run_gcloud_legacy: bool = False,
|
|
382
388
|
) -> None:
|
|
383
389
|
"""Initializes credentials by running gcloud flows."""
|
|
@@ -429,7 +435,7 @@ def _start_server(port: int):
|
|
|
429
435
|
class Handler(http.server.BaseHTTPRequestHandler):
|
|
430
436
|
"""Handles the OAuth callback and reports a success page."""
|
|
431
437
|
|
|
432
|
-
code:
|
|
438
|
+
code: str | None = None
|
|
433
439
|
|
|
434
440
|
def do_GET(self) -> None: # pylint: disable=invalid-name
|
|
435
441
|
Handler.code = urllib.parse.parse_qs(
|
|
@@ -439,7 +445,7 @@ def _start_server(port: int):
|
|
|
439
445
|
self.end_headers()
|
|
440
446
|
self.wfile.write(
|
|
441
447
|
b'\n\nGoogle Earth Engine authorization successful!\n\n\n'
|
|
442
|
-
b'Credentials have been retrieved.
|
|
448
|
+
b'Credentials have been retrieved. Please close this window.\n\n'
|
|
443
449
|
b' \xf0\x9f\x8c\x8d \xe2\x9a\x99\xef\xb8\x8f \xf0\x9f\x8c\x8f'
|
|
444
450
|
b' \xe2\x9a\x99\xef\xb8\x8f \xf0\x9f\x8c\x8e ') # Earth emoji
|
|
445
451
|
|
|
@@ -454,7 +460,7 @@ def _start_server(port: int):
|
|
|
454
460
|
self.server = http.server.HTTPServer(('localhost', port), Handler)
|
|
455
461
|
self.url = 'http://localhost:%s' % self.server.server_address[1]
|
|
456
462
|
|
|
457
|
-
def fetch_code(self) ->
|
|
463
|
+
def fetch_code(self) -> str | None:
|
|
458
464
|
self.server.handle_request() # Blocks until a single request arrives.
|
|
459
465
|
self.server.server_close()
|
|
460
466
|
return Handler.code
|
|
@@ -463,24 +469,24 @@ def _start_server(port: int):
|
|
|
463
469
|
|
|
464
470
|
|
|
465
471
|
def authenticate(
|
|
466
|
-
cli_authorization_code:
|
|
467
|
-
quiet:
|
|
468
|
-
cli_code_verifier:
|
|
469
|
-
auth_mode:
|
|
470
|
-
scopes:
|
|
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,
|
|
471
477
|
force: bool = False,
|
|
472
|
-
) ->
|
|
478
|
+
) -> bool | None:
|
|
473
479
|
"""Prompts the user to authorize access to Earth Engine via OAuth2.
|
|
474
480
|
|
|
475
481
|
Args:
|
|
476
|
-
cli_authorization_code: An optional authorization code.
|
|
482
|
+
cli_authorization_code: An optional authorization code. Supports CLI mode,
|
|
477
483
|
where the code is passed as an argument to `earthengine authenticate`.
|
|
478
484
|
quiet: If true, do not require interactive prompts and force --no-browser
|
|
479
485
|
mode for gcloud-legacy. If false, never supply --no-browser. Default is
|
|
480
486
|
None, which autodetects the --no-browser setting.
|
|
481
|
-
cli_code_verifier: PKCE verifier to prevent auth code stealing.
|
|
487
|
+
cli_code_verifier: PKCE verifier to prevent auth code stealing. Must be
|
|
482
488
|
provided if cli_authorization_code is given.
|
|
483
|
-
auth_mode: The authorization mode.
|
|
489
|
+
auth_mode: The authorization mode. One of:
|
|
484
490
|
"colab" - use the Colab authentication flow.
|
|
485
491
|
"notebook" - send user to notebook authenticator page. Intended for
|
|
486
492
|
web users who do not run code locally. Credentials expire in 7 days.
|
|
@@ -508,6 +514,13 @@ def authenticate(
|
|
|
508
514
|
Exception: on invalid arguments.
|
|
509
515
|
"""
|
|
510
516
|
|
|
517
|
+
if auth_mode == 'colab' and scopes is not None and set(scopes) != set(SCOPES):
|
|
518
|
+
raise ee_exception.EEException(
|
|
519
|
+
'Scopes cannot be customized when auth_mode is "colab". Please see'
|
|
520
|
+
' https://developers.google.com/earth-engine/guides/auth#quick_reference_guide_and_table'
|
|
521
|
+
' for more information.'
|
|
522
|
+
)
|
|
523
|
+
|
|
511
524
|
if cli_authorization_code:
|
|
512
525
|
_obtain_and_write_token(cli_authorization_code, cli_code_verifier, scopes)
|
|
513
526
|
return
|
|
@@ -551,11 +564,11 @@ class Flow:
|
|
|
551
564
|
"""Holds state for auth flows."""
|
|
552
565
|
code_verifier: str
|
|
553
566
|
scopes: Sequence[str]
|
|
554
|
-
server:
|
|
567
|
+
server: Any | None
|
|
555
568
|
auth_url: str
|
|
556
569
|
|
|
557
570
|
def __init__(
|
|
558
|
-
self, auth_mode: str = 'notebook', scopes:
|
|
571
|
+
self, auth_mode: str = 'notebook', scopes: Sequence[str] | None = None
|
|
559
572
|
):
|
|
560
573
|
"""Initializes auth URL and PKCE verifier, for use in save_code().
|
|
561
574
|
|
|
@@ -588,7 +601,7 @@ class Flow:
|
|
|
588
601
|
# pylint:disable-next=broad-exception-raised
|
|
589
602
|
raise ee_exception.EEException('Unknown auth_mode "%s"' % auth_mode)
|
|
590
603
|
|
|
591
|
-
def save_code(self, code:
|
|
604
|
+
def save_code(self, code: str | None = None) -> None:
|
|
592
605
|
"""Fetches auth code if not given, and saves the generated credentials."""
|
|
593
606
|
redirect_uri = None
|
|
594
607
|
if self.server and not code:
|
|
@@ -596,7 +609,7 @@ class Flow:
|
|
|
596
609
|
code = self.server.fetch_code() # Waits for oauth callback
|
|
597
610
|
_obtain_and_write_token(code, self.code_verifier, self.scopes, redirect_uri)
|
|
598
611
|
|
|
599
|
-
def display_instructions(self, quiet:
|
|
612
|
+
def display_instructions(self, quiet: bool | None = None) -> bool:
|
|
600
613
|
"""Prints to stdout, and returns True if a browser should be opened."""
|
|
601
614
|
|
|
602
615
|
if quiet:
|
ee/pixeltype.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""A wrapper for PixelTypes."""
|
|
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 apifunction
|
|
@@ -52,12 +52,12 @@ class PixelType(computedobject.ComputedObject):
|
|
|
52
52
|
|
|
53
53
|
def __init__(
|
|
54
54
|
self,
|
|
55
|
-
precision:
|
|
55
|
+
precision: _arg_types.String,
|
|
56
56
|
# pylint: disable=invalid-name
|
|
57
|
-
minValue:
|
|
58
|
-
maxValue:
|
|
57
|
+
minValue: _arg_types.Number | None = None,
|
|
58
|
+
maxValue: _arg_types.Number | None = None,
|
|
59
59
|
# pylint: enable=invalid-name
|
|
60
|
-
dimensions:
|
|
60
|
+
dimensions: _arg_types.Integer | None = None,
|
|
61
61
|
):
|
|
62
62
|
"""Creates a PixelType wrapper.
|
|
63
63
|
|
|
@@ -72,7 +72,7 @@ class PixelType(computedobject.ComputedObject):
|
|
|
72
72
|
"""
|
|
73
73
|
self.initialize()
|
|
74
74
|
|
|
75
|
-
args:
|
|
75
|
+
args: dict[str, Any] = {'precision': precision}
|
|
76
76
|
if minValue is not None:
|
|
77
77
|
args['minValue'] = minValue
|
|
78
78
|
if maxValue is not None:
|
ee/projection.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""A wrapper for Projections."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from typing import Any, Union
|
|
5
6
|
|
|
6
7
|
from ee import _arg_types
|
|
7
8
|
from ee import apifunction
|
|
@@ -45,9 +46,9 @@ class Projection(computedobject.ComputedObject):
|
|
|
45
46
|
def __init__(
|
|
46
47
|
self,
|
|
47
48
|
crs: _arg_types.String,
|
|
48
|
-
transform:
|
|
49
|
+
transform: _NumberSequenceType | None = None,
|
|
49
50
|
# pylint: disable-next=invalid-name
|
|
50
|
-
transformWkt:
|
|
51
|
+
transformWkt: _arg_types.String | None = None,
|
|
51
52
|
):
|
|
52
53
|
"""Creates a Projection wrapper.
|
|
53
54
|
|
|
@@ -80,7 +81,7 @@ class Projection(computedobject.ComputedObject):
|
|
|
80
81
|
super().__init__(crs.func, crs.args, crs.varName)
|
|
81
82
|
return
|
|
82
83
|
|
|
83
|
-
args:
|
|
84
|
+
args: dict[str, Any] = {'crs': crs}
|
|
84
85
|
if transform is not None:
|
|
85
86
|
args['transform'] = transform
|
|
86
87
|
if transformWkt is not None:
|