Skip to content

Commit 8516478

Browse files
authored
fix: support polymodel in local structured property (#497)
refs #481
1 parent 6e37f77 commit 8516478

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

packages/google-cloud-ndb/google/cloud/ndb/model.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,12 @@ def new_entity(key):
636636

637637
continue
638638

639+
if prop is None and kind != model_class.__name__:
640+
# kind and model_class name do not match, so this is probably a
641+
# polymodel. We need to check if the prop belongs to the subclass.
642+
model_subclass = Model._lookup_model(kind)
643+
prop = getattr(model_subclass, name, None)
644+
639645
def base_value_or_none(value):
640646
return None if value is None else _BaseValue(value)
641647

@@ -4357,7 +4363,14 @@ def _from_base_type(self, value):
43574363
value = entity_value
43584364
if not self._keep_keys and value.key:
43594365
value.key = None
4360-
return _entity_from_ds_entity(value, model_class=self._model_class)
4366+
model_class = self._model_class
4367+
kind = self._model_class.__name__
4368+
if "class" in value and value["class"]:
4369+
kind = value["class"][-1] or model_class
4370+
if kind != self._model_class.__name__:
4371+
# if this is a polymodel, find correct subclass.
4372+
model_class = Model._lookup_model(kind)
4373+
return _entity_from_ds_entity(value, model_class=model_class)
43614374

43624375
def _prepare_for_put(self, entity):
43634376
values = self._get_user_value(entity)

packages/google-cloud-ndb/tests/system/test_crud.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,3 +1473,27 @@ class SomeKind(ndb.Model):
14731473
ourkind.bar = "confusing"
14741474

14751475
assert somekind.bar is None
1476+
1477+
1478+
@pytest.mark.usefixtures("client_context")
1479+
def test_local_structured_property_with_polymodel(dispose_of):
1480+
"""Regression test for #481
1481+
1482+
https://github.com/googleapis/python-ndb/issues/481
1483+
"""
1484+
1485+
class Base(ndb.PolyModel):
1486+
pass
1487+
1488+
class SubKind(Base):
1489+
foo = ndb.StringProperty()
1490+
1491+
class Container(ndb.Model):
1492+
child = ndb.LocalStructuredProperty(Base)
1493+
1494+
entity = Container(child=SubKind(foo="bar"))
1495+
key = entity.put()
1496+
dispose_of(key._key)
1497+
1498+
entity = entity.key.get()
1499+
assert entity.child.foo == "bar"

packages/google-cloud-ndb/tests/unit/test_model.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3863,6 +3863,34 @@ class ContainerA(model.Model):
38633863
assert data.pop("_exclude_from_indexes") == ["child_a"]
38643864
assert data["child_a"]["child_b"] is None
38653865

3866+
@staticmethod
3867+
def test_local_structured_property_with_polymodel(in_context):
3868+
class Base(polymodel.PolyModel):
3869+
pass
3870+
3871+
class SubKind(Base):
3872+
foo = model.StringProperty()
3873+
3874+
class Container(model.Model):
3875+
child = model.LocalStructuredProperty(Base)
3876+
3877+
entity = Container(child=SubKind(foo="bar"))
3878+
value = b"".join(
3879+
[
3880+
b"\x1a \n\x05class\x12\x17J\x15\n\x07\x8a\x01\x04Base\n\n",
3881+
b"\x8a\x01\x07SubKind\x1a\r\n\x03foo\x12\x06\x8a\x01\x03bar",
3882+
]
3883+
)
3884+
3885+
child = entity._properties["child"]._from_base_type(value)
3886+
assert child.foo == "bar"
3887+
3888+
pb = entity_pb2.Entity()
3889+
pb.MergeFromString(value)
3890+
value = helpers.entity_from_protobuf(pb)
3891+
child = model._entity_from_ds_entity(value, model_class=Base)
3892+
assert child._values["foo"].b_val == "bar"
3893+
38663894

38673895
class TestGenericProperty:
38683896
@staticmethod

0 commit comments

Comments
 (0)