1818"""
1919
2020import datetime
21+ import itertools
2122
2223from google .protobuf import struct_pb2
2324from google .type import latlng_pb2
@@ -45,10 +46,9 @@ def _get_meaning(value_pb, is_list=False):
4546
4647 :rtype: int
4748 :returns: The meaning for the ``value_pb`` if one is set, else
48- :data:`None`.
49- :raises: :class:`ValueError <exceptions.ValueError>` if a list value
50- has disagreeing meanings (in sub-elements) or has some
51- elements with meanings and some without.
49+ :data:`None`. For a list value, if there are disagreeing
50+ means it just returns a list of meanings. If all the
51+ list meanings agree, it just condenses them.
5252 """
5353 meaning = None
5454 if is_list :
@@ -59,15 +59,15 @@ def _get_meaning(value_pb, is_list=False):
5959
6060 # We check among all the meanings, some of which may be None,
6161 # the rest which may be enum/int values.
62- all_meanings = set ( _get_meaning (sub_value_pb )
63- for sub_value_pb in value_pb .array_value .values )
64- meaning = all_meanings . pop ( )
65- # The value we popped off should have been unique. If not
66- # then we can't handle a list with values that have more
67- # than one meaning.
68- if all_meanings :
69- raise ValueError ( 'Different meanings set on values '
70- 'within an array_value' )
62+ all_meanings = [ _get_meaning (sub_value_pb )
63+ for sub_value_pb in value_pb .array_value .values ]
64+ unique_meanings = set ( all_meanings )
65+ if len ( unique_meanings ) == 1 :
66+ # If there is a unique meaning, we preserve it.
67+ meaning = unique_meanings . pop ()
68+ else : # We know len(value_pb.array_value.values) > 0.
69+ # If the meaning is not unique, just return all of them.
70+ meaning = all_meanings
7171 elif value_pb .meaning : # Simple field (int32)
7272 meaning = value_pb .meaning
7373
@@ -155,6 +155,48 @@ def entity_from_protobuf(pb):
155155 return entity
156156
157157
158+ def _set_pb_meaning_from_entity (entity , name , value , value_pb ,
159+ is_list = False ):
160+ """Add meaning information (from an entity) to a protobuf.
161+
162+ :type entity: :class:`gcloud.datastore.entity.Entity`
163+ :param entity: The entity to be turned into a protobuf.
164+
165+ :type name: string
166+ :param name: The name of the property.
167+
168+ :type value: object
169+ :param value: The current value stored as property ``name``.
170+
171+ :type value_pb: :class:`gcloud.datastore._generated.entity_pb2.Value`
172+ :param value_pb: The protobuf value to add meaning / meanings to.
173+
174+ :type is_list: bool
175+ :param is_list: (Optional) Boolean indicating if the ``value`` is
176+ a list value.
177+ """
178+ if name not in entity ._meanings :
179+ return
180+
181+ meaning , orig_value = entity ._meanings [name ]
182+ # Only add the meaning back to the protobuf if the value is
183+ # unchanged from when it was originally read from the API.
184+ if orig_value is not value :
185+ return
186+
187+ # For lists, we set meaning on each sub-element.
188+ if is_list :
189+ if not isinstance (meaning , list ):
190+ meaning = itertools .repeat (meaning )
191+ val_iter = six .moves .zip (value_pb .array_value .values ,
192+ meaning )
193+ for sub_value_pb , sub_meaning in val_iter :
194+ if sub_meaning is not None :
195+ sub_value_pb .meaning = sub_meaning
196+ else :
197+ value_pb .meaning = meaning
198+
199+
158200def entity_to_protobuf (entity ):
159201 """Converts an entity into a protobuf.
160202
@@ -187,17 +229,8 @@ def entity_to_protobuf(entity):
187229 sub_value .exclude_from_indexes = True
188230
189231 # Add meaning information to protobuf.
190- if name in entity ._meanings :
191- meaning , orig_value = entity ._meanings [name ]
192- # Only add the meaning back to the protobuf if the value is
193- # unchanged from when it was originally read from the API.
194- if orig_value is value :
195- # For lists, we set meaning on each sub-element.
196- if value_is_list :
197- for sub_value_pb in value_pb .array_value .values :
198- sub_value_pb .meaning = meaning
199- else :
200- value_pb .meaning = meaning
232+ _set_pb_meaning_from_entity (entity , name , value , value_pb ,
233+ is_list = value_is_list )
201234
202235 return entity_pb
203236
0 commit comments