sybrenstuvel / flickrapi

Python Flickr API implementation
https://stuvel.eu/flickrapi
Other
155 stars 33 forks source link

MemcachedKeyCharacterError: Control/space characters not allowed #122

Open euan-forrester opened 5 years ago

euan-forrester commented 5 years ago

When trying to use this package with memcached, I get the following error:

memcache.MemcachedKeyCharacterError: Control/space characters not allowed (key=b":1:{'user_id': '86466248@N00', 'extras': 'url_l,url_m', 'per_page': 500, 'page': 1, 'method': 'flickr.favorites.getList', 'format': 'json', 'nojsoncallback': 1}")

It looks like the issue is the space character in the key name, and this seems similar to https://github.com/sybrenstuvel/flickrapi/issues/29

I didn't see any resolution in that issue, but the suggestion of replacing the space character with a $ or similar character seems sound to me.

Any chance that this is a quick fix?

Thanks very much! I've enjoyed using this package so far: it's helped me get up and running quickly!

euan-forrester commented 5 years ago

After spending some time looking in the django and flickrapi source code, I came up with the following solution/workaround. I had to do quite a lot of googling to get memcached to work with this package, so hopefully this is helpful for someone else:

from django.core.cache import cache
from django.conf import settings
def make_memcached_key(key, key_prefix, version):
    # Similar to the default key function, except that we translate the key first. The FlickrAPI package
    # uses objects as keys, then calls repr() on it to translate it into a string. This means the string will have 
    # spaces in the name, but memcached won't accept spaces in the key names, so we have to replace those

    translated_key = repr(key).replace(' ', '$')

    return '%s:%s:%s' % (key_prefix, version, translated_key)

settings.configure(CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': memcached_location,
        'KEY_FUNCTION' : make_memcached_key,
    }
})

and then I was able to use the django cache as it said in the flickrapi documentation:

flickr = flickrapi.FlickrAPI(flickr_api_key, flickr_api_secret, format='parsed-json', cache=True)
flickr.cache = cache

The crux of the issue seems to be that flickrapi passes a dictionary as the key, whereas django expects a string. This workaround solves my issue, but I wanted to post it here in case it's helpful for someone else.