earthengine-api 1.6.13__py3-none-any.whl → 1.7.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of earthengine-api might be problematic. Click here for more details.
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/METADATA +2 -3
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/RECORD +44 -44
- ee/__init__.py +13 -13
- ee/_cloud_api_utils.py +29 -28
- ee/_helpers.py +6 -6
- ee/_utils.py +2 -1
- ee/apitestcase.py +10 -10
- ee/batch.py +7 -0
- ee/cli/commands.py +6 -10
- ee/cli/utils.py +28 -23
- ee/collection.py +3 -2
- ee/computedobject.py +4 -1
- ee/customfunction.py +2 -1
- ee/data.py +32 -31
- ee/deprecation.py +8 -2
- ee/deserializer.py +10 -10
- ee/ee_number.py +6 -16
- ee/encodable.py +2 -1
- ee/image_converter.py +3 -3
- ee/imagecollection.py +2 -2
- ee/model.py +29 -31
- ee/oauth.py +37 -37
- ee/reducer.py +2 -0
- ee/serializer.py +6 -6
- ee/table_converter.py +3 -3
- ee/terrain.py +1 -1
- ee/tests/batch_test.py +67 -3
- ee/tests/collection_test.py +35 -0
- ee/tests/data_test.py +300 -4
- ee/tests/deprecation_test.py +4 -2
- ee/tests/deserializer_test.py +47 -0
- ee/tests/ee_number_test.py +40 -1
- ee/tests/image_converter_test.py +1 -3
- ee/tests/kernel_test.py +4 -0
- ee/tests/model_test.py +12 -0
- ee/tests/oauth_test.py +170 -7
- ee/tests/reducer_test.py +13 -0
- ee/tests/serializer_test.py +29 -2
- ee/tests/table_converter_test.py +49 -5
- ee/tests/terrain_test.py +8 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/WHEEL +0 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/entry_points.txt +0 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/licenses/LICENSE +0 -0
- {earthengine_api-1.6.13.dist-info → earthengine_api-1.7.4.dist-info}/top_level.txt +0 -0
ee/tests/oauth_test.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Test for the oauth module."""
|
|
3
3
|
|
|
4
|
+
import http.client
|
|
5
|
+
import io
|
|
4
6
|
import json
|
|
5
7
|
import sys
|
|
6
8
|
import tempfile
|
|
@@ -34,20 +36,33 @@ class OAuthTest(unittest.TestCase):
|
|
|
34
36
|
self.assertEqual('xyz', parsed[b'code_verifier'][0].decode())
|
|
35
37
|
return MockResponse(parsed[b'code'][0])
|
|
36
38
|
|
|
37
|
-
with mock.patch(
|
|
39
|
+
with mock.patch.object(urllib.request, 'urlopen', new=mock_urlopen):
|
|
38
40
|
auth_code = '123'
|
|
39
41
|
verifier = 'xyz'
|
|
40
42
|
refresh_token = oauth.request_token(auth_code, verifier)
|
|
41
43
|
self.assertEqual('123456', refresh_token)
|
|
42
44
|
|
|
45
|
+
def test_request_token_http_error(self):
|
|
46
|
+
mock_fp = io.BytesIO(b'error details')
|
|
47
|
+
http_error = urllib.error.HTTPError(
|
|
48
|
+
'url', 400, 'message', hdrs=http.client.HTTPMessage(), fp=mock_fp
|
|
49
|
+
)
|
|
50
|
+
with mock.patch.object(urllib.request, 'urlopen', side_effect=http_error):
|
|
51
|
+
with self.assertRaisesRegex(
|
|
52
|
+
Exception,
|
|
53
|
+
r"Problem requesting tokens.*HTTP Error 400: message.*b'error"
|
|
54
|
+
r" details'",
|
|
55
|
+
):
|
|
56
|
+
oauth.request_token('auth_code', 'code_verifier')
|
|
57
|
+
|
|
43
58
|
def test_write_token(self):
|
|
44
59
|
|
|
45
60
|
def mock_credentials_path():
|
|
46
|
-
return self.test_tmpdir
|
|
61
|
+
return f'{self.test_tmpdir}/tempfile'
|
|
47
62
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
with mock.patch.object(
|
|
64
|
+
oauth, 'get_credentials_path', new=mock_credentials_path
|
|
65
|
+
):
|
|
51
66
|
client_info = dict(refresh_token='123')
|
|
52
67
|
oauth.write_private_json(oauth.get_credentials_path(), client_info)
|
|
53
68
|
|
|
@@ -55,6 +70,46 @@ class OAuthTest(unittest.TestCase):
|
|
|
55
70
|
token = json.load(f)
|
|
56
71
|
self.assertEqual({'refresh_token': '123'}, token)
|
|
57
72
|
|
|
73
|
+
def test_get_credentials_arguments(self):
|
|
74
|
+
credentials_path = f'{self.test_tmpdir}/temp_creds'
|
|
75
|
+
|
|
76
|
+
creds = {
|
|
77
|
+
'refresh_token': 'REFRESH_TOKEN',
|
|
78
|
+
'client_id': 'CLIENT_ID',
|
|
79
|
+
'project': 'PROJECT',
|
|
80
|
+
}
|
|
81
|
+
with open(credentials_path, 'w') as f:
|
|
82
|
+
json.dump(creds, f)
|
|
83
|
+
|
|
84
|
+
with mock.patch.object(
|
|
85
|
+
oauth, 'get_credentials_path', return_value=credentials_path
|
|
86
|
+
):
|
|
87
|
+
args = oauth.get_credentials_arguments()
|
|
88
|
+
|
|
89
|
+
expected_args = {
|
|
90
|
+
'token_uri': oauth.TOKEN_URI,
|
|
91
|
+
'refresh_token': 'REFRESH_TOKEN',
|
|
92
|
+
'client_id': 'CLIENT_ID',
|
|
93
|
+
'client_secret': oauth.CLIENT_SECRET,
|
|
94
|
+
'scopes': oauth.SCOPES,
|
|
95
|
+
'quota_project_id': 'PROJECT',
|
|
96
|
+
}
|
|
97
|
+
self.assertEqual(expected_args, args)
|
|
98
|
+
|
|
99
|
+
def test_is_valid_credentials(self):
|
|
100
|
+
self.assertFalse(oauth.is_valid_credentials(None))
|
|
101
|
+
|
|
102
|
+
mock_credentials_valid = mock.MagicMock()
|
|
103
|
+
self.assertTrue(oauth.is_valid_credentials(mock_credentials_valid))
|
|
104
|
+
mock_credentials_valid.refresh.assert_called_once()
|
|
105
|
+
|
|
106
|
+
mock_credentials_invalid = mock.MagicMock()
|
|
107
|
+
mock_credentials_invalid.refresh.side_effect = (
|
|
108
|
+
oauth.google.auth.exceptions.RefreshError()
|
|
109
|
+
)
|
|
110
|
+
self.assertFalse(oauth.is_valid_credentials(mock_credentials_invalid))
|
|
111
|
+
mock_credentials_invalid.refresh.assert_called_once()
|
|
112
|
+
|
|
58
113
|
def test_in_colab_shell(self):
|
|
59
114
|
with mock.patch.dict(sys.modules, {'google.colab': None}):
|
|
60
115
|
self.assertFalse(oauth.in_colab_shell())
|
|
@@ -78,7 +133,7 @@ class OAuthTest(unittest.TestCase):
|
|
|
78
133
|
)
|
|
79
134
|
)
|
|
80
135
|
|
|
81
|
-
def
|
|
136
|
+
def test_colab_mode_with_nonstandard_scopes_raises_exception(self):
|
|
82
137
|
with self.assertRaisesRegex(
|
|
83
138
|
ee_exception.EEException,
|
|
84
139
|
'Scopes cannot be customized when auth_mode is "colab".'
|
|
@@ -88,7 +143,7 @@ class OAuthTest(unittest.TestCase):
|
|
|
88
143
|
scopes=['https://www.googleapis.com/auth/earthengine.readonly']
|
|
89
144
|
)
|
|
90
145
|
|
|
91
|
-
def
|
|
146
|
+
def test_colab_auth_mode_with_standard_scopes_succeeds(self):
|
|
92
147
|
# Should not raise an exception if the scopes are not narrowed.
|
|
93
148
|
with mock.patch.dict(sys.modules, {'google.colab': mock.MagicMock()}):
|
|
94
149
|
try:
|
|
@@ -96,5 +151,113 @@ class OAuthTest(unittest.TestCase):
|
|
|
96
151
|
except ee_exception.EEException:
|
|
97
152
|
self.fail('authenticate raised an exception unexpectedly.')
|
|
98
153
|
|
|
154
|
+
def test_authenticate_appdefault(self):
|
|
155
|
+
with mock.patch.object(
|
|
156
|
+
oauth,
|
|
157
|
+
'_valid_credentials_exist',
|
|
158
|
+
return_value=False,
|
|
159
|
+
), mock.patch.object(
|
|
160
|
+
sys, 'stderr', new_callable=io.StringIO
|
|
161
|
+
) as mock_stderr:
|
|
162
|
+
oauth.authenticate(auth_mode='appdefault')
|
|
163
|
+
self.assertIn('appdefault no longer necessary', mock_stderr.getvalue())
|
|
164
|
+
|
|
165
|
+
@mock.patch.object(oauth, '_load_gcloud_credentials')
|
|
166
|
+
@mock.patch.object(oauth, '_valid_credentials_exist', return_value=False)
|
|
167
|
+
@mock.patch.object(oauth, 'in_colab_shell', return_value=False)
|
|
168
|
+
@mock.patch.object(oauth, '_in_jupyter_shell', return_value=False)
|
|
169
|
+
@mock.patch.object(oauth, '_localhost_is_viable', return_value=False)
|
|
170
|
+
def test_authenticate_default_gcloud(
|
|
171
|
+
self,
|
|
172
|
+
mock_localhost_viable,
|
|
173
|
+
mock_jupyter,
|
|
174
|
+
mock_colab,
|
|
175
|
+
mock_valid_creds,
|
|
176
|
+
mock_load_gcloud,
|
|
177
|
+
):
|
|
178
|
+
del (
|
|
179
|
+
mock_localhost_viable,
|
|
180
|
+
mock_jupyter,
|
|
181
|
+
mock_colab,
|
|
182
|
+
mock_valid_creds,
|
|
183
|
+
) # Unused
|
|
184
|
+
oauth.authenticate()
|
|
185
|
+
mock_load_gcloud.assert_called_once_with(None, None, False)
|
|
186
|
+
|
|
187
|
+
def test_localhost_fetch_code(self):
|
|
188
|
+
mock_server = mock.MagicMock()
|
|
189
|
+
mock_server.url = 'http://localhost:8085'
|
|
190
|
+
mock_server.fetch_code.return_value = 'FETCHED_CODE'
|
|
191
|
+
with mock.patch.object(
|
|
192
|
+
oauth, '_start_server', return_value=mock_server
|
|
193
|
+
), mock.patch.object(oauth, '_obtain_and_write_token') as mock_obtain:
|
|
194
|
+
flow = oauth.Flow(auth_mode='localhost')
|
|
195
|
+
flow.save_code()
|
|
196
|
+
mock_server.fetch_code.assert_called_once()
|
|
197
|
+
mock_obtain.assert_called_once_with(
|
|
198
|
+
'FETCHED_CODE',
|
|
199
|
+
flow.code_verifier,
|
|
200
|
+
flow.scopes,
|
|
201
|
+
'http://localhost:8085',
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
@mock.patch.object(oauth, '_display_auth_instructions_for_noninteractive')
|
|
205
|
+
def test_display_instructions_quiet(self, mock_display):
|
|
206
|
+
flow = oauth.Flow(auth_mode='notebook')
|
|
207
|
+
self.assertTrue(flow.display_instructions(quiet=True))
|
|
208
|
+
mock_display.assert_called_once_with(flow.auth_url, flow.code_verifier)
|
|
209
|
+
|
|
210
|
+
@mock.patch.object(oauth, '_display_auth_instructions_with_print')
|
|
211
|
+
@mock.patch.object(oauth, 'in_colab_shell', return_value=True)
|
|
212
|
+
def test_display_instructions_colab(self, mock_in_colab, mock_display_print):
|
|
213
|
+
del mock_in_colab # Unused
|
|
214
|
+
flow = oauth.Flow(auth_mode='notebook')
|
|
215
|
+
self.assertTrue(flow.display_instructions())
|
|
216
|
+
mock_display_print.assert_called_once_with(flow.auth_url, None)
|
|
217
|
+
|
|
218
|
+
@mock.patch.object(oauth, '_display_auth_instructions_with_html')
|
|
219
|
+
@mock.patch.object(oauth, '_in_jupyter_shell', return_value=True)
|
|
220
|
+
def test_display_instructions_jupyter(
|
|
221
|
+
self, mock_in_jupyter, mock_display_html
|
|
222
|
+
):
|
|
223
|
+
del mock_in_jupyter # Unused
|
|
224
|
+
flow = oauth.Flow(auth_mode='notebook')
|
|
225
|
+
self.assertTrue(flow.display_instructions())
|
|
226
|
+
mock_display_html.assert_called_once_with(flow.auth_url, None)
|
|
227
|
+
|
|
228
|
+
@mock.patch.object(oauth, '_display_auth_instructions_with_print')
|
|
229
|
+
@mock.patch.object(oauth, 'in_colab_shell', return_value=False)
|
|
230
|
+
@mock.patch.object(oauth, '_in_jupyter_shell', return_value=False)
|
|
231
|
+
def test_display_instructions_print(
|
|
232
|
+
self, mock_in_jupyter, mock_in_colab, mock_display_print
|
|
233
|
+
):
|
|
234
|
+
del mock_in_jupyter, mock_in_colab # Unused
|
|
235
|
+
flow = oauth.Flow(auth_mode='notebook')
|
|
236
|
+
self.assertTrue(flow.display_instructions())
|
|
237
|
+
mock_display_print.assert_called_once_with(flow.auth_url, None)
|
|
238
|
+
|
|
239
|
+
@mock.patch.object(oauth, '_display_auth_instructions_with_print')
|
|
240
|
+
@mock.patch.object(oauth, 'in_colab_shell', return_value=True)
|
|
241
|
+
@mock.patch.object(oauth.http.server, 'HTTPServer')
|
|
242
|
+
def test_display_instructions_localhost_colab(
|
|
243
|
+
self, mock_http_server, mock_in_colab, mock_display_print
|
|
244
|
+
):
|
|
245
|
+
del mock_http_server, mock_in_colab # Unused
|
|
246
|
+
flow = oauth.Flow(auth_mode='localhost')
|
|
247
|
+
self.assertTrue(flow.display_instructions())
|
|
248
|
+
mock_display_print.assert_called_once_with(
|
|
249
|
+
flow.auth_url, oauth.WAITING_CODA
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def test_flow_unknown_auth_mode(self):
|
|
253
|
+
with self.assertRaisesRegex(ee_exception.EEException, 'Unknown auth_mode'):
|
|
254
|
+
oauth.Flow(auth_mode='unknown')
|
|
255
|
+
|
|
256
|
+
def test_flow_localhost_with_port(self):
|
|
257
|
+
with mock.patch.object(oauth, '_start_server') as mock_start_server:
|
|
258
|
+
oauth.Flow(auth_mode='localhost:1234')
|
|
259
|
+
mock_start_server.assert_called_once_with(1234)
|
|
260
|
+
|
|
261
|
+
|
|
99
262
|
if __name__ == '__main__':
|
|
100
263
|
unittest.main()
|
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
|
ee/tests/serializer_test.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Test for the ee.serializer module."""
|
|
3
3
|
|
|
4
|
+
from collections.abc import Callable
|
|
4
5
|
import datetime
|
|
5
6
|
import json
|
|
6
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
7
8
|
|
|
8
9
|
import unittest
|
|
9
10
|
import ee
|
|
@@ -11,7 +12,7 @@ from ee import apitestcase
|
|
|
11
12
|
from ee import serializer
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
def _max_depth(x:
|
|
15
|
+
def _max_depth(x: dict[str, Any] | list[Any] | str) -> int:
|
|
15
16
|
"""Computes the maximum nesting level of some dict, list, or str."""
|
|
16
17
|
if isinstance(x, dict):
|
|
17
18
|
return 1 + max(_max_depth(v) for v in x.values())
|
|
@@ -284,6 +285,32 @@ class SerializerTest(apitestcase.ApiTestCase):
|
|
|
284
285
|
self.assertIn('\n', serializer.toJSON(ee.Image(0), opt_pretty=True))
|
|
285
286
|
self.assertNotIn('\n', serializer.toJSON(ee.Image(0), opt_pretty=False))
|
|
286
287
|
|
|
288
|
+
def test_datetime_serialization_legacy(self):
|
|
289
|
+
a_date = datetime.datetime(2014, 8, 10, tzinfo=datetime.timezone.utc)
|
|
290
|
+
# 1407628800000000 microseconds.
|
|
291
|
+
expected = {
|
|
292
|
+
'type': 'CompoundValue',
|
|
293
|
+
'scope': [],
|
|
294
|
+
'value': {
|
|
295
|
+
'type': 'Invocation',
|
|
296
|
+
'functionName': 'Date',
|
|
297
|
+
'arguments': {'value': 1407628800000.0},
|
|
298
|
+
},
|
|
299
|
+
}
|
|
300
|
+
self.assertEqual(expected, serializer.encode(a_date, for_cloud_api=False))
|
|
301
|
+
|
|
302
|
+
def test_single_value_no_compound(self):
|
|
303
|
+
"""Verifies serialization of a single non-primitive value."""
|
|
304
|
+
self.assertEqual([1], serializer.encode([1], for_cloud_api=False))
|
|
305
|
+
|
|
306
|
+
def test_unencodable_object(self):
|
|
307
|
+
class Unencodable:
|
|
308
|
+
pass
|
|
309
|
+
with self.assertRaisesRegex(ee.EEException, 'Cannot encode object: .*'):
|
|
310
|
+
serializer.encode(Unencodable(), for_cloud_api=False)
|
|
311
|
+
with self.assertRaisesRegex(ee.EEException, 'Cannot encode object: .*'):
|
|
312
|
+
serializer.encode(Unencodable(), for_cloud_api=True)
|
|
313
|
+
|
|
287
314
|
|
|
288
315
|
if __name__ == '__main__':
|
|
289
316
|
unittest.main()
|
ee/tests/table_converter_test.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Tests for the table_converter module."""
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import builtins
|
|
5
|
+
from typing import Any
|
|
6
|
+
from unittest import mock
|
|
5
7
|
|
|
6
8
|
from absl.testing import parameterized
|
|
7
9
|
import geopandas
|
|
@@ -28,8 +30,8 @@ class TableConverterTest(parameterized.TestCase):
|
|
|
28
30
|
def test_from_file_format(
|
|
29
31
|
self,
|
|
30
32
|
data_format: str,
|
|
31
|
-
expected:
|
|
32
|
-
)
|
|
33
|
+
expected: type[table_converter.TableConverter] | None,
|
|
34
|
+
):
|
|
33
35
|
"""Verifies `from_file_format` returns the correct converter class."""
|
|
34
36
|
if expected is None:
|
|
35
37
|
self.assertIsNone(table_converter.from_file_format(data_format))
|
|
@@ -38,7 +40,17 @@ class TableConverterTest(parameterized.TestCase):
|
|
|
38
40
|
table_converter.from_file_format(data_format), expected
|
|
39
41
|
)
|
|
40
42
|
|
|
41
|
-
def
|
|
43
|
+
def test_from_file_format_instance(self):
|
|
44
|
+
"""Verifies `from_file_format` returns the same instance."""
|
|
45
|
+
converter = table_converter.PandasConverter()
|
|
46
|
+
self.assertIs(table_converter.from_file_format(converter), converter)
|
|
47
|
+
|
|
48
|
+
def test_table_converter_fails(self):
|
|
49
|
+
"""Verifies `TableConverter` cannot be used for conversion."""
|
|
50
|
+
with self.assertRaises(NotImplementedError):
|
|
51
|
+
table_converter.TableConverter().do_conversion(iter([]))
|
|
52
|
+
|
|
53
|
+
def test_pandas_converter(self):
|
|
42
54
|
"""Verifies `PandasConverter` does the correct conversion."""
|
|
43
55
|
converter = table_converter.PandasConverter()
|
|
44
56
|
|
|
@@ -69,7 +81,23 @@ class TableConverterTest(parameterized.TestCase):
|
|
|
69
81
|
]),
|
|
70
82
|
)
|
|
71
83
|
|
|
72
|
-
def
|
|
84
|
+
def test_pandas_converter_importerror(self):
|
|
85
|
+
"""Ensures ImportError is raised when pandas is not available."""
|
|
86
|
+
real_import = builtins.__import__
|
|
87
|
+
|
|
88
|
+
def mock_import(name, globals=None, locals=None, fromlist=(), level=0):
|
|
89
|
+
if name == 'pandas':
|
|
90
|
+
raise ImportError
|
|
91
|
+
return real_import(name, globals, locals, fromlist, level)
|
|
92
|
+
|
|
93
|
+
with mock.patch('builtins.__import__', mock_import):
|
|
94
|
+
converter = table_converter.PandasConverter()
|
|
95
|
+
with self.assertRaisesRegex(
|
|
96
|
+
ImportError, 'Using format PANDAS_DATAFRAME requires pandas.'
|
|
97
|
+
):
|
|
98
|
+
converter.do_conversion(iter([]))
|
|
99
|
+
|
|
100
|
+
def test_geopandas_converter(self):
|
|
73
101
|
"""Verifies `GeoPandasConverter` does the correct conversion."""
|
|
74
102
|
converter = table_converter.GeoPandasConverter()
|
|
75
103
|
|
|
@@ -105,6 +133,22 @@ class TableConverterTest(parameterized.TestCase):
|
|
|
105
133
|
geopandas.GeoDataFrame.from_features(feature_coll),
|
|
106
134
|
)
|
|
107
135
|
|
|
136
|
+
def test_geopandas_converter_importerror(self):
|
|
137
|
+
"""Ensures ImportError is raised when geopandas is not available."""
|
|
138
|
+
real_import = builtins.__import__
|
|
139
|
+
|
|
140
|
+
def mock_import(name, globals=None, locals=None, fromlist=(), level=0):
|
|
141
|
+
if name == 'geopandas':
|
|
142
|
+
raise ImportError
|
|
143
|
+
return real_import(name, globals, locals, fromlist, level)
|
|
144
|
+
|
|
145
|
+
with mock.patch('builtins.__import__', mock_import):
|
|
146
|
+
converter = table_converter.GeoPandasConverter()
|
|
147
|
+
with self.assertRaisesRegex(
|
|
148
|
+
ImportError, 'Using format GEOPANDAS_GEODATAFRAME requires geopandas.'
|
|
149
|
+
):
|
|
150
|
+
converter.do_conversion(iter([]))
|
|
151
|
+
|
|
108
152
|
|
|
109
153
|
if __name__ == '__main__':
|
|
110
154
|
unittest.main()
|
ee/tests/terrain_test.py
CHANGED
|
@@ -141,6 +141,14 @@ class TerrainTest(apitestcase.ApiTestCase):
|
|
|
141
141
|
result = json.loads(expression.serialize())
|
|
142
142
|
self.assertEqual(expect, result)
|
|
143
143
|
|
|
144
|
+
def test_init(self):
|
|
145
|
+
message = r'Terrain should not be used as an object.*'
|
|
146
|
+
with self.assertRaisesRegex(RuntimeError, message):
|
|
147
|
+
ee.Terrain()
|
|
148
|
+
|
|
149
|
+
def test_name(self):
|
|
150
|
+
self.assertEqual('Terrain', ee.Terrain.name())
|
|
151
|
+
|
|
144
152
|
|
|
145
153
|
if __name__ == '__main__':
|
|
146
154
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|