diff --git a/google/cloud/datastore/helpers.py b/google/cloud/datastore/helpers.py index d491360c..cdce291c 100644 --- a/google/cloud/datastore/helpers.py +++ b/google/cloud/datastore/helpers.py @@ -18,6 +18,7 @@ """ import datetime +import itertools from google.protobuf import struct_pb2 from google.type import latlng_pb2 @@ -182,7 +183,15 @@ def _set_pb_meaning_from_entity(entity, name, value, value_pb, is_list=False): return elif is_list: # for lists, set meaning on the root pb and on each sub-element - root_meaning, sub_meaning_list = meaning + if isinstance(meaning, tuple): + root_meaning, sub_meaning_list = meaning + else: + # if meaning isn't a tuple, fall back to pre-v2.20.2 meaning format + root_meaning = None + if isinstance(meaning, list): + sub_meaning_list = meaning + else: + sub_meaning_list = itertools.repeat(meaning) if root_meaning is not None: value_pb.meaning = root_meaning if sub_meaning_list: diff --git a/tests/unit/test_helpers.py b/tests/unit/test_helpers.py index a6f63a80..710a6cb7 100644 --- a/tests/unit/test_helpers.py +++ b/tests/unit/test_helpers.py @@ -1318,6 +1318,61 @@ def test__set_pb_meaning_w_value_unset(orig_meaning): assert value_pb.meaning == orig_meaning +def test__set_pb_meaning_w_list_and_single_value(): + """ + v2.20.2 uses a tuple to represent list meanings (https://github.com/googleapis/python-datastore/pull/575) + + This check ensures _set_pb_meaning_from_entity is backwards + compatible with the old meaning style, still used by python-ndb + """ + from google.cloud.datastore_v1.types import entity as entity_pb2 + from google.cloud.datastore.helpers import _set_pb_meaning_from_entity + from google.cloud.datastore.entity import Entity + + orig_root_meaning = 1 + updated_meaning = 22 + orig_pb = entity_pb2.Entity() + value_pb = orig_pb._pb.properties.get_or_create("value") + value_pb.meaning = orig_root_meaning + sub_value_pb1 = value_pb.array_value.values.add() + sub_value_pb2 = value_pb.array_value.values.add() + + entity = Entity(key="key") + entity._meanings = {"value": (updated_meaning, None)} + _set_pb_meaning_from_entity(entity, "value", None, value_pb, is_list=True) + assert value_pb.meaning == orig_root_meaning + assert sub_value_pb1.meaning == updated_meaning + assert sub_value_pb2.meaning == updated_meaning + + +def test__set_pb_meaning_w_list_and_list(): + """ + v2.20.2 uses a tuple to represent list meanings (https://github.com/googleapis/python-datastore/pull/575) + + This check ensures _set_pb_meaning_from_entity is backwards + compatible with the old meaning style, still used by python-ndb + """ + from google.cloud.datastore_v1.types import entity as entity_pb2 + from google.cloud.datastore.helpers import _set_pb_meaning_from_entity + from google.cloud.datastore.entity import Entity + + orig_root_meaning = 1 + updated_meaning_1 = 12 + updated_meaning_2 = 4 + orig_pb = entity_pb2.Entity() + value_pb = orig_pb._pb.properties.get_or_create("value") + value_pb.meaning = orig_root_meaning + sub_value_pb1 = value_pb.array_value.values.add() + sub_value_pb2 = value_pb.array_value.values.add() + + entity = Entity(key="key") + entity._meanings = {"value": ([updated_meaning_1, updated_meaning_2], None)} + _set_pb_meaning_from_entity(entity, "value", None, value_pb, is_list=True) + assert value_pb.meaning == orig_root_meaning + assert sub_value_pb1.meaning == updated_meaning_1 + assert sub_value_pb2.meaning == updated_meaning_2 + + def test__array_w_meaning_end_to_end(): """ Test proto->entity->proto with an array with a meaning field