Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Block(object):
- def render(self, dest):
- # ...
- pass
- class TemplateBlock(Block):
- def render(self, dest):
- # ...
- pass
- # blocks.ext.django
- import blocks
- import django.http
- class Block(blocks.Block):
- def render_to_response(self):
- # ...
- result = self.render(dest)
- return django.http.HtppRequest(result)
- # blocks.ext.django
- # ...
- class TemplateBlock(blocks.TemplateBlock, Block):
- pass
- class Test(object):
- ext = ExtensionManager()
- def __init__(self, v):
- self.v = v
- class Extensions():
- __metaclass__ = ExtensionClassMeta
- managers = [Test.ext]
- @Extension('method')
- def print_v(self):
- print self.v
- Test('Value of Test instance').ext.print_v()
- print Extensions
- C:UsersniklasDesktopblog>python -m blocks.utils.ext_manager
- Value of Test instance
- (<__main__.ExtensionManager object at 0x021725B0>,)
- class CoolLookupManager(LookupManager):
- extension_types = ('ice',)
- def wrap_ice(self, name, object, instance, owner):
- return "%s is cool as ice." % object(instance)
- class Test(object):
- ext = ExtensionManager(lookup_manager=CoolLookupManager())
- def __init__(self, v):
- self.v = v
- class Extensions():
- __metaclass__ = ExtensionClassMeta
- managers = [Test.ext]
- @Extension('ice')
- def get_v(self):
- return self.v
- print Test('StackOverflow').ext.get_v
- C:UsersniklasDesktopblog>python -m blocks.utils.ext_manager
- StackOverflow is cool as ice.
- # coding: UTF-8
- # file: blocks/utils/ext_manager.py
- #
- # Copyright (C) 2012, Niklas Rosenstein
- """ blocks.utils.ext_manager - Class extension-manager. """
- import functools
- class ExtensionTypeError(Exception):
- """ Raised when an extension type is not supported. """
- class Extension(object):
- """ This decorator is used to mark an attribute on an extension class
- as being actually an extension. """
- def __init__(self, type):
- super(Extension, self).__init__()
- self.type = type
- self.object = None
- def __str__(self):
- return '<Extension: %s>' % self.type
- def __call__(self, object):
- self.object = object
- return self
- class ExtensionClassMeta(type):
- """ This meta-class processes an extension class and adds the defined
- extensions into the `ExtensionManager` objects defined in the
- extension class. """
- def __new__(self, name, bases, dict):
- # Ensure there is no base.
- if bases:
- raise ValueError('the ExtensionClassMeta meta-class does not accept bases.')
- # Obtain a list of the managers that need to be extended.
- managers = dict.pop('managers', None)
- if not managers:
- raise ValueError('at least one manager must be given in the class.')
- # A single ExtensionManager instance of the `managers` attribute is
- # allowed, so convert it to a list to ensure that the next test
- # will not fail.
- if isinstance(managers, ExtensionManager):
- managers = [managers]
- # Make sure the managers is a list.
- if not isinstance(managers, (list, tuple)):
- raise ValueError('managers names must be list or tuple.')
- # Iterate over all managers to ensure they're all ExtensionManager
- # instances.
- for manager in managers:
- if not isinstance(manager, ExtensionManager):
- raise ValueError('object in managers not instance of ExtensionManager class.')
- # Iterate over all attributes of the class and extend the managers.
- for name, value in dict.iteritems():
- # Only `Extension` instances will be registered to the extension
- # managers. Other values are just ignored.
- if isinstance(value, Extension):
- for manager in managers:
- manager.register_extension(name, value.object, value.type)
- return tuple(managers)
- class ExtensionManager(object):
- """ This class is used as a property to dynamically add methods and
- data-fields (also called extensions in this context) to a class.
- Any attribute that will be gathered from this object will be wrapped
- according to the type of extension (see `register_extension()`). """
- def __init__(self, lookup_manager=None):
- super(ExtensionManager, self).__init__()
- self._extensions = {}
- if not lookup_manager:
- lookup_manager = StandartLookupManager()
- self.lookup_manager = lookup_manager
- def __get__(self, instance, owner):
- if not instance:
- return self
- else:
- return ExtensionToAttributeConnector(self, instance, owner)
- def __set__(self, instance, value):
- raise AttributeError("can't overwrite ExtensionManager property.")
- def __delete__(self, instance):
- raise AttributeError("can't delete ExtensionManager property.")
- def register_extension(self, name, object, type='method'):
- """ Register an extension to the manager. The type of *object* depends
- on the value of *type*. The extensions name must be passed with
- *name*. It is associated with *object* and used on attribute
- lookup. If the type is not valid, the lookup manager will
- raise an *ExtensionTypeError*.
- """
- self.lookup_manager.validate_type(type)
- self._extensions[name] = [object, type]
- def do_lookup(self, name, instance, owner):
- """ Forward the extension lookup to the lookup manager to obtain the
- value of an extension. """
- return self.lookup_manager.do_lookup(self._extensions, name, instance, owner)
- class LookupManager(object):
- """ This is the base-class for lookup managers. A lookup manager is created
- by an `ExtensionManager` instance when watching out for a specific
- attribute on an instance.
- The `ExtensionManager` will ask the `LookupManager` to validate the
- type of an extension. The lookup manager itself will call functions
- depending on the type of an extension.
- If you have a lookup manager which supports the type `'FOO'`,
- and an extension of that type is requested, it will call the
- function `wrap_FOO()`. Such a method has the following signature:
- * `self`: The `LookupManager` instance.
- * `ext_name`: A string defining the name of the extension that
- is looked up.
- * `instance`: The invoking instance, as passed by `__get__`.
- * `owner`: The invoking class, as passed by `__get__`.
- The `wrap_FOO()` function must wrap and return *object* so it can
- be used by the requestor.
- The types of extensions the lookup manager supports is defined in
- the `extension_types` attribute which *must* be an iterable of string.
- """
- extension_types = ()
- def do_lookup(self, extensions, name, instance, owner):
- """ Perform a lookup on the passed *extensions* and call the
- corresponding `wrap_FOO()` method. *extensions* should be a
- dictionary containing `(object, type)` pairs only where *object*
- is the registered extension and *type* is its type.
- *connector* is an instance of `ExtensionToAttributeConnector`. """
- object = extensions.get(name, None)
- if not object:
- raise AttributeError('no extension named %s.' % name)
- object, type = object
- lookup_name = 'wrap_%s' % type
- processor = getattr(self, lookup_name, None)
- if not processor:
- raise RuntimeError('no processor %s found in lookup manager.' % lookup_name)
- return processor(name, object, instance, owner)
- def validate_type(self, type):
- """ Validate the passed *type* by raising *ExtensionTypeError* if
- it is not supported. The default implementation checks if the
- passed type is defined in the `extension_types` field. """
- if not type in self.extension_types:
- raise ExtensionTypeError('Invalid type %s passed.' % type)
- class StandartLookupManager(LookupManager):
- """ This is the standart lookup manager implementing the `'method'`,
- `'property'` and `'attr'` extension types. """
- extension_types = ('method', 'property', 'attr')
- def wrap_method(self, name, object, instance, owner):
- func = lambda *args, **kwargs: object(instance, *args, **kwargs)
- func = functools.wraps(object)(func)
- func.func_name = name
- func.__name__ = name
- return func
- def wrap_property(self, name, object, instance, owner):
- return object(instance)
- def wrap_attr(self, name, object, instance, owner):
- return object
- class ExtensionToAttributeConnector(object):
- """ This class is the direct communication layer between the extensions
- and the user of the `ExtensionManager`. It is returned when the
- `ExtensionManager` is requested on an instance, so an attribute-lookup
- on an instance of this class will result in an extension-lookup. """
- def __init__(self, manager, instance, caller):
- super(ExtensionToAttributeConnector, self).__init__()
- self.manager = manager
- self.instance = instance
- self.caller = caller
- def __getattr__(self, name):
- return self.manager.do_lookup(name, self.instance, self.caller)
- from blocks.utils.ext_manager import ExtensionManager
- class Block(object):
- ext = ExtensionManager()
- # ...
- def Block_render_response(self):
- # ...
- blocks.Block.ext.register_extension('render_response', Block_render_response, 'method')
- from blocks.ext.django import TemplateView
- def index(request):
- block = TemplateView(template_name='foo.html')
- return block.ext.render_response()
- # coding: UTF-8
- # file: blocks/utils/ext_manager.py
- """ blocks.utils.ext_manager - Class extension-manager. """
- import functools
- class ExtensionManager(object):
- """ This class is used as a property to dynamically add methods and
- data-fields (also called extensions in this context) to a class.
- Any attribute that will be gathered from this object will be wrapped
- according to the type of extension (see `register_extension()`). """
- def __init__(self):
- super(ExtensionManager, self).__init__()
- self._extensions = {}
- def __get__(self, instance, owner):
- if not instance:
- return self
- else:
- return ExtensionLookup(self._extensions, instance, owner)
- def __set__(self, instance, value):
- raise AttributeError("can't overwrite ExtensionManager property.")
- def register_extension(self, name, object, type='method'):
- """ Register an extension to the manager. The type of *object* depends
- on the value of *type*. The extensions name must be passed with
- *name*. It is associated with *object* and used on attribute
- lookup.
- * `type == 'method'`:
- *object* is assumed to be callable and is passed the calling
- instance of the host-class plus the arguments passed on
- method invocation.
- * `type == 'classmethod`:
- *object* is assumed to be callable and is passed the host-class
- plus the arguments passed on invocation.
- * `type == 'property'`:
- *object* can be of anytype and is returned as is.
- """
- self._extensions[name] = [object, type]
- class ExtensionLookup(object):
- """ This is a private class used by the `ExtensionManager` class to
- wrap the registered together with an instance.
- Attribute lookup will be redirected to the registered extensions. """
- def __init__(self, extensions, instance, owner):
- super(ExtensionLookup, self).__init__()
- self.extensions = extensions
- self.instance = instance
- self.owner = owner
- def __getattr__(self, name):
- object, type = self.extensions[name]
- if type == 'method':
- func = lambda *args, **kwargs: object(self.instance, *args, **kwargs)
- elif type == 'staticmethod':
- func = lambda *args, **kwargs: object(self.owner, *args, **kwargs)
- elif type == 'property':
- return object
- else:
- raise RuntimeError('invalid extension-type found.')
- func = functools.wraps(object)(func)
- return func
Add Comment
Please, Sign In to add comment