earthengine-api 1.6.10__py3-none-any.whl → 1.6.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of earthengine-api might be problematic. Click here for more details.
- {earthengine_api-1.6.10.dist-info → earthengine_api-1.6.11.dist-info}/METADATA +1 -1
- {earthengine_api-1.6.10.dist-info → earthengine_api-1.6.11.dist-info}/RECORD +19 -19
- ee/__init__.py +1 -1
- ee/_cloud_api_utils.py +2 -10
- ee/_helpers.py +12 -9
- ee/apifunction.py +1 -1
- ee/batch.py +2 -3
- ee/blob.py +8 -10
- ee/data.py +77 -75
- ee/tests/_cloud_api_utils_test.py +4 -5
- ee/tests/_helpers_test.py +53 -0
- ee/tests/batch_test.py +6 -3
- ee/tests/blob_test.py +2 -2
- ee/tests/data_test.py +128 -0
- ee/tests/ee_test.py +1 -1
- {earthengine_api-1.6.10.dist-info → earthengine_api-1.6.11.dist-info}/WHEEL +0 -0
- {earthengine_api-1.6.10.dist-info → earthengine_api-1.6.11.dist-info}/entry_points.txt +0 -0
- {earthengine_api-1.6.10.dist-info → earthengine_api-1.6.11.dist-info}/licenses/LICENSE +0 -0
- {earthengine_api-1.6.10.dist-info → earthengine_api-1.6.11.dist-info}/top_level.txt +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
earthengine_api-1.6.
|
|
2
|
-
ee/__init__.py,sha256=
|
|
1
|
+
earthengine_api-1.6.11.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
2
|
+
ee/__init__.py,sha256=Ykj2QoWR5H-fXLBPEx5fC4-hzETVrDR0zwtTN8Ofb4o,16808
|
|
3
3
|
ee/_arg_types.py,sha256=nrJrnPFnAS8fzMxAGmG3TbUOi_yFVrnSGW5IP8ATzDQ,2662
|
|
4
|
-
ee/_cloud_api_utils.py,sha256=
|
|
5
|
-
ee/_helpers.py,sha256=
|
|
4
|
+
ee/_cloud_api_utils.py,sha256=sG1WtO9zy_xNSSGWiG1Y9ltrvkl5dExqIoWMw5O6llE,32192
|
|
5
|
+
ee/_helpers.py,sha256=71xYDbCO_1usY3SnedoA9zi7j6dnPBijru1eUh4o25g,4859
|
|
6
6
|
ee/_utils.py,sha256=SAXQ_ZefZUaOtyV6Lp3pdYqEFqblMEA6Bvxz0ltLjzA,1329
|
|
7
|
-
ee/apifunction.py,sha256=
|
|
7
|
+
ee/apifunction.py,sha256=5oatxvJH1KAFYz5Ae8T58wi40fK33-8y9ajEQz0wpW4,8733
|
|
8
8
|
ee/apitestcase.py,sha256=K3zHLYFCJ_QhwdhoImIeD-DJjSgd_nAGQpftKYvjF-Q,14959
|
|
9
|
-
ee/batch.py,sha256=
|
|
10
|
-
ee/blob.py,sha256=
|
|
9
|
+
ee/batch.py,sha256=opkPNZ8V1tGQiMnVKVtSn1XA19AJhxrlTW5u77o8EmY,82401
|
|
10
|
+
ee/blob.py,sha256=cnnqmrHl998U2zEmfKcxQglaGk14Ip6pjObk_Ody6Uk,3221
|
|
11
11
|
ee/classifier.py,sha256=3STLrLT6Ddwzjs2324E02wRWM8VEpeifgOO81geTHJQ,23410
|
|
12
12
|
ee/clusterer.py,sha256=986D68b2eJ4xiiOiIOTNZ1psF8Ro-MFNQFKed058FS4,12256
|
|
13
13
|
ee/collection.py,sha256=20g_Y_UnkhABGFOSybyE_IGmKvod5kR9xm5eKLjzNcE,32277
|
|
14
14
|
ee/computedobject.py,sha256=o5F4y00PK-fye2pduA5QmMd6XIERA1lhC3yLs88zRpY,9082
|
|
15
15
|
ee/confusionmatrix.py,sha256=e6vz-FcT6acWxk5pDEK0vLIN1pUjYMh5Gyn1QSGJT3I,4233
|
|
16
16
|
ee/customfunction.py,sha256=k57sl03_vhOuEwAmgFpg0z3Ze9J3gy_W6n4u3uMaryA,7384
|
|
17
|
-
ee/data.py,sha256
|
|
17
|
+
ee/data.py,sha256=-vgLRmxLmCunjxbK7D0riSNYreD5jqPjv3WLUbuZmGs,88549
|
|
18
18
|
ee/daterange.py,sha256=nrRYkR2M2aVU0ZJyG7yiZStFt-W2TvYVuazoZK_WZqM,4948
|
|
19
19
|
ee/deprecation.py,sha256=dkTRDZcdT90_j41z_mMlhtX8u5eD5N2BuKL90Q0oWYc,6085
|
|
20
20
|
ee/deserializer.py,sha256=Xz9Dis85JgZeLvpF-4yw3ZRv39rjvCTBYHjio8DE1kM,8424
|
|
@@ -54,20 +54,20 @@ ee/cli/commands.py,sha256=P2KPuSx0wKcp1lfo7hwkTqwnjxORnxTKqJ0RwrX3O8c,70534
|
|
|
54
54
|
ee/cli/eecli.py,sha256=iws34w24UJI6H7Wl9WsEUwy-uN57Pw-bgHtr2f92olY,3044
|
|
55
55
|
ee/cli/eecli_wrapper.py,sha256=Z7R3IJcht2uG1h57oY7BSrkPiwQzNmmYlyCSX1_7L7c,1089
|
|
56
56
|
ee/cli/utils.py,sha256=YWrgN_5k8GRWndST20KkGljn4Ee8F8935ID91qiLRtY,13796
|
|
57
|
-
ee/tests/_cloud_api_utils_test.py,sha256=
|
|
58
|
-
ee/tests/_helpers_test.py,sha256=
|
|
57
|
+
ee/tests/_cloud_api_utils_test.py,sha256=YpTG4wBTuSIyb7XolAre41VuQCiH9di_7olCE_71S1U,18754
|
|
58
|
+
ee/tests/_helpers_test.py,sha256=p_GJaXr9xcQbBFkMp7f9H_h2OBqI1YPH1pRHGNE8cA4,3964
|
|
59
59
|
ee/tests/_utils_test.py,sha256=bOarVj3U-VFo9Prog8WQN_hAOMwJOiWKJxevUbdFPBQ,2753
|
|
60
60
|
ee/tests/algorithms.json,sha256=Vx1Kx_MhHv0z0B3WTeVAvchM8xVd3zYE7L-qT3gDGzA,729368
|
|
61
61
|
ee/tests/apifunction_test.py,sha256=62El-6jcgQmD7qt9eEDdM7IeIQmpV8M5xQ439g-zfN4,3767
|
|
62
|
-
ee/tests/batch_test.py,sha256=
|
|
63
|
-
ee/tests/blob_test.py,sha256=
|
|
62
|
+
ee/tests/batch_test.py,sha256=Vo-0_LoH2Ccutta6SAfgbk4VcptfeW2DA5yXJPWJj_Y,62399
|
|
63
|
+
ee/tests/blob_test.py,sha256=uCrM-ubRfAmNgHwhmUhWn7MiXqbNQutybcXIKdVsD_Q,3587
|
|
64
64
|
ee/tests/classifier_test.py,sha256=K6-wNZ2uh9oPYo7BV0vtfU73SBFpeNcFRMRmvEFc6Pg,19087
|
|
65
65
|
ee/tests/cloud_api_discovery_document.json,sha256=SnOeL8One57YdeHa7XxGZM-ptDPCeDSymBc7-Bo_hkA,41154
|
|
66
66
|
ee/tests/clusterer_test.py,sha256=B4m06wAtBeqvnIhRD2lnNy1UHDB_caleK_CqcrAU8dk,11620
|
|
67
67
|
ee/tests/collection_test.py,sha256=dnZwFADWQ8oShJHRTcYSzuP-waAxetTdM_CtVckWbMM,7563
|
|
68
68
|
ee/tests/computedobject_test.py,sha256=B27rDq9Urpvy0WqpdbKRYbt6AcT1i93HX-es7hrhWVY,4840
|
|
69
69
|
ee/tests/confusionmatrix_test.py,sha256=46JJh1-91AiYISXWZ6-2lvY5_Njvc8ompO9kmwqlFdg,7437
|
|
70
|
-
ee/tests/data_test.py,sha256=
|
|
70
|
+
ee/tests/data_test.py,sha256=9zDGICUCeJFi4Q6lX2mB0Qca9C-eUMEn4vzpTZI5Imk,40222
|
|
71
71
|
ee/tests/daterange_test.py,sha256=a5fpg2lko3kCJzxQPCoAc_vjXkKy2zYcXbeSZKAFovI,8583
|
|
72
72
|
ee/tests/deprecation_test.py,sha256=_sCs59l6c-ijeyt5yPO-IRJsh8GGPp7ArSg3Y12u4mQ,8352
|
|
73
73
|
ee/tests/deserializer_test.py,sha256=-tbrL0cjrXdSLF7M3wl-QQuj6TjXJdkjp7RZvVErUy4,3427
|
|
@@ -77,7 +77,7 @@ ee/tests/ee_date_test.py,sha256=8rLUXfjyiW3LiBOCSneA7ZGgmoFgN5oZr58x5THtKGY,1110
|
|
|
77
77
|
ee/tests/ee_list_test.py,sha256=yd2EWZGdg7pLJhsHSR5AbK58ZhT31GY-n2o1dDT3p9A,21797
|
|
78
78
|
ee/tests/ee_number_test.py,sha256=3MxX8Awie_L3FfwyltrL2UXNdqTyvtYJB9qIi73wlPM,33442
|
|
79
79
|
ee/tests/ee_string_test.py,sha256=9QuseILwZtbcczCyNyJ751kva96_9gPKXLRdgkgWMPs,9389
|
|
80
|
-
ee/tests/ee_test.py,sha256=
|
|
80
|
+
ee/tests/ee_test.py,sha256=_HELrvUb7Wpmeji4Jd_rlZfCcXWQ4mPxRTG7d88u0zI,17082
|
|
81
81
|
ee/tests/ee_types_test.py,sha256=oRnqplaTWg47zuYfAYTTVwembCnw8XT20HPNMdAvgNE,921
|
|
82
82
|
ee/tests/element_test.py,sha256=Kqu_Z65FQcYHX4LebKm3LD0mWkRTRZccs-qAGz3bLsE,1964
|
|
83
83
|
ee/tests/errormargin_test.py,sha256=YEBzvBFsD756nicZBcjnPFAXy06jZNKiSSAa2hAzN-M,5061
|
|
@@ -100,8 +100,8 @@ ee/tests/reducer_test.py,sha256=NYJTmX6AmBZyXGjOkgUh4t3tB6E8_vGlPYQIxJQbV9Q,3151
|
|
|
100
100
|
ee/tests/serializer_test.py,sha256=xZQBQMDK8dlGYLS-6s1JHhR1L5FKoaIwEkxdKlcpQTE,8802
|
|
101
101
|
ee/tests/table_converter_test.py,sha256=2F7DyEj-iHVbt9-W1iwAHDl-K1GA_2QHalTXzac2ot8,3373
|
|
102
102
|
ee/tests/terrain_test.py,sha256=8TmvGconOR-GkGrll4joXhpU9zi0b_8GFxvX_JlcCos,4328
|
|
103
|
-
earthengine_api-1.6.
|
|
104
|
-
earthengine_api-1.6.
|
|
105
|
-
earthengine_api-1.6.
|
|
106
|
-
earthengine_api-1.6.
|
|
107
|
-
earthengine_api-1.6.
|
|
103
|
+
earthengine_api-1.6.11.dist-info/METADATA,sha256=7x-iancpCSqSTC9-76xKwI7OVX8r6jej7mlsYogq9_Q,2194
|
|
104
|
+
earthengine_api-1.6.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
105
|
+
earthengine_api-1.6.11.dist-info/entry_points.txt,sha256=-Ax4SCU-S474r8OD2LIxata6PRmkZoDrppQ4fP_exNc,50
|
|
106
|
+
earthengine_api-1.6.11.dist-info/top_level.txt,sha256=go5zOwCgm5lIS3yTR-Vsxp1gNI4qdS-MP5eY-7zMxVY,3
|
|
107
|
+
earthengine_api-1.6.11.dist-info/RECORD,,
|
ee/__init__.py
CHANGED
ee/_cloud_api_utils.py
CHANGED
|
@@ -35,9 +35,6 @@ ASSET_NAME_PATTERN = (r'^projects/((?:\w+(?:[\w\-]+\.[\w\-]+)*?\.\w+\:)?'
|
|
|
35
35
|
ASSET_ROOT_PATTERN = (r'^projects/((?:\w+(?:[\w\-]+\.[\w\-]+)*?\.\w+\:)?'
|
|
36
36
|
r'[a-z][a-z0-9\-]{4,28}[a-z0-9])/assets/?$')
|
|
37
37
|
|
|
38
|
-
# The default user project to use when making Cloud API calls.
|
|
39
|
-
_cloud_api_user_project: Optional[str] = None
|
|
40
|
-
|
|
41
38
|
|
|
42
39
|
class _Http:
|
|
43
40
|
"""A httplib2.Http-like object based on requests."""
|
|
@@ -136,11 +133,6 @@ def _wrap_request(
|
|
|
136
133
|
return builder
|
|
137
134
|
|
|
138
135
|
|
|
139
|
-
def set_cloud_api_user_project(cloud_api_user_project: str) -> None:
|
|
140
|
-
global _cloud_api_user_project
|
|
141
|
-
_cloud_api_user_project = cloud_api_user_project
|
|
142
|
-
|
|
143
|
-
|
|
144
136
|
def build_cloud_resource(
|
|
145
137
|
api_base_url: str,
|
|
146
138
|
session: requests.Session,
|
|
@@ -560,9 +552,9 @@ def convert_operation_name_to_task_id(operation_name: str) -> str:
|
|
|
560
552
|
return found.group(1) if found else operation_name
|
|
561
553
|
|
|
562
554
|
|
|
563
|
-
def convert_task_id_to_operation_name(task_id: str) -> str:
|
|
555
|
+
def convert_task_id_to_operation_name(project: str, task_id: str) -> str:
|
|
564
556
|
"""Converts a task ID to an Operation name."""
|
|
565
|
-
return f'projects/{
|
|
557
|
+
return f'projects/{project}/operations/{task_id}'
|
|
566
558
|
|
|
567
559
|
|
|
568
560
|
def convert_params_to_image_manifest(params: dict[str, Any]) -> dict[str, Any]:
|
ee/_helpers.py
CHANGED
|
@@ -22,13 +22,14 @@ from ee import data
|
|
|
22
22
|
from ee import ee_exception
|
|
23
23
|
from ee import oauth
|
|
24
24
|
|
|
25
|
-
|
|
26
25
|
# Number of times to retry fetching profile data.
|
|
27
26
|
_PROFILE_RETRIES = 5
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
def ServiceAccountCredentials(
|
|
31
|
-
email:
|
|
30
|
+
email: Optional[str] = None,
|
|
31
|
+
key_file: Optional[str] = None,
|
|
32
|
+
key_data: Optional[str] = None,
|
|
32
33
|
) -> service_account.Credentials:
|
|
33
34
|
"""Configure OAuth2 credentials for a Google Service Account.
|
|
34
35
|
|
|
@@ -42,6 +43,10 @@ def ServiceAccountCredentials(
|
|
|
42
43
|
Returns:
|
|
43
44
|
An OAuth2 credentials object.
|
|
44
45
|
"""
|
|
46
|
+
if not email and not key_file and not key_data:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
'At least one of email, key_file, or key_data must be specified.'
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
# Assume anything that doesn't end in '.pem' is a JSON key.
|
|
47
52
|
if key_file and not key_file.endswith('.pem'):
|
|
@@ -119,14 +124,13 @@ def profilePrinting(destination: TextIO = sys.stderr) -> Iterator[None]:
|
|
|
119
124
|
The profile will be printed when the context ends, whether or not any error
|
|
120
125
|
occurred within the context.
|
|
121
126
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
Example:
|
|
128
|
+
with ee.profilePrinting():
|
|
129
|
+
print(ee.Number(1).add(1).getInfo())
|
|
125
130
|
|
|
126
131
|
Args:
|
|
127
132
|
destination: A file-like object to which the profile text is written.
|
|
128
133
|
Defaults to sys.stderr.
|
|
129
|
-
|
|
130
134
|
"""
|
|
131
135
|
# Profile.getProfiles is `hidden`, so call it explicitly.
|
|
132
136
|
get_profiles = apifunction.ApiFunction.lookup('Profile.getProfiles').call
|
|
@@ -136,12 +140,11 @@ def profilePrinting(destination: TextIO = sys.stderr) -> Iterator[None]:
|
|
|
136
140
|
yield
|
|
137
141
|
finally:
|
|
138
142
|
# Make several attempts in case of transient errors.
|
|
139
|
-
|
|
140
|
-
for i in range(_PROFILE_RETRIES):
|
|
143
|
+
for attempt in range(_PROFILE_RETRIES):
|
|
141
144
|
try:
|
|
142
145
|
profile_text = get_profiles(ids=profile_ids).getInfo()
|
|
143
146
|
destination.write(profile_text)
|
|
144
147
|
break
|
|
145
148
|
except ee_exception.EEException as exception:
|
|
146
|
-
if
|
|
149
|
+
if attempt == _PROFILE_RETRIES - 1:
|
|
147
150
|
raise exception
|
ee/apifunction.py
CHANGED
|
@@ -60,7 +60,7 @@ class ApiFunction(function.Function):
|
|
|
60
60
|
return (isinstance(other, ApiFunction) and
|
|
61
61
|
self.getSignature() == other.getSignature())
|
|
62
62
|
|
|
63
|
-
#
|
|
63
|
+
# __hash__ is needed because __eq__ is defined.
|
|
64
64
|
# See https://docs.python.org/3/reference/datamodel.html#object.__hash__
|
|
65
65
|
def __hash__(self) -> int:
|
|
66
66
|
return hash(computedobject.ComputedObject.freeze(self.getSignature()))
|
ee/batch.py
CHANGED
|
@@ -112,7 +112,7 @@ class Task:
|
|
|
112
112
|
- description: The name of the task, a freeform string.
|
|
113
113
|
- sourceUrl: An optional URL for the script that generated the task.
|
|
114
114
|
Specific task types have other custom config fields.
|
|
115
|
-
name: The name of the operation.
|
|
115
|
+
name: The name of the operation.
|
|
116
116
|
"""
|
|
117
117
|
self.id = self._request_id = task_id
|
|
118
118
|
self.config = config and config.copy()
|
|
@@ -123,10 +123,9 @@ class Task:
|
|
|
123
123
|
|
|
124
124
|
@property
|
|
125
125
|
def operation_name(self) -> str | None:
|
|
126
|
+
"""The server-assigned name for this task."""
|
|
126
127
|
if self.name:
|
|
127
128
|
return self.name
|
|
128
|
-
if self.id:
|
|
129
|
-
return _cloud_api_utils.convert_task_id_to_operation_name(self.id)
|
|
130
129
|
return None
|
|
131
130
|
|
|
132
131
|
def start(self) -> None:
|
ee/blob.py
CHANGED
|
@@ -46,24 +46,22 @@ class Blob(computedobject.ComputedObject):
|
|
|
46
46
|
"""
|
|
47
47
|
self.initialize()
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
func = apifunction.ApiFunction(self.name())
|
|
51
|
-
|
|
52
|
-
if isinstance(url, str):
|
|
53
|
-
if not url.startswith('gs://'):
|
|
54
|
-
raise ValueError(f'{self.name()} url must start with "gs://": "{url}"')
|
|
55
|
-
|
|
56
|
-
elif isinstance(url, computedobject.ComputedObject):
|
|
49
|
+
if isinstance(url, computedobject.ComputedObject):
|
|
57
50
|
if self.is_func_returning_same(url):
|
|
58
51
|
# If it is a call that is already returning a Blob, just cast.
|
|
59
52
|
super().__init__(url.func, url.args, url.varName)
|
|
60
53
|
return
|
|
61
|
-
|
|
54
|
+
elif isinstance(url, str):
|
|
55
|
+
if not url.startswith('gs://'):
|
|
56
|
+
raise ValueError(f'{self.name()} url must start with "gs://": "{url}"')
|
|
62
57
|
else:
|
|
63
58
|
raise ValueError(
|
|
64
|
-
f'{self.name()} url must be a string
|
|
59
|
+
f'{self.name()} url must be a string or ComputedObject: '
|
|
60
|
+
f'{type(url)} -> "{url}"'
|
|
65
61
|
)
|
|
66
62
|
|
|
63
|
+
func = apifunction.ApiFunction(self.name())
|
|
64
|
+
args: dict[str, Any] = {'url': url}
|
|
67
65
|
super().__init__(func, func.promoteArgs(args))
|
|
68
66
|
|
|
69
67
|
@classmethod
|
ee/data.py
CHANGED
|
@@ -35,6 +35,64 @@ from ee import table_converter
|
|
|
35
35
|
|
|
36
36
|
from ee import __version__
|
|
37
37
|
|
|
38
|
+
# The HTTP header through which profile results are returned.
|
|
39
|
+
# Lowercase because that's how httplib2 does things.
|
|
40
|
+
_PROFILE_RESPONSE_HEADER_LOWERCASE = 'x-earth-engine-computation-profile'
|
|
41
|
+
|
|
42
|
+
# The HTTP header through which profiling is requested when using the Cloud API.
|
|
43
|
+
_PROFILE_REQUEST_HEADER = 'X-Earth-Engine-Computation-Profiling'
|
|
44
|
+
|
|
45
|
+
# The HTTP header through which a user project override is provided.
|
|
46
|
+
_USER_PROJECT_OVERRIDE_HEADER = 'X-Goog-User-Project'
|
|
47
|
+
|
|
48
|
+
# The HTTP header used to indicate the version of the client library used.
|
|
49
|
+
_API_CLIENT_VERSION_HEADER = 'X-Goog-Api-Client'
|
|
50
|
+
|
|
51
|
+
# The HTTP header used to indicate the user agent.
|
|
52
|
+
_USER_AGENT_HEADER = 'user-agent'
|
|
53
|
+
|
|
54
|
+
# Optional HTTP header returned to display initialization-time messages.
|
|
55
|
+
_INIT_MESSAGE_HEADER = 'x-earth-engine-init-message' # lowercase for httplib2
|
|
56
|
+
|
|
57
|
+
# Maximum time to wait before retrying a rate-limited request (in milliseconds).
|
|
58
|
+
MAX_RETRY_WAIT = 120000
|
|
59
|
+
|
|
60
|
+
# Base time (in ms) to wait when performing exponential backoff in request
|
|
61
|
+
# retries.
|
|
62
|
+
BASE_RETRY_WAIT = 1000
|
|
63
|
+
|
|
64
|
+
# The default base URL for API calls.
|
|
65
|
+
DEFAULT_API_BASE_URL = 'https://earthengine.googleapis.com/api'
|
|
66
|
+
HIGH_VOLUME_API_BASE_URL = 'https://earthengine-highvolume.googleapis.com'
|
|
67
|
+
|
|
68
|
+
# The default base URL for media/tile calls.
|
|
69
|
+
DEFAULT_TILE_BASE_URL = 'https://earthengine.googleapis.com'
|
|
70
|
+
|
|
71
|
+
# The default base URL for Cloud API calls.
|
|
72
|
+
DEFAULT_CLOUD_API_BASE_URL = 'https://earthengine.googleapis.com'
|
|
73
|
+
|
|
74
|
+
# The default project to use for Cloud API calls.
|
|
75
|
+
DEFAULT_CLOUD_API_USER_PROJECT = 'earthengine-legacy'
|
|
76
|
+
|
|
77
|
+
# Asset types recognized by create_assets().
|
|
78
|
+
ASSET_TYPE_FOLDER = 'Folder'
|
|
79
|
+
ASSET_TYPE_IMAGE_COLL = 'ImageCollection'
|
|
80
|
+
# Cloud API versions of the asset types.
|
|
81
|
+
ASSET_TYPE_FOLDER_CLOUD = 'FOLDER'
|
|
82
|
+
ASSET_TYPE_IMAGE_COLL_CLOUD = 'IMAGE_COLLECTION'
|
|
83
|
+
# Max length of the above type names
|
|
84
|
+
MAX_TYPE_LENGTH = len(ASSET_TYPE_IMAGE_COLL_CLOUD)
|
|
85
|
+
|
|
86
|
+
# The maximum number of tasks to retrieve in each request to "/tasklist".
|
|
87
|
+
_TASKLIST_PAGE_SIZE = 500
|
|
88
|
+
|
|
89
|
+
# Next page token key for list endpoints.
|
|
90
|
+
_NEXT_PAGE_TOKEN_KEY = 'nextPageToken'
|
|
91
|
+
|
|
92
|
+
_NOT_INITIALIZED_MESSAGE = (
|
|
93
|
+
'Earth Engine client library not initialized. See http://goo.gle/ee-auth.'
|
|
94
|
+
)
|
|
95
|
+
|
|
38
96
|
# OAuth2 credentials object. This may be set by ee.Initialize().
|
|
39
97
|
_credentials: Optional[credentials_lib.Credentials] = None
|
|
40
98
|
|
|
@@ -60,7 +118,7 @@ _cloud_api_resource = None
|
|
|
60
118
|
_cloud_api_resource_raw = None
|
|
61
119
|
|
|
62
120
|
# The default user project to use when making Cloud API calls.
|
|
63
|
-
_cloud_api_user_project:
|
|
121
|
+
_cloud_api_user_project: str = DEFAULT_CLOUD_API_USER_PROJECT
|
|
64
122
|
|
|
65
123
|
# The API client version number to send when making requests.
|
|
66
124
|
_cloud_api_client_version: Optional[str] = None
|
|
@@ -102,64 +160,6 @@ class _ThreadLocals(threading.local):
|
|
|
102
160
|
|
|
103
161
|
_thread_locals = _ThreadLocals()
|
|
104
162
|
|
|
105
|
-
# The HTTP header through which profile results are returned.
|
|
106
|
-
# Lowercase because that's how httplib2 does things.
|
|
107
|
-
_PROFILE_RESPONSE_HEADER_LOWERCASE = 'x-earth-engine-computation-profile'
|
|
108
|
-
|
|
109
|
-
# The HTTP header through which profiling is requested when using the Cloud API.
|
|
110
|
-
_PROFILE_REQUEST_HEADER = 'X-Earth-Engine-Computation-Profiling'
|
|
111
|
-
|
|
112
|
-
# The HTTP header through which a user project override is provided.
|
|
113
|
-
_USER_PROJECT_OVERRIDE_HEADER = 'X-Goog-User-Project'
|
|
114
|
-
|
|
115
|
-
# The HTTP header used to indicate the version of the client library used.
|
|
116
|
-
_API_CLIENT_VERSION_HEADER = 'X-Goog-Api-Client'
|
|
117
|
-
|
|
118
|
-
# The HTTP header used to indicate the user agent.
|
|
119
|
-
_USER_AGENT_HEADER = 'user-agent'
|
|
120
|
-
|
|
121
|
-
# Optional HTTP header returned to display initialization-time messages.
|
|
122
|
-
_INIT_MESSAGE_HEADER = 'x-earth-engine-init-message' # lowercase for httplib2
|
|
123
|
-
|
|
124
|
-
# Maximum time to wait before retrying a rate-limited request (in milliseconds).
|
|
125
|
-
MAX_RETRY_WAIT = 120000
|
|
126
|
-
|
|
127
|
-
# Base time (in ms) to wait when performing exponential backoff in request
|
|
128
|
-
# retries.
|
|
129
|
-
BASE_RETRY_WAIT = 1000
|
|
130
|
-
|
|
131
|
-
# The default base URL for API calls.
|
|
132
|
-
DEFAULT_API_BASE_URL = 'https://earthengine.googleapis.com/api'
|
|
133
|
-
HIGH_VOLUME_API_BASE_URL = 'https://earthengine-highvolume.googleapis.com'
|
|
134
|
-
|
|
135
|
-
# The default base URL for media/tile calls.
|
|
136
|
-
DEFAULT_TILE_BASE_URL = 'https://earthengine.googleapis.com'
|
|
137
|
-
|
|
138
|
-
# The default base URL for Cloud API calls.
|
|
139
|
-
DEFAULT_CLOUD_API_BASE_URL = 'https://earthengine.googleapis.com'
|
|
140
|
-
|
|
141
|
-
# The default project to use for Cloud API calls.
|
|
142
|
-
DEFAULT_CLOUD_API_USER_PROJECT = 'earthengine-legacy'
|
|
143
|
-
|
|
144
|
-
# Asset types recognized by create_assets().
|
|
145
|
-
ASSET_TYPE_FOLDER = 'Folder'
|
|
146
|
-
ASSET_TYPE_IMAGE_COLL = 'ImageCollection'
|
|
147
|
-
# Cloud API versions of the asset types.
|
|
148
|
-
ASSET_TYPE_FOLDER_CLOUD = 'FOLDER'
|
|
149
|
-
ASSET_TYPE_IMAGE_COLL_CLOUD = 'IMAGE_COLLECTION'
|
|
150
|
-
# Max length of the above type names
|
|
151
|
-
MAX_TYPE_LENGTH = len(ASSET_TYPE_IMAGE_COLL_CLOUD)
|
|
152
|
-
|
|
153
|
-
# The maximum number of tasks to retrieve in each request to "/tasklist".
|
|
154
|
-
_TASKLIST_PAGE_SIZE = 500
|
|
155
|
-
|
|
156
|
-
# Next page token key for list endpoints.
|
|
157
|
-
_NEXT_PAGE_TOKEN_KEY = 'nextPageToken'
|
|
158
|
-
|
|
159
|
-
_NOT_INITIALIZED_MESSAGE = (
|
|
160
|
-
'Earth Engine client library not initialized. See http://goo.gle/ee-auth.'
|
|
161
|
-
)
|
|
162
|
-
|
|
163
163
|
|
|
164
164
|
def initialize(
|
|
165
165
|
credentials: Any = None,
|
|
@@ -231,9 +231,8 @@ def initialize(
|
|
|
231
231
|
|
|
232
232
|
if project is not None:
|
|
233
233
|
_cloud_api_user_project = project
|
|
234
|
-
_cloud_api_utils.set_cloud_api_user_project(project)
|
|
235
234
|
else:
|
|
236
|
-
|
|
235
|
+
_cloud_api_user_project = DEFAULT_CLOUD_API_USER_PROJECT
|
|
237
236
|
|
|
238
237
|
_initialized = True
|
|
239
238
|
|
|
@@ -302,18 +301,14 @@ def reset() -> None:
|
|
|
302
301
|
_cloud_api_key = None
|
|
303
302
|
_cloud_api_resource = None
|
|
304
303
|
_cloud_api_resource_raw = None
|
|
305
|
-
_cloud_api_user_project =
|
|
306
|
-
_cloud_api_utils.set_cloud_api_user_project(DEFAULT_CLOUD_API_USER_PROJECT)
|
|
304
|
+
_cloud_api_user_project = DEFAULT_CLOUD_API_USER_PROJECT
|
|
307
305
|
_http_transport = None
|
|
308
306
|
_initialized = False
|
|
309
307
|
|
|
310
308
|
|
|
311
309
|
def _get_projects_path() -> str:
|
|
312
310
|
"""Returns the projects path to use for constructing a request."""
|
|
313
|
-
|
|
314
|
-
return 'projects/' + _cloud_api_user_project
|
|
315
|
-
else:
|
|
316
|
-
return 'projects/' + DEFAULT_CLOUD_API_USER_PROJECT
|
|
311
|
+
return f'projects/{_cloud_api_user_project}'
|
|
317
312
|
|
|
318
313
|
|
|
319
314
|
def _install_cloud_api_resource() -> None:
|
|
@@ -372,7 +367,7 @@ def _make_request_headers() -> Optional[dict[str, Any]]:
|
|
|
372
367
|
headers[_API_CLIENT_VERSION_HEADER] = ' '.join(client_version_header_values)
|
|
373
368
|
if _thread_locals.profile_hook:
|
|
374
369
|
headers[_PROFILE_REQUEST_HEADER] = '1'
|
|
375
|
-
if _cloud_api_user_project is not
|
|
370
|
+
if _cloud_api_user_project is not DEFAULT_CLOUD_API_USER_PROJECT:
|
|
376
371
|
headers[_USER_PROJECT_OVERRIDE_HEADER] = _cloud_api_user_project
|
|
377
372
|
if headers:
|
|
378
373
|
return headers
|
|
@@ -455,7 +450,6 @@ def setCloudApiKey(cloud_api_key: str) -> None:
|
|
|
455
450
|
def setCloudApiUserProject(cloud_api_user_project: str) -> None:
|
|
456
451
|
global _cloud_api_user_project
|
|
457
452
|
_cloud_api_user_project = cloud_api_user_project
|
|
458
|
-
_cloud_api_utils.set_cloud_api_user_project(_cloud_api_user_project)
|
|
459
453
|
|
|
460
454
|
|
|
461
455
|
def setUserAgent(user_agent: str) -> None:
|
|
@@ -1683,7 +1677,8 @@ def getTaskStatus(taskId: Union[list[str], str]) -> list[Any]:
|
|
|
1683
1677
|
"""Retrieve status of one or more long-running tasks.
|
|
1684
1678
|
|
|
1685
1679
|
Args:
|
|
1686
|
-
taskId: ID of the task or a list of multiple IDs.
|
|
1680
|
+
taskId: ID of the task or a list of multiple IDs. These will be assumed to
|
|
1681
|
+
be running in the currently initialized project.
|
|
1687
1682
|
|
|
1688
1683
|
Returns:
|
|
1689
1684
|
List containing one object for each queried task, in the same order as
|
|
@@ -1698,19 +1693,22 @@ def getTaskStatus(taskId: Union[list[str], str]) -> list[Any]:
|
|
|
1698
1693
|
taskId = [taskId]
|
|
1699
1694
|
result = []
|
|
1700
1695
|
for one_id in taskId:
|
|
1696
|
+
# Don't use getOperation as it will translate the exception, and we need
|
|
1697
|
+
# to handle 404s specially.
|
|
1698
|
+
name = _cloud_api_utils.convert_task_id_to_operation_name(
|
|
1699
|
+
_cloud_api_user_project, one_id
|
|
1700
|
+
)
|
|
1701
1701
|
try:
|
|
1702
|
-
# Don't use getOperation as it will translate the exception, and we need
|
|
1703
|
-
# to handle 404s specially.
|
|
1704
1702
|
operation = (
|
|
1705
1703
|
_get_cloud_projects()
|
|
1706
1704
|
.operations()
|
|
1707
|
-
.get(name=
|
|
1705
|
+
.get(name=name)
|
|
1708
1706
|
.execute(num_retries=_max_retries)
|
|
1709
1707
|
)
|
|
1710
1708
|
result.append(_cloud_api_utils.convert_operation_to_task(operation))
|
|
1711
1709
|
except googleapiclient.errors.HttpError as e:
|
|
1712
1710
|
if e.resp.status == 404:
|
|
1713
|
-
result.append({'id': one_id, 'state': 'UNKNOWN'})
|
|
1711
|
+
result.append({'id': one_id, 'state': 'UNKNOWN', 'name': name})
|
|
1714
1712
|
else:
|
|
1715
1713
|
raise _translate_cloud_exception(e) # pylint: disable=raise-missing-from
|
|
1716
1714
|
return result
|
|
@@ -1734,7 +1732,11 @@ def getOperation(operation_name: str) -> Any:
|
|
|
1734
1732
|
@deprecation.Deprecated('Use cancelOperation')
|
|
1735
1733
|
def cancelTask(taskId: str) -> None:
|
|
1736
1734
|
"""Cancels a batch task."""
|
|
1737
|
-
cancelOperation(
|
|
1735
|
+
cancelOperation(
|
|
1736
|
+
_cloud_api_utils.convert_task_id_to_operation_name(
|
|
1737
|
+
_cloud_api_user_project, taskId
|
|
1738
|
+
)
|
|
1739
|
+
)
|
|
1738
1740
|
|
|
1739
1741
|
|
|
1740
1742
|
def cancelOperation(operation_name: str) -> None:
|
|
@@ -16,10 +16,6 @@ from ee import ee_exception
|
|
|
16
16
|
|
|
17
17
|
class CloudApiUtilsTest(unittest.TestCase):
|
|
18
18
|
|
|
19
|
-
def setUp(self):
|
|
20
|
-
super().setUp()
|
|
21
|
-
_cloud_api_utils.set_cloud_api_user_project('earthengine-legacy')
|
|
22
|
-
|
|
23
19
|
def test_build_cloud_resource(self):
|
|
24
20
|
base = 'https://earthengine.basetest'
|
|
25
21
|
path = '$discovery/rest?version=v1&prettyPrint=false'
|
|
@@ -171,7 +167,10 @@ class CloudApiUtilsTest(unittest.TestCase):
|
|
|
171
167
|
def test_convert_task_id_to_operation_name(self):
|
|
172
168
|
self.assertEqual(
|
|
173
169
|
'projects/earthengine-legacy/operations/taskId',
|
|
174
|
-
_cloud_api_utils.convert_task_id_to_operation_name(
|
|
170
|
+
_cloud_api_utils.convert_task_id_to_operation_name(
|
|
171
|
+
'earthengine-legacy', 'taskId'
|
|
172
|
+
),
|
|
173
|
+
)
|
|
175
174
|
|
|
176
175
|
def test_encode_number_as_cloud_value(self):
|
|
177
176
|
self.assertEqual({
|
ee/tests/_helpers_test.py
CHANGED
|
@@ -7,14 +7,67 @@ name since that is the name we want to ensure works.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import io
|
|
10
|
+
import json
|
|
10
11
|
import unittest
|
|
12
|
+
from unittest import mock
|
|
11
13
|
|
|
12
14
|
import unittest
|
|
13
15
|
import ee
|
|
16
|
+
from ee import _helpers
|
|
14
17
|
from ee import apifunction
|
|
15
18
|
from ee import apitestcase
|
|
16
19
|
from ee import computedobject
|
|
17
20
|
from ee import ee_exception
|
|
21
|
+
from ee import oauth
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ServiceAccountCredentialsTest(unittest.TestCase):
|
|
25
|
+
|
|
26
|
+
def testNoArgs(self):
|
|
27
|
+
with self.assertRaisesRegex(ValueError, 'At least one of'):
|
|
28
|
+
ee.ServiceAccountCredentials()
|
|
29
|
+
|
|
30
|
+
@mock.patch('google.oauth2.service_account.Credentials')
|
|
31
|
+
def testJsonFile(self, mock_credentials):
|
|
32
|
+
ee.ServiceAccountCredentials(key_file='foo.json')
|
|
33
|
+
mock_credentials.from_service_account_file.assert_called_with(
|
|
34
|
+
'foo.json', scopes=oauth.SCOPES
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@mock.patch('google.oauth2.service_account.Credentials')
|
|
38
|
+
def testJsonKeyData(self, mock_credentials):
|
|
39
|
+
key_data = {'client_email': 'foo@bar.com'}
|
|
40
|
+
ee.ServiceAccountCredentials(key_data=json.dumps(key_data))
|
|
41
|
+
mock_credentials.from_service_account_info.assert_called_with(
|
|
42
|
+
key_data, scopes=oauth.SCOPES
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@mock.patch('google.auth.crypt.RSASigner')
|
|
46
|
+
@mock.patch('google.oauth2.service_account.Credentials')
|
|
47
|
+
def testPemKeyData(self, mock_credentials, mock_signer):
|
|
48
|
+
ee.ServiceAccountCredentials(email='foo@bar.com', key_data='pem_key_data')
|
|
49
|
+
mock_signer.from_string.assert_called_with('pem_key_data')
|
|
50
|
+
self.assertEqual(
|
|
51
|
+
mock_credentials.call_args[0][1], 'foo@bar.com'
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@mock.patch('google.auth.crypt.RSASigner')
|
|
55
|
+
@mock.patch('google.oauth2.service_account.Credentials')
|
|
56
|
+
def testPemFile(self, mock_credentials, mock_signer):
|
|
57
|
+
with mock.patch.object(
|
|
58
|
+
_helpers, 'open', mock.mock_open(read_data='pem_key_data')
|
|
59
|
+
):
|
|
60
|
+
ee.ServiceAccountCredentials(email='foo@bar.com', key_file='foo.pem')
|
|
61
|
+
mock_signer.from_string.assert_called_with('pem_key_data')
|
|
62
|
+
self.assertEqual(
|
|
63
|
+
mock_credentials.call_args[0][1], 'foo@bar.com'
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def testBadJsonKeyData(self):
|
|
67
|
+
# This causes a different failure based on where the test is run.
|
|
68
|
+
message = r'Could not deserialize key data|No key could be detected'
|
|
69
|
+
with self.assertRaisesRegex(ValueError, message):
|
|
70
|
+
ee.ServiceAccountCredentials(key_data='not json')
|
|
18
71
|
|
|
19
72
|
|
|
20
73
|
class ProfilingTest(apitestcase.ApiTestCase):
|
ee/tests/batch_test.py
CHANGED
|
@@ -72,7 +72,8 @@ class TaskTest(unittest.TestCase):
|
|
|
72
72
|
task.start()
|
|
73
73
|
|
|
74
74
|
def testStatusWithId(self):
|
|
75
|
-
|
|
75
|
+
name = 'projects/test-project/operations/test_1'
|
|
76
|
+
task = batch.Task('an id', 'a task type', 'a state', name=name)
|
|
76
77
|
with mock.patch.object(
|
|
77
78
|
data, 'getOperation', return_value=RUNNING_OPERATION
|
|
78
79
|
) as m:
|
|
@@ -97,7 +98,8 @@ class TaskTest(unittest.TestCase):
|
|
|
97
98
|
)
|
|
98
99
|
|
|
99
100
|
def testStatusWithIdStateUnknown(self):
|
|
100
|
-
|
|
101
|
+
name = 'projects/test-project/operations/an id'
|
|
102
|
+
task = batch.Task('an id', 'a task type', 'a state', name=name)
|
|
101
103
|
with mock.patch.object(
|
|
102
104
|
data, 'getOperation', return_value=UNKNOWN_OPERATION
|
|
103
105
|
) as m:
|
|
@@ -111,7 +113,8 @@ class TaskTest(unittest.TestCase):
|
|
|
111
113
|
self.assertEqual('UNSUBMITTED', task.status()['state'])
|
|
112
114
|
|
|
113
115
|
def testActive(self):
|
|
114
|
-
|
|
116
|
+
name = 'projects/test-project/operations/an id'
|
|
117
|
+
task = batch.Task('an id', 'a task type', 'a state', name=name)
|
|
115
118
|
with mock.patch.object(
|
|
116
119
|
data, 'getOperation', return_value=RUNNING_OPERATION
|
|
117
120
|
):
|
ee/tests/blob_test.py
CHANGED
|
@@ -75,9 +75,9 @@ class BlobTest(apitestcase.ApiTestCase):
|
|
|
75
75
|
self.assertEqual({'value': 'fakeValue'}, result.getInfo())
|
|
76
76
|
|
|
77
77
|
def test_wrong_arg_type(self):
|
|
78
|
-
message = '
|
|
78
|
+
message = r'url must be a string or ComputedObject: <class \'int\'> -> "13"'
|
|
79
79
|
with self.assertRaisesRegex(ValueError, message):
|
|
80
|
-
ee.Blob(
|
|
80
|
+
ee.Blob(13) # pytype: disable=wrong-arg-types
|
|
81
81
|
|
|
82
82
|
def test_does_not_start_with_gs(self):
|
|
83
83
|
url = 'http://example.com/something'
|
ee/tests/data_test.py
CHANGED
|
@@ -49,6 +49,7 @@ class DataTest(unittest.TestCase):
|
|
|
49
49
|
|
|
50
50
|
def tearDown(self):
|
|
51
51
|
super().tearDown()
|
|
52
|
+
ee.data.reset()
|
|
52
53
|
mock.patch.stopall()
|
|
53
54
|
|
|
54
55
|
def testIsInitialized(self):
|
|
@@ -56,6 +57,27 @@ class DataTest(unittest.TestCase):
|
|
|
56
57
|
with apitestcase.UsingCloudApi():
|
|
57
58
|
self.assertTrue(ee.data.is_initialized())
|
|
58
59
|
|
|
60
|
+
@mock.patch.object(ee.data, '_install_cloud_api_resource', return_value=None)
|
|
61
|
+
def testInitialize(self, mock_install_cloud_api_resource):
|
|
62
|
+
ee.data.initialize()
|
|
63
|
+
|
|
64
|
+
self.assertTrue(ee.data.is_initialized())
|
|
65
|
+
mock_install_cloud_api_resource.assert_called_once()
|
|
66
|
+
|
|
67
|
+
@mock.patch.object(ee.data, '_install_cloud_api_resource', return_value=None)
|
|
68
|
+
def testInitializeWithProject(self, unused_mock_install_cloud_api_resource):
|
|
69
|
+
ee.data.initialize(project='my-project')
|
|
70
|
+
|
|
71
|
+
self.assertTrue(ee.data.is_initialized())
|
|
72
|
+
self.assertEqual(ee.data._cloud_api_user_project, 'my-project')
|
|
73
|
+
|
|
74
|
+
@mock.patch.object(ee.data, '_install_cloud_api_resource', return_value=None)
|
|
75
|
+
def testInitializeWithNoProject(self, unused_mock_install_cloud_api_resource):
|
|
76
|
+
ee.data.initialize()
|
|
77
|
+
|
|
78
|
+
self.assertTrue(ee.data.is_initialized())
|
|
79
|
+
self.assertEqual(ee.data._cloud_api_user_project, 'earthengine-legacy')
|
|
80
|
+
|
|
59
81
|
def testSetMaxRetries_badValues(self):
|
|
60
82
|
with self.assertRaises(ValueError):
|
|
61
83
|
ee.data.setMaxRetries(-1)
|
|
@@ -108,6 +130,112 @@ class DataTest(unittest.TestCase):
|
|
|
108
130
|
with apitestcase.UsingCloudApi(mock_http=mock_http):
|
|
109
131
|
self.assertEqual([], ee.data.listOperations())
|
|
110
132
|
|
|
133
|
+
def testGetOperation(self):
|
|
134
|
+
cloud_api_resource = mock.MagicMock()
|
|
135
|
+
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
|
|
136
|
+
name = 'projects/test-project/operations/foo'
|
|
137
|
+
cloud_api_resource.projects().operations().get.execute.return_value = {
|
|
138
|
+
'name': name,
|
|
139
|
+
'done': False,
|
|
140
|
+
}
|
|
141
|
+
ee.data.getOperation(name)
|
|
142
|
+
cloud_api_resource.projects().operations().get.assert_called_once_with(
|
|
143
|
+
name=name
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
def testGetTaskStatus(self):
|
|
147
|
+
cloud_api_resource = mock.MagicMock()
|
|
148
|
+
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
|
|
149
|
+
cloud_api_resource.projects().operations().get.return_value.execute.return_value = {
|
|
150
|
+
'name': 'projects/earthengine-legacy/operations/foo',
|
|
151
|
+
'done': False,
|
|
152
|
+
'metadata': {'state': 'RUNNING'},
|
|
153
|
+
}
|
|
154
|
+
result = ee.data.getTaskStatus('foo')
|
|
155
|
+
cloud_api_resource.projects().operations().get.assert_called_once_with(
|
|
156
|
+
name='projects/earthengine-legacy/operations/foo'
|
|
157
|
+
)
|
|
158
|
+
self.assertEqual(
|
|
159
|
+
result,
|
|
160
|
+
[{
|
|
161
|
+
'id': 'foo',
|
|
162
|
+
'state': 'RUNNING',
|
|
163
|
+
'name': 'projects/earthengine-legacy/operations/foo',
|
|
164
|
+
}],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def testGetTaskStatus_withNotFound(self):
|
|
168
|
+
cloud_api_resource = mock.MagicMock()
|
|
169
|
+
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
|
|
170
|
+
cloud_api_resource.projects().operations().get.return_value.execute.side_effect = [
|
|
171
|
+
{
|
|
172
|
+
'name': 'projects/earthengine-legacy/operations/foo',
|
|
173
|
+
'done': False,
|
|
174
|
+
'metadata': {'state': 'RUNNING'},
|
|
175
|
+
},
|
|
176
|
+
NotFoundError(),
|
|
177
|
+
{
|
|
178
|
+
'name': 'projects/earthengine-legacy/operations/bar',
|
|
179
|
+
'done': True,
|
|
180
|
+
'metadata': {'state': 'SUCCEEDED'},
|
|
181
|
+
},
|
|
182
|
+
]
|
|
183
|
+
result = ee.data.getTaskStatus(['foo', 'missing', 'bar'])
|
|
184
|
+
cloud_api_resource.projects().operations().get.assert_has_calls([
|
|
185
|
+
mock.call(name='projects/earthengine-legacy/operations/foo'),
|
|
186
|
+
mock.call().execute(num_retries=5),
|
|
187
|
+
mock.call(name='projects/earthengine-legacy/operations/missing'),
|
|
188
|
+
mock.call().execute(num_retries=5),
|
|
189
|
+
mock.call(name='projects/earthengine-legacy/operations/bar'),
|
|
190
|
+
mock.call().execute(num_retries=5),
|
|
191
|
+
])
|
|
192
|
+
self.assertEqual(
|
|
193
|
+
3,
|
|
194
|
+
cloud_api_resource.projects()
|
|
195
|
+
.operations()
|
|
196
|
+
.get.return_value.execute.call_count,
|
|
197
|
+
)
|
|
198
|
+
self.assertEqual(
|
|
199
|
+
result,
|
|
200
|
+
[
|
|
201
|
+
{
|
|
202
|
+
'id': 'foo',
|
|
203
|
+
'state': 'RUNNING',
|
|
204
|
+
'name': 'projects/earthengine-legacy/operations/foo',
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
'id': 'missing',
|
|
208
|
+
'state': 'UNKNOWN',
|
|
209
|
+
'name': 'projects/earthengine-legacy/operations/missing',
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
'id': 'bar',
|
|
213
|
+
'state': 'COMPLETED',
|
|
214
|
+
'name': 'projects/earthengine-legacy/operations/bar',
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def testCancelOperation(self):
|
|
220
|
+
cloud_api_resource = mock.MagicMock()
|
|
221
|
+
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
|
|
222
|
+
cancel_mock = cloud_api_resource.projects().operations().cancel
|
|
223
|
+
cancel_mock.execute.return_value = {}
|
|
224
|
+
ee.data.cancelOperation('projects/test-project/operations/foo')
|
|
225
|
+
cancel_mock.assert_called_once_with(
|
|
226
|
+
name='projects/test-project/operations/foo', body={}
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
def testCancelTask(self):
|
|
230
|
+
cloud_api_resource = mock.MagicMock()
|
|
231
|
+
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
|
|
232
|
+
cancel_mock = cloud_api_resource.projects().operations().cancel
|
|
233
|
+
cancel_mock.execute.return_value = {}
|
|
234
|
+
ee.data.cancelTask('foo')
|
|
235
|
+
cancel_mock.assert_called_once_with(
|
|
236
|
+
name='projects/earthengine-legacy/operations/foo', body={}
|
|
237
|
+
)
|
|
238
|
+
|
|
111
239
|
def testCreateAsset(self):
|
|
112
240
|
cloud_api_resource = mock.MagicMock()
|
|
113
241
|
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
|
ee/tests/ee_test.py
CHANGED
|
@@ -49,7 +49,7 @@ class EETestCase(apitestcase.ApiTestCase):
|
|
|
49
49
|
ee.Reset()
|
|
50
50
|
self.assertFalse(ee.data._initialized)
|
|
51
51
|
self.assertIsNone(ee.data._api_base_url)
|
|
52
|
-
self.
|
|
52
|
+
self.assertEqual(ee.data._cloud_api_user_project, 'earthengine-legacy')
|
|
53
53
|
self.assertEqual(ee.ApiFunction._api, {})
|
|
54
54
|
self.assertFalse(ee.Image._initialized)
|
|
55
55
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|