diff --git a/imagekit/conf.py b/imagekit/conf.py index 7eb3afc..4c39edc 100644 --- a/imagekit/conf.py +++ b/imagekit/conf.py @@ -3,11 +3,11 @@ from django.conf import settings class ImageKitConf(AppConf): - DEFAULT_GENERATEDFILE_BACKEND = 'imagekit.generators.filebackends.Simple' + DEFAULT_GENERATEDFILE_BACKEND = 'imagekit.generatedfiles.backends.Simple' CACHE_BACKEND = None GENERATED_FILE_DIR = 'generated/images' CACHE_PREFIX = 'imagekit:' - DEFAULT_IMAGE_GENERATOR_STRATEGY = 'imagekit.generators.strategies.JustInTime' + DEFAULT_GENERATEDFILE_STRATEGY = 'imagekit.generatedfiles.strategies.JustInTime' DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' def configure_cache_backend(self, value): diff --git a/imagekit/files.py b/imagekit/files.py index 441d2cb..fb4375c 100644 --- a/imagekit/files.py +++ b/imagekit/files.py @@ -1,13 +1,7 @@ -from django.conf import settings -from django.core.files.base import ContentFile, File -from django.core.files.images import ImageFile +from django.core.files.base import File, ContentFile from django.utils.encoding import smart_str, smart_unicode -from django.utils.functional import LazyObject import os -from .registry import generator_registry -from .signals import before_access -from .utils import (format_to_mimetype, extension_to_mimetype, get_logger, - get_singleton, generate) +from .utils import format_to_mimetype, extension_to_mimetype class BaseIKFile(File): @@ -72,63 +66,6 @@ class BaseIKFile(File): file.close() -class GeneratedImageFile(BaseIKFile, ImageFile): - """ - A file that represents the result of a generator. Creating an instance of - this class is not enough to trigger the generation of the file. In fact, - one of the main points of this class is to allow the creation of the file - to be deferred until the time that the image generator strategy requires it. - - """ - def __init__(self, generator, name=None, storage=None, generatedfile_backend=None): - """ - :param generator: The object responsible for generating a new image. - :param name: The filename - :param storage: A Django storage object that will be used to save the - file. - :param generatedfile_backend: The object responsible for managing the - state of the file. - - """ - self.generator = generator - - self.name = name or getattr(generator, 'generatedfile_name', None) - storage = storage or getattr(generator, 'generatedfile_storage', - None) or get_singleton(settings.IMAGEKIT_DEFAULT_FILE_STORAGE, - 'file storage backend') - self.generatedfile_backend = generatedfile_backend or getattr(generator, - 'generatedfile_backend', None) - - super(GeneratedImageFile, self).__init__(storage=storage) - - def _require_file(self): - before_access.send(sender=self, file=self) - return super(GeneratedImageFile, self)._require_file() - - def generate(self, force=False): - if force: - self._generate() - else: - self.generatedfile_backend.ensure_exists(self) - - def _generate(self): - # Generate the file - content = generate(self.generator) - - actual_name = self.storage.save(self.name, content) - - if actual_name != self.name: - get_logger().warning('The storage backend %s did not save the file' - ' with the requested name ("%s") and instead used' - ' "%s". This may be because a file already existed with' - ' the requested name. If so, you may have meant to call' - ' ensure_exists() instead of generate(), or there may be a' - ' race condition in the file backend %s. The saved file' - ' will not be used.' % (self.storage, - self.name, actual_name, - self.generatedfile_backend)) - - class IKContentFile(ContentFile): """ Wraps a ContentFile in a file-like object with a filename and a @@ -156,14 +93,3 @@ class IKContentFile(ContentFile): def __unicode__(self): return smart_unicode(self.file.name or u'') - - -class LazyGeneratedImageFile(LazyObject): - def __init__(self, generator_id, *args, **kwargs): - super(LazyGeneratedImageFile, self).__init__() - - def setup(): - generator = generator_registry.get(generator_id, *args, **kwargs) - self._wrapped = GeneratedImageFile(generator) - - self.__dict__['_setup'] = setup diff --git a/imagekit/generatedfiles/__init__.py b/imagekit/generatedfiles/__init__.py new file mode 100644 index 0000000..5249451 --- /dev/null +++ b/imagekit/generatedfiles/__init__.py @@ -0,0 +1,75 @@ +from django.conf import settings +from django.core.files.images import ImageFile +from django.utils.functional import LazyObject +from ..files import BaseIKFile +from ..registry import generator_registry +from ..signals import before_access +from ..utils import get_logger, get_singleton, generate + + +class GeneratedImageFile(BaseIKFile, ImageFile): + """ + A file that represents the result of a generator. Creating an instance of + this class is not enough to trigger the generation of the file. In fact, + one of the main points of this class is to allow the creation of the file + to be deferred until the time that the generated file strategy requires it. + + """ + def __init__(self, generator, name=None, storage=None, generatedfile_backend=None): + """ + :param generator: The object responsible for generating a new image. + :param name: The filename + :param storage: A Django storage object that will be used to save the + file. + :param generatedfile_backend: The object responsible for managing the + state of the file. + + """ + self.generator = generator + + self.name = name or getattr(generator, 'generatedfile_name', None) + storage = storage or getattr(generator, 'generatedfile_storage', + None) or get_singleton(settings.IMAGEKIT_DEFAULT_FILE_STORAGE, + 'file storage backend') + self.generatedfile_backend = generatedfile_backend or getattr(generator, + 'generatedfile_backend', None) + + super(GeneratedImageFile, self).__init__(storage=storage) + + def _require_file(self): + before_access.send(sender=self, file=self) + return super(GeneratedImageFile, self)._require_file() + + def generate(self, force=False): + if force: + self._generate() + else: + self.generatedfile_backend.ensure_exists(self) + + def _generate(self): + # Generate the file + content = generate(self.generator) + + actual_name = self.storage.save(self.name, content) + + if actual_name != self.name: + get_logger().warning('The storage backend %s did not save the file' + ' with the requested name ("%s") and instead used' + ' "%s". This may be because a file already existed with' + ' the requested name. If so, you may have meant to call' + ' ensure_exists() instead of generate(), or there may be a' + ' race condition in the file backend %s. The saved file' + ' will not be used.' % (self.storage, + self.name, actual_name, + self.generatedfile_backend)) + + +class LazyGeneratedImageFile(LazyObject): + def __init__(self, generator_id, *args, **kwargs): + super(LazyGeneratedImageFile, self).__init__() + + def setup(): + generator = generator_registry.get(generator_id, *args, **kwargs) + self._wrapped = GeneratedImageFile(generator) + + self.__dict__['_setup'] = setup diff --git a/imagekit/generators/actions.py b/imagekit/generatedfiles/actions.py similarity index 100% rename from imagekit/generators/actions.py rename to imagekit/generatedfiles/actions.py diff --git a/imagekit/generators/filebackends.py b/imagekit/generatedfiles/backends.py similarity index 100% rename from imagekit/generators/filebackends.py rename to imagekit/generatedfiles/backends.py diff --git a/imagekit/generators/strategies.py b/imagekit/generatedfiles/strategies.py similarity index 95% rename from imagekit/generators/strategies.py rename to imagekit/generatedfiles/strategies.py index b1c6f56..72bc1df 100644 --- a/imagekit/generators/strategies.py +++ b/imagekit/generatedfiles/strategies.py @@ -39,7 +39,7 @@ class DictStrategy(object): class StrategyWrapper(LazyObject): def __init__(self, strategy): if isinstance(strategy, basestring): - strategy = get_singleton(strategy, 'generator strategy') + strategy = get_singleton(strategy, 'generated file strategy') elif isinstance(strategy, dict): strategy = DictStrategy(strategy) elif callable(strategy): diff --git a/imagekit/generators/__init__.py b/imagekit/generators/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/imagekit/models/fields/__init__.py b/imagekit/models/fields/__init__.py index 0cfcf5b..ee9a789 100644 --- a/imagekit/models/fields/__init__.py +++ b/imagekit/models/fields/__init__.py @@ -27,14 +27,14 @@ class ImageSpecField(SpecHostField): """ def __init__(self, processors=None, format=None, options=None, source=None, generatedfile_storage=None, autoconvert=None, - generatedfile_backend=None, generator_strategy=None, spec=None, + generatedfile_backend=None, generatedfile_strategy=None, spec=None, id=None): SpecHost.__init__(self, processors=processors, format=format, options=options, generatedfile_storage=generatedfile_storage, autoconvert=autoconvert, generatedfile_backend=generatedfile_backend, - generator_strategy=generator_strategy, spec=spec, + generatedfile_strategy=generatedfile_strategy, spec=spec, spec_id=id) # TODO: Allow callable for source. See https://github.com/jdriscoll/django-imagekit/issues/158#issuecomment-10921664 diff --git a/imagekit/models/fields/utils.py b/imagekit/models/fields/utils.py index e549a6b..d9a2976 100644 --- a/imagekit/models/fields/utils.py +++ b/imagekit/models/fields/utils.py @@ -1,4 +1,4 @@ -from ...files import GeneratedImageFile +from ...generatedfiles import GeneratedImageFile from django.db.models.fields.files import ImageField diff --git a/imagekit/registry.py b/imagekit/registry.py index 3a998f0..309bb54 100644 --- a/imagekit/registry.py +++ b/imagekit/registry.py @@ -54,8 +54,8 @@ class GeneratorRegistry(object): class SourceGroupRegistry(object): """ The source group registry is responsible for listening to source_* signals - on source groups, and relaying them to the image generator strategies of the - appropriate generators. + on source groups, and relaying them to the image generated file strategies + of the appropriate generators. In addition, registering a new source group also registers its generated files with that registry. @@ -92,7 +92,7 @@ class SourceGroupRegistry(object): Relay source group signals to the appropriate spec strategy. """ - from .files import GeneratedImageFile + from .generatedfiles import GeneratedImageFile source_group = sender # Ignore signals from unregistered groups. diff --git a/imagekit/specs/__init__.py b/imagekit/specs/__init__.py index c156b52..7c096a2 100644 --- a/imagekit/specs/__init__.py +++ b/imagekit/specs/__init__.py @@ -3,8 +3,8 @@ from django.db.models.fields.files import ImageFieldFile from hashlib import md5 import os import pickle -from ..generators.filebackends import get_default_generatedfile_backend -from ..generators.strategies import StrategyWrapper +from ..generatedfiles.backends import get_default_generatedfile_backend +from ..generatedfiles.strategies import StrategyWrapper from ..processors import ProcessorPipeline from ..utils import open_image, img_to_fobj, suggest_extension from ..registry import generator_registry, register @@ -27,17 +27,17 @@ class BaseImageSpec(object): """ - generator_strategy = settings.IMAGEKIT_DEFAULT_IMAGE_GENERATOR_STRATEGY + generatedfile_strategy = settings.IMAGEKIT_DEFAULT_GENERATEDFILE_STRATEGY """ A dictionary containing callbacks that allow you to customize how and when the image file is created. Defaults to - ``IMAGEKIT_DEFAULT_IMAGE_GENERATOR_STRATEGY``. + ``IMAGEKIT_DEFAULT_GENERATEDFILE_STRATEGY``. """ def __init__(self): self.generatedfile_backend = self.generatedfile_backend or get_default_generatedfile_backend() - self.generator_strategy = StrategyWrapper(self.generator_strategy) + self.generatedfile_strategy = StrategyWrapper(self.generatedfile_strategy) def generate(self): raise NotImplementedError diff --git a/imagekit/specs/sourcegroups.py b/imagekit/specs/sourcegroups.py index 5e82144..e828f91 100644 --- a/imagekit/specs/sourcegroups.py +++ b/imagekit/specs/sourcegroups.py @@ -3,7 +3,7 @@ Source groups are the means by which image spec sources are identified. They have two responsibilities: 1. To dispatch ``source_created``, ``source_changed``, and ``source_deleted`` - signals. (These will be relayed to the corresponding specs' generator + signals. (These will be relayed to the corresponding specs' generated file strategies.) 2. To provide the source files that they represent, via a generator method named ``files()``. (This is used by the generateimages management command for @@ -13,7 +13,7 @@ have two responsibilities: from django.db.models.signals import post_init, post_save, post_delete from django.utils.functional import wraps -from ..files import LazyGeneratedImageFile +from ..generatedfiles import LazyGeneratedImageFile from ..signals import source_created, source_changed, source_deleted diff --git a/imagekit/templatetags/imagekit.py b/imagekit/templatetags/imagekit.py index 555c693..8a59242 100644 --- a/imagekit/templatetags/imagekit.py +++ b/imagekit/templatetags/imagekit.py @@ -2,7 +2,7 @@ from django import template from django.utils.html import escape from django.utils.safestring import mark_safe from .compat import parse_bits -from ..files import GeneratedImageFile +from ..generatedfiles import GeneratedImageFile from ..registry import generator_registry diff --git a/imagekit/utils.py b/imagekit/utils.py index 59ef235..e210576 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -425,7 +425,7 @@ def generate(generator): def call_strategy_method(generator, method_name, *args, **kwargs): - strategy = getattr(generator, 'generator_strategy', None) + strategy = getattr(generator, 'generatedfile_strategy', None) fn = getattr(strategy, method_name, None) if fn is not None: fn(*args, **kwargs)