xrea-banner xreaad

decorators

namespace kilrey; / python / 自作ライブラリ / decorators

kilrey.decoratosライブラリです。 便利なデコレータ、メタクラスを提供します。 (download)

kilrey.decorators.mimic

デコレータ 'mimic' は関数のメタ情報をコピーした関数を生成します。 他の類似デコレータと比べてコピーするメタ情報が多いのが特徴です。 例えば、標準で付属している functools.wraps では __module__, __name__, __doc__ といった 書き換え可能な属性をラッパーに設定するだけですが、 kilrey.decoratos.mimic.mimic では func_code やトレースバックまで書き換えます。

kilrey.decorators.docassert

デコレータ 'docassert', メタクラス 'DocAssert' は python にて Design by Contract(DbC) を実現します。 すでにある DbC ライブラリとの最大の違いは docstring 中に条件を端的に書くので pydoc などのドキュメントシステムと相性が良い点です。 以前のdocassertから細かい点が変わっていますが、 基本的な使い方は変わっていません。

今、自分で使いながら少しずつ機能を追加しているところです。 あまりドキュメントを書いていないので その代わりに pydoc の出力を載せておきます。 機能の追加や日本語の解説などへの要望は id:kilrey へお願いします。

kilrey.decorators.mimic
Help on module mimic:

NAME
    mimic - kilrey.decorators.mimic

FILE
    kilrey/decorators/mimic.py

DESCRIPTION
    The decorator 'mimic' builds a wrapper function
    with the meta informations of another function.
    The advantage over the others is
    that the overwritten meta informations are
    not only of the function itself but of the func_code.
    
    The overwritten meta informations are following.
    - __module__
    - func_name and __name__
    - func_doc and __doc__
    - func_defaults
    - func_globals
    - func_code.co_argcount
    - func_code.co_filename
    - func_code.co_firstlineno
    - func_code.co_name
    - func_code.co_nlocals
    - func_code.co_varnames
    - The tracebacks in the raised exception.

FUNCTIONS
    metainfo(_func, _file, _line, _fname, _spec, _assigned, _updated)
        Decorate a function(_func) with metainfos.
    
    mimic(_orig)
        >>> from kilrey.decorators.mimic import mimic
        >>> def test(_args0, _args1=1, *_args, **_dict):
        ...     'This is the docstring of test.'
        ...     raise SyntaxError
        >>> @mimic(test)
        ... def dummy(*_args, **_dict):
        ...     return test(*_args, **_dict)
        >>> dummy == test
        False
        >>> dummy.__name__
        'test'
        >>> dummy.__doc__
        'This is the docstring of test.'
        >>> dummy.func_name == test.func_name
        True
        >>> dummy.func_doc == test.func_doc
        True
        >>> dummy.func_defaults == test.func_defaults
        True
        >>> dummy.func_globals == test.func_globals
        True
        >>> dummy.func_code.co_argcount == test.func_code.co_argcount
        True
        >>> dummy.func_code.co_filename == test.func_code.co_filename
        True
        >>> dummy.func_code.co_firstlineno == test.func_code.co_firstlineno
        True
        >>> dummy.func_code.co_name == test.func_code.co_name
        True
        >>> dummy.func_code.co_nlocals == test.func_code.co_nlocals
        True
        >>> dummy.func_code.co_varnames == test.func_code.co_varnames
        True
        >>> import sys
        >>> import traceback
        >>> try:#doctest:+ELLIPSIS
        ...     test(0)
        ... except:
        ...     traceback.print_exception(file=sys.stdout, *sys.exc_info())
        ...     pass
        Traceback (most recent call last):
          File "<doctest __main__.mimic[...]>", line 2, in <module>
            test(0)
          File "<doctest __main__.mimic[1]>", line 3, in test
            raise SyntaxError
        SyntaxError: None
        >>> try:#doctest:+ELLIPSIS
        ...     dummy(0)
        ... except:
        ...     traceback.print_exception(file=sys.stdout, *sys.exc_info())
        ...     pass
        Traceback (most recent call last):
          File "<doctest __main__.mimic[...]>", line 2, in <module>
            dummy(0)
          File "<doctest __main__.mimic[1]>", line 3, in test
            raise SyntaxError
        SyntaxError: None

DATA
    __author__ = 'kilrey@kilrey.com'
    __date__ = '2008/11/30'
    __licence__ = 'The MIT License\n\nCopyright (c) 2008 kilrey@kilre...RE...

DATE
    2008/11/30

AUTHOR
    kilrey@kilrey.com
        
kilrey.decorators.docassert
Help on module docassert:

NAME
    docassert - kilrey.decorators.docassert

FILE
    kilrey/decorators/docassert.py

