Hello community, here is the log from the commit of package python3-decorator for openSUSE:Factory checked in at 2015-01-10 23:05:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-decorator (Old) and /work/SRC/openSUSE:Factory/.python3-decorator.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-decorator" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-decorator/python3-decorator.changes 2013-06-21 19:01:35.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python3-decorator.new/python3-decorator.changes 2015-01-10 23:05:26.000000000 +0100 @@ -1,0 +2,13 @@ +Fri Jan 9 23:51:03 UTC 2015 - a...@gmx.de + +- specfile: update copyright year + +- update to version 3.4.0: + * Added the ability to use classes and generic callables as callers + and implemented a signature-preserving contexmanager + decorator. + * Fixed a bug with the signature f(**kw) in Python 3 and + * fixed a couple of doctests broken by Python 3.3, both issues + pointed out by Dominic Sacré (18/10/2012) + +------------------------------------------------------------------- Old: ---- decorator-3.3.3.tar.gz New: ---- decorator-3.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-decorator.spec ++++++ --- /var/tmp/diff_new_pack.lp9ve6/_old 2015-01-10 23:05:27.000000000 +0100 +++ /var/tmp/diff_new_pack.lp9ve6/_new 2015-01-10 23:05:27.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package python3-decorator # -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: python3-decorator -Version: 3.3.3 +Version: 3.4.0 Release: 0 Url: http://pypi.python.org/pypi/decorator Summary: Better living through Python with decorators ++++++ decorator-3.3.3.tar.gz -> decorator-3.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-3.3.3/PKG-INFO new/decorator-3.4.0/PKG-INFO --- old/decorator-3.3.3/PKG-INFO 2012-04-23 16:52:05.000000000 +0200 +++ new/decorator-3.4.0/PKG-INFO 2012-10-18 10:53:16.000000000 +0200 @@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: decorator -Version: 3.3.3 +Version: 3.4.0 Summary: Better living through Python with decorators Home-page: http://pypi.python.org/pypi/decorator Author: Michele Simionato diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-3.3.3/documentation.py new/decorator-3.4.0/documentation.py --- old/decorator-3.3.3/documentation.py 2011-11-09 15:21:29.000000000 +0100 +++ new/decorator-3.4.0/documentation.py 2012-10-18 10:48:36.000000000 +0200 @@ -340,18 +340,16 @@ implemented as a function returning a decorator. For more complex situations, it is more convenient to implement decorator factories as classes returning -callable objects that can be used as signature-preserving -decorators. The suggested pattern to do that is to introduce -a helper method ``call(self, func, *args, **kw)`` and to call -it in the ``__call__(self, func)`` method. +callable objects that can be converted into decorators. -As an example, here I show a decorator +As an example, here will I show a decorator which is able to convert a blocking function into an asynchronous function. The function, when called, is executed in a separate thread. Moreover, it is possible to set three callbacks ``on_success``, ``on_failure`` and ``on_closing``, -to specify how to manage the function call. -The implementation is the following: +to specify how to manage the function call (of course the code here +is just an example, it is not a recommended way of doing multi-threaded +programming). The implementation is the following: $$on_success $$on_failure @@ -369,7 +367,7 @@ .. code-block:: python - >>> async = Async(threading.Thread) + >>> async = decorator(Async(threading.Thread)) >>> datalist = [] # for simplicity the written data are stored into a list. @@ -399,6 +397,71 @@ >>> print datalist ['data1', 'data2'] +contextmanager +------------------------------------- + +For a long time Python had in its standard library a ``contextmanager`` +decorator, able to convert generator functions into ``GeneratorContextManager`` +factories. For instance if you write + +.. code-block:: python + + >>> from contextlib import contextmanager + >>> @contextmanager + ... def before_after(before, after): + ... print(before) + ... yield + ... print(after) + + +then ``before_after`` is a factory function returning +``GeneratorContextManager`` objects which can be used with +the ``with`` statement: + +.. code-block:: python + + >>> ba = before_after('BEFORE', 'AFTER') + >>> type(ba) + <class 'contextlib.GeneratorContextManager'> + >>> with ba: + ... print 'hello' + BEFORE + hello + AFTER + +Basically, it is as if the content of the ``with`` block was executed +in the place of the ``yield`` expression in the generator function. +In Python 3.2 ``GeneratorContextManager`` +objects were enhanced with a ``__call__`` +method, so that they can be used as decorators as in this example: + +.. code-block:: python + + >>> @ba # doctest: +SKIP + ... def hello(): + ... print 'hello' + ... + >>> hello() # doctest: +SKIP + BEFORE + hello + AFTER + +The ``ba`` decorator is basically inserting a ``with ba:`` +block inside the function. +However there two issues: the first is that ``GeneratorContextManager`` +objects are callable only in Python 3.2, so the previous example will break +in older versions of Python; the second is that +``GeneratorContextManager`` objects do not preserve the signature +of the decorated functions: the decorated ``hello`` function here will have +a generic signature ``hello(*args, **kwargs)`` but will break when +called with more than zero arguments. For such reasons the decorator +module, starting with release 3.4, offers a ``decorator.contextmanager`` +decorator that solves both problems and works even in Python 2.5. +The usage is the same and factories decorated with ``decorator.contextmanager`` +will returns instances of ``ContextManager``, a subclass of +``contextlib.GeneratorContextManager`` with a ``__call__`` method +acting as a signature-preserving decorator. + The ``FunctionMaker`` class --------------------------------------------------------------- @@ -862,29 +925,28 @@ async_with_processes = Async(multiprocessing.Process) """ - def __init__(self, threadfactory): - self.threadfactory = threadfactory - - def __call__(self, func, on_success=on_success, + def __init__(self, threadfactory, on_success=on_success, on_failure=on_failure, on_closing=on_closing): - # every decorated function has its own independent thread counter - func.counter = itertools.count(1) - func.on_success = on_success - func.on_failure = on_failure - func.on_closing = on_closing - return decorator(self.call, func) - - def call(self, func, *args, **kw): + self.threadfactory = threadfactory + self.on_success = on_success + self.on_failure = on_failure + self.on_closing = on_closing + + def __call__(self, func, *args, **kw): + try: + counter = func.counter + except AttributeError: # instantiate the counter at the first call + counter = func.counter = itertools.count(1) + name = '%s-%s' % (func.__name__, counter.next()) def func_wrapper(): try: result = func(*args, **kw) except: - func.on_failure(sys.exc_info()) + self.on_failure(sys.exc_info()) else: - return func.on_success(result) + return self.on_success(result) finally: - func.on_closing() - name = '%s-%s' % (func.__name__, func.counter.next()) + self.on_closing() thread = self.threadfactory(None, func_wrapper, name) thread.start() return thread @@ -1048,5 +1110,25 @@ 'The good old factorial' """ +@contextmanager +def before_after(before, after): + print(before) + yield + print(after) + +ba = before_after('BEFORE', 'AFTER') # ContextManager instance + +@ba +def hello(user): + """ + >>> ba.__class__.__name__ + 'ContextManager' + >>> hello('michele') + BEFORE + hello michele + AFTER + """ + print('hello %s' % user) + if __name__ == '__main__': import doctest; doctest.testmod() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-3.3.3/documentation3.py new/decorator-3.4.0/documentation3.py --- old/decorator-3.3.3/documentation3.py 2012-04-23 16:48:39.000000000 +0200 +++ new/decorator-3.4.0/documentation3.py 2012-10-18 10:49:13.000000000 +0200 @@ -130,7 +130,7 @@ .. code-block:: python - >>> f1(0, 1) + >>> f1(0, 1) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TypeError: f1() takes exactly 1 positional argument (2 given) @@ -302,7 +302,8 @@ >>> @decorator ... def trace(f, *args, **kw): - ... print("calling %s with args %s, %s" % (f.__name__, args, kw)) + ... kwstr = ', '.join('%r: %r' % (k, kw[k]) for k in sorted(kw)) + ... print("calling %s with args %s, {%s}" % (f.__name__, args, kwstr)) ... return f(*args, **kw) and now ``trace`` will be a decorator. Actually ``trace`` is a ``partial`` @@ -370,18 +371,16 @@ implemented as a function returning a decorator. For more complex situations, it is more convenient to implement decorator factories as classes returning -callable objects that can be used as signature-preserving -decorators. The suggested pattern to do that is to introduce -a helper method ``call(self, func, *args, **kw)`` and to call -it in the ``__call__(self, func)`` method. +callable objects that can be converted into decorators. -As an example, here I show a decorator +As an example, here will I show a decorator which is able to convert a blocking function into an asynchronous function. The function, when called, is executed in a separate thread. Moreover, it is possible to set three callbacks ``on_success``, ``on_failure`` and ``on_closing``, -to specify how to manage the function call. -The implementation is the following: +to specify how to manage the function call (of course the code here +is just an example, it is not a recommended way of doing multi-threaded +programming). The implementation is the following: $$on_success $$on_failure @@ -399,7 +398,7 @@ .. code-block:: python - >>> async = Async(threading.Thread) + >>> async = decorator(Async(threading.Thread)) >>> datalist = [] # for simplicity the written data are stored into a list. @@ -429,6 +428,71 @@ >>> print(datalist) ['data1', 'data2'] +contextmanager +------------------------------------- + +For a long time Python had in its standard library a ``contextmanager`` +decorator, able to convert generator functions into ``_GeneratorContextManager`` +factories. For instance if you write + +.. code-block:: python + + >>> from contextlib import contextmanager + >>> @contextmanager + ... def before_after(before, after): + ... print(before) + ... yield + ... print(after) + + +then ``before_after`` is a factory function returning +``_GeneratorContextManager`` objects which can be used with +the ``with`` statement: + +.. code-block:: python + + >>> ba = before_after('BEFORE', 'AFTER') + >>> type(ba) + <class 'contextlib._GeneratorContextManager'> + >>> with ba: + ... print('hello') + BEFORE + hello + AFTER + +Basically, it is as if the content of the ``with`` block was executed +in the place of the ``yield`` expression in the generator function. +In Python 3.2 ``_GeneratorContextManager`` +objects were enhanced with a ``__call__`` +method, so that they can be used as decorators as in this example: + +.. code-block:: python + + >>> @ba # doctest: +SKIP + ... def hello(): + ... print('hello') + ... + >>> hello() # doctest: +SKIP + BEFORE + hello + AFTER + +The ``ba`` decorator is basically inserting a ``with ba:`` +block inside the function. +However there two issues: the first is that ``_GeneratorContextManager`` +objects are callable only in Python 3.2, so the previous example will break +in older versions of Python; the second is that +``_GeneratorContextManager`` objects do not preserve the signature +of the decorated functions: the decorated ``hello`` function here will have +a generic signature ``hello(*args, **kwargs)`` but will break when +called with more than zero arguments. For such reasons the decorator +module, starting with release 3.4, offers a ``decorator.contextmanager`` +decorator that solves both problems and works even in Python 2.5. +The usage is the same and factories decorated with ``decorator.contextmanager`` +will returns instances of ``ContextManager``, a subclass of +``contextlib._GeneratorContextManager`` with a ``__call__`` method +acting as a signature-preserving decorator. + The ``FunctionMaker`` class --------------------------------------------------------------- @@ -832,7 +896,8 @@ dict(decorated=dec(func)), __wrapped__=func) def _trace(f, *args, **kw): - print("calling %s with args %s, %s" % (f.__name__, args, kw)) + kwstr = ', '.join('%r: %r' % (k, kw[k]) for k in sorted(kw)) + print("calling %s with args %s, {%s}" % (f.__name__, args, kwstr)) return f(*args, **kw) def trace(f): @@ -859,29 +924,28 @@ async_with_processes = Async(multiprocessing.Process) """ - def __init__(self, threadfactory): - self.threadfactory = threadfactory - - def __call__(self, func, on_success=on_success, + def __init__(self, threadfactory, on_success=on_success, on_failure=on_failure, on_closing=on_closing): - # every decorated function has its own independent thread counter - func.counter = itertools.count(1) - func.on_success = on_success - func.on_failure = on_failure - func.on_closing = on_closing - return decorator(self.call, func) - - def call(self, func, *args, **kw): + self.threadfactory = threadfactory + self.on_success = on_success + self.on_failure = on_failure + self.on_closing = on_closing + + def __call__(self, func, *args, **kw): + try: + counter = func.counter + except AttributeError: # instantiate the counter at the first call + counter = func.counter = itertools.count(1) + name = '%s-%s' % (func.__name__, next(counter)) def func_wrapper(): try: result = func(*args, **kw) except: - func.on_failure(sys.exc_info()) + self.on_failure(sys.exc_info()) else: - return func.on_success(result) + return self.on_success(result) finally: - func.on_closing() - name = '%s-%s' % (func.__name__, next(func.counter)) + self.on_closing() thread = self.threadfactory(None, func_wrapper, name) thread.start() return thread @@ -1039,7 +1103,7 @@ >>> decorator(_memoize).__name__ '_memoize' - Here is another bug of version 3.1.1 missing the docstring to avoid: + Here is another bug of version 3.1.1 missing the docstring: >>> factorial.__doc__ 'The good old factorial' @@ -1061,9 +1125,46 @@ ... return y, z ... >>> func('a', 'b', 'c', 'd', 'e', y='y', z='z', cat='dog') - calling func with args ('a', 'b', 'c', 'd', 'e'), {'y': 'y', 'z': 'z', 'cat': 'dog'} + calling func with args ('a', 'b', 'c', 'd', 'e'), {'cat': 'dog', 'y': 'y', 'z': 'z'} ('y', 'z') """ +def test_kwonly_no_args(): + """# this was broken with decorator 3.3.3 + >>> @trace + ... def f(**kw): pass + ... + >>> f() + calling f with args (), {} + """ +def test_kwonly_star_notation(): + """ + >>> @trace + ... def f(*, a=1, **kw): pass + ... + >>> inspect.getfullargspec(f) + FullArgSpec(args=[], varargs=None, varkw='kw', defaults=None, kwonlyargs=['a'], kwonlydefaults={'a': 1}, annotations={}) + """ + +@contextmanager +def before_after(before, after): + print(before) + yield + print(after) + +ba = before_after('BEFORE', 'AFTER') # ContextManager instance + +@ba +def hello(user): + """ + >>> ba.__class__.__name__ + 'ContextManager' + >>> hello('michele') + BEFORE + hello michele + AFTER + """ + print('hello %s' % user) + if __name__ == '__main__': import doctest; doctest.testmod() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-3.3.3/setup.cfg new/decorator-3.4.0/setup.cfg --- old/decorator-3.3.3/setup.cfg 2012-04-23 16:52:05.000000000 +0200 +++ new/decorator-3.4.0/setup.cfg 2012-10-18 10:53:16.000000000 +0200 @@ -1,5 +1,5 @@ [egg_info] tag_build = -tag_date = 0 tag_svn_revision = 0 +tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-3.3.3/src/decorator.egg-info/PKG-INFO new/decorator-3.4.0/src/decorator.egg-info/PKG-INFO --- old/decorator-3.3.3/src/decorator.egg-info/PKG-INFO 2012-04-23 16:52:03.000000000 +0200 +++ new/decorator-3.4.0/src/decorator.egg-info/PKG-INFO 2012-10-18 10:52:49.000000000 +0200 @@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: decorator -Version: 3.3.3 +Version: 3.4.0 Summary: Better living through Python with decorators Home-page: http://pypi.python.org/pypi/decorator Author: Michele Simionato diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-3.3.3/src/decorator.py new/decorator-3.4.0/src/decorator.py --- old/decorator-3.3.3/src/decorator.py 2012-04-23 16:48:39.000000000 +0200 +++ new/decorator-3.4.0/src/decorator.py 2012-10-18 10:49:13.000000000 +0200 @@ -32,28 +32,15 @@ for the documentation. """ -__version__ = '3.3.3' +__version__ = '3.4.0' -__all__ = ["decorator", "FunctionMaker", "partial"] +__all__ = ["decorator", "FunctionMaker", "contextmanager"] import sys, re, inspect - -try: - from functools import partial -except ImportError: # for Python version < 2.5 - class partial(object): - "A simple replacement of functools.partial" - def __init__(self, func, *args, **kw): - self.func = func - self.args = args - self.keywords = kw - def __call__(self, *otherargs, **otherkw): - kw = self.keywords.copy() - kw.update(otherkw) - return self.func(*(self.args + otherargs), **kw) - if sys.version >= '3': from inspect import getfullargspec + def get_init(cls): + return cls.__init__ else: class getfullargspec(object): "A quick and dirty replacement for getfullargspec for Python 2.X" @@ -67,6 +54,8 @@ yield self.varargs yield self.varkw yield self.defaults + def get_init(cls): + return cls.__init__.im_func DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(') @@ -100,17 +89,21 @@ inspect.formatargspec( formatvalue=lambda val: "", *argspec)[1:-1] else: # Python 3 way - self.signature = self.shortsignature = ', '.join(self.args) + allargs = list(self.args) + allshortargs = list(self.args) if self.varargs: - self.signature += ', *' + self.varargs - self.shortsignature += ', *' + self.varargs - if self.kwonlyargs: - for a in self.kwonlyargs: - self.signature += ', %s=None' % a - self.shortsignature += ', %s=%s' % (a, a) + allargs.append('*' + self.varargs) + allshortargs.append('*' + self.varargs) + elif self.kwonlyargs: + allargs.append('*') # single star syntax + for a in self.kwonlyargs: + allargs.append('%s=None' % a) + allshortargs.append('%s=%s' % (a, a)) if self.varkw: - self.signature += ', **' + self.varkw - self.shortsignature += ', **' + self.varkw + allargs.append('**' + self.varkw) + allshortargs.append('**' + self.varkw) + self.signature = ', '.join(allargs) + self.shortsignature = ', '.join(allshortargs) self.dict = func.__dict__.copy() # func=None happens when decorating a caller if name: @@ -206,15 +199,53 @@ func, "return _call_(_func_, %(shortsignature)s)", evaldict, undecorated=func, __wrapped__=func) else: # returns a decorator - if isinstance(caller, partial): - return partial(decorator, caller) - # otherwise assume caller is a function - first = inspect.getargspec(caller)[0][0] # first arg - evaldict = caller.func_globals.copy() + if inspect.isclass(caller): + name = caller.__name__.lower() + callerfunc = get_init(caller) + doc = 'decorator(%s) converts functions/generators into ' \ + 'factories of %s objects' % (caller.__name__, caller.__name__) + fun = getfullargspec(callerfunc).args[1] # second arg + elif inspect.isfunction(caller): + name = '_lambda_' if caller.__name__ == '<lambda>' \ + else caller.__name__ + callerfunc = caller + doc = caller.__doc__ + fun = getfullargspec(callerfunc).args[0] # first arg + else: # assume caller is an object with a __call__ method + name = caller.__class__.__name__.lower() + callerfunc = caller.__call__.im_func + doc = caller.__call__.__doc__ + fun = getfullargspec(callerfunc).args[1] # second arg + evaldict = callerfunc.func_globals.copy() evaldict['_call_'] = caller evaldict['decorator'] = decorator return FunctionMaker.create( - '%s(%s)' % (caller.__name__, first), - 'return decorator(_call_, %s)' % first, + '%s(%s)' % (name, fun), + 'return decorator(_call_, %s)' % fun, evaldict, undecorated=caller, __wrapped__=caller, - doc=caller.__doc__, module=caller.__module__) + doc=doc, module=caller.__module__) + +######################### contextmanager ######################## + +def __call__(self, func): + 'Context manager decorator' + return FunctionMaker.create( + func, "with _self_: return _func_(%(shortsignature)s)", + dict(_self_=self, _func_=func), __wrapped__=func) + +try: # Python >= 3.2 + + from contextlib import _GeneratorContextManager + ContextManager = type( + 'ContextManager', (_GeneratorContextManager,), dict(__call__=__call__)) + +except ImportError: # Python >= 2.5 + + from contextlib import GeneratorContextManager + def __init__(self, f, *a, **k): + return GeneratorContextManager.__init__(self, f(*a, **k)) + ContextManager = type( + 'ContextManager', (GeneratorContextManager,), + dict(__call__=__call__, __init__=__init__)) + +contextmanager = decorator(ContextManager) -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org