Django

Code

Ticket #7496 (closed: fixed)

Opened 6 months ago

Last modified 3 months ago

Getting cached instance of SortedDict using db cache backend throws AttributeError

Reported by: John Huddleston <huddlej@wwu.edu> Assigned to: huddlej
Milestone: 1.0 Component: Cache system
Version: SVN Keywords:
Cc: Triage Stage: Accepted
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

Description

Using database caching, I set a non-empty SortedDict instance in the cache. When I try to retrieve it, I get an AttributeError with the message "'SortedDict' object has no attribute 'keyOrder'". Here is the code to recreate the problem:

# Using database cache backend
from django.core.cache import cache
from django.utils.datastructures import SortedDict
value = SortedDict()
value['1'] = 1
cache.set('my_dict', value)
cache.get('my_dict')

I looked into the database cache backend and traced the problem to the pickling of the SortedDict instance which can be recreated like this:

import base64
import pickle
from django.utils.datastructures import SortedDict
value = SortedDict()
value['1'] = 1
encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
decoded = pickle.loads(base64.decodestring(encoded))

The call to pickle.loads results in the AttributeError. If the pickling protocol is changed in dumps to 0, the call to loads works. The problem appears to be that protocol 2 calls SortedDict.__new__ instead of creating an empty SortedDict. When __new__ is called, __init__ is not being called so keyOrder is not being initialized.

Possible Solutions:

If this is really unexpected behavior, the problem could be solved by changing the pickle protocol in the database caching backend from 2 to 0. It looks like the database cache backend is the only backend using pickle protocol 2 while the local memory backend is using protocol 0.

Another solution would be to subclass SortedDict.__new__ so keyOrder is always set:

def __new__(cls, *args, **kwargs):
    instance = super(SortedDict, cls).__new__(cls, *args, **kwargs)
    instance.keyOrder = []
    return instance 

I have attached patches reflecting both of these solutions (db.py.diff and datastructures.py.diff, respectively).

Attachments

db.py.diff (0.7 kB) - added by John Huddleston <huddlej@wwu.edu> on 06/18/08 11:20:57.
db cache backend patch
datastructures.py.diff (0.6 kB) - added by John Huddleston <huddlej@wwu.edu> on 06/18/08 11:21:29.
SortedDict patch

Change History

06/18/08 11:20:57 changed by John Huddleston <huddlej@wwu.edu>

  • attachment db.py.diff added.

db cache backend patch

06/18/08 11:21:29 changed by John Huddleston <huddlej@wwu.edu>

  • attachment datastructures.py.diff added.

SortedDict patch

06/26/08 10:31:28 changed by huddlej

  • owner changed from nobody to huddlej.
  • needs_better_patch changed.
  • status changed from new to assigned.
  • needs_tests changed.
  • needs_docs changed.

08/08/08 14:39:30 changed by ericholscher

  • stage changed from Unreviewed to Accepted.
  • milestone set to 1.0.

08/24/08 23:00:24 changed by mtredinnick

  • status changed from assigned to closed.
  • resolution set to fixed.

(In [8531]) Fixed #7496 -- It's now possible to pickle SortedDicts? with pickle protocol 2 (used in caching). Thanks, John Huddleston.


Add/Change #7496 (Getting cached instance of SortedDict using db cache backend throws AttributeError)




Change Properties
Action