From 0575011529d26ad092f20b7cac6c9546c4007fdc Mon Sep 17 00:00:00 2001 From: Venelin Stoykov Date: Mon, 19 Aug 2013 21:27:50 +0300 Subject: [PATCH 01/12] Add Python 3 suport and drop support for Python 2.5 --- imagekit/cachefiles/__init__.py | 6 +++++- imagekit/cachefiles/strategies.py | 7 +++++-- imagekit/files.py | 10 +++++++--- imagekit/hashers.py | 16 ++++++++++------ imagekit/lib.py | 23 ++++++++++++++++++++--- imagekit/models/fields/__init__.py | 4 +++- imagekit/templatetags/imagekit.py | 12 ++++++++---- imagekit/utils.py | 5 +++-- setup.py | 8 ++++++-- 9 files changed, 67 insertions(+), 24 deletions(-) diff --git a/imagekit/cachefiles/__init__.py b/imagekit/cachefiles/__init__.py index 2c602ff..6e2bf19 100644 --- a/imagekit/cachefiles/__init__.py +++ b/imagekit/cachefiles/__init__.py @@ -120,7 +120,7 @@ class ImageCacheFile(BaseIKFile, ImageFile): ) ) - def __nonzero__(self): + def __bool__(self): if not self.name: return False @@ -129,6 +129,10 @@ class ImageCacheFile(BaseIKFile, ImageFile): existence_required.send(sender=self, file=self) return self.cachefile_backend.exists(self) + def __nonzero__(self): + # Python 2 compatibility + return self.__bool__() + class LazyImageCacheFile(SimpleLazyObject): def __init__(self, generator_id, *args, **kwargs): diff --git a/imagekit/cachefiles/strategies.py b/imagekit/cachefiles/strategies.py index fba6a0f..0d11dae 100644 --- a/imagekit/cachefiles/strategies.py +++ b/imagekit/cachefiles/strategies.py @@ -1,4 +1,7 @@ +import six + from django.utils.functional import LazyObject +from ..lib import force_text from ..utils import get_singleton @@ -35,7 +38,7 @@ class DictStrategy(object): class StrategyWrapper(LazyObject): def __init__(self, strategy): - if isinstance(strategy, basestring): + if isinstance(strategy, six.string_types): strategy = get_singleton(strategy, 'cache file strategy') elif isinstance(strategy, dict): strategy = DictStrategy(strategy) @@ -50,7 +53,7 @@ class StrategyWrapper(LazyObject): self._wrapped = state['_wrapped'] def __unicode__(self): - return unicode(self._wrapped) + return force_text(self._wrapped) def __str__(self): return str(self._wrapped) diff --git a/imagekit/files.py b/imagekit/files.py index fb4375c..e717888 100644 --- a/imagekit/files.py +++ b/imagekit/files.py @@ -1,6 +1,9 @@ -from django.core.files.base import File, ContentFile -from django.utils.encoding import smart_str, smart_unicode +from __future__ import unicode_literals import os + +from django.core.files.base import File, ContentFile +from django.utils.encoding import smart_str +from .lib import smart_text from .utils import format_to_mimetype, extension_to_mimetype @@ -92,4 +95,5 @@ class IKContentFile(ContentFile): return smart_str(self.file.name or '') def __unicode__(self): - return smart_unicode(self.file.name or u'') + # Python 2 + return smart_text(self.file.name or '') diff --git a/imagekit/hashers.py b/imagekit/hashers.py index 4231fa5..12825bd 100644 --- a/imagekit/hashers.py +++ b/imagekit/hashers.py @@ -1,12 +1,16 @@ from copy import copy from hashlib import md5 -from pickle import Pickler, MARK, DICT -from types import DictionaryType +from pickle import MARK, DICT +try: + from pickle import _Pickler +except ImportError: + # Python 2 compatible + from pickle import Pickler as _Pickler from .lib import StringIO -class CanonicalizingPickler(Pickler): - dispatch = copy(Pickler.dispatch) +class CanonicalizingPickler(_Pickler): + dispatch = copy(_Pickler.dispatch) def save_set(self, obj): rv = obj.__reduce_ex__(0) @@ -20,9 +24,9 @@ class CanonicalizingPickler(Pickler): write(MARK + DICT) self.memoize(obj) - self._batch_setitems(sorted(obj.iteritems())) + self._batch_setitems(sorted(obj.items())) - dispatch[DictionaryType] = save_dict + dispatch[dict] = save_dict def pickle(obj): diff --git a/imagekit/lib.py b/imagekit/lib.py index 6da2bfb..4fe2c05 100644 --- a/imagekit/lib.py +++ b/imagekit/lib.py @@ -19,9 +19,12 @@ except ImportError: raise ImportError('ImageKit was unable to import the Python Imaging Library. Please confirm it`s installed and available on your current Python path.') try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO + from io import BytesIO as StringIO +except: + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO try: from logging import NullHandler @@ -31,3 +34,17 @@ except ImportError: class NullHandler(Handler): def emit(self, record): pass + +# Try to import `force_text` available from Django 1.5 +# This function will replace `unicode` used in the code +# If Django version is under 1.5 then use `force_unicde` +# It is used for compatibility between Python 2 and Python 3 +# NOTE: I'm not sure if this is the right place. Maybe this can be in `utils`. +try: + from django.utils.encoding import force_text, smart_text +except ImportError: + # Django < 1.5 + from django.utils.encoding import force_unicode as force_text, smart_unicode as smart_text + +__all__ = ['Image', 'ImageColor', 'ImageChops', 'ImageEnhance', 'ImageFile', 'ImageFilter', + 'ImageDraw', 'ImageStat', 'StringIO', 'NullHandler', 'force_text', 'smart_text'] diff --git a/imagekit/models/fields/__init__.py b/imagekit/models/fields/__init__.py index 91c6252..e2ccf26 100644 --- a/imagekit/models/fields/__init__.py +++ b/imagekit/models/fields/__init__.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django.db import models from .files import ProcessedImageFieldFile from .utils import ImageSpecFileDescriptor @@ -13,7 +15,7 @@ class SpecHostField(SpecHost): # Generate a spec_id to register the spec with. The default spec id is # ":_" if not spec_id: - spec_id = (u'%s:%s:%s' % (cls._meta.app_label, + spec_id = ('%s:%s:%s' % (cls._meta.app_label, cls._meta.object_name, name)).lower() # Register the spec with the id. This allows specs to be overridden diff --git a/imagekit/templatetags/imagekit.py b/imagekit/templatetags/imagekit.py index 2df5b4d..25c2cca 100644 --- a/imagekit/templatetags/imagekit.py +++ b/imagekit/templatetags/imagekit.py @@ -1,9 +1,13 @@ +from __future__ import unicode_literals + from django import template from django.utils.html import escape from django.utils.safestring import mark_safe + from .compat import parse_bits from ..cachefiles import ImageCacheFile from ..registry import generator_registry +from ..lib import force_text register = template.Library() @@ -40,7 +44,7 @@ class GenerateImageAssignmentNode(template.Node): self._variable_name = variable_name def get_variable_name(self, context): - return unicode(self._variable_name) + return force_text(self._variable_name) def render(self, context): variable_name = self.get_variable_name(context) @@ -70,7 +74,7 @@ class GenerateImageTagNode(template.Node): attrs['src'] = file.url attr_str = ' '.join('%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items()) - return mark_safe(u'' % attr_str) + return mark_safe('' % attr_str) class ThumbnailAssignmentNode(template.Node): @@ -83,7 +87,7 @@ class ThumbnailAssignmentNode(template.Node): self._generator_kwargs = generator_kwargs def get_variable_name(self, context): - return unicode(self._variable_name) + return force_text(self._variable_name) def render(self, context): variable_name = self.get_variable_name(context) @@ -131,7 +135,7 @@ class ThumbnailImageTagNode(template.Node): attrs['src'] = file.url attr_str = ' '.join('%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items()) - return mark_safe(u'' % attr_str) + return mark_safe('' % attr_str) def parse_ik_tag_bits(parser, bits): diff --git a/imagekit/utils.py b/imagekit/utils.py index 13bd843..598be43 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import logging from tempfile import NamedTemporaryFile @@ -11,7 +12,7 @@ import re from .lib import NullHandler -bad_memcached_key_chars = re.compile(ur'[\u0000-\u001f\s]+') +bad_memcached_key_chars = re.compile(r'[\u0000-\u001f\s]+') _autodiscovered = False @@ -32,7 +33,7 @@ def get_by_qname(path, desc): module, objname = path[:dot], path[dot + 1:] try: mod = import_module(module) - except ImportError, e: + except ImportError as e: raise ImproperlyConfigured('Error importing %s module %s: "%s"' % (desc, module, e)) try: diff --git a/setup.py b/setup.py index da959a0..2f30679 100644 --- a/setup.py +++ b/setup.py @@ -19,10 +19,12 @@ if 'publish' in sys.argv: read = lambda filepath: codecs.open(filepath, 'r', 'utf-8').read() +def exec_file(filepath, globalz=None, localz=None): + exec(read(filepath), globalz, localz) # Load package meta from the pkgmeta module without loading imagekit. pkgmeta = {} -execfile(os.path.join(os.path.dirname(__file__), +exec_file(os.path.join(os.path.dirname(__file__), 'imagekit', 'pkgmeta.py'), pkgmeta) @@ -51,6 +53,7 @@ setup( install_requires=[ 'django-appconf>=0.5', 'pilkit>=0.2.0', + 'six', ], extras_require={ 'async': ['django-celery>=3.0'], @@ -62,9 +65,10 @@ setup( 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', 'Topic :: Utilities' ], ) From 183efabca7573c29908f38de160dd86074a2be2c Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Sun, 1 Sep 2013 21:55:37 -0400 Subject: [PATCH 02/12] Delay Django import until needed --- imagekit/importers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagekit/importers.py b/imagekit/importers.py index cddcd83..b2896cf 100644 --- a/imagekit/importers.py +++ b/imagekit/importers.py @@ -1,4 +1,3 @@ -from django.utils.importlib import import_module import re import sys @@ -22,6 +21,7 @@ class ProcessorImporter(object): if name in sys.modules: return sys.modules[name] + from django.utils.importlib import import_module new_name = self.pattern.sub(r'pilkit.processors\1', name) return import_module(new_name) From 3732b2ee099989ed46e264f031b9b47c414cf6c6 Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Sun, 1 Sep 2013 21:55:58 -0400 Subject: [PATCH 03/12] Insert importer at beginning of list --- imagekit/importers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagekit/importers.py b/imagekit/importers.py index b2896cf..67d2b51 100644 --- a/imagekit/importers.py +++ b/imagekit/importers.py @@ -26,4 +26,4 @@ class ProcessorImporter(object): return import_module(new_name) -sys.meta_path.append(ProcessorImporter()) +sys.meta_path.insert(0, ProcessorImporter()) From 2e4d435f4f9c7f582ef9db4b00941bec4a87cea6 Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Sun, 1 Sep 2013 21:56:28 -0400 Subject: [PATCH 04/12] Test for Python 3 --- setup.py | 6 +++--- tox.ini | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 2f30679..c54c041 100644 --- a/setup.py +++ b/setup.py @@ -44,9 +44,9 @@ setup( include_package_data=True, tests_require=[ 'beautifulsoup4==4.1.3', - 'nose==1.2.1', - 'nose-progressive==1.3', - 'django-nose==1.1', + 'nose==1.3.0', + 'nose-progressive==1.5', + 'django-nose==1.2', 'Pillow<3.0', ], test_suite='testrunner.run_tests', diff --git a/tox.ini b/tox.ini index 46ca387..1dc2b41 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,23 @@ [tox] envlist = + py33-django15, + py32-django15, py27-django15, py27-django14, py27-django13, py27-django12, py26-django15, py26-django14, py26-django13, py26-django12 [testenv] commands = python setup.py test +[testenv:py33-django15] +basepython = python3.3 +deps = + Django>=1.5,<1.6 + +[testenv:py32-django15] +basepython = python3.2 +deps = + Django>=1.5,<1.6 + [testenv:py27-django15] basepython = python2.7 deps = From bf1b45c943715efd8eef2e73ef77d6681da5658f Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Sun, 1 Sep 2013 21:56:42 -0400 Subject: [PATCH 05/12] Add module to sys.modules --- imagekit/importers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imagekit/importers.py b/imagekit/importers.py index 67d2b51..87ba2b6 100644 --- a/imagekit/importers.py +++ b/imagekit/importers.py @@ -23,7 +23,9 @@ class ProcessorImporter(object): from django.utils.importlib import import_module new_name = self.pattern.sub(r'pilkit.processors\1', name) - return import_module(new_name) + mod = import_module(new_name) + sys.modules[name] = mod + return mod sys.meta_path.insert(0, ProcessorImporter()) From fb947b19374244bc28dbe09100dfd0e628b16ad4 Mon Sep 17 00:00:00 2001 From: Venelin Stoykov Date: Sat, 14 Dec 2013 18:56:47 +0200 Subject: [PATCH 06/12] Fix sanitizing cache key under Python 3 --- imagekit/utils.py | 10 +++++++--- tests/test_cachefiles.py | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/imagekit/utils.py b/imagekit/utils.py index 598be43..baaf234 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -1,14 +1,18 @@ from __future__ import unicode_literals import logging +import re from tempfile import NamedTemporaryFile +from hashlib import md5 from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.files import File from django.utils.importlib import import_module -from hashlib import md5 +try: + from django.utils.encoding import force_bytes +except ImportError: + from django.utils.encoding import smart_str as force_bytes from pilkit.utils import * -import re from .lib import NullHandler @@ -148,7 +152,7 @@ def sanitize_cache_key(key): # The also can't be > 250 chars long. Since we don't know what the # user's cache ``KEY_FUNCTION`` setting is like, we'll limit it to 200. if len(new_key) >= 200: - new_key = '%s:%s' % (new_key[:200-33], md5(key).hexdigest()) + new_key = '%s:%s' % (new_key[:200-33], md5(force_bytes(key)).hexdigest()) key = new_key return key diff --git a/tests/test_cachefiles.py b/tests/test_cachefiles.py index 4338a82..ba250fb 100644 --- a/tests/test_cachefiles.py +++ b/tests/test_cachefiles.py @@ -1,4 +1,8 @@ from django.conf import settings +try: + from django.utils.encoding import force_bytes +except ImportError: + from django.utils.encoding import smart_str as force_bytes from hashlib import md5 from imagekit.cachefiles import ImageCacheFile, LazyImageCacheFile from imagekit.cachefiles.backends import Simple @@ -73,7 +77,7 @@ def test_memcached_cache_key(): eq_(backend.get_key(file), '%s%s:%s' % ( settings.IMAGEKIT_CACHE_PREFIX, '1' * (200 - len(':') - 32 - len(settings.IMAGEKIT_CACHE_PREFIX)), - md5('%s%s-state' % (settings.IMAGEKIT_CACHE_PREFIX, filename)).hexdigest())) + md5(force_bytes('%s%s-state' % (settings.IMAGEKIT_CACHE_PREFIX, filename))).hexdigest())) def test_lazyfile_stringification(): From c1e16696b14a71049985d6a49a4005a2cd93c593 Mon Sep 17 00:00:00 2001 From: Matthew Dapena-Tretter Date: Sat, 14 Dec 2013 12:54:26 -0500 Subject: [PATCH 07/12] Don't use a raw string with \u escapes Apparently, Python 3.2 doesn't process these in raw strings. See https://mail.python.org/pipermail/python-list/2012-May/624756.html and https://mail.python.org/pipermail/python-dev/2007-May/073042.html --- imagekit/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagekit/utils.py b/imagekit/utils.py index baaf234..c889e28 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -16,7 +16,7 @@ from pilkit.utils import * from .lib import NullHandler -bad_memcached_key_chars = re.compile(r'[\u0000-\u001f\s]+') +bad_memcached_key_chars = re.compile('[\u0000-\u001f\\s]+') _autodiscovered = False From 87983c5e6de8030737803791670284ae0bd410ef Mon Sep 17 00:00:00 2001 From: Matthew Dapena-Tretter Date: Sat, 14 Dec 2013 13:02:21 -0500 Subject: [PATCH 08/12] Move force_bytes into lib module --- imagekit/lib.py | 11 +++++++---- imagekit/utils.py | 6 +----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/imagekit/lib.py b/imagekit/lib.py index 4fe2c05..12460c9 100644 --- a/imagekit/lib.py +++ b/imagekit/lib.py @@ -41,10 +41,13 @@ except ImportError: # It is used for compatibility between Python 2 and Python 3 # NOTE: I'm not sure if this is the right place. Maybe this can be in `utils`. try: - from django.utils.encoding import force_text, smart_text + from django.utils.encoding import force_text, force_bytes, smart_text except ImportError: # Django < 1.5 - from django.utils.encoding import force_unicode as force_text, smart_unicode as smart_text + from django.utils.encoding import (force_unicode as force_text, + smart_str as force_bytes, + smart_unicode as smart_text) -__all__ = ['Image', 'ImageColor', 'ImageChops', 'ImageEnhance', 'ImageFile', 'ImageFilter', - 'ImageDraw', 'ImageStat', 'StringIO', 'NullHandler', 'force_text', 'smart_text'] +__all__ = ['Image', 'ImageColor', 'ImageChops', 'ImageEnhance', 'ImageFile', + 'ImageFilter', 'ImageDraw', 'ImageStat', 'StringIO', 'NullHandler', + 'force_text', 'force_bytes', 'smart_text'] diff --git a/imagekit/utils.py b/imagekit/utils.py index c889e28..0973d35 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -8,12 +8,8 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.files import File from django.utils.importlib import import_module -try: - from django.utils.encoding import force_bytes -except ImportError: - from django.utils.encoding import smart_str as force_bytes from pilkit.utils import * -from .lib import NullHandler +from .lib import NullHandler, force_bytes bad_memcached_key_chars = re.compile('[\u0000-\u001f\\s]+') From 45f10075b644dc00f3a274223cc1d9aacd1af24b Mon Sep 17 00:00:00 2001 From: Matthew Dapena-Tretter Date: Sat, 14 Dec 2013 13:03:02 -0500 Subject: [PATCH 09/12] Remove @vstoykov's note. Seems like the right place to me (: --- imagekit/lib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/imagekit/lib.py b/imagekit/lib.py index 12460c9..5a4240b 100644 --- a/imagekit/lib.py +++ b/imagekit/lib.py @@ -39,7 +39,6 @@ except ImportError: # This function will replace `unicode` used in the code # If Django version is under 1.5 then use `force_unicde` # It is used for compatibility between Python 2 and Python 3 -# NOTE: I'm not sure if this is the right place. Maybe this can be in `utils`. try: from django.utils.encoding import force_text, force_bytes, smart_text except ImportError: From 8a600d30b32aee0dd95ff28c02c6e211e6749160 Mon Sep 17 00:00:00 2001 From: Venelin Stoykov Date: Sun, 15 Dec 2013 01:58:22 +0200 Subject: [PATCH 10/12] Use force_bytes from imagekit.lib in test_cachefiles --- tests/test_cachefiles.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_cachefiles.py b/tests/test_cachefiles.py index ba250fb..8a93e71 100644 --- a/tests/test_cachefiles.py +++ b/tests/test_cachefiles.py @@ -1,11 +1,8 @@ from django.conf import settings -try: - from django.utils.encoding import force_bytes -except ImportError: - from django.utils.encoding import smart_str as force_bytes from hashlib import md5 from imagekit.cachefiles import ImageCacheFile, LazyImageCacheFile from imagekit.cachefiles.backends import Simple +from imagekit.lib import force_bytes from nose.tools import raises, eq_ from .imagegenerators import TestSpec from .utils import (assert_file_is_truthy, assert_file_is_falsy, From 26aa19eeef7cbc679f87f7482651386df47d7410 Mon Sep 17 00:00:00 2001 From: Venelin Stoykov Date: Sun, 15 Dec 2013 02:34:25 +0200 Subject: [PATCH 11/12] Improve logic of contributing ImageSpecFields to Models - If `source` is defined then register source group immediately - If `source` is not defined then create a signal handler and attach it to `class_prepared` signal which will see if there is only one ImageField in the given model. This will fix problems coused in Python 3 about using ImageSpecField without providing a `source`. --- imagekit/models/fields/__init__.py | 51 +++++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/imagekit/models/fields/__init__.py b/imagekit/models/fields/__init__.py index e2ccf26..61a7dd3 100644 --- a/imagekit/models/fields/__init__.py +++ b/imagekit/models/fields/__init__.py @@ -1,6 +1,8 @@ from __future__ import unicode_literals from django.db import models +from django.db.models.signals import class_prepared +from django.dispatch import receiver from .files import ProcessedImageFieldFile from .utils import ImageSpecFileDescriptor from ...specs import SpecHost @@ -46,27 +48,38 @@ class ImageSpecField(SpecHostField): def contribute_to_class(self, cls, name): # If the source field name isn't defined, figure it out. - source = self.source - if not source: - image_fields = [f.attname for f in cls._meta.fields if - isinstance(f, models.ImageField)] - if len(image_fields) == 0: - raise Exception( - '%s does not define any ImageFields, so your %s' - ' ImageSpecField has no image to act on.' % - (cls.__name__, name)) - elif len(image_fields) > 1: - raise Exception( - '%s defines multiple ImageFields, but you have not' - ' specified a source for your %s ImageSpecField.' % - (cls.__name__, name)) - source = image_fields[0] - setattr(cls, name, ImageSpecFileDescriptor(self, name, source)) - self._set_spec_id(cls, name) + def register_source_group(source): + setattr(cls, name, ImageSpecFileDescriptor(self, name, source)) + self._set_spec_id(cls, name) + + # Add the model and field as a source for this spec id + register.source_group(self.spec_id, ImageFieldSourceGroup(cls, source)) + + if self.source: + register_source_group(self.source) + else: + # The source argument is not defined + # Then we need to see if there is only one ImageField in that model + # But we need to do that after full model initialization + + @receiver(class_prepared, sender=cls, weak=False) + def handle_model_preparation(sender, **kwargs): + + image_fields = [f.attname for f in cls._meta.fields if + isinstance(f, models.ImageField)] + if len(image_fields) == 0: + raise Exception( + '%s does not define any ImageFields, so your %s' + ' ImageSpecField has no image to act on.' % + (cls.__name__, name)) + elif len(image_fields) > 1: + raise Exception( + '%s defines multiple ImageFields, but you have not' + ' specified a source for your %s ImageSpecField.' % + (cls.__name__, name)) + register_source_group(image_fields[0]) - # Add the model and field as a source for this spec id - register.source_group(self.spec_id, ImageFieldSourceGroup(cls, source)) class ProcessedImageField(models.ImageField, SpecHostField): From 3667c09d8221681d68e9ad93504d3380b61f889b Mon Sep 17 00:00:00 2001 From: Venelin Stoykov Date: Mon, 16 Dec 2013 22:38:05 +0200 Subject: [PATCH 12/12] Add Venelin Stoykov to AUTHORS --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 255827b..6f4c238 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,6 +28,7 @@ Contributors * `Jannis Leidel`_ * `Sean Bell`_ * `Saul Shanabrook`_ +* `Venelin Stoykov`_ .. _Justin Driscoll: http://github.com/jdriscoll .. _HZDG: http://hzdg.com @@ -49,3 +50,4 @@ Contributors .. _Jannis Leidel: https://github.com/jezdez .. _Sean Bell: https://github.com/seanbell .. _Saul Shanabrook: https://github.com/saulshanabrook +.. _Venelin Stoykov: https://github.com/vstoykov