From d80f426d3cbb24bbdb0d92cba3ba7f9484767104 Mon Sep 17 00:00:00 2001 From: Roman Gorbil Date: Tue, 10 Oct 2017 17:39:46 +0700 Subject: [PATCH] Fix `ImageCacheFile.__repr__` to not send signals Cachefile strategy may be configured to generate file when file existance required. To generate images, async backends passes `ImageCacheFile` instance to worker. Both celery and RQ calls `__repr__` method for each argument to enque call. And if `__repr__` of object will send `existnace_required` signal, we will get endless recursion. Issue: #434 --- imagekit/cachefiles/__init__.py | 6 ++++++ tests/test_cachefiles.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/imagekit/cachefiles/__init__.py b/imagekit/cachefiles/__init__.py index 2ba5cb8..594df57 100644 --- a/imagekit/cachefiles/__init__.py +++ b/imagekit/cachefiles/__init__.py @@ -3,6 +3,7 @@ from django.conf import settings from django.core.files import File from django.core.files.images import ImageFile from django.utils.functional import SimpleLazyObject +from django.utils.encoding import smart_str from ..files import BaseIKFile from ..registry import generator_registry from ..signals import content_required, existence_required @@ -149,6 +150,11 @@ class ImageCacheFile(BaseIKFile, ImageFile): # Python 2 compatibility return self.__bool__() + def __repr__(self): + return smart_str("<%s: %s>" % ( + self.__class__.__name__, self if self.name else "None") + ) + class LazyImageCacheFile(SimpleLazyObject): def __init__(self, generator_id, *args, **kwargs): diff --git a/tests/test_cachefiles.py b/tests/test_cachefiles.py index 8a93e71..ad01dda 100644 --- a/tests/test_cachefiles.py +++ b/tests/test_cachefiles.py @@ -1,3 +1,4 @@ +import mock from django.conf import settings from hashlib import md5 from imagekit.cachefiles import ImageCacheFile, LazyImageCacheFile @@ -48,6 +49,31 @@ def test_no_source_error(): file.generate() +def test_repr_does_not_send_existence_required(): + """ + Ensure that `__repr__` method does not send `existance_required` signal + + Cachefile strategy may be configured to generate file on + `existance_required`. + To generate images, backend passes `ImageCacheFile` instance to worker. + Both celery and RQ calls `__repr__` method for each argument to enque call. + And if `__repr__` of object will send this signal, we will get endless + recursion + + """ + with mock.patch('imagekit.cachefiles.existence_required') as signal: + # import here to apply mock + from imagekit.cachefiles import ImageCacheFile + + spec = TestSpec(source=get_unique_image_file()) + file = ImageCacheFile( + spec, + cachefile_backend=DummyAsyncCacheFileBackend() + ) + file.__repr__() + eq_(signal.send.called, False) + + def test_memcached_cache_key(): """ Ensure the default cachefile backend is sanitizing its cache key for