Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-decorator for 
openSUSE:Factory checked in at 2021-08-11 11:46:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-decorator (Old)
 and      /work/SRC/openSUSE:Factory/.python-decorator.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-decorator"

Wed Aug 11 11:46:59 2021 rev:23 rq:910347 version:5.0.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-decorator/python-decorator.changes        
2020-03-27 00:24:30.340232740 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-decorator.new.1899/python-decorator.changes  
    2021-08-11 11:47:01.369760525 +0200
@@ -1,0 +2,19 @@
+Thu Aug  5 15:25:53 UTC 2021 - Mark??ta Machov?? <mmach...@suse.com>
+
+- Add upstream patch kwsyntax.patch
+
+-------------------------------------------------------------------
+Tue Jul 27 06:15:15 UTC 2021 - Dirk M??ller <dmuel...@suse.com>
+
+- update to 5.0.9:
+  * Fixed a test breaking PyPy. Restored support for Sphinx.
+  * Made the decorator module more robust when decorating builtin functions
+    lacking dunder attributes, like `dict.__setitem__`.
+  * The decorator module was not passing correctly the defaults inside the
+    `*args` tuple, thanks to Dan Shult for the fix.
+  * The decorator module was not copying the __module__ attribute anymore.
+  * Dropped support for Python < 3.5 with a substantial simplification of
+    the code base (now building a decorator does not require calling "exec").
+    Added a way to mimic functools.wraps-generated decorators.
+
+-------------------------------------------------------------------

Old:
----
  decorator-4.4.2.tar.gz

New:
----
  decorator-5.0.9.tar.gz
  kwsyntax.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-decorator.spec ++++++
--- /var/tmp/diff_new_pack.bygCBI/_old  2021-08-11 11:47:02.633759005 +0200
+++ /var/tmp/diff_new_pack.bygCBI/_new  2021-08-11 11:47:02.637759000 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-decorator
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,14 +19,17 @@
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
+%global skip_python2 1
 Name:           python-decorator
-Version:        4.4.2
+Version:        5.0.9
 Release:        0
 Summary:        Decorators for Humans
 License:        BSD-2-Clause
 Group:          Development/Languages/Python
 URL:            https://github.com/micheles/decorator
 Source:         
https://files.pythonhosted.org/packages/source/d/decorator/decorator-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM 
https://github.com/micheles/decorator/commit/817d070db3c9cc5900d118837c533c039982b050
 Fixed decorator.decorator not passing kwsyntax
+Patch0:         kwsyntax.patch
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  dos2unix
 BuildRequires:  fdupes
@@ -45,6 +48,7 @@
 
 %prep
 %setup -q -n decorator-%{version}
+%autopatch -p1
 
 %build
 %python_build

++++++ decorator-4.4.2.tar.gz -> decorator-5.0.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/CHANGES.md 
new/decorator-5.0.9/CHANGES.md
--- old/decorator-4.4.2/CHANGES.md      2020-02-29 06:22:24.000000000 +0100
+++ new/decorator-5.0.9/CHANGES.md      2021-05-16 06:06:15.000000000 +0200
@@ -3,6 +3,34 @@
 
 ## unreleased
 
