mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-16 21:30:23 +00:00
Remove specs.SpecRegistry; add registry module
The registry module splits the work that specs.SpecRegistry used to do into two classes: GeneratorRegistry and SourceGroupRegistry. These two registries are wrapped in Register and Unregister utilities for API convenience.
This commit is contained in:
parent
d253fe281a
commit
e0567e8fa7
7 changed files with 170 additions and 121 deletions
|
|
@ -3,3 +3,4 @@
|
|||
from . import conf
|
||||
from .specs import ImageSpec
|
||||
from .pkgmeta import *
|
||||
from .registry import register, unregister
|
||||
|
|
|
|||
|
|
@ -14,5 +14,5 @@ class UnknownFormatError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class MissingSpecId(Exception):
|
||||
class MissingGeneratorId(Exception):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
import re
|
||||
from ...files import ImageSpecCacheFile
|
||||
from ...specs import registry
|
||||
from ...registry import generator_registry, source_group_registry
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
|
@ -11,7 +11,7 @@ class Command(BaseCommand):
|
|||
args = '[spec_ids]'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
specs = registry.get_spec_ids()
|
||||
specs = generator_registry.get_ids()
|
||||
|
||||
if args:
|
||||
patterns = self.compile_patterns(args)
|
||||
|
|
@ -19,8 +19,8 @@ class Command(BaseCommand):
|
|||
|
||||
for spec_id in specs:
|
||||
self.stdout.write('Validating spec: %s\n' % spec_id)
|
||||
spec = registry.get_spec(spec_id) # TODO: HINTS! (Probably based on source, so this will need to be moved into loop below.)
|
||||
for source in registry.get_sources(spec_id):
|
||||
spec = generator_registry.get(spec_id) # TODO: HINTS! (Probably based on source, so this will need to be moved into loop below.)
|
||||
for source in source_group_registry.get(spec_id):
|
||||
for source_file in source.files():
|
||||
if source_file:
|
||||
self.stdout.write(' %s\n' % source_file)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from django.db import models
|
||||
from .files import ProcessedImageFieldFile
|
||||
from .utils import ImageSpecFileDescriptor
|
||||
from ... import specs
|
||||
from ...specs import SpecHost
|
||||
from ...specs.sourcegroups import ImageFieldSourceGroup
|
||||
from ...registry import register
|
||||
|
||||
|
||||
class SpecHostField(SpecHost):
|
||||
|
|
@ -44,7 +44,7 @@ class ImageSpecField(SpecHostField):
|
|||
self.set_spec_id(cls, name)
|
||||
|
||||
# Add the model and field as a source for this spec id
|
||||
specs.registry.add_sources(self.spec_id,
|
||||
register.sources(self.spec_id,
|
||||
[ImageFieldSourceGroup(cls, self.source)])
|
||||
|
||||
|
||||
|
|
|
|||
156
imagekit/registry.py
Normal file
156
imagekit/registry.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
from .exceptions import AlreadyRegistered, NotRegistered, MissingGeneratorId
|
||||
from .signals import (before_access, source_created, source_changed,
|
||||
source_deleted)
|
||||
|
||||
|
||||
class GeneratorRegistry(object):
|
||||
"""
|
||||
An object for registering generators (specs). 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 = {}
|
||||
|
||||
def register(self, generator, id=None):
|
||||
# TODO: Should we really allow a nested Config class, since it's not necessarily associated with its container?
|
||||
config = getattr(generator, 'Config', None)
|
||||
|
||||
if id is None:
|
||||
id = getattr(config, 'id', None)
|
||||
|
||||
if id is None:
|
||||
raise MissingGeneratorId('No id provided for %s. You must either'
|
||||
' pass an id to the register function, or add'
|
||||
' an id attribute to the inner Config class of'
|
||||
' your spec or generator.' % generator)
|
||||
|
||||
if id in self._generators:
|
||||
raise AlreadyRegistered('The spec or generator with id %s is'
|
||||
' already registered' % id)
|
||||
self._generators[id] = generator
|
||||
|
||||
source_groups = getattr(config, 'source_groups', None) or []
|
||||
source_group_registry.register(id, source_groups)
|
||||
|
||||
def unregister(self, id, generator):
|
||||
try:
|
||||
del self._generators[id]
|
||||
except KeyError:
|
||||
raise NotRegistered('The spec or generator with id %s is not'
|
||||
' registered' % id)
|
||||
|
||||
def get(self, id, **kwargs):
|
||||
try:
|
||||
generator = self._generators[id]
|
||||
except KeyError:
|
||||
raise NotRegistered('The spec or 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()
|
||||
|
||||
|
||||
class SourceGroupRegistry(object):
|
||||
"""
|
||||
An object for registering source groups with specs. 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 ``source_groups``
|
||||
attribute on specs) so that specs can be overridden without losing the
|
||||
associated sources. That way, a distributable app can define its own
|
||||
specs without locking the users of the app into it.
|
||||
|
||||
"""
|
||||
|
||||
_source_signals = [
|
||||
source_created,
|
||||
source_changed,
|
||||
source_deleted,
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
self._sources = {}
|
||||
for signal in self._source_signals:
|
||||
signal.connect(self.source_receiver)
|
||||
before_access.connect(self.before_access_receiver)
|
||||
|
||||
def register(self, spec_id, sources):
|
||||
"""
|
||||
Associates sources with a spec id
|
||||
|
||||
"""
|
||||
for source in sources:
|
||||
if source not in self._sources:
|
||||
self._sources[source] = set()
|
||||
self._sources[source].add(spec_id)
|
||||
|
||||
def unregister(self, spec_id, sources):
|
||||
"""
|
||||
Disassociates sources with a spec id
|
||||
|
||||
"""
|
||||
for source in sources:
|
||||
try:
|
||||
self._sources[source].remove(spec_id)
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
def get(self, spec_id):
|
||||
return [source for source in self._sources
|
||||
if spec_id in self._sources[source]]
|
||||
|
||||
def before_access_receiver(self, sender, generator, file, **kwargs):
|
||||
generator.image_cache_strategy.invoke_callback('before_access', file)
|
||||
|
||||
def source_receiver(self, sender, source_file, signal, info, **kwargs):
|
||||
"""
|
||||
Redirects signals dispatched on sources to the appropriate specs.
|
||||
|
||||
"""
|
||||
source = sender
|
||||
if source not in self._sources:
|
||||
return
|
||||
|
||||
for spec in (generator_registry.get(id, source_file=source_file, **info)
|
||||
for id in self._sources[source]):
|
||||
event_name = {
|
||||
source_created: 'source_created',
|
||||
source_changed: 'source_changed',
|
||||
source_deleted: 'source_deleted',
|
||||
}
|
||||
spec._handle_source_event(event_name, source_file)
|
||||
|
||||
|
||||
class Register(object):
|
||||
"""
|
||||
Register specs and sources.
|
||||
|
||||
"""
|
||||
def spec(self, id, spec):
|
||||
generator_registry.register(id, spec)
|
||||
|
||||
def sources(self, spec_id, sources):
|
||||
source_group_registry.register(spec_id, sources)
|
||||
|
||||
|
||||
class Unregister(object):
|
||||
"""
|
||||
Unregister specs and sources.
|
||||
|
||||
"""
|
||||
def spec(self, id, spec):
|
||||
generator_registry.unregister(id, spec)
|
||||
|
||||
def sources(self, spec_id, sources):
|
||||
source_group_registry.unregister(spec_id, sources)
|
||||
|
||||
|
||||
generator_registry = GeneratorRegistry()
|
||||
source_group_registry = SourceGroupRegistry()
|
||||
register = Register()
|
||||
unregister = Unregister()
|
||||
|
|
@ -2,113 +2,13 @@ from django.conf import settings
|
|||
from hashlib import md5
|
||||
import os
|
||||
import pickle
|
||||
from ..exceptions import (UnknownExtensionError, AlreadyRegistered,
|
||||
NotRegistered, MissingSpecId)
|
||||
from ..exceptions import UnknownExtensionError
|
||||
from ..files import ImageSpecCacheFile, IKContentFile
|
||||
from ..imagecache.backends import get_default_image_cache_backend
|
||||
from ..imagecache.strategies import StrategyWrapper
|
||||
from ..processors import ProcessorPipeline
|
||||
from ..signals import (before_access, source_created, source_changed,
|
||||
source_deleted)
|
||||
from ..utils import open_image, extension_to_format, img_to_fobj
|
||||
|
||||
|
||||
class SpecRegistry(object):
|
||||
"""
|
||||
An object for registering specs and sources. The two are associated with
|
||||
eachother via a string id. We do this (as opposed to associating them
|
||||
directly by, for example, putting a ``sources`` attribute on specs) so that
|
||||
specs can be overridden without losing the associated sources. That way,
|
||||
a distributable app can define its own specs without locking the users of
|
||||
the app into it.
|
||||
|
||||
"""
|
||||
|
||||
_source_signals = [
|
||||
source_created,
|
||||
source_changed,
|
||||
source_deleted,
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
self._specs = {}
|
||||
self._sources = {}
|
||||
for signal in self._source_signals:
|
||||
signal.connect(self.source_receiver)
|
||||
before_access.connect(self.before_access_receiver)
|
||||
|
||||
def register(self, spec, id=None):
|
||||
# TODO: Should we really allow a nested Config class, since it's not necessarily associated with its container?
|
||||
config = getattr(spec, 'Config', None)
|
||||
|
||||
if id is None:
|
||||
id = getattr(config, 'id', None)
|
||||
|
||||
if id is None:
|
||||
raise MissingSpecId('No id provided for %s. You must either pass an'
|
||||
' id to the register function, or add an id'
|
||||
' attribute to the inner Config class of your'
|
||||
' spec.' % spec)
|
||||
|
||||
if id in self._specs:
|
||||
raise AlreadyRegistered('The spec with id %s is already registered' % id)
|
||||
self._specs[id] = spec
|
||||
|
||||
sources = getattr(config, 'source_groups', None) or []
|
||||
self.add_sources(id, sources)
|
||||
|
||||
def unregister(self, id, spec):
|
||||
try:
|
||||
del self._specs[id]
|
||||
except KeyError:
|
||||
raise NotRegistered('The spec with id %s is not registered' % id)
|
||||
|
||||
def get_spec(self, id, **kwargs):
|
||||
try:
|
||||
spec = self._specs[id]
|
||||
except KeyError:
|
||||
raise NotRegistered('The spec with id %s is not registered' % id)
|
||||
if callable(spec):
|
||||
return spec(**kwargs)
|
||||
else:
|
||||
return spec
|
||||
|
||||
def get_spec_ids(self):
|
||||
return self._specs.keys()
|
||||
|
||||
def add_sources(self, spec_id, sources):
|
||||
"""
|
||||
Associates sources with a spec id
|
||||
|
||||
"""
|
||||
for source in sources:
|
||||
if source not in self._sources:
|
||||
self._sources[source] = set()
|
||||
self._sources[source].add(spec_id)
|
||||
|
||||
def get_sources(self, spec_id):
|
||||
return [source for source in self._sources if spec_id in self._sources[source]]
|
||||
|
||||
def before_access_receiver(self, sender, generator, file, **kwargs):
|
||||
generator.image_cache_strategy.invoke_callback('before_access', file)
|
||||
|
||||
def source_receiver(self, sender, source_file, signal, info, **kwargs):
|
||||
"""
|
||||
Redirects signals dispatched on sources to the appropriate specs.
|
||||
|
||||
"""
|
||||
source = sender
|
||||
if source not in self._sources:
|
||||
return
|
||||
|
||||
for spec in (self.get_spec(id, source_file=source_file, **info)
|
||||
for id in self._sources[source]):
|
||||
event_name = {
|
||||
source_created: 'source_created',
|
||||
source_changed: 'source_changed',
|
||||
source_deleted: 'source_deleted',
|
||||
}
|
||||
spec._handle_source_event(event_name, source_file)
|
||||
from ..registry import generator_registry, register
|
||||
|
||||
|
||||
class BaseImageSpec(object):
|
||||
|
|
@ -270,7 +170,7 @@ class SpecHost(object):
|
|||
|
||||
"""
|
||||
self.spec_id = id
|
||||
registry.register(self._original_spec, id)
|
||||
register.spec(self._original_spec, id)
|
||||
|
||||
def get_spec(self, **kwargs):
|
||||
"""
|
||||
|
|
@ -282,12 +182,4 @@ class SpecHost(object):
|
|||
"""
|
||||
if not getattr(self, 'spec_id', None):
|
||||
raise Exception('Object %s has no spec id.' % self)
|
||||
return registry.get_spec(self.spec_id, **kwargs)
|
||||
|
||||
|
||||
registry = SpecRegistry()
|
||||
register = registry.register
|
||||
|
||||
|
||||
def unregister(id, spec):
|
||||
registry.unregister(id, spec)
|
||||
return generator_registry.get(self.spec_id, **kwargs)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from django import template
|
|||
from django.utils.safestring import mark_safe
|
||||
import re
|
||||
from ..files import ImageSpecCacheFile
|
||||
from .. import specs
|
||||
from ..registry import generator_registry
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
|
@ -34,7 +34,7 @@ class SpecResultNodeMixin(object):
|
|||
from ..utils import autodiscover
|
||||
autodiscover()
|
||||
spec_id = self._spec_id.resolve(context)
|
||||
spec = specs.registry.get_spec(spec_id) # TODO: What "hints" here?
|
||||
spec = generator_registry.get(spec_id) # TODO: What "hints" here?
|
||||
return spec
|
||||
|
||||
def get_source_file(self, context):
|
||||
|
|
|
|||
Loading…
Reference in a new issue