forked from GISGIT/GEE-Python-API
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeserializer.py
More file actions
executable file
·143 lines (119 loc) · 4.79 KB
/
deserializer.py
File metadata and controls
executable file
·143 lines (119 loc) · 4.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python
"""A deserializer that decodes EE object trees from JSON DAGs."""
# Using lowercase function naming to match the JavaScript names.
# pylint: disable=g-bad-name
# pylint: disable=g-bad-import-order
import json
import numbers
import six
from . import apifunction
from . import computedobject
from . import customfunction
from . import ee_date
from . import ee_exception
from . import encodable
from . import function
from . import geometry
def fromJSON(json_obj):
"""Deserialize an object from a JSON string appropriate for API calls.
Args:
json_obj: The JSON represenation of the input.
Returns:
The deserialized object.
"""
return decode(json.loads(json_obj))
def decode(json_obj):
"""Decodes an object previously encoded using the EE API v2 (DAG) format.
Args:
json_obj: The serialied object to decode.
Returns:
The decoded object.
"""
named_values = {}
# Incrementally decode scope entries if there are any.
if isinstance(json_obj, dict) and json_obj['type'] == 'CompoundValue':
for i, (key, value) in enumerate(json_obj['scope']):
if key in named_values:
raise ee_exception.EEException(
'Duplicate scope key "%s" in scope #%d.' % (key, i))
named_values[key] = _decodeValue(value, named_values)
json_obj = json_obj['value']
# Decode the final value.
return _decodeValue(json_obj, named_values)
def _decodeValue(json_obj, named_values):
"""Decodes an object previously encoded using the EE API v2 (DAG) format.
This uses a provided scope for ValueRef lookup and does not not allow the
input to be a CompoundValue.
Args:
json_obj: The serialied object to decode.
named_values: The objects that can be referenced by ValueRefs.
Returns:
The decoded object.
"""
# Check for primitive values.
if (json_obj is None or
isinstance(json_obj, (bool, numbers.Number, six.string_types))):
return json_obj
# Check for array values.
if isinstance(json_obj, (list, tuple)):
return [_decodeValue(element, named_values) for element in json_obj]
# Ensure that we've got a proper object at this point.
if not isinstance(json_obj, dict):
raise ee_exception.EEException('Cannot decode object: ' + json_obj)
# Check for explicitly typed values.
type_name = json_obj['type']
if type_name == 'ValueRef':
if json_obj['value'] in named_values:
return named_values[json_obj['value']]
else:
raise ee_exception.EEException('Unknown ValueRef: ' + json_obj)
elif type_name == 'ArgumentRef':
var_name = json_obj['value']
if not isinstance(var_name, six.string_types):
raise ee_exception.EEException('Invalid variable name: ' + var_name)
return customfunction.CustomFunction.variable(None, var_name) # pylint: disable=protected-access
elif type_name == 'Date':
microseconds = json_obj['value']
if not isinstance(microseconds, numbers.Number):
raise ee_exception.EEException('Invalid date value: ' + microseconds)
return ee_date.Date(microseconds / 1e3)
elif type_name == 'Bytes':
result = encodable.Encodable()
result.encode = lambda encoder: json_obj
return result
elif type_name == 'Invocation':
if 'functionName' in json_obj:
func = apifunction.ApiFunction.lookup(json_obj['functionName'])
else:
func = _decodeValue(json_obj['function'], named_values)
args = dict((key, _decodeValue(value, named_values))
for (key, value) in json_obj['arguments'].items())
if isinstance(func, function.Function):
return func.apply(args)
elif isinstance(func, computedobject.ComputedObject):
# We have to allow ComputedObjects for cases where invocations
# return a function, e.g. Image.parseExpression().
return computedobject.ComputedObject(func, args)
else:
raise ee_exception.EEException(
'Invalid function value: %s' % json_obj['function'])
elif type_name == 'Dictionary':
return dict((key, _decodeValue(value, named_values))
for (key, value) in json_obj['value'].items())
elif type_name == 'Function':
body = _decodeValue(json_obj['body'], named_values)
signature = {
'name': '',
'args': [{'name': arg_name, 'type': 'Object', 'optional': False}
for arg_name in json_obj['argumentNames']],
'returns': 'Object'
}
return customfunction.CustomFunction(signature, lambda *args: body)
elif type_name in ('Point', 'MultiPoint', 'LineString', 'MultiLineString',
'Polygon', 'MultiPolygon', 'LinearRing',
'GeometryCollection'):
return geometry.Geometry(json_obj)
elif type_name == 'CompoundValue':
raise ee_exception.EEException('Nested CompoundValues are disallowed.')
else:
raise ee_exception.EEException('Unknown encoded object type: ' + type_name)