+## 5.0.9 (2021-05-16)
+
+Fixed a test breaking PyPy. Restored support for Sphinx.
+
+## 5.0.8 (2021-05-15)
+
+Made the decorator module more robust when decorating builtin functions
+lacking dunder attributes, like `dict.__setitem__`.
+
+## 5.0.7 (2021-04-14)
+
+The decorator module was not passing correctly the defaults inside the
+`*args` tuple, thanks to Dan Shult for the fix. Also fixed some mispellings
+in the documentation and integrated codespell in the CI, thanks to 
+Christian Clauss.
+
+## 5.0.6 (2021-04-08)
+
+The decorator module was not copying the __module__ attribute anymore. Thanks 
to
+Nikolay Markov for the notice.
+
+## 5.0.5 (2021-04-04)
+
+Dropped support for Python < 3.5 with a substantial simplification of
+the code base (now building a decorator does not require calling "exec").
+Added a way to mimic functools.wraps-generated decorators.
+Ported the Continuous Integration from Travis to GitHub.
+
 ## 4.4.2 (2020-02-29)
 
 Sylvan Mosberger (https://github.com/Infinisil) contributed a patch to
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/PKG-INFO new/decorator-5.0.9/PKG-INFO
--- old/decorator-4.4.2/PKG-INFO        2020-02-29 06:24:41.000000000 +0100
+++ new/decorator-5.0.9/PKG-INFO        2021-05-16 06:08:31.094942800 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: decorator
-Version: 4.4.2
+Version: 5.0.9
 Summary: Decorators for Humans
 Home-page: https://github.com/micheles/decorator
 Author: Michele Simionato
@@ -113,17 +113,12 @@
 Classifier: Natural Language :: English
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Topic :: Software Development :: Libraries
 Classifier: Topic :: Utilities
-Requires-Python: >=2.6, !=3.0.*, !=3.1.*
+Requires-Python: >=3.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/setup.cfg 
new/decorator-5.0.9/setup.cfg
--- old/decorator-4.4.2/setup.cfg       2020-02-29 06:24:41.000000000 +0100
+++ new/decorator-5.0.9/setup.cfg       2021-05-16 06:08:31.094942800 +0200
@@ -1,6 +1,3 @@
-[bdist_wheel]
-universal = 1
-
 [upload_docs]
 upload-dir = docs
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/setup.py new/decorator-5.0.9/setup.py
--- old/decorator-4.4.2/setup.py        2019-10-27 08:59:44.000000000 +0100
+++ new/decorator-5.0.9/setup.py        2021-04-02 13:31:16.000000000 +0200
@@ -18,23 +18,18 @@
           py_modules=['decorator'],
           keywords="decorators generic utility",
           platforms=["All"],
-          python_requires='>=2.6, !=3.0.*, !=3.1.*',
+          python_requires='>=3.5',
           classifiers=['Development Status :: 5 - Production/Stable',
                        'Intended Audience :: Developers',
                        'License :: OSI Approved :: BSD License',
                        'Natural Language :: English',
                        'Operating System :: OS Independent',
                        'Programming Language :: Python',
-                       'Programming Language :: Python :: 2',
-                       'Programming Language :: Python :: 2.6',
-                       'Programming Language :: Python :: 2.7',
-                       'Programming Language :: Python :: 3',
-                       'Programming Language :: Python :: 3.2',
-                       'Programming Language :: Python :: 3.3',
-                       'Programming Language :: Python :: 3.4',
                        'Programming Language :: Python :: 3.5',
                        'Programming Language :: Python :: 3.6',
                        'Programming Language :: Python :: 3.7',
+                       'Programming Language :: Python :: 3.8',
+                       'Programming Language :: Python :: 3.9',
                        'Programming Language :: Python :: Implementation :: 
CPython',
                        'Topic :: Software Development :: Libraries',
                        'Topic :: Utilities'],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/src/decorator.egg-info/PKG-INFO 
new/decorator-5.0.9/src/decorator.egg-info/PKG-INFO
--- old/decorator-4.4.2/src/decorator.egg-info/PKG-INFO 2020-02-29 
06:24:40.000000000 +0100
+++ new/decorator-5.0.9/src/decorator.egg-info/PKG-INFO 2021-05-16 
06:08:30.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: decorator
-Version: 4.4.2
+Version: 5.0.9
 Summary: Decorators for Humans
 Home-page: https://github.com/micheles/decorator
 Author: Michele Simionato
@@ -113,17 +113,12 @@
 Classifier: Natural Language :: English
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Topic :: Software Development :: Libraries
 Classifier: Topic :: Utilities
-Requires-Python: >=2.6, !=3.0.*, !=3.1.*
+Requires-Python: >=3.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/src/decorator.py 
new/decorator-5.0.9/src/decorator.py
--- old/decorator-4.4.2/src/decorator.py        2020-02-29 06:20:33.000000000 
+0100
+++ new/decorator-5.0.9/src/decorator.py        2021-05-16 06:05:29.000000000 
+0200
@@ -1,6 +1,6 @@
 # #########################     LICENSE     ############################ #
 
-# Copyright (c) 2005-2018, Michele Simionato
+# Copyright (c) 2005-2021, Michele Simionato
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
@@ -28,55 +28,26 @@
 # DAMAGE.
 
 """
-Decorator module, see http://pypi.python.org/pypi/decorator
+Decorator module, see
+https://github.com/micheles/decorator/blob/master/docs/documentation.md
 for the documentation.
 """
-from __future__ import print_function
-
 import re
 import sys
 import inspect
 import operator
 import itertools
-import collections
-
-__version__ = '4.4.2'
-
-if sys.version_info >= (3,):
-    from inspect import getfullargspec
-
-    def get_init(cls):
-        return cls.__init__
-else:
-    FullArgSpec = collections.namedtuple(
-        'FullArgSpec', 'args varargs varkw defaults '
-        'kwonlyargs kwonlydefaults annotations')
-
-    def getfullargspec(f):
-        "A quick and dirty replacement for getfullargspec for Python 2.X"
-        return FullArgSpec._make(inspect.getargspec(f) + ([], None, {}))
-
-    def get_init(cls):
-        return cls.__init__.__func__
-
-try:
-    iscoroutinefunction = inspect.iscoroutinefunction
-except AttributeError:
-    # let's assume there are no coroutine functions in old Python
-    def iscoroutinefunction(f):
-        return False
-try:
-    from inspect import isgeneratorfunction
-except ImportError:
-    # assume no generator function in old Python versions
-    def isgeneratorfunction(caller):
-        return False
+from contextlib import _GeneratorContextManager
+from inspect import getfullargspec, iscoroutinefunction, isgeneratorfunction
 
+__version__ = '5.0.9'
 
 DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(')
+POS = inspect.Parameter.POSITIONAL_OR_KEYWORD
+EMPTY = inspect.Parameter.empty
 
 
-# basic functionality
+# this is not used anymore in the core, but kept for backward compatibility
 class FunctionMaker(object):
     """
     An object with the ability to create functions with a given signature.
@@ -143,7 +114,9 @@
             raise TypeError('You are decorating a non function: %s' % func)
 
     def update(self, func, **kw):
-        "Update the signature of func with the data in self"
+        """
+        Update the signature of func with the data in self
+        """
         func.__name__ = self.name
         func.__doc__ = getattr(self, 'doc', None)
         func.__dict__ = getattr(self, 'dict', {})
@@ -160,7 +133,9 @@
         func.__dict__.update(kw)
 
     def make(self, src_templ, evaldict=None, addsource=False, **attrs):
-        "Make a new function from a given template and update the signature"
+        """
+        Make a new function from a given template and update the signature
+        """
         src = src_templ % vars(self)  # expand name and signature
         evaldict = evaldict or {}
         mo = DEF.search(src)
@@ -221,105 +196,112 @@
         return self.make(body, evaldict, addsource, **attrs)
 
 
-def decorate(func, caller, extras=()):
+def fix(args, kwargs, sig):
     """
-    decorate(func, caller) decorates a function using a caller.
-    If the caller is a generator function, the resulting function
-    will be a generator function.
+    Fix args and kwargs to be consistent with the signature
     """
-    evaldict = dict(_call_=caller, _func_=func)
-    es = ''
-    for i, extra in enumerate(extras):
-        ex = '_e%d_' % i
-        evaldict[ex] = extra
-        es += ex + ', '
-
-    if '3.5' <= sys.version < '3.6':
-        # with Python 3.5 isgeneratorfunction returns True for all coroutines
-        # however we know that it is NOT possible to have a generator
-        # coroutine in python 3.5: PEP525 was not there yet
-        generatorcaller = isgeneratorfunction(
-            caller) and not iscoroutinefunction(caller)
-    else:
-        generatorcaller = isgeneratorfunction(caller)
-    if generatorcaller:
-        fun = FunctionMaker.create(
-            func, "for res in _call_(_func_, %s%%(shortsignature)s):\n"
-                  "    yield res" % es, evaldict, __wrapped__=func)
+    ba = sig.bind(*args, **kwargs)
+    ba.apply_defaults()  # needed for test_dan_schult
+    return ba.args, ba.kwargs
+
+
+def decorate(func, caller, extras=(), kwsyntax=False):
+    """
+    Decorates a function/generator/coroutine using a caller.
+    If kwsyntax is True calling the decorated functions with keyword
+    syntax will pass the named arguments inside the ``kw`` dictionary,
+    even if such argument are positional, similarly to what functools.wraps
+    does. By default kwsyntax is False and the the arguments are untouched.
+    """
+    sig = inspect.signature(func)
+    if iscoroutinefunction(caller):
+        async def fun(*args, **kw):
+            if not kwsyntax:
+                args, kw = fix(args, kw, sig)
+            return await caller(func, *(extras + args), **kw)
+    elif isgeneratorfunction(caller):
+        def fun(*args, **kw):
+            if not kwsyntax:
+                args, kw = fix(args, kw, sig)
+            for res in caller(func, *(extras + args), **kw):
+                yield res
     else:
-        fun = FunctionMaker.create(
-            func, "return _call_(_func_, %s%%(shortsignature)s)" % es,
-            evaldict, __wrapped__=func)
-    if hasattr(func, '__qualname__'):
-        fun.__qualname__ = func.__qualname__
+        def fun(*args, **kw):
+            if not kwsyntax:
+                args, kw = fix(args, kw, sig)
+            return caller(func, *(extras + args), **kw)
+    fun.__name__ = func.__name__
+    fun.__doc__ = func.__doc__
+    fun.__wrapped__ = func
+    fun.__signature__ = sig
+    fun.__qualname__ = func.__qualname__
+    # builtin functions like defaultdict.__setitem__ lack many attributes
+    try:
+        fun.__defaults__ = func.__defaults__
+    except AttributeError:
+        pass
+    try:
+        fun.__kwdefaults__ = func.__kwdefaults__
+    except AttributeError:
+        pass
+    try:
+        fun.__annotations__ = func.__annotations__
+    except AttributeError:
+        pass
+    try:
+        fun.__module__ = func.__module__
+    except AttributeError:
+        pass
+    try:
+        fun.__dict__.update(func.__dict__)
+    except AttributeError:
+        pass
     return fun
 
 
-def decorator(caller, _func=None):
-    """decorator(caller) converts a caller function into a decorator"""
+def decorator(caller, _func=None, kwsyntax=False):
+    """
+    decorator(caller) converts a caller function into a decorator
+    """
     if _func is not None:  # return a decorated function
         # this is obsolete behavior; you should use decorate instead
         return decorate(_func, caller)
     # else return a decorator function
-    defaultargs, defaults = '', ()
-    if inspect.isclass(caller):
-        name = caller.__name__.lower()
-        doc = 'decorator(%s) converts functions/generators into ' \
-            'factories of %s objects' % (caller.__name__, caller.__name__)
-    elif inspect.isfunction(caller):
-        if caller.__name__ == '<lambda>':
-            name = '_lambda_'
+    sig = inspect.signature(caller)
+    dec_params = [p for p in sig.parameters.values() if p.kind is POS]
+
+    def dec(func=None, *args, **kw):
+        na = len(args) + 1
+        extras = args + tuple(kw.get(p.name, p.default)
+                              for p in dec_params[na:]
+                              if p.default is not EMPTY)
+        if func is None:
+            return lambda func: decorate(func, caller, extras, kwsyntax)
         else:
-            name = caller.__name__
-        doc = caller.__doc__
-        nargs = caller.__code__.co_argcount
-        ndefs = len(caller.__defaults__ or ())
-        defaultargs = ', '.join(caller.__code__.co_varnames[nargs-ndefs:nargs])
-        if defaultargs:
-            defaultargs += ','
-        defaults = caller.__defaults__
-    else:  # assume caller is an object with a __call__ method
-        name = caller.__class__.__name__.lower()
-        doc = caller.__call__.__doc__
-    evaldict = dict(_call=caller, _decorate_=decorate)
-    dec = FunctionMaker.create(
-        '%s(func, %s)' % (name, defaultargs),
-        'if func is None: return lambda func:  _decorate_(func, _call, (%s))\n'
-        'return _decorate_(func, _call, (%s))' % (defaultargs, defaultargs),
-        evaldict, doc=doc, module=caller.__module__, __wrapped__=caller)
-    if defaults:
-        dec.__defaults__ = (None,) + defaults
+            return decorate(func, caller, extras, kwsyntax)
+    dec.__signature__ = sig.replace(parameters=dec_params)
+    dec.__name__ = caller.__name__
+    dec.__doc__ = caller.__doc__
+    dec.__wrapped__ = caller
+    dec.__qualname__ = caller.__qualname__
+    dec.__kwdefaults__ = getattr(caller, '__kwdefaults__', None)
+    dec.__dict__.update(caller.__dict__)
     return dec
 
 
 # ####################### contextmanager ####################### #
 
-try:  # Python >= 3.2
-    from contextlib import _GeneratorContextManager
-except ImportError:  # Python >= 2.5
-    from contextlib import GeneratorContextManager as _GeneratorContextManager
-
 
 class ContextManager(_GeneratorContextManager):
-    def __call__(self, func):
-        """Context manager decorator"""
-        return FunctionMaker.create(
-            func, "with _self_: return _func_(%(shortsignature)s)",
-            dict(_self_=self, _func_=func), __wrapped__=func)
-
-
-init = getfullargspec(_GeneratorContextManager.__init__)
-n_args = len(init.args)
-if n_args == 2 and not init.varargs:  # (self, genobj) Python 2.7
-    def __init__(self, g, *a, **k):
-        return _GeneratorContextManager.__init__(self, g(*a, **k))
-    ContextManager.__init__ = __init__
-elif n_args == 2 and init.varargs:  # (self, gen, *a, **k) Python 3.4
-    pass
-elif n_args == 4:  # (self, gen, args, kwds) Python 3.5
     def __init__(self, g, *a, **k):
         return _GeneratorContextManager.__init__(self, g, a, k)
-    ContextManager.__init__ = __init__
+
+    def __call__(self, func):
+        def caller(f, *a, **k):
+            with self:
+                return f(*a, **k)
+        return decorate(func, caller)
+
 
 _contextmanager = decorator(ContextManager)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/src/tests/documentation.py 
new/decorator-5.0.9/src/tests/documentation.py
--- old/decorator-4.4.2/src/tests/documentation.py      2020-02-29 
06:10:07.000000000 +0100
+++ new/decorator-5.0.9/src/tests/documentation.py      2021-04-11 
07:52:37.000000000 +0200
@@ -1,16 +1,12 @@
-from __future__ import print_function
 import sys
+import inspect
 import threading
 import time
 import functools
 import itertools
 import collections
-try:
-    import collections.abc as c
-except ImportError:
-    c = collections
-    collections.abc = collections
-from decorator import (decorator, decorate, FunctionMaker, contextmanager,
+import collections.abc as c
+from decorator import (decorator, decorate, FunctionMaker,
                        dispatch_on, __version__)
 
 doc = r"""Decorators for Humans
@@ -20,7 +16,7 @@
 |---|---|
 |E-mail | michele.simion...@gmail.com|
 |Version| $VERSION ($DATE)|
-|Supports| Python 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8|
+|Supports| Python 3.5, 3.6, 3.7, 3.8, 3.9|
 |Download page| http://pypi.python.org/pypi/decorator/$VERSION|
 |Installation| ``pip install decorator``|
 |License | BSD license|
@@ -30,29 +26,32 @@
 
 The ``decorator`` module is over ten years old, but still alive and
 kicking. It is used by several frameworks (IPython, scipy, authkit,
-pylons, pycuda, sugar, ...) and has been stable for a *long*
-time. It is your best option if you want to preserve the signature of
-decorated functions in a consistent way across Python
-releases. Version 4 is fully compatible with the past, except for
-one thing: support for Python 2.4 and 2.5 has been dropped. That
-decision made it possible to use a single code base both for Python
-2.X and Python 3.X. This is a *huge* bonus, since I could remove over
-2,000 lines of duplicated documentation/doctests. Having to maintain
-separate docs for Python 2 and Python 3 effectively stopped any
-development on the module for several years. Moreover, it is now
-trivial to distribute the module as an universal
- [wheel](http://pythonwheels.com) since 2to3 is no more
-required. Since Python 2.5 has been released ages ago (in 2006), I felt that
-it was reasonable to drop the support for it. If you need to support
-ancient versions of Python, stick with the decorator module version
-3.4.2.  The current version supports all Python releases from 2.6 up.
+pylons, pycuda, sugar, ...) and has been stable for a *long* time. It
+is your best option if you want to preserve the signature of decorated
+functions in a consistent way across Python releases. Versions 5.X
+supports Python versions greater than 3.4, versions 4.X supports Python
+versions back to 2.6; versions 3.X are able to support even Python 2.5 and
+2.4.
+
+What's New in version 5
+-----------------------
+
+Version 5 of the decorator module features a major simplification of
+the code base made possible by dropping support for Python releases
+older than 3.5. From that version the ``Signature`` object works well
+enough that it is possible to fix the signature of a decorated
+function without resorting to ``exec`` tricks. The simplification
+has a very neat advantage: in case of exceptions raised in decorated
+functions the traceback is nicer than it used to be. Moreover, it is
+now possible to mimic the behavior of decorators defined with
+``functool.wraps``: see the section about the ``kwsyntax`` flag below.
 
 What's New in version 4
 -----------------------
 
 - **New documentation**
   There is now a single manual for all Python versions, so I took the
-  opportunity to overhaul the documentation and to move it to readthedocs.org.
+  opportunity to overhaul the documentation.
   Even if you are a long-time user, you may want to revisit the docs, since
   several examples have been improved.
 
@@ -94,8 +93,8 @@
 matters. In principle, their introduction in Python 2.4 changed
 nothing, since they did not provide any new functionality which was not
 already present in the language. In practice, their introduction has
-significantly changed the way we structure our programs in Python. I
-believe the change is for the best, and that decorators are a great
+significantly changed the way we structure our programs.
+I believe the change is for the best, and that decorators are a great
 idea since:
 
 * decorators help reducing boilerplate code;
@@ -176,10 +175,6 @@
 ``__name__``, ``__doc__``, ``__module__``, and ``__dict__``
 to the decorated function by hand).
 
-Here is an example of usage:
-
-$$f1
-
 This works insofar as the decorator accepts functions with generic signatures.
 Unfortunately, it is *not* a signature-preserving decorator, since
 ``memoize_uw`` generally returns a function with a *different signature*
@@ -194,17 +189,17 @@
 keyword arguments:
 
 ```python
->>> from decorator import getfullargspec
+>>> from inspect import getfullargspec
 >>> print(getfullargspec(f1))
 FullArgSpec(args=[], varargs='args', varkw='kw', defaults=None, kwonlyargs=[], 
kwonlydefaults=None, annotations={})
 
 ```
 
-This means that introspection tools (like ``pydoc``) will give false
-information about the signature of ``f1`` -- unless you are using
-Python 3.5. This is pretty bad: ``pydoc`` will tell you that the
-function accepts the generic signature ``*args, **kw``, but
-calling the function with more than one argument raises an error:
+This means that introspection tools like ``getfullargspec`` will give
+you false information about the signature of ``f1`` This is pretty bad:
+``getfullargspec`` says that the function accepts the generic
+signature ``*args, **kw``, but calling the function with more than one
+argument raises an error:
 
 ```python
 >>> f1(0, 1) # doctest: +IGNORE_EXCEPTION_DETAIL
@@ -214,9 +209,8 @@
 
 ```
 
-Notice that ``inspect.getfullargspec``
-will give the wrong signature, even in the latest Python, i.e. version 3.6
-at the time of writing.
+Notice that ``pydoc`` will give the right signature, but only in Python
+versions greater than 3.5.
 
 The solution
 -----------------------------------------
@@ -315,16 +309,17 @@
 
 ```python
 >>> @trace
-... def f(x, y=1, z=2, *args, **kw):
+... def f(x, y=1, *args, **kw):
 ...     pass
 
 >>> f(0, 3)
-calling f with args (0, 3, 2), {}
+calling f with args (0, 3), {}
 
 >>> print(getfullargspec(f))
-FullArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2), 
kwonlyargs=[], kwonlydefaults=None, annotations={})
+FullArgSpec(args=['x', 'y'], varargs='args', varkw='kw', defaults=(1,), 
kwonlyargs=[], kwonlydefaults=None, annotations={})
 
 ```
+
 $FUNCTION_ANNOTATIONS
 
 ``decorator.decorator``
@@ -340,8 +335,6 @@
 
 ```python
 >>> from decorator import decorator
->>> print(decorator.__doc__)
-decorator(caller) converts a caller function into a decorator
 
 ```
 The ``decorator`` function can be used as a signature-changing
@@ -380,6 +373,69 @@
 
 ```
 
+Mimicking the behavior of functools.wrap
+----------------------------------------
+
+Often people are confused by the decorator module since, contrarily
+to ``functools.wraps`` in the standard library, it tries very hard
+to keep the semantics of the arguments: in particular, positional arguments
+stay positional even if they are called with the keyword argument syntax.
+An example will make the issue clear. Here is a simple caller
+
+$$chatty
+
+and here is a function to decorate:
+
+$$printsum
+
+In this example ``x`` and ``y`` are positional arguments (with
+defaults). From the caller perspective, it does not matter if the user
+calls them as named arguments, they will stay inside the ``args``
+tuple and not inside the ``kwargs`` dictionary:
+
+```python
+>>> printsum(y=2, x=1)
+(1, 2) []
+3
+
+```
+
+This is quite different from the behavior of ``functools.wraps``; if you
+define the decorator as follows
+
+$$chattywrapper
+
+you will see that calling ``printsum`` with named arguments will pass
+such arguments to ``kwargs``, while ``args`` will be the empty tuple.
+Since version 5 of the decorator module it is possible to mimic that
+behavior by using the ``kwsyntax`` flag:
+
+$$printsum2
+
+Here is how it works:
+
+```python
+>>> printsum2(y=2, x=1)
+() [('x', 1), ('y', 2)]
+3
+
+```
+
+This is exactly what the ``chattywrapper`` decorator would print:
+positional arguments are seen as keyword arguments, but only if the
+client code calls them with the keyword syntax. Otherwise they stay
+positional, i.e. they belongs to the ``args`` tuple and not to ``kwargs``:
+
+```python
+>>> printsum2(1, 2)
+(1, 2) []
+3
+
+```
+
+Decorator factories
+-------------------------------------------
+
 The `decorator` function can also be used to define factories of decorators,
 i.e. functions returning decorators. In general you can just write something
 like this:
@@ -392,9 +448,8 @@
 ```
 
 This is fully general but requires an additional level of nesting. For this
-reason since version 4.2 there is a facility to build
-decorator factories by using a single caller with default arguments i.e.
-writing something like this:
+reason since version 4.2 there is a facility to build decorator factories by
+using a single caller with default arguments:
 
 ```python
 def caller(f, param1=default1, param2=default2, ..., *args, **kw):
@@ -408,22 +463,17 @@
 of the family which uses the default values for all parameters. Such
 decorator can be written as ``decfactory()`` with no parameters specified;
 moreover, as a shortcut, it is also possible to elide the parenthesis,
-a feature much requested by the users. For years I have been opposite
-to this feature request, since having explicit parenthesis to me is more clear
+a feature much requested by the users. For years I have been opposing
+the request, since having explicit parenthesis to me is more clear
 and less magic; however once this feature entered in decorators of
 the Python standard library (I am referring to the [dataclass decorator](
 https://www.python.org/dev/peps/pep-0557/)) I finally gave up.
 
-The example below will show how it works in practice.
-
-Decorator factories
--------------------------------------------
-
-Sometimes one has to deal with blocking resources, such as ``stdin``.
-Sometimes it is better to receive a "busy" message than just blocking
-everything.
-This can be accomplished with a suitable family of decorators (decorator
-factory), parameterize by a string, the busy message:
+The example below shows how it works in practice. The goal is to
+convert a function relying on a blocking resource into a function
+returning a "busy" message if the resource is not available.
+This can be accomplished with a suitable family of decorators
+parameterize by a string, the busy message:
 
 $$blocking
 
@@ -529,8 +579,7 @@
 ```
 
 ...then ``before_after`` is a factory function that returns
-``GeneratorContextManager`` objects, which provide the
-use of the ``with`` statement:
+``GeneratorContextManager`` objects, usable with the ``with`` statement:
 
 ```python
 >>> with before_after('BEFORE', 'AFTER'):
@@ -564,17 +613,10 @@
 The ``ba`` decorator basically inserts a ``with ba:`` block
 inside the function.
 
-However, there are two issues:
-
-1. ``GeneratorContextManager`` objects are only callable in Python 3.2,
-   so the previous example breaks in older versions of Python.
-   (You can solve this by installing ``contextlib2``, which backports
-   the Python 3 functionality to Python 2.)
-
-2. ``GeneratorContextManager`` objects do not preserve the signature of
-   the decorated functions. The decorated ``hello`` function above will
-   have the generic signature ``hello(*args, **kwargs)``, but fails if
-   called with more than zero arguments.
+However ``GeneratorContextManager`` objects do not preserve the signature of
+the decorated functions. The decorated ``hello`` function above will
+have the generic signature ``hello(*args, **kwargs)``, but fails if
+called with more than zero arguments.
 
 For these reasons, the `decorator` module, starting from release 3.4, offers a
 ``decorator.contextmanager`` decorator that solves both problems,
@@ -588,14 +630,13 @@
 The ``FunctionMaker`` class
 ---------------------------------------------------------------
 
-You may wonder how the functionality of the ``decorator`` module
-is implemented. The basic building block is
-a ``FunctionMaker`` class. It generates on-the-fly functions
+The ``decorator`` module also provides a ``FunctionMaker`` class, which
+is able to generate on-the-fly functions
 with a given name and signature from a function template
 passed as a string.
 
 If you're just writing ordinary decorators, then you probably won't
-need to use ``FunctionMaker`` directly. But in some circumstances, it
+need to use ``FunctionMaker``. But in some circumstances, it
 can be handy. You will see an example shortly--in
 the implementation of a cool decorator utility (``decorator_apply``).
 
@@ -655,9 +696,9 @@
 
 - If first argument of ``FunctionMaker.create`` is a function,
   an instance of ``FunctionMaker`` is created with the attributes
-  ``args``, ``varargs``, ``keywords``, and ``defaults``.
-  (These mirror the return values of the standard library's
-  ``inspect.getfullargspec``.)
+  ``args``, ``varargs``, ``keywords``, and ``defaults``
+  (these mirror the return values of the standard library's
+  ``inspect.getfullargspec``).
 
 - For each item in ``args`` (a list of strings of the names of all required
   arguments), an attribute ``arg0``, ``arg1``, ..., ``argN`` is also generated.
@@ -685,28 +726,6 @@
 decorated functions. In IPython, this means that the usual ``??`` trick
 will give you the (right on the spot) message ``Dynamically generated
 function. No source code available``.
-
-In the past, I considered this acceptable, since ``inspect.getsource``
-does not really work with "regular" decorators. In those cases,
-``inspect.getsource`` gives you the wrapper source code, which is probably
-not what you want:
-
-$$identity_dec
-$$example
-
-```python
->>> import inspect
->>> print(inspect.getsource(example))
-    def wrapper(*args, **kw):
-        return func(*args, **kw)
-<BLANKLINE>
-
-```
-
-(See bug report [1764286](http://bugs.python.org/issue1764286)
-for an explanation of what is happening).
-Unfortunately the bug still exists in all versions of Python < 3.5.
-
 However, there is a workaround. The decorated function has the ``__wrapped__``
 attribute, pointing to the original function. The simplest way to get the
 source code is to call ``inspect.getsource`` on the undecorated function:
@@ -791,11 +810,10 @@
 Python 3.5 coroutines
 -----------------------
 
-I am personally not using Python 3.5 coroutines yet, because at work we are
-still maintaining compatibility with Python 2.7. However, some users requested
-support for coroutines and since version 4.1 the decorator module has it.
-You should consider the support experimental and kindly report issues if
-you find any.
+I am personally not using Python 3.5 coroutines yet. However, some
+users requested support for coroutines and since version 4.1 the
+decorator module has it.  You should consider the support experimental
+and kindly report issues if you find any.
 
 Here I will give a single example of usage. Suppose you want to log the moment
 a coroutine starts and the moment it stops for debugging purposes. You could
@@ -807,7 +825,7 @@
 from asyncio import get_event_loop, sleep, wait
 from decorator import decorator
 
- @decorator
+@decorator
 async def log_start_stop(coro, *args, **kwargs):
     logging.info('Starting %s%s', coro.__name__, args)
     t0 = time.time()
@@ -855,8 +873,8 @@
      return get_event_loop().run_until_complete(coro(*args, **kw))
 ```
 
-Notice the diffence: the caller in ``log_start_stop`` was a coroutine
-function and the associate decorator was converting coroutines->coroutines;
+Notice the difference: the caller in ``log_start_stop`` was a coroutine
+function and the associate decorator was converting coroutines in coroutines;
 the caller in ``coro_to_func`` is a regular function and converts
 coroutines -> functions.
 
@@ -982,7 +1000,7 @@
 
 ```
 
-You can introspect the precedence used by the dispath algorithm by
+You can introspect the precedence used by the dispatch algorithm by
 calling ``.dispatch_info(*types)``:
 
 ```python
@@ -1146,106 +1164,12 @@
 Caveats and limitations
 -------------------------------------------
 
-One thing you should be aware of, is the performance penalty of decorators.
-The worse case is shown by the following example:
-
-```bash
- $ cat performance.sh
- python3 -m timeit -s "
- from decorator import decorator
-
- @decorator
- def do_nothing(func, *args, **kw):
-     return func(*args, **kw)
-
- @do_nothing
- def f():
-     pass
- " "f()"
-
- python3 -m timeit -s "
- def f():
-     pass
- " "f()"
-
-```
-On my laptop, using the ``do_nothing`` decorator instead of the
-plain function is five times slower:
-
-```bash
- $ bash performance.sh
- 1000000 loops, best of 3: 1.39 usec per loop
- 1000000 loops, best of 3: 0.278 usec per loop
-```
-Of course, a real life function probably does something more useful
-than the function ``f`` here, so the real life performance penalty
-*could* be negligible.  As always, the only way to know if there is a
-penalty in your specific use case is to measure it.
-
-More importantly, you should be aware that decorators will make your
-tracebacks longer and more difficult to understand.
-
-Consider this example:
-
-```python
->>> @trace
-... def f():
-...     1/0
-
-```
-
-Calling ``f()`` gives you a ``ZeroDivisionError``.
-But since the function is decorated, the traceback is longer:
-
-```python
->>> f() # doctest: +ELLIPSIS
-Traceback (most recent call last):
-  ...
-     File "<string>", line 2, in f
-     File "<doctest __main__[22]>", line 4, in trace
-       return f(*args, **kw)
-     File "<doctest __main__[51]>", line 3, in f
-       1/0
-ZeroDivisionError: ...
-
-```
-
-You see here the inner call to the decorator ``trace``, which calls
-``f(*args, **kw)``, and a reference to  ``File "<string>", line 2, in f``.
-
-This latter reference is due to the fact that, internally, the decorator
-module uses ``exec`` to generate the decorated function. Notice that
-``exec`` is *not* responsible for the performance penalty, since is the
-called *only once* (at function decoration time); it is *not* called
-each time the decorated function is called.
-
-Presently, there is no clean way to avoid ``exec``. A clean solution
-would require changing the CPython implementation, by
-adding a hook to functions (to allow changing their signature directly).
-
-Even in Python 3.5, it is impossible to change the
-function signature directly. Thus, the ``decorator`` module is
-still useful!  As a matter of fact, this is the main reason why I still
-maintain the module and release new versions.
-
-It should be noted that in Python 3.5, a *lot* of improvements have
-been made: you can decorate a function with
-``func_tools.update_wrapper``, and ``pydoc`` will see the correct
-signature. Unfortunately, the function will still have an incorrect
-signature internally, as you can see by using
-``inspect.getfullargspec``; so, all documentation tools using
-``inspect.getfullargspec`` - which has been rightly deprecated -
-will see the wrong signature.
-
 In the present implementation, decorators generated by ``decorator``
-can only be used on user-defined Python functions or methods.
-They cannot be used on generic callable objects or built-in functions,
-due to limitations of the standard library's ``inspect`` module, especially
-for Python 2. In Python 3.5, many such limitations have been removed, but
-I still think that it is cleaner and safer to decorate only functions and
-coroutines. If you want to decorate things like classmethods/staticmethods
-and general callables - which I will never support in the decorator module -
-I suggest you to look at the [wrapt](https://wrapt.readthedocs.io/en/latest/)
+can only be used on user-defined Python functions, methods or coroutines.
+I have no interest in decorating generic callable objects. If you want to
+decorate things like classmethods/staticmethods and general callables -
+which I will never support in the decorator module - I suggest you
+to look at the [wrapt](https://wrapt.readthedocs.io/en/latest/)
 project by Graeme Dumpleton.
 
 There is a strange quirk when decorating functions with keyword
@@ -1270,7 +1194,7 @@
 The error message looks really strange... until you realize that
 the caller function `_memoize` uses `func` as first argument,
 so there is a confusion between the positional argument and the
-keywork arguments.
+keyword arguments.
 
 The solution is to change the name of the first argument in `_memoize`,
 or to change the implementation like so:
@@ -1297,22 +1221,7 @@
 keyword arguments is not such a good idea, and you may want not to do
 that.
 
-On a similar note, there is a restriction on argument names. For instance,
-if you name an argument ``_call_`` or ``_func_``, you will get a ``NameError``:
-
-```python
->>> @trace
-... def f(_func_): print(f)
-...
-Traceback (most recent call last):
-  ...
-NameError: _func_ is overridden in
-def f(_func_):
-    return _call_(_func_, _func_)
-
-```
-
-Finally, the implementation is such that the decorated function makes
+The implementation is such that the decorated function makes
 a (shallow) copy of the original function dictionary:
 
 ```python
@@ -1330,6 +1239,43 @@
 
 ```
 
+Finally, you should be aware of the performance penalty of decorators.
+The worse case is shown by the following example:
+
+```bash
+ $ cat performance.sh
+ python3 -m timeit -s "
+ from decorator import decorator
+
+ @decorator
+ def do_nothing(func, *args, **kw):
+     return func(*args, **kw)
+
+ @do_nothing
+ def f():
+     pass
+ " "f()"
+
+ python3 -m timeit -s "
+ def f():
+     pass
+ " "f()"
+
+```
+On my laptop, using the ``do_nothing`` decorator instead of the
+plain function is five times slower:
+
+```bash
+ $ bash performance.sh
+ 1000000 loops, best of 3: 1.39 usec per loop
+ 1000000 loops, best of 3: 0.278 usec per loop
+```
+
+Of course, a real life function probably does something more useful
+than the function ``f`` here, so the real life performance penalty
+*could* be negligible.  As always, the only way to know if there is a
+penalty in your specific use case is to measure it.
+
 LICENSE (2-clause BSD)
 ---------------------------------------------
 
@@ -1384,8 +1330,8 @@
 
 ```
 
-In order to introspect functions with annotations, one needs the
-utility ``inspect.getfullargspec`` (introduced in Python 3, then
+In order to introspect functions with annotations, one needs
+``inspect.getfullargspec`` (introduced in Python 3, then
 deprecated in Python 3.5, then undeprecated in Python 3.6):
 
 ```python
@@ -1420,7 +1366,6 @@
 Another attribute copied from the original function is ``__qualname__``,
 the qualified name. This attribute was introduced in Python 3.3.
 """
-
 if sys.version_info < (3,):
     function_annotations = ''
 
@@ -1654,71 +1599,48 @@
     """
 
 
-if sys.version_info >= (3,):  # tests for signatures specific to Python 3
+def test_kwonlydefaults():
+    """
+    >>> @trace
+    ... def f(arg, defarg=1, *args, kwonly=2): pass
+    ...
+    >>> f.__kwdefaults__
+    {'kwonly': 2}
+    """
+
+
+def test_kwonlyargs():
+    """
+    >>> @trace
+    ... def func(a, b, *args, y=2, z=3, **kwargs):
+    ...     return y, z
+    ...
+    >>> func('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_kwonlydefaults():
-        """
-        >>> @trace
-        ... def f(arg, defarg=1, *args, kwonly=2): pass
-        ...
-        >>> f.__kwdefaults__
-        {'kwonly': 2}
-        """
-
-    def test_kwonlyargs():
-        """
-        >>> @trace
-        ... def func(a, b, *args, y=2, z=3, **kwargs):
-        ...     return y, z
-        ...
-        >>> func('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
-        ...
-        >>> import inspect
-        >>> 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
+def test_kwonly_no_args():
+    """# this was broken with decorator 3.3.3
+    >>> @trace
+    ... def f(**kw): pass
+    ...
+    >>> f()
+    calling f with args (), {}
     """
-    print('hello %s' % user)
 
 
+def test_kwonly_star_notation():
+    """
+    >>> @trace
+    ... def f(*, a=1, **kw): pass
+    ...
+    >>> import inspect
+    >>> inspect.getfullargspec(f)
+    FullArgSpec(args=[], varargs=None, varkw='kw', defaults=None, 
kwonlyargs=['a'], kwonlydefaults={'a': 1}, annotations={})
+    """
+
 # #######################  multiple dispatch ############################ #
 
 
@@ -1892,6 +1814,73 @@
     time.sleep(.1)
 
 
+def chatty(func, *args, **kwargs):
+    print(args, sorted(kwargs.items()))
+    return func(*args, **kwargs)
+
+
+@decorator(chatty)
+def printsum(x=1, y=2):
+    print(x + y)
+
+
+@decorator(chatty, kwsyntax=True)
+def printsum2(x=1, y=2):
+    print(x + y)
+
+
+def chattywrapper(func):
+    @functools.wraps(func)
+    def wrapper(*args, **kwargs):
+        print(args, kwargs)
+        return func(*args, **kwargs)
+    return functools.wraps(wrapper)
+
+# #######################  changing the signature ########################## #
+
+
+# see https://github.com/micheles/decorator/pull/85
+def to_method(f):
+    """
+    Takes a function with signature (..., context) and returns a new
+    function with signature (self, ...) to be used a a method in a
+    class with a .context attribute.
+    """
+    sig = inspect.signature(f)
+    params = list(sig.parameters.values())
+    assert params[-1].name == 'context'
+    self = inspect.Parameter('self', inspect.Parameter.POSITIONAL_OR_KEYWORD)
+    params.insert(0, self)  # insert self
+    del params[-1]  # remove context
+    newsig = '%s%s' % (f.__name__, sig.replace(parameters=params))
+    return FunctionMaker.create(
+        newsig, 'context = self.context; return _func_%s' % sig,
+        dict(_func_=f))
+
+
+def foo(x, context=None):
+    return x
+
+
+def bar(x, y, context):
+    return x + y
+
+
+class Client:
+    def __init__(self, context):
+        self.context = context
+
+
+def test_change_sig():
+    """
+    >>> Client.foo = to_method(foo)
+    >>> Client.bar = to_method(bar)
+    >>> c = Client(None)
+    >>> assert c.foo(1) == 1
+    >>> assert c.bar(1, 2) == 3
+    """
+
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/decorator-4.4.2/src/tests/test.py 
new/decorator-5.0.9/src/tests/test.py
--- old/decorator-4.4.2/src/tests/test.py       2020-02-29 05:50:53.000000000 
+0100
+++ new/decorator-5.0.9/src/tests/test.py       2021-05-16 05:34:45.000000000 
+0200
@@ -1,21 +1,15 @@
-from __future__ import absolute_import
 import sys
 import doctest
 import unittest
 import decimal
 import inspect
-import functools
-import collections
-from collections import defaultdict
-try:
-    c = collections.abc
-except AttributeError:
-    c = collections
+from asyncio import get_event_loop
+from collections import defaultdict, ChainMap, abc as c
 from decorator import dispatch_on, contextmanager, decorator
 try:
-    from . import documentation as doc
-except (ImportError, ValueError, SystemError):  # depending on the py-version
-    import documentation as doc
+    from . import documentation as doc  # good with pytest
+except ImportError:
+    import documentation as doc  # good with `python src/tests/test.py`
 
 
 @contextmanager
@@ -29,22 +23,21 @@
         raise Exception('Expected %s' % etype.__name__)
 
 
-if sys.version_info >= (3, 5):
-    exec('''from asyncio import get_event_loop
-
 @decorator
 async def before_after(coro, *args, **kwargs):
     return "<before>" + (await coro(*args, **kwargs)) + "<after>"
 
+
 @decorator
 def coro_to_func(coro, *args, **kw):
     return get_event_loop().run_until_complete(coro(*args, **kw))
 
+
 class CoroutineTestCase(unittest.TestCase):
     def test_before_after(self):
         @before_after
         async def coro(x):
-           return x
+            return x
         self.assertTrue(inspect.iscoroutinefunction(coro))
         out = get_event_loop().run_until_complete(coro('x'))
         self.assertEqual(out, '<before>x<after>')
@@ -55,7 +48,6 @@
             return x
         self.assertFalse(inspect.iscoroutinefunction(coro))
         self.assertEqual(coro('x'), 'x')
-''')
 
 
 def gen123():
@@ -80,28 +72,42 @@
         err = doctest.testmod(doc)[0]
         self.assertEqual(err, 0)
 
+    def test_copy_dunder_attrs(self):
+        traced = doc.trace(doc.foo)
+        self.assertIn('documentation', traced.__module__)
+        self.assertEqual(traced.__annotations__, {})
+        self.assertEqual(traced.__defaults__, (None,))
+
     def test_singledispatch1(self):
-        if hasattr(functools, 'singledispatch'):
-            with assertRaises(RuntimeError):
-                doc.singledispatch_example1()
+        with assertRaises(RuntimeError):
+            doc.singledispatch_example1()
 
     def test_singledispatch2(self):
-        if hasattr(functools, 'singledispatch'):
-            doc.singledispatch_example2()
+        doc.singledispatch_example2()
+
+    def test_context_manager(self):
+
+        @contextmanager
+        def before_after(before, after):
+            print(before)
+            yield
+            print(after)
+
+        @before_after('BEFORE', 'AFTER')
+        def hello_user(user):
+            print('hello %s' % user)
+
+        argspec = inspect.getfullargspec(hello_user)
+        self.assertEqual(argspec.args, ['user'])
 
 
 class ExtraTestCase(unittest.TestCase):
     def test_qualname(self):
-        if sys.version_info >= (3, 3):
-            self.assertEqual(doc.hello.__qualname__, 'hello')
-        else:
-            with assertRaises(AttributeError):
-                doc.hello.__qualname__
+        self.assertEqual(doc.operation1.__qualname__, 'operation1')
 
     def test_signature(self):
-        if hasattr(inspect, 'signature'):
-            sig = inspect.signature(doc.f1)
-            self.assertEqual(str(sig), '(x)')
+        sig = inspect.signature(doc.f1)
+        self.assertEqual(str(sig), '(x)')
 
     def test_unique_filenames(self):
         @decorator
@@ -125,10 +131,13 @@
         @d1
         def f1(x, y, z):
             pass
-        self.assertNotEqual(d1.__code__.co_filename, d2.__code__.co_filename)
-        self.assertNotEqual(f1.__code__.co_filename, f2.__code__.co_filename)
-        self.assertNotEqual(f1_orig.__code__.co_filename,
-                            f1.__code__.co_filename)
+
+        self.assertEqual(d1.__code__.co_filename,
+                         d2.__code__.co_filename)
+        self.assertEqual(f1.__code__.co_filename,
+                         f2.__code__.co_filename)
+        self.assertEqual(f1_orig.__code__.co_filename,
+                         f1.__code__.co_filename)
 
     def test_no_first_arg(self):
         @decorator
@@ -137,17 +146,19 @@
 
         @example
         def func(**kw):
+            "Docstring"
             return kw
 
         # there is no confusion when passing args as a keyword argument
         self.assertEqual(func(args='a'), {'args': 'a'})
+        self.assertEqual(func.__doc__, "Docstring")
 
     def test_decorator_factory(self):
         # similar to what IPython is doing in traitlets.config.application
         @decorator
         def catch_config_error(method, app, *args, **kwargs):
             return method(app)
-        catch_config_error(lambda app: None)
+        catch_config_error(lambda app, **kw: None)(1)
 
     def test_add1(self):
         # similar to what IPython is doing in traitlets.config.application
@@ -159,6 +170,29 @@
             return x
         self.assertEqual(add(f, 2)(0), 2)
 
+    def test_dan_schult(self):
+        # see https://github.com/micheles/decorator/issues/120
+        @decorator
+        def prnt(func, index=0, *args, **kw):
+            print(args[index])
+            return func(*args, **kw)
+
+        @prnt(index=2)  # print the value of the third argument
+        def f(a, b, c=None):
+            return [a, b, c]
+
+        self.assertEqual(f(0, 1), [0, 1, None])
+
+    def test_slow_wrapper(self):
+        # see https://github.com/micheles/decorator/issues/123
+        dd = defaultdict(list)
+        doc.trace(defaultdict.__setitem__)(dd, 'x', [1])
+        self.assertEqual(dd['x'], [1])
+        doc.trace(defaultdict.__delitem__)(dd, 'x')
+        self.assertEqual(dd['x'], [])
+        # NB: defaultdict.__getitem__ has no signature and cannot be
+        # decorated in CPython, while it is regular in PyPy
+
 
 # ################### test dispatch_on ############################# #
 # adapted from test_functools in Python 3.5
@@ -290,14 +324,13 @@
         self.assertEqual(g(f), "sized")
         self.assertEqual(g(t), "sized")
 
-        if hasattr(c, 'ChainMap'):
-            g.register(c.ChainMap)(lambda obj: "chainmap")
-            # irrelevant ABCs registered
-            self.assertEqual(g(d), "mutablemapping")
-            self.assertEqual(g(l), "sized")
-            self.assertEqual(g(s), "sized")
-            self.assertEqual(g(f), "sized")
-            self.assertEqual(g(t), "sized")
+        g.register(ChainMap)(lambda obj: "chainmap")
+        # irrelevant ABCs registered
+        self.assertEqual(g(d), "mutablemapping")
+        self.assertEqual(g(l), "sized")
+        self.assertEqual(g(s), "sized")
+        self.assertEqual(g(f), "sized")
+        self.assertEqual(g(t), "sized")
 
         g.register(c.MutableSequence)(lambda obj: "mutablesequence")
         self.assertEqual(g(d), "mutablemapping")

++++++ kwsyntax.patch ++++++
>From 817d070db3c9cc5900d118837c533c039982b050 Mon Sep 17 00:00:00 2001
From: Michele Simionato <michele.simion...@gmail.com>
Date: Fri, 28 May 2021 08:30:09 +0200
Subject: [PATCH] Fixed decorator.decorator not passing kwsyntax

---
 CHANGES.md       | 2 ++
 src/decorator.py | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/CHANGES.md b/CHANGES.md
index 596559b..876df34 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -3,6 +3,8 @@ HISTORY
 
 ## unreleased
 
+decorator.decorator was not passing the kwsyntax.
+
 ## 5.0.9 (2021-05-16)
 
 Fixed a test breaking PyPy. Restored support for Sphinx.
diff --git a/src/decorator.py b/src/decorator.py
index 438dff6..dab0d7c 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -265,7 +265,7 @@ def decorator(caller, _func=None, kwsyntax=False):
     """
     if _func is not None:  # return a decorated function
         # this is obsolete behavior; you should use decorate instead
-        return decorate(_func, caller)
+        return decorate(_func, caller, (), kwsyntax)
     # else return a decorator function
     sig = inspect.signature(caller)
     dec_params = [p for p in sig.parameters.values() if p.kind is POS]

Reply via email to