Search code examples
google-app-engineapp-engine-ndb

Datastore error: BadValueError: Expected integer, got [0, 1, 2, 3]


Others have reported a similar error, but the solutions given do not solve my problem. For example there is a good answer here. The answer in the link mentions how ndb changes from a first use to a later use and suggests there is a problem because a first run produces a None in the Datastore. I cannot reproduce or see that happening in the Datastore for my sdk, but that may be because I am running it here from the interactive console.

I am pretty sure I got an initial good run with the GAE interactive console, but every run since then has failed with the error in my Title to this question.

I have left the print statements in the following code because they show good results and assure me that the error is occuring in the put() at the very end.

from google.appengine.ext import ndb

class Account(ndb.Model):

    week = ndb.IntegerProperty(repeated=True)
    weeksNS = ndb.IntegerProperty(repeated=True)
    weeksEW = ndb.IntegerProperty(repeated=True)

terry=Account(week=[],weeksNS=[],weeksEW=[])
terry_key=terry.put()
terry = terry_key.get()
print terry

for t in list(range(4)):     #just dummy input, but like real input
    terry.week.append(t)
print terry.week

region = 1                   #same error message for region = 0
if region :
    terry.weeksEW.append(terry.week)
else:
    terry.weeksNS.append(terry.week)

print 'EW'+str(terry.weeksEW)
print 'NS'+str(terry.weeksNS)
terry.week = []
print 'week'+str(terry.week)
terry.put()

The idea of my code is to first build up the terry.week list values incrementally and then later store the whole list to the appropriate region, either NS or EW. So I'm looking for a workaround for this scheme.

The error message is likely of no value but I am reproducing it here.

Traceback (most recent call last):
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/runtime/request_handler.py", line 237, in handle_interactive_request
    exec(compiled_code, self._command_globals)
  File "<string>", line 55, in <module>
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 3458, in _put
    return self._put_async(**ctx_options).get_result()
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/tasklets.py", line 383, in get_result
    self.check_success()
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/tasklets.py", line 427, in _help_tasklet_along
    value = gen.throw(exc.__class__, exc, tb)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/context.py", line 824, in put
    key = yield self._put_batcher.add(entity, options)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/tasklets.py", line 430, in _help_tasklet_along
    value = gen.send(val)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/context.py", line 358, in _put_tasklet
    keys = yield self._conn.async_put(options, datastore_entities)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1858, in async_put
    pbs = [entity_to_pb(entity) for entity in entities]
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 697, in entity_to_pb
    pb = ent._to_pb()
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 3167, in _to_pb
    prop._serialize(self, pb, projection=self._projection)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1422, in _serialize
    values = self._get_base_value_unwrapped_as_list(entity)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1192, in _get_base_value_unwrapped_as_list
    wrapped = self._get_base_value(entity)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1180, in _get_base_value
    return self._apply_to_values(entity, self._opt_call_to_base_type)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1352, in _apply_to_values
    value[:] = map(function, value)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1234, in _opt_call_to_base_type
    value = _BaseValue(self._call_to_base_type(value))
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1255, in _call_to_base_type
    return call(value)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1331, in call
    newvalue = method(self, value)
  File "/Users/brian/google-cloud-sdk/platform/google_appengine/google/appengine/ext/ndb/model.py", line 1781, in _validate
    (value,))
BadValueError: Expected integer, got [0, 1, 2, 3]

Solution

  • I believe the error comes from these lines:

    terry.weeksEW.append(terry.week)
    terry.weeksNS.append(terry.week)
    

    You are not appending another integer; You are appending a list, when an integer is expected.

    >>> aaa = [1,2,3]
    >>> bbb = [4,5,6]
    >>> aaa.append(bbb)
    >>> aaa
    [1, 2, 3, [4, 5, 6]]
    >>> 
    

    This fails the ndb.IntegerProperty test.

    Try:

    terry.weeksEW += terry.week
    terry.weeksNS += terry.week
    

    EDIT: To save a list of lists, do not use the IntegerProperty(), but instead the JsonProperty(). Better still, the ndb datastore is deprecated, so... I recommend Firestore, which uses JSON objects by default. At least use Cloud Datastore, or Cloud NDB.