DESCRIPTION
    The decorator 'docassert' and metaclass 'DocAssert'
    are for the Design by Contract in python
    using assertions written in docstrings.
    The contracts for classes are enforced recursively.
    Only if __debug__ is true,
    the contracts will weaved into the functions.
    
    Write contract expressions with tags in docstrings.
    For functions, decorate them with @docassert.
    For classes, set DocAssert as __metaclass__.
    Examples are written in docassert.__doc__.
    Write such as '@setup <statements>' or '@invariant <expression>'
    
    In contract expressions,
    you should know some additional rules.
    - The arguments can be used as their own identifiers.
    - The function itself is called '__func'.
    - The return value can be used as '__retval'.
    - The exception value can be used as '__except'.
    - The decorators need '@@' not '@'.
    
    Description:
    1) The defined tags.
    1-1) @setup
    @setup is statements working before the function.
    1-2) @teardown
    @teardown is statements working after the function.
    1-3) @invariant
    @invariant is a contract for invariant-conditions.
    1-4) @precond
    @precond is a contract expression for pre-conditions.
    1-5) @postcond
    @postcond is a contract expression for post-conditions.
    1-6) @return
    @return is a contract expression for post-conditions
    asserting in returning normally.
    1-7) @except
    @except is a contract expression for post-conditions
    asserting in raising exceptions.
    
    2) The evaluating sequence.
    2-1)  Execute @setup of the class.
    2-2)  Assert  @invariant of the class.
    2-3)  Assert  @precond of the class.
    2-4)  Execute @setup of the function.
    2-5)  Assert  @invariant of the function.
    2-6)  Assert  @precond of the function.
    2-7)  Call the function itself.
    2-8)  Assert  @return or @except of the function.
    2-9)  Assert  @postcond of the function.
    2-10) Assert  @invariant of the function.
    2-11) Execute @teardown of the function.
    2-12) Assert  @return or @except of the class.
    2-13) Assert  @postcond of the class.
    2-14) Assert  @invariant of the class.
    2-15) Execute @teardown of the class.
    
    3) The notices.
    3-1) In executing or asserting a contract,
         any contracts are ignored.
    3-2) The guard conditions are sometimes needed,
         such as 'not hasattr(self, 'x') or self.x == 0'.

CLASSES
    __builtin__.type(__builtin__.object)
        DocAssert
    
    class DocAssert(__builtin__.type)
     |  Wrap the all methods of the class(_class)
     |  with the contracts in the docstring(_doc).
     |  >>> from kilrey.decorators.docassert import *
     |  >>> class Test:
     |  ...     """
     |  ...     @setup print "setup"
     |  ...     @teardown print "teardown"
     |  ...     @invariant not hasattr(self, 'x') or self.x == 0
     |  ...     """
     |  ...     __metaclass__ = DocAssert
     |  ...     def __init__(self, x):
     |  ...         self.x = x
     |  ...         pass
     |  ...     def test(self):
     |  ...         self.x += 1
     |  ...         pass
     |  ...     pass
     |  >>> _t = Test(0)
     |  setup
     |  setup
     |  teardown
     |  teardown
     |  >>> _t.x
     |  setup
     |  teardown
     |  0
     |  >>> _t.test()
     |  Traceback (most recent call last):
     |  ...
     |  AssertionError: @invariant not hasattr(self, 'x') or self.x == 0
     |  >>> _t.x = 1
     |  Traceback (most recent call last):
     |  ...
     |  AssertionError: @invariant not hasattr(self, 'x') or self.x == 0
     |  >>> _t.x
     |  Traceback (most recent call last):
     |  ...
     |  AssertionError: @invariant not hasattr(self, 'x') or self.x == 0
     |  
     |  Method resolution order:
     |      DocAssert
     |      __builtin__.type
     |      __builtin__.object
     |  
     |  Static methods defined here:
     |  
     |  __new__(mcs, _clsname, _clsbases, _clsdict)
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from __builtin__.type:
     |  
     |  __call__(...)
     |      x.__call__(...) <==> x(...)
     |  
     |  __cmp__(...)
     |      x.__cmp__(y) <==> cmp(x,y)
     |  
     |  __delattr__(...)
     |      x.__delattr__('name') <==> del x.name
     |  
     |  __getattribute__(...)
     |      x.__getattribute__('name') <==> x.name
     |  
     |  __hash__(...)
     |      x.__hash__() <==> hash(x)
     |  
     |  __repr__(...)
     |      x.__repr__() <==> repr(x)
     |  
     |  __setattr__(...)
     |      x.__setattr__('name', value) <==> x.name = value
     |  
     |  __subclasses__(...)
     |      __subclasses__() -> list of immediate subclasses
     |  
     |  mro(...)
     |      mro() -> list
     |      return a type's method resolution order
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors inherited from __builtin__.type:
     |  
     |  __base__
     |  
     |  __bases__
     |  
     |  __basicsize__
     |  
     |  __dict__
     |  
     |  __dictoffset__
     |  
     |  __flags__
     |  
     |  __itemsize__
     |  
     |  __mro__
     |  
     |  __weakrefoffset__

FUNCTIONS
    docassert(_func)
        Wrap the function(_func)
        with the contracts in the docstring(_doc).
        >>> from kilrey.decorators.docassert import *
        >>> @docassert
        ... def test(_arg0):
        ...     """
        ...     @setup print "setup"
        ...     @teardown print "teardown"
        ...     @invariant _arg0 == 0
        ...     @precond _arg0 == 0
        ...     @postcond _arg0 == 0
        ...     @return __retval == 1
        ...     @except __except.message == 'ERROR'
        ...     """
        ...     return _arg0+1
        >>> test(0)
        setup
        teardown
        1
        >>> test(1)
        Traceback (most recent call last):
        ...
        AssertionError: @invariant _arg0 == 0

DATA
    __author__ = 'kilrey@kilrey.com'
    __date__ = '2008/11/30'
    __licence__ = 'The MIT License\n\nCopyright (c) 2008 kilrey@kilre...RE...

DATE
    2008/11/30

AUTHOR
    kilrey@kilrey.com