Skip to content

Commit

Permalink
add minimal documentation for lift and onlyliftedfrom
Browse files Browse the repository at this point in the history
  • Loading branch information
mcdonc committed May 28, 2013
1 parent 2ee54b1 commit 6ae8509
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Expand Up @@ -3,6 +3,10 @@

- Drop support of Python 2.4 / 2.5 / Jython.

- Add ``lift`` and ``onlyliftedfrom`` class decorators to allow for inheritance
of venusian decorators attached to superclass methods. See the API
documentation for more information.

1.0a8 (2013-04-15)
------------------

Expand Down
5 changes: 4 additions & 1 deletion docs/api.rst
Expand Up @@ -9,5 +9,8 @@ API Documentation for Venusian

.. autoclass:: AttachInfo

.. autofunction:: attach(wrapped, callback, category=None)
.. autofunction:: attach(wrapped, callback, category=None, name=None)

.. autoclass:: lift

.. auutoclass:: onlyliftedfrom
102 changes: 101 additions & 1 deletion venusian/__init__.py
Expand Up @@ -270,7 +270,15 @@ def attached_to(self, obj):
def attach(wrapped, callback, category=None, depth=1, name=None):
""" Attach a callback to the wrapped object. It will be found
later during a scan. This function returns an instance of the
:class:`venusian.AttachInfo` class."""
:class:`venusian.AttachInfo` class.
``category`` should be ``None`` or a string representing a decorator
category name.
``name`` should be ``None`` or a string representing a subcategory within
the category. This will be used by the ``lift`` class decorator to
determine if decorations of a method should be inherited or overridden.
"""

frame = sys._getframe(depth+1)
scope, module, f_locals, f_globals, codeinfo = getFrameInfo(frame)
Expand Down Expand Up @@ -373,7 +381,69 @@ def seen(p, m={}):
else:
yield importer, name, ispkg


class lift(object):
"""
A class decorator which 'lifts' superclass venusian configuration
decorations into subclasses. For example::
from venusian import lift
from somepackage import venusian_decorator
class Super(object):
@venusian_decorator()
def boo(self): pass
@venusian_decorator()
def hiss(self): pass
@venusian_decorator()
def jump(self): pass
@lift()
class Sub(Super):
def boo(self): pass
def hiss(self): pass
@venusian_decorator()
def smack(self): pass
The above configuration will cause the callbacks of seven venusian
decorators. The ones attached to Super.boo, Super.hiss, and Super.jump
*plus* ones attached to Sub.boo, Sub.hiss, Sub.hump and Sub.smack.
If a subclass overrides a decorator on a method, its superclass decorators
will be ignored for the subclass. That means that in this configuration:
from venusian import lift
from somepackage import venusian_decorator
class Super(object):
@venusian_decorator()
def boo(self): pass
@venusian_decorator()
def hiss(self): pass
@lift()
class Sub(Super):
def boo(self): pass
@venusian_decorator()
def hiss(self): pass
Only four, not five decorator callbacks will be run: the ones attached to
Super.boo and Super.hiss, the inherited one of Sub.boo and the
non-inherited one of Sub.hiss. The inherited decorator on Super.hiss will
be ignored for the subclass.
The ``lift`` decorator takes a single argument named 'categories'. If
supplied, it should be a tuple of category names. Only decorators
in this category will be lifted if it is suppled.
"""
def __init__(self, categories=None):
self.categories = categories

Expand Down Expand Up @@ -417,6 +487,36 @@ def __call__(self, wrapped):
return wrapped

class onlyliftedfrom(object):
"""
A class decorator which marks a class as 'only lifted from'. Decorations
made on methods of the class won't have their callbacks called directly,
but classes which inherit from only-lifted-from classes which also use the
``lift`` class decorator will use the superclass decoration callbacks.
For example::
from venusian import lift, onlyliftedfrom
from somepackage import venusian_decorator
@onlyliftedfrom()
class Super(object):
@venusian_decorator()
def boo(self): pass
@venusian_decorator()
def hiss(self): pass
@lift()
class Sub(Super):
def boo(self): pass
def hiss(self): pass
Only two decorator callbacks will be run: the ones attached to Sub.boo and
Sub.hiss. The inherited decorators on Super.boo and Super.hiss will be
not be registered.
"""
def __call__(self, wrapped):
if not isclass(wrapped):
raise RuntimeError(
Expand Down

0 comments on commit 6ae8509

Please sign in to comment.