Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.
This repository was archived by the owner on Mar 6, 2026. It is now read-only.

[python 2.7, google-cloud-ndb==0.2.0] StringProperty(repeated=True) deserializes list of empty strings into list of None #300

@VladNF

Description

@VladNF

Environment details

  1. mkvirtualenv py2-ndb-issue -p python2
  2. pip install google-cloud-ndb==0.2.0 pytest pytest-env
  3. Cloud SDK
    Google Cloud SDK 274.0.0
    app-engine-python 1.9.87
    app-engine-python-extras 1.9.87
    beta 2019.05.17
    bq 2.0.51
    cloud-datastore-emulator 2.1.0
    core 2019.12.17
    gsutil 4.46
  4. run with datastore emulator (same behavior in a GCP env)

Steps to reproduce

  1. Define a model with a repeated string property
  2. Set this property to list of empty string and put into the datastore
  3. Get entity from the datastore, verify a value should equals to the list of empty strings
  4. Actual behavior - you get list of None.

Code example

class NullableModel(ndb.Model):
    list_prop = ndb.StringProperty(repeated=True)
    ord_prop = ndb.StringProperty()
    # child3 = NullableStringProperty(repeated=True)

@pytest.mark.parametrize("changeset", [
    ["abc", u"абв"],
    ["", ""],
    [u"", u""],
])
def test_repeated_string_property_none(changeset):
    entity = NullableModel()
    entity.list_prop = changeset
    entity.ord_prop = ""
    entity.put()

    entity = entity.key.get()
    assert entity.ord_prop == ""
    assert entity.list_prop == changeset
    assert entity.put()

Stack trace

============================= test session starts ==============================
platform darwin -- Python 2.7.16, pytest-4.6.9, py-1.8.1, pluggy-0.13.1 -- /Users/vladimir/Virtualenvs/py2-ndb-issue/bin/python2
cachedir: .pytest_cache
rootdir: /Users/vladimir/Projects/py2-ndb-issues, inifile: setup.cfg
plugins: env-0.6.2
collecting ... collected 4 items

test_get_multi.py::test_create_many_change_one_get_multi_all PASSED      [ 25%]
test_get_multi.py::test_repeated_string_property_none[changeset0] 
test_get_multi.py::test_repeated_string_property_none[changeset1] PASSED [ 50%]FAILED [ 75%]
test_get_multi.py:73 (test_repeated_string_property_none[changeset1])
[None, None] != ['', '']

Expected :['', '']
Actual   :[None, None]
<Click to see difference>

changeset = ['', '']

    @pytest.mark.parametrize("changeset", [
        ["abc", u"абв"],
        ["", ""],
        [u"", u""],
    ])
    def test_repeated_string_property_none(changeset):
        entity = NullableModel()
        entity.list_prop = changeset
        entity.ord_prop = ""
        entity.put()
    
        entity = entity.key.get()
        assert entity.ord_prop == ""
>       assert entity.list_prop == changeset
E       AssertionError: assert [None, None] == ['', '']

test_get_multi.py:87: AssertionError
FAILED [100%]
test_get_multi.py:73 (test_repeated_string_property_none[changeset2])
[None, None] != [u'', u'']

Expected :[u'', u'']
Actual   :[None, None]
<Click to see difference>

changeset = ['', '']

    @pytest.mark.parametrize("changeset", [
        ["abc", u"абв"],
        ["", ""],
        [u"", u""],
    ])
    def test_repeated_string_property_none(changeset):
        entity = NullableModel()
        entity.list_prop = changeset
        entity.ord_prop = ""
        entity.put()
    
        entity = entity.key.get()
        assert entity.ord_prop == ""
>       assert entity.list_prop == changeset
E       AssertionError: assert [None, None] == [u'', u'']

test_get_multi.py:87: AssertionError

Assertion failed

test_get_multi.py::test_repeated_string_property_none[changeset2]

The issue seems are in model.py#_entity_from_ds_entity and the following part of the method just in the end ** if sub_value else None **

        if value is not None:
            if prop._repeated:
                value = [
                    (_BaseValue(sub_value) if sub_value else None)
                    for sub_value in value
                ]
            else:
                value = _BaseValue(value)

Metadata

Metadata

Assignees

Labels

🚨This issue needs some love.priority: p1Important issue which blocks shipping the next release. Will be fixed prior to next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions