def testThumb_withDimensionsRegionCrs(self): """Verifies Thumbnail ID and URL generation in the Cloud API.""" with apitestcase.UsingCloudApi( cloud_api_resource=self.cloud_api_resource): url = self.base_image.getThumbURL({ 'dimensions': [13, 42], 'region': self.geo_json, 'crs': 'EPSG:4326', }) self.assertEqual('/v1alpha/thumbName:getPixels', url) _, kwargs = self.cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( kwargs['body']['expression'], serializer.encode(self.base_image.setDefaultProjection( crs='EPSG:4326', crsTransform=[1, 0, 0, 0, -1, 0]).clipToBoundsAndScale( geometry=ee.Geometry(self.geo_json, opt_geodesic=False), width=13, height=42), for_cloud_api=True)) self.assertEqual(kwargs['parent'], 'projects/earthengine-legacy')
def testDepthLimit_withAlgorithms(self): x = ee.Number(0) for i in range(100): x = x.add(ee.Number(i)) encoded = serializer.encode(x, for_cloud_api=True) # The default depth limit is 50, but there's some slop, so be a little loose # on the test. self.assertLess(_max_depth(encoded), 60)
def testDownloadURL(self): """Verifies that the getDownloadURL request is constructed correctly.""" with apitestcase.UsingCloudApi(cloud_api_resource=self.cloud_api_resource): url = self.base_image.getDownloadURL() _, kwargs = self.cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( serializer.encode(self.base_image, for_cloud_api=True), kwargs['body']['expression']) self.assertEqual('ZIPPED_GEO_TIFF_PER_BAND', kwargs['body']['fileFormat']) self.assertEqual('projects/earthengine-legacy', kwargs['parent']) self.assertEqual('/%s/thumbName:getPixels' % _cloud_api_utils.VERSION, url)
def testThumb_withVisualizationParams(self): with apitestcase.UsingCloudApi( cloud_api_resource=self.cloud_api_resource): self.base_image.getThumbURL({ 'dimensions': [13, 42], 'region': self.geo_json, 'min': 0 }) _, kwargs = self.cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( kwargs['body']['expression'], serializer.encode(self.base_image.clipToBoundsAndScale( geometry=self.expected_geometry, width=13, height=42).visualize(min=0), for_cloud_api=True))
def testThumb_withDimensionsRegionJson(self): # Try it with the region as a GeoJSON string. with apitestcase.UsingCloudApi( cloud_api_resource=self.cloud_api_resource): self.base_image.getThumbURL({ 'dimensions': [13, 42], 'region': json.dumps(self.geo_json), }) _, kwargs = self.cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( kwargs['body']['expression'], serializer.encode(self.base_image.clipToBoundsAndScale( geometry=self.expected_geometry, width=13, height=42), for_cloud_api=True)) self.assertEqual(kwargs['parent'], 'projects/earthengine-legacy')
def testThumb_withDimensionsListMinMax(self): # Try it with the region as a list of coordinates. with apitestcase.UsingCloudApi(cloud_api_resource=self.cloud_api_resource): self.base_image.getThumbURL({ 'dimensions': [13, 42], 'region': [-180, -90, 180, 90], }) _, kwargs = self.cloud_api_resource.projects().thumbnails( ).create.call_args expected_geometry = ee.Geometry.Rectangle( [-180, -90, 180, 90], proj=None, geodesic=False) self.assertEqual( kwargs['body']['expression'], serializer.encode( self.base_image.clipToBoundsAndScale( geometry=expected_geometry, width=13, height=42), for_cloud_api=True)) self.assertEqual(kwargs['parent'], 'projects/earthengine-legacy')
def testRepeats(self): """Verifies serialization finds and removes repeated values.""" test1 = ee.Image(5).mask(ee.Image(5)) # pylint: disable-msg=no-member expected1 = { 'type': 'CompoundValue', 'scope': [[ '0', { 'type': 'Invocation', 'arguments': { 'value': 5 }, 'functionName': 'Image.constant' } ], [ '1', { 'type': 'Invocation', 'arguments': { 'image': { 'type': 'ValueRef', 'value': '0' }, 'mask': { 'type': 'ValueRef', 'value': '0' } }, 'functionName': 'Image.mask' } ]], 'value': { 'type': 'ValueRef', 'value': '1' } } self.assertEqual( expected1, json.loads(serializer.toJSON(test1, for_cloud_api=False))) expected_cloud = { 'values': { '0': { 'functionInvocationValue': { 'arguments': { 'image': { 'valueReference': '1' }, 'mask': { 'valueReference': '1' } }, 'functionName': 'Image.mask' } }, '1': { 'functionInvocationValue': { 'arguments': { 'value': { 'constantValue': 5 } }, 'functionName': 'Image.constant' } } }, 'result': '0' } expected_cloud_pretty = { 'functionInvocationValue': { 'arguments': { 'image': { 'functionInvocationValue': { 'arguments': { 'value': { 'constantValue': 5 } }, 'functionName': 'Image.constant' } }, 'mask': { 'functionInvocationValue': { 'arguments': { 'value': { 'constantValue': 5 } }, 'functionName': 'Image.constant' } } }, 'functionName': 'Image.mask' } } self.assertEqual(expected_cloud, serializer.encode(test1, for_cloud_api=True)) self.assertEqual( expected_cloud_pretty, serializer.encode(test1, is_compound=False, for_cloud_api=True))
def testSerialization(self): """Verifies a complex serialization case.""" class ByteString(ee.Encodable): """A custom Encodable class that does not use invocations. This one is actually supported by the EE API encoding. """ def __init__(self, value): """Creates a bytestring with a given string value.""" self._value = value def encode(self, unused_encoder): # pylint: disable-msg=g-bad-name return {'type': 'Bytes', 'value': self._value} def encode_cloud_value(self, unused_encoder): # Proto3 JSON embedding of "bytes" values uses base64 encoding, which # this already is. return {'bytesValue': self._value} call = ee.ComputedObject('String.cat', { 'string1': 'x', 'string2': 'y' }) body = lambda x, y: ee.CustomFunction.variable(None, 'y') sig = { 'returns': 'Object', 'args': [{ 'name': 'x', 'type': 'Object' }, { 'name': 'y', 'type': 'Object' }] } custom_function = ee.CustomFunction(sig, body) to_encode = [ None, True, 5, 7, 3.4, 112233445566778899, 'hello', ee.Date(1234567890000), ee.Geometry(ee.Geometry.LineString(1, 2, 3, 4), 'SR-ORG:6974'), ee.Geometry.Polygon([[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[5, 6], [7, 6], [7, 8], [5, 8]], [[1, 1], [2, 1], [2, 2], [1, 2]]]), ByteString('aGVsbG8='), { 'foo': 'bar', 'baz': call }, call, custom_function ] self.assertEqual( apitestcase.ENCODED_JSON_SAMPLE, json.loads(serializer.toJSON(to_encode, for_cloud_api=False))) encoded = serializer.encode(to_encode, for_cloud_api=True) self.assertEqual(apitestcase.ENCODED_CLOUD_API_JSON_SAMPLE, encoded) pretty_encoded = serializer.encode(to_encode, is_compound=False, for_cloud_api=True) self.assertEqual(apitestcase.ENCODED_CLOUD_API_JSON_SAMPLE_PRETTY, pretty_encoded) encoded_json = serializer.toJSON(to_encode, for_cloud_api=True) decoded_encoded_json = json.loads(encoded_json) self.assertEqual(encoded, decoded_encoded_json)
def testDepthLimit_withDictionaries(self): x = ee.Dictionary({0: 0}) for i in range(100): x = ee.Dictionary({i: x}) encoded = serializer.encode(x, for_cloud_api=True) self.assertLess(_max_depth(encoded), 60)
def testDepthLimit_withLists(self): x = ee.List([0]) for i in range(100): x = ee.List([i, x]) encoded = serializer.encode(x, for_cloud_api=True) self.assertLess(_max_depth(encoded), 60)
def assertImageEqual(self, expected, actual): self.assertDictEqual( serializer.encode(expected, for_cloud_api=ee.data._use_cloud_api), serializer.encode(actual, for_cloud_api=ee.data._use_cloud_api))
def testExpressionInCloudAPI(self): """Verifies the behavior of ee.Image.expression() in the Cloud API.""" image = ee.Image(1).expression('a', {'b': 'c'}) self.assertEqual( { 'result': '0', 'values': { '0': { 'functionInvocationValue': { 'arguments': { 'b': { 'functionInvocationValue': { 'arguments': { 'id': { 'constantValue': 'c' } }, 'functionName': 'Image.load' } }, 'DEFAULT_EXPRESSION_IMAGE': { 'functionInvocationValue': { 'arguments': { 'value': { 'constantValue': 1 } }, 'functionName': 'Image.constant' } } }, 'functionReference': '1' } }, '1': { 'functionInvocationValue': { 'arguments': { 'expression': { 'constantValue': 'a' }, 'argName': { 'valueReference': '2' }, 'vars': { 'arrayValue': { 'values': [{ 'valueReference': '2' }, { 'constantValue': 'b' }] } } }, 'functionName': 'Image.parseExpression' } }, '2': { 'constantValue': 'DEFAULT_EXPRESSION_IMAGE' } } }, serializer.encode(image, for_cloud_api=True))
def assertImageEqual(self, expected, actual): self.assertDictEqual(serializer.encode(expected), serializer.encode(actual))
def testThumbInCloudApi(self): """Verifies Thumbnail ID and URL generation in the Cloud API.""" geo_json = { 'type': 'Polygon', 'coordinates': [[ [-112.587890625, 44.94924926661151], [-114.873046875, 39.48708498168749], [-103.623046875, 41.82045509614031], ]], } cloud_api_resource = mock.MagicMock() cloud_api_resource.projects().thumbnails().create( ).execute.return_value = { 'name': 'thumbName' } with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource): url = ee.Image(1).getThumbURL({ 'dimensions': [13, 42], 'region': geo_json, 'crs': 'EPSG:4326', }) self.assertEqual('/v1alpha/thumbName:getPixels', url) _, kwargs = cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( kwargs['body']['expression'], serializer.encode(ee.Image(1).setDefaultProjection( crs='EPSG:4326', crsTransform=[1, 0, 0, 0, -1, 0]).clipToBoundsAndScale(geometry=geo_json, width=13, height=42), for_cloud_api=True)) self.assertEqual(kwargs['parent'], 'projects/earthengine-legacy') # Try it with the region as a GeoJSON string. with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource): url = ee.Image(1).getThumbURL({ 'dimensions': [13, 42], 'region': json.dumps(geo_json), }) _, kwargs = cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( kwargs['body']['expression'], serializer.encode(ee.Image(1).clipToBoundsAndScale( geometry=geo_json, width=13, height=42), for_cloud_api=True)) self.assertEqual(kwargs['parent'], 'projects/earthengine-legacy') # Again with visualization parameters with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource): url = ee.Image(1).getThumbURL({ 'dimensions': [13, 42], 'region': geo_json, 'min': 0 }) _, kwargs = cloud_api_resource.projects().thumbnails( ).create.call_args self.assertEqual( kwargs['body']['expression'], serializer.encode(ee.Image(1).clipToBoundsAndScale( geometry=geo_json, width=13, height=42).visualize(min=0), for_cloud_api=True))