Search code examples
google-app-enginepickleapp-engine-ndbdefaultdict

Pickling on GAE ndb


I am trying to pickle and unpickle structured data into an ndb.PickleProperty() property like so:

month = MonthRecord.get_or_insert(month_yr_str, parent=ndb.Key('Type','Grocery'), record=pickle.dumps(defaultdict(list_list)))
names_dict = pickle.loads(month.record) # unpickle for updating
# ...                                   # some modifications on names_dict
month.record = pickle.dumps(names_dict) # pickle
month.put()                             # commit changes

where the model MonthRecord is defined as:

class MonthRecord(ndb.Model):
    record = ndb.PickleProperty() # {name: [[date&time],[expenses]]}

and list_list as:

def list_list(): # placeholder function needed by pickle at module level
    return [[],[]]

The first run works fine (where insert case is hit in get_or_insert, creating a new MonthRecord entity). However, during succeeding runs (i.e. new expenses within current month to be recorded) the following error occurs:

Traceback (most recent call last):
  File "C:\GAE_Projects\qb_lite\fin.py", line 31, in update_db
    names_dict = pickle.loads(month.record)
  File "C:\Python27\lib\pickle.py", line 1382, in loads
    return Unpickler(file).load()
  File "C:\Python27\lib\pickle.py", line 858, in load
    dispatch[key](self)
  File "C:\Python27\lib\pickle.py", line 1133, in load_reduce
    value = func(*args)
TypeError: __init__() takes exactly 4 arguments (1 given)

Any ideas as to the cause of error?


Solution

  • You don't have to pickle your objects, that will be handled by PickleProperty.

    Instead of:

    month = MonthRecord.get_or_insert(
        month_yr_str,
        parent=ndb.Key('Type','Grocery'),
        record=pickle.dumps(defaultdict(list_list)))
    

    do:

    month = MonthRecord.get_or_insert(
        month_yr_str,
        parent=ndb.Key('Type','Grocery'),
        record=defaultdict(list_list))
    

    Pickling and unpickling will be taken care of internally.