mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-17 05:40:25 +00:00
As discussed in #214, source_created and source_changed didn't really have clear definitions. In truth, their names and separation betray their origins as model receivers in earlier versions. The "source group" abstraction helped us get away from thinking about things exclusively in terms of models, but these remained as an artifact.
200 lines
6.6 KiB
Python
200 lines
6.6 KiB
Python
from .exceptions import AlreadyRegistered, NotRegistered
|
|
from .signals import (content_required, existence_required, source_saved,
|
|
source_deleted)
|
|
from .utils import call_strategy_method
|
|
|
|
|
|
class GeneratorRegistry(object):
|
|
"""
|
|
An object for registering generators. This registry provides
|
|
a convenient way for a distributable app to define default generators
|
|
without locking the users of the app into it.
|
|
|
|
"""
|
|
def __init__(self):
|
|
self._generators = {}
|
|
content_required.connect(self.content_required_receiver)
|
|
existence_required.connect(self.existence_required_receiver)
|
|
|
|
def register(self, id, generator):
|
|
registered_generator = self._generators.get(id)
|
|
if registered_generator and generator != self._generators[id]:
|
|
raise AlreadyRegistered('The generator with id %s is'
|
|
' already registered' % id)
|
|
self._generators[id] = generator
|
|
|
|
def unregister(self, id):
|
|
try:
|
|
del self._generators[id]
|
|
except KeyError:
|
|
raise NotRegistered('The generator with id %s is not'
|
|
' registered' % id)
|
|
|
|
def get(self, id, **kwargs):
|
|
try:
|
|
generator = self._generators[id]
|
|
except KeyError:
|
|
raise NotRegistered('The generator with id %s is not'
|
|
' registered' % id)
|
|
if callable(generator):
|
|
return generator(**kwargs)
|
|
else:
|
|
return generator
|
|
|
|
def get_ids(self):
|
|
return self._generators.keys()
|
|
|
|
def content_required_receiver(self, sender, file, **kwargs):
|
|
self._receive(file, 'on_content_required')
|
|
|
|
def existence_required_receiver(self, sender, file, **kwargs):
|
|
self._receive(file, 'on_existence_required')
|
|
|
|
def _receive(self, file, callback):
|
|
generator = file.generator
|
|
|
|
# FIXME: I guess this means you can't register functions?
|
|
if generator.__class__ in self._generators.values():
|
|
# Only invoke the strategy method for registered generators.
|
|
call_strategy_method(file, callback)
|
|
|
|
|
|
class SourceGroupRegistry(object):
|
|
"""
|
|
The source group registry is responsible for listening to source_* signals
|
|
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.
|
|
|
|
"""
|
|
_signals = {
|
|
source_saved: 'on_source_saved',
|
|
source_deleted: 'on_source_deleted',
|
|
}
|
|
|
|
def __init__(self):
|
|
self._source_groups = {}
|
|
for signal in self._signals.keys():
|
|
signal.connect(self.source_group_receiver)
|
|
|
|
def register(self, generator_id, source_group):
|
|
from .specs.sourcegroups import SourceGroupFilesGenerator
|
|
generator_ids = self._source_groups.setdefault(source_group, set())
|
|
generator_ids.add(generator_id)
|
|
cachefile_registry.register(generator_id,
|
|
SourceGroupFilesGenerator(source_group, generator_id))
|
|
|
|
def unregister(self, generator_id, source_group):
|
|
from .specs.sourcegroups import SourceGroupFilesGenerator
|
|
generator_ids = self._source_groups.setdefault(source_group, set())
|
|
if generator_id in generator_ids:
|
|
generator_ids.remove(generator_id)
|
|
cachefile_registry.unregister(generator_id,
|
|
SourceGroupFilesGenerator(source_group, generator_id))
|
|
|
|
def source_group_receiver(self, sender, source, signal, **kwargs):
|
|
"""
|
|
Relay source group signals to the appropriate spec strategy.
|
|
|
|
"""
|
|
from .cachefiles import ImageCacheFile
|
|
source_group = sender
|
|
|
|
# Ignore signals from unregistered groups.
|
|
if source_group not in self._source_groups:
|
|
return
|
|
|
|
specs = [generator_registry.get(id, source=source) for id in
|
|
self._source_groups[source_group]]
|
|
callback_name = self._signals[signal]
|
|
|
|
for spec in specs:
|
|
file = ImageCacheFile(spec)
|
|
call_strategy_method(file, callback_name)
|
|
|
|
|
|
class CacheFileRegistry(object):
|
|
"""
|
|
An object for registering generated files with image generators. The two are
|
|
associated with each other via a string id. We do this (as opposed to
|
|
associating them directly by, for example, putting a ``cachefiles``
|
|
attribute on image generators) so that image generators can be overridden
|
|
without losing the associated files. That way, a distributable app can
|
|
define its own generators without locking the users of the app into it.
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
self._cachefiles = {}
|
|
|
|
def register(self, generator_id, cachefiles):
|
|
"""
|
|
Associates generated files with a generator id
|
|
|
|
"""
|
|
if cachefiles not in self._cachefiles:
|
|
self._cachefiles[cachefiles] = set()
|
|
self._cachefiles[cachefiles].add(generator_id)
|
|
|
|
def unregister(self, generator_id, cachefiles):
|
|
"""
|
|
Disassociates generated files with a generator id
|
|
|
|
"""
|
|
try:
|
|
self._cachefiles[cachefiles].remove(generator_id)
|
|
except KeyError:
|
|
pass
|
|
|
|
def get(self, generator_id):
|
|
for k, v in self._cachefiles.items():
|
|
if generator_id in v:
|
|
for file in k():
|
|
yield file
|
|
|
|
|
|
class Register(object):
|
|
"""
|
|
Register generators and generated files.
|
|
|
|
"""
|
|
def generator(self, id, generator=None):
|
|
if generator is None:
|
|
# Return a decorator
|
|
def decorator(cls):
|
|
self.generator(id, cls)
|
|
return cls
|
|
return decorator
|
|
|
|
generator_registry.register(id, generator)
|
|
|
|
# iterable that returns kwargs or callable that returns iterable of kwargs
|
|
def cachefiles(self, generator_id, cachefiles):
|
|
cachefile_registry.register(generator_id, cachefiles)
|
|
|
|
def source_group(self, generator_id, source_group):
|
|
source_group_registry.register(generator_id, source_group)
|
|
|
|
|
|
class Unregister(object):
|
|
"""
|
|
Unregister generators and generated files.
|
|
|
|
"""
|
|
def generator(self, id):
|
|
generator_registry.unregister(id)
|
|
|
|
def cachefiles(self, generator_id, cachefiles):
|
|
cachefile_registry.unregister(generator_id, cachefiles)
|
|
|
|
def source_group(self, generator_id, source_group):
|
|
source_group_registry.unregister(generator_id, source_group)
|
|
|
|
|
|
generator_registry = GeneratorRegistry()
|
|
cachefile_registry = CacheFileRegistry()
|
|
source_group_registry = SourceGroupRegistry()
|
|
register = Register()
|
|
unregister = Unregister()
|