Guest User

Untitled

a guest
Jan 17th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.35 KB | None | 0 0
  1. class Block(object):
  2.  
  3. def render(self, dest):
  4. # ...
  5. pass
  6.  
  7. class TemplateBlock(Block):
  8.  
  9. def render(self, dest):
  10. # ...
  11. pass
  12.  
  13. # blocks.ext.django
  14.  
  15. import blocks
  16. import django.http
  17.  
  18. class Block(blocks.Block):
  19.  
  20. def render_to_response(self):
  21. # ...
  22. result = self.render(dest)
  23. return django.http.HtppRequest(result)
  24.  
  25. # blocks.ext.django
  26.  
  27. # ...
  28.  
  29. class TemplateBlock(blocks.TemplateBlock, Block):
  30.  
  31. pass
  32.  
  33. class Test(object):
  34.  
  35. ext = ExtensionManager()
  36.  
  37. def __init__(self, v):
  38. self.v = v
  39.  
  40. class Extensions():
  41. __metaclass__ = ExtensionClassMeta
  42. managers = [Test.ext]
  43.  
  44. @Extension('method')
  45. def print_v(self):
  46. print self.v
  47.  
  48. Test('Value of Test instance').ext.print_v()
  49. print Extensions
  50.  
  51. C:UsersniklasDesktopblog>python -m blocks.utils.ext_manager
  52. Value of Test instance
  53. (<__main__.ExtensionManager object at 0x021725B0>,)
  54.  
  55. class CoolLookupManager(LookupManager):
  56.  
  57. extension_types = ('ice',)
  58.  
  59. def wrap_ice(self, name, object, instance, owner):
  60. return "%s is cool as ice." % object(instance)
  61.  
  62. class Test(object):
  63.  
  64. ext = ExtensionManager(lookup_manager=CoolLookupManager())
  65.  
  66. def __init__(self, v):
  67. self.v = v
  68.  
  69. class Extensions():
  70. __metaclass__ = ExtensionClassMeta
  71. managers = [Test.ext]
  72.  
  73. @Extension('ice')
  74. def get_v(self):
  75. return self.v
  76.  
  77. print Test('StackOverflow').ext.get_v
  78.  
  79. C:UsersniklasDesktopblog>python -m blocks.utils.ext_manager
  80. StackOverflow is cool as ice.
  81.  
  82. # coding: UTF-8
  83. # file: blocks/utils/ext_manager.py
  84. #
  85. # Copyright (C) 2012, Niklas Rosenstein
  86. """ blocks.utils.ext_manager - Class extension-manager. """
  87.  
  88. import functools
  89.  
  90. class ExtensionTypeError(Exception):
  91. """ Raised when an extension type is not supported. """
  92.  
  93. class Extension(object):
  94. """ This decorator is used to mark an attribute on an extension class
  95. as being actually an extension. """
  96.  
  97. def __init__(self, type):
  98. super(Extension, self).__init__()
  99. self.type = type
  100. self.object = None
  101.  
  102. def __str__(self):
  103. return '<Extension: %s>' % self.type
  104.  
  105. def __call__(self, object):
  106. self.object = object
  107. return self
  108.  
  109. class ExtensionClassMeta(type):
  110. """ This meta-class processes an extension class and adds the defined
  111. extensions into the `ExtensionManager` objects defined in the
  112. extension class. """
  113.  
  114. def __new__(self, name, bases, dict):
  115. # Ensure there is no base.
  116. if bases:
  117. raise ValueError('the ExtensionClassMeta meta-class does not accept bases.')
  118.  
  119. # Obtain a list of the managers that need to be extended.
  120. managers = dict.pop('managers', None)
  121. if not managers:
  122. raise ValueError('at least one manager must be given in the class.')
  123.  
  124. # A single ExtensionManager instance of the `managers` attribute is
  125. # allowed, so convert it to a list to ensure that the next test
  126. # will not fail.
  127. if isinstance(managers, ExtensionManager):
  128. managers = [managers]
  129.  
  130. # Make sure the managers is a list.
  131. if not isinstance(managers, (list, tuple)):
  132. raise ValueError('managers names must be list or tuple.')
  133.  
  134. # Iterate over all managers to ensure they're all ExtensionManager
  135. # instances.
  136. for manager in managers:
  137. if not isinstance(manager, ExtensionManager):
  138. raise ValueError('object in managers not instance of ExtensionManager class.')
  139.  
  140. # Iterate over all attributes of the class and extend the managers.
  141. for name, value in dict.iteritems():
  142. # Only `Extension` instances will be registered to the extension
  143. # managers. Other values are just ignored.
  144. if isinstance(value, Extension):
  145. for manager in managers:
  146. manager.register_extension(name, value.object, value.type)
  147.  
  148. return tuple(managers)
  149.  
  150. class ExtensionManager(object):
  151. """ This class is used as a property to dynamically add methods and
  152. data-fields (also called extensions in this context) to a class.
  153.  
  154. Any attribute that will be gathered from this object will be wrapped
  155. according to the type of extension (see `register_extension()`). """
  156.  
  157. def __init__(self, lookup_manager=None):
  158. super(ExtensionManager, self).__init__()
  159. self._extensions = {}
  160.  
  161. if not lookup_manager:
  162. lookup_manager = StandartLookupManager()
  163. self.lookup_manager = lookup_manager
  164.  
  165. def __get__(self, instance, owner):
  166. if not instance:
  167. return self
  168. else:
  169. return ExtensionToAttributeConnector(self, instance, owner)
  170.  
  171. def __set__(self, instance, value):
  172. raise AttributeError("can't overwrite ExtensionManager property.")
  173.  
  174. def __delete__(self, instance):
  175. raise AttributeError("can't delete ExtensionManager property.")
  176.  
  177. def register_extension(self, name, object, type='method'):
  178. """ Register an extension to the manager. The type of *object* depends
  179. on the value of *type*. The extensions name must be passed with
  180. *name*. It is associated with *object* and used on attribute
  181. lookup. If the type is not valid, the lookup manager will
  182. raise an *ExtensionTypeError*.
  183. """
  184. self.lookup_manager.validate_type(type)
  185. self._extensions[name] = [object, type]
  186.  
  187. def do_lookup(self, name, instance, owner):
  188. """ Forward the extension lookup to the lookup manager to obtain the
  189. value of an extension. """
  190. return self.lookup_manager.do_lookup(self._extensions, name, instance, owner)
  191.  
  192. class LookupManager(object):
  193. """ This is the base-class for lookup managers. A lookup manager is created
  194. by an `ExtensionManager` instance when watching out for a specific
  195. attribute on an instance.
  196.  
  197. The `ExtensionManager` will ask the `LookupManager` to validate the
  198. type of an extension. The lookup manager itself will call functions
  199. depending on the type of an extension.
  200.  
  201. If you have a lookup manager which supports the type `'FOO'`,
  202. and an extension of that type is requested, it will call the
  203. function `wrap_FOO()`. Such a method has the following signature:
  204.  
  205. * `self`: The `LookupManager` instance.
  206. * `ext_name`: A string defining the name of the extension that
  207. is looked up.
  208. * `instance`: The invoking instance, as passed by `__get__`.
  209. * `owner`: The invoking class, as passed by `__get__`.
  210.  
  211. The `wrap_FOO()` function must wrap and return *object* so it can
  212. be used by the requestor.
  213.  
  214. The types of extensions the lookup manager supports is defined in
  215. the `extension_types` attribute which *must* be an iterable of string.
  216. """
  217.  
  218. extension_types = ()
  219.  
  220. def do_lookup(self, extensions, name, instance, owner):
  221. """ Perform a lookup on the passed *extensions* and call the
  222. corresponding `wrap_FOO()` method. *extensions* should be a
  223. dictionary containing `(object, type)` pairs only where *object*
  224. is the registered extension and *type* is its type.
  225.  
  226. *connector* is an instance of `ExtensionToAttributeConnector`. """
  227.  
  228. object = extensions.get(name, None)
  229. if not object:
  230. raise AttributeError('no extension named %s.' % name)
  231.  
  232. object, type = object
  233. lookup_name = 'wrap_%s' % type
  234. processor = getattr(self, lookup_name, None)
  235. if not processor:
  236. raise RuntimeError('no processor %s found in lookup manager.' % lookup_name)
  237.  
  238. return processor(name, object, instance, owner)
  239.  
  240. def validate_type(self, type):
  241. """ Validate the passed *type* by raising *ExtensionTypeError* if
  242. it is not supported. The default implementation checks if the
  243. passed type is defined in the `extension_types` field. """
  244. if not type in self.extension_types:
  245. raise ExtensionTypeError('Invalid type %s passed.' % type)
  246.  
  247. class StandartLookupManager(LookupManager):
  248. """ This is the standart lookup manager implementing the `'method'`,
  249. `'property'` and `'attr'` extension types. """
  250.  
  251. extension_types = ('method', 'property', 'attr')
  252.  
  253. def wrap_method(self, name, object, instance, owner):
  254. func = lambda *args, **kwargs: object(instance, *args, **kwargs)
  255. func = functools.wraps(object)(func)
  256. func.func_name = name
  257. func.__name__ = name
  258. return func
  259.  
  260. def wrap_property(self, name, object, instance, owner):
  261. return object(instance)
  262.  
  263. def wrap_attr(self, name, object, instance, owner):
  264. return object
  265.  
  266. class ExtensionToAttributeConnector(object):
  267. """ This class is the direct communication layer between the extensions
  268. and the user of the `ExtensionManager`. It is returned when the
  269. `ExtensionManager` is requested on an instance, so an attribute-lookup
  270. on an instance of this class will result in an extension-lookup. """
  271.  
  272. def __init__(self, manager, instance, caller):
  273. super(ExtensionToAttributeConnector, self).__init__()
  274. self.manager = manager
  275. self.instance = instance
  276. self.caller = caller
  277.  
  278. def __getattr__(self, name):
  279. return self.manager.do_lookup(name, self.instance, self.caller)
  280.  
  281. from blocks.utils.ext_manager import ExtensionManager
  282.  
  283. class Block(object):
  284.  
  285. ext = ExtensionManager()
  286.  
  287. # ...
  288.  
  289. def Block_render_response(self):
  290. # ...
  291.  
  292. blocks.Block.ext.register_extension('render_response', Block_render_response, 'method')
  293.  
  294. from blocks.ext.django import TemplateView
  295.  
  296. def index(request):
  297. block = TemplateView(template_name='foo.html')
  298. return block.ext.render_response()
  299.  
  300. # coding: UTF-8
  301. # file: blocks/utils/ext_manager.py
  302. """ blocks.utils.ext_manager - Class extension-manager. """
  303.  
  304. import functools
  305.  
  306. class ExtensionManager(object):
  307. """ This class is used as a property to dynamically add methods and
  308. data-fields (also called extensions in this context) to a class.
  309.  
  310. Any attribute that will be gathered from this object will be wrapped
  311. according to the type of extension (see `register_extension()`). """
  312.  
  313. def __init__(self):
  314. super(ExtensionManager, self).__init__()
  315. self._extensions = {}
  316.  
  317. def __get__(self, instance, owner):
  318. if not instance:
  319. return self
  320. else:
  321. return ExtensionLookup(self._extensions, instance, owner)
  322.  
  323. def __set__(self, instance, value):
  324. raise AttributeError("can't overwrite ExtensionManager property.")
  325.  
  326. def register_extension(self, name, object, type='method'):
  327. """ Register an extension to the manager. The type of *object* depends
  328. on the value of *type*. The extensions name must be passed with
  329. *name*. It is associated with *object* and used on attribute
  330. lookup.
  331.  
  332. * `type == 'method'`:
  333.  
  334. *object* is assumed to be callable and is passed the calling
  335. instance of the host-class plus the arguments passed on
  336. method invocation.
  337.  
  338. * `type == 'classmethod`:
  339.  
  340. *object* is assumed to be callable and is passed the host-class
  341. plus the arguments passed on invocation.
  342.  
  343. * `type == 'property'`:
  344.  
  345. *object* can be of anytype and is returned as is.
  346. """
  347.  
  348. self._extensions[name] = [object, type]
  349.  
  350. class ExtensionLookup(object):
  351. """ This is a private class used by the `ExtensionManager` class to
  352. wrap the registered together with an instance.
  353.  
  354. Attribute lookup will be redirected to the registered extensions. """
  355.  
  356. def __init__(self, extensions, instance, owner):
  357. super(ExtensionLookup, self).__init__()
  358. self.extensions = extensions
  359. self.instance = instance
  360. self.owner = owner
  361.  
  362. def __getattr__(self, name):
  363. object, type = self.extensions[name]
  364. if type == 'method':
  365. func = lambda *args, **kwargs: object(self.instance, *args, **kwargs)
  366. elif type == 'staticmethod':
  367. func = lambda *args, **kwargs: object(self.owner, *args, **kwargs)
  368. elif type == 'property':
  369. return object
  370. else:
  371. raise RuntimeError('invalid extension-type found.')
  372.  
  373. func = functools.wraps(object)(func)
  374. return func
Add Comment
Please, Sign In to add comment