Encodes a subtree as a Value in the EE API v2 (DAG) format. If _is_compound is True, this will fill the _scope and _encoded properties. Args: obj: The object to encode. Returns: An encoded object.
(self, obj: Any)
| 107 | return value |
| 108 | |
| 109 | def _encode_value(self, obj: Any) -> Any: |
| 110 | """Encodes a subtree as a Value in the EE API v2 (DAG) format. |
| 111 | |
| 112 | If _is_compound is True, this will fill the _scope and _encoded properties. |
| 113 | |
| 114 | Args: |
| 115 | obj: The object to encode. |
| 116 | |
| 117 | Returns: |
| 118 | An encoded object. |
| 119 | """ |
| 120 | obj_id = id(obj) |
| 121 | hashval = self._hashcache.get(obj_id) |
| 122 | encoded = self._encoded.get(hashval, None) |
| 123 | if self._is_compound and encoded: |
| 124 | # Already encoded objects are encoded as ValueRefs and returned directly. |
| 125 | return {'type': 'ValueRef', 'value': encoded} |
| 126 | elif obj is None or isinstance(obj, (bool, float, int, str)): |
| 127 | # Primitives are encoded as is and not saved in the scope. |
| 128 | return obj |
| 129 | elif isinstance(obj, datetime.datetime): |
| 130 | # A raw date slipped through. Wrap it. Calling ee.Date from here would |
| 131 | # cause a circular dependency, so we encode it manually. |
| 132 | return { |
| 133 | 'type': 'Invocation', |
| 134 | 'functionName': 'Date', |
| 135 | 'arguments': { |
| 136 | 'value': DatetimeToMicroseconds(obj) / 1e3 |
| 137 | } |
| 138 | } |
| 139 | elif isinstance(obj, encodable.Encodable): |
| 140 | # Some objects know how to encode themselves. |
| 141 | result = obj.encode(self._encode_value) |
| 142 | if (not isinstance(result, (list, tuple)) and |
| 143 | (not isinstance(result, (dict)) or result['type'] == 'ArgumentRef')): |
| 144 | # Optimization: simple enough that adding it to the scope is probably |
| 145 | # not worth it. |
| 146 | return result |
| 147 | elif isinstance(obj, encodable.EncodableFunction): |
| 148 | result = obj.encode_invocation(self._encode_value) |
| 149 | if (not isinstance(result, (list, tuple)) and |
| 150 | (not isinstance(result, (dict)) or result['type'] == 'ArgumentRef')): |
| 151 | # Optimization: simple enough that adding it to the scope is probably |
| 152 | # not worth it. |
| 153 | return result |
| 154 | elif isinstance(obj, (list, tuple)): |
| 155 | # Lists are encoded recursively. |
| 156 | result = [self._encode_value(i) for i in obj] |
| 157 | elif isinstance(obj, dict): |
| 158 | # Dictionary are encoded recursively and wrapped in a type specifier. |
| 159 | result = { |
| 160 | 'type': |
| 161 | 'Dictionary', |
| 162 | 'value': |
| 163 | {key: self._encode_value(value) for key, value in obj.items()} |
| 164 | } |
| 165 | else: |
| 166 | raise ee_exception.EEException('Cannot encode object: %s' % obj) |
no test coverage detected