Browse Source

[libs] Adding decorator which is a pyphoenix dependency

Romain 5 years ago
parent
commit
6a0642479f

+ 341 - 0
desktop/core/ext-py/decorator-4.4.2/CHANGES.md

@@ -0,0 +1,341 @@
+HISTORY
+--------
+
+## unreleased
+
+## 4.4.2 (2020-02-29)
+
+Sylvan Mosberger (https://github.com/Infinisil) contributed a patch to
+some doctests that were breaking on NixOS.
+John Vandenberg (https://github.com/jayvdb) made a case for removing the usage
+of `__file__`, that was breaking PyOxidizer.
+Miro Hrončok (https://github.com/hroncok) contributed some fixes for the
+future Python 3.9.
+Hugo van Kemenade (https://github.com/hugovk) contributed some fixes for the
+future Python 3.10.
+
+## 4.4.1 (2019-10-27)
+
+Changed the description to "Decorators for Humans" are requested by
+several users. Fixed a .rst bug in the description as seen in PyPI.
+
+## 4.4.0 (2019-03-16)
+
+Fixed a regression with decorator factories breaking the case with no
+arguments by going back to the syntax used in version 4.2.
+Accepted a small fix from Eric Larson (https://github.com/larsoner) affecting
+`isgeneratorfunction` for old Python versions.
+Moved the documentation from ReadTheDocs to GitHub to simplify the
+release process and replaced ReStructuredText with Markdown: it is
+an inferior solution, but it works better with GitHub and it is good enough.
+
+## 4.3.2 (2019-01-24)
+
+Accepted a patch from Sylvain Marie (https://github.com/smarie): now the
+decorator module can decorate generator functions by preserving their
+being generator functions. Set `python_requires='>=2.6, !=3.0.*, !=3.1.*'`
+in setup.py, as suggested by https://github.com/hugovk.
+
+## 4.3.1 (2018-08-04)
+
+Added a section "For the impatient" to the README, addressing an issue
+raised by Amir Malekpour. Added support for Python 3.7. Now 
+the path to the decorator module appears in the tracebacks, as suggested
+by an user at EuroPython 2018.
+
+## 4.3.0 (2018-04-15)
+
+Extended the decorator family facility to work with positional
+arguments and updated the documentation. Removed
+`decorator.getargspec` and provided `decorator.getfullargspec`
+instead.  This is convenient for users of Python 2.6/2.7, the others
+can just use `inspect.getfullargspec`.
+
+## 4.2.1 (2018-01-14)
+
+Fixed a regression breaking IPython reported by https://github.com/spapini .
+
+## 4.2.0 (2018-01-14)
+
+Added a facility to define families of decorators (aka decorators with
+arguments) as requested by several users. Accepted a pylint patch by
+David Allouche.
+
+## 4.1.2 (2017-07-23)
+
+Made it possible to define decorators converting coroutines into regular
+functions, as requested by Itaï Ben Yaacov.
+
+## 4.1.1 (2017-07-16)
+
+Changed the documentation build system to sphinx and uploaded the docs
+on readthedocs.org.
+
+## 4.1.0 (2017-07-15)
+
+Support for Python 3.5 coroutines defined with `async def`, thanks to
+Victor-Nicolae Savu who raised the issue of `iscoroutinefunction` not
+giving the right answer for coroutines decorated with the decorator module.
+
+## 4.0.11 (2017-01-15)
+
+Small improvements to the documentation and tested with Python 3.6
+
+## 4.0.10 (2016-06-07)
+
+Improved the documentation thanks to Tony Goodchild (zearin) who also
+provided a much better CSS than the one I was using.
+
+## 4.0.9 (2016-02-08)
+
+Same as 4.0.7 and 4.0.8, re-uploaded due to issues on PyPI.
+
+## 4.0.7 (2016-02-06)
+
+Switched to a new changelog format (the one in http://keepachangelog.com/)
+since it was contributed by Alexander Artemenko. Re-added a newline to support
+old version of Python, as requested by [azjps](https://github.com/azjps).
+
+## 4.0.6 (2015-12-11)
+
+Removed a file x.py accidentally entered in the tarball.
+
+## 4.0.5 (2015-12-09)
+
+Documented a quirk signaled by David Goldstein when writing decorators
+for functions with keyword arguments. Avoided copying the globals,
+as signaled by Benjamin Peterson.
+
+## 4.0.4 (2015-09-25)
+
+Included a patch from Zev Benjamin: now decorated functions play well
+with cProfile.
+
+## 4.0.3 (2015-09-25)
+
+Added a warning about the memoize example, as requested by Robert
+Buchholz.
+
+## 4.0.2 (2015-07-28)
+
+docs/README.rst was not included in MANIFEST.in by accident,
+thus breaking the source installation.
+
+## 4.0.1 (2015-07-28)
+
+Added docs directory and upload_docs command. Fixed bug with
+`__qualname__`, reported by Lucian Petrut.
+
+## 4.0.0 (2015-07-24)
+
+Removed the need for 2to3 by dropping the support for Python 2.5.
+Added a MANIFEST.in file and produced a proper wheel. Improved
+the integration with setuptools so that `python setup.py test` works.
+Reworked the documentation and introduced `decorator.decorated`.
+Removed any dependence from `inspect.getargspec`, which is deprecated
+in Python 3.5, as signaled by Ralf Gommers.
+Fixed `contextmanager` to work with Python 3.5.
+Copied the `__qualname__` attribute, as requested by Frazer McLean.
+Added a `dispatch_on` facility to implement generic functions.
+
+## 3.4.2 (2015-03-22)
+
+Same as 3.4.1, re-uploaded to PyPI.
+
+## 3.4.1 (2015-03-16)
+
+Ported the repository from GoogleCode to GitHub and added Travis CI
+support. Tests are executed with the new command `python test.py -v`.
+setuptools is now mandatory in Python 3. The suggested
+installation tool is now `pip`, not `easy_install`. Supported IronPython
+and other Python implementations without sys._getframe, as requested by
+Doug Blank.
+
+## 3.4.0 (2012-10-18)
+
+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é.
+
+## 3.3.3 (2012-04-23)
+
+Fixed a bug with kwonlyargs for Python 3, submitted by Chris
+Ellison.
+
+## 3.3.2 (2011-09-01)
+
+Fixed a bug with __kwdefaults__ for Python 3, submitted by Chris
+Ellison.
+
+## 3.3.1 (2011-04-22)
+
+Fixed a doctest broken for Python 3.2, as noted by
+Arfrever Frehtes Taifersar Arahesis; changed the name of
+the attribute ``undecorated`` to ``__wrapped__``, by following the
+Python 3.2 convention, as requested by Ram Rachum; added
+the Python 3 classifier to setup.py.
+
+## 3.3 (2011-01-01)
+
+Added support for function annotations.
+
+## 3.2.1 (2010-12-28)
+
+Now the .func_globals of the decorated function are the same of
+the undecorated function, as requested by Paul Ollis.
+
+## 3.2 (2010-05-22)
+
+Added __version__ (thanks to Gregg Lind), removed functionality which 
+has been deprecated for years, removed the confusing decorator_factory
+example and added official support for Python 3 (requested by Claus Klein).
+Moved the documentation from PyPI to googlecode.
+
+## 3.1.2 (2009-08-25)
+
+Added attributes args, varargs, keywords and arg0, ..., argN
+to FunctionMaker objects generated from a function; fixed another
+Pylons-breaking bug signaled by Lawrence Oluyede.
+
+## 3.1.1 (2009-08-18)
+
+Fixed a bug which was breaking Pylons, signaled by
+Gabriel de Perthuis, and added a test for it.
+
+## 3.1 (2009-08-16)
+
+Added decorator.factory, an easy way to define families of decorators
+(requested by various users, including David Laban). Refactored the
+FunctionMaker class and added an easier to use .create classmethod.
+Internally, functools.partial is used for Python >= 2.5.
+
+## 3.0.1 (2009-02-16)
+
+Improved the error message in case a bound/unbound method is passed
+instead of a function and documented this case; that should make life
+easier for users like Gustavo Nerea.
+
+## 3.0 (2008-12-14)
+
+New major version introducing ``FunctionMaker`` and the two-argument
+syntax for ``decorator``. Moreover, added support for getting the
+source code. This version is Python 3.0 ready.  Major overhaul of the
+documentation, now hosted on http://packages.python.org/decorator.
+
+## 2.3.2 (2008-12-01)
+
+Small optimization in the code for decorator factories. First version
+with the code uploaded to PyPI.
+
+## 2.3.1 (2008-07-25)
+
+Set the zipsafe flag to False, since I want my users to have the source,
+not a zipped egg.
+
+## 2.3.0 (2008-07-10)
+
+Added support for writing decorator factories with minimal effort
+(feature requested by Matthew Wilson); implemented it by enhancing
+'decorator' to a Python 2.6 class decorator.
+
+## 2.2.0. (2007-07-31)
+
+Added a note on 'inspect.getsource' not working for decorated
+functions; referenced PEP 326; highlighted the snippets in the 
+documentation with pygments; slightly simplified the code.
+
+## 2.1.0. (2007-07-03)
+
+Replaced the utility 'update_wrapper' with 'new_wrapper' and
+updated the documentation accordingly; fixed and improved the 
+doctester argument parsing, signaled by Sam Wyse.
+
+## 2.0.1 (2007-02-17)
+
+Included the licence in the source code too; fixed a versioning
+issue by adding the version number to the zip file and fixing
+the link to it on the web page, thanks to Philip Jenvey.
+
+## 2.0 (2007-01-13)
+
+Rewritten and simplified the implementation; broken compatibility
+with previous versions (in minor ways); added the utility function
+'update_wrapper' instead of 'newfunc'.
+
+## 1.1 (2006-12-02)
+
+'decorator' instances now have attributes __name__, __doc__,
+__module__ and __dict__ coming from the associated caller function; 
+included the licence into the documentation.
+
+## 1.0 (2006-08-10)
+
+Added LICENSE.txt; added a setuptools-friendly setup.py script 
+contributed by Luke Arno.
+
+## 0.8.1 (2006-06-21)
+
+Minor fixes to the documentation.
+
+## 0.8 (2006-06-16)
+
+Improved the documentation, added the 'caveats' section.
+
+## 0.7.1 (2006-05-15)
+
+Improved the tail_recursive example.
+
+## 0.7 (2006-05-10)
+
+Renamed 'copyfunc' into 'newfunc' and added the ability to copy
+the signature from a model function;   improved '_decorator' to
+set the '__module__' attribute too, with the intent of improving 
+error messages; updated the documentation.
+
+## 0.6 (2005-12-20)
+
+Changed decorator.__call__ so that the module somewhat works
+even for Python 2.3 (but the signature-preserving feature is
+lost).
+
+## 0.5.2 (2005-06-28)
+
+Minor changes to the documentation; improved `getattr_` and
+shortened `locked`.
+
+## 0.5.1 (2005-05-20)
+
+Minor corrections to the documentation.
+
+## 0.5 (2005-05-19)
+
+Fixed a bug with out-of-the-mind signatures, added a check for
+reserved names in the argument list and simplified the code (thanks to
+Duncan Booth).
+
+## 0.4.1 (2005-05-17)
+
+Fixed a typo in the documentation (thanks to Anthon van der Neut).
+
+## 0.4 (2005-05-12)
+
+Added getinfo, some tests and improved the documentation.
+
+## 0.3 (2005-05-10)
+
+Simplified copyfunc, renamed deferred to delayed and added the
+nonblocking example.
+
+## 0.2 (2005-05-09)
+
+Added copyfunc, improved the multithreading examples, improved the
+doctester program.
+
+## 0.1.1 (2005-05-06)
+
+Added the license specification and two docstrings.
+
+## 0.1 (2005-05-04)
+
+Initial release.

+ 26 - 0
desktop/core/ext-py/decorator-4.4.2/LICENSE.txt

@@ -0,0 +1,26 @@
+Copyright (c) 2005-2018, Michele Simionato
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  Redistributions in bytecode form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.

+ 2 - 0
desktop/core/ext-py/decorator-4.4.2/MANIFEST.in

@@ -0,0 +1,2 @@
+include README.rst LICENSE.txt CHANGES.md performance.sh documentation.pdf
+recursive-include src/tests *.py

+ 129 - 0
desktop/core/ext-py/decorator-4.4.2/PKG-INFO

@@ -0,0 +1,129 @@
+Metadata-Version: 1.2
+Name: decorator
+Version: 4.4.2
+Summary: Decorators for Humans
+Home-page: https://github.com/micheles/decorator
+Author: Michele Simionato
+Author-email: michele.simionato@gmail.com
+License: new BSD License
+Description: Decorators for Humans
+        =====================
+        
+        The goal of the decorator module is to make it easy to define
+        signature-preserving function decorators and decorator factories.
+        It also includes an implementation of multiple dispatch and other niceties
+        (please check the docs). It is released under a two-clauses
+        BSD license, i.e. basically you can do whatever you want with it but I am not
+        responsible.
+        
+        Installation
+        -------------
+        
+        If you are lazy, just perform
+        
+         ``$ pip install decorator``
+        
+        which will install just the module on your system.
+        
+        If you prefer to install the full distribution from source, including
+        the documentation, clone the `GitHub repo`_ or download the tarball_, unpack it and run
+        
+         ``$ pip install .``
+        
+        in the main directory, possibly as superuser.
+        
+        .. _tarball: https://pypi.org/project/decorator/#files
+        .. _GitHub repo: https://github.com/micheles/decorator
+        
+        Testing
+        --------
+        
+        If you have the source code installation you can run the tests with
+        
+         `$ python src/tests/test.py -v`
+        
+        or (if you have setuptools installed)
+        
+         `$ python setup.py test`
+        
+        Notice that you may run into trouble if in your system there
+        is an older version of the decorator module; in such a case remove the
+        old version. It is safe even to copy the module `decorator.py` over
+        an existing one, since we kept backward-compatibility for a long time.
+        
+        Repository
+        ---------------
+        
+        The project is hosted on GitHub. You can look at the source here:
+        
+         https://github.com/micheles/decorator
+        
+        Documentation
+        ---------------
+        
+        The documentation has been moved to https://github.com/micheles/decorator/blob/master/docs/documentation.md
+        
+        From there you can get a PDF version by simply using the print
+        functionality of your browser.
+        
+        Here is the documentation for previous versions of the module:
+        
+        https://github.com/micheles/decorator/blob/4.3.2/docs/tests.documentation.rst
+        https://github.com/micheles/decorator/blob/4.2.1/docs/tests.documentation.rst
+        https://github.com/micheles/decorator/blob/4.1.2/docs/tests.documentation.rst
+        https://github.com/micheles/decorator/blob/4.0.0/documentation.rst
+        https://github.com/micheles/decorator/blob/3.4.2/documentation.rst
+        
+        For the impatient
+        -----------------
+        
+        Here is an example of how to define a family of decorators tracing slow
+        operations:
+        
+        .. code-block:: python
+        
+           from decorator import decorator
+        
+           @decorator
+           def warn_slow(func, timelimit=60, *args, **kw):
+               t0 = time.time()
+               result = func(*args, **kw)
+               dt = time.time() - t0
+               if dt > timelimit:
+                   logging.warn('%s took %d seconds', func.__name__, dt)
+               else:
+                   logging.info('%s took %d seconds', func.__name__, dt)
+               return result
+        
+           @warn_slow  # warn if it takes more than 1 minute
+           def preprocess_input_files(inputdir, tempdir):
+               ...
+        
+           @warn_slow(timelimit=600)  # warn if it takes more than 10 minutes
+           def run_calculation(tempdir, outdir):
+               ...
+        
+        Enjoy!
+        
+Keywords: decorators generic utility
+Platform: All
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+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 :: Implementation :: CPython
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Utilities
+Requires-Python: >=2.6, !=3.0.*, !=3.1.*

+ 98 - 0
desktop/core/ext-py/decorator-4.4.2/README.rst

@@ -0,0 +1,98 @@
+Decorators for Humans
+=====================
+
+The goal of the decorator module is to make it easy to define
+signature-preserving function decorators and decorator factories.
+It also includes an implementation of multiple dispatch and other niceties
+(please check the docs). It is released under a two-clauses
+BSD license, i.e. basically you can do whatever you want with it but I am not
+responsible.
+
+Installation
+-------------
+
+If you are lazy, just perform
+
+ ``$ pip install decorator``
+
+which will install just the module on your system.
+
+If you prefer to install the full distribution from source, including
+the documentation, clone the `GitHub repo`_ or download the tarball_, unpack it and run
+
+ ``$ pip install .``
+
+in the main directory, possibly as superuser.
+
+.. _tarball: https://pypi.org/project/decorator/#files
+.. _GitHub repo: https://github.com/micheles/decorator
+
+Testing
+--------
+
+If you have the source code installation you can run the tests with
+
+ `$ python src/tests/test.py -v`
+
+or (if you have setuptools installed)
+
+ `$ python setup.py test`
+
+Notice that you may run into trouble if in your system there
+is an older version of the decorator module; in such a case remove the
+old version. It is safe even to copy the module `decorator.py` over
+an existing one, since we kept backward-compatibility for a long time.
+
+Repository
+---------------
+
+The project is hosted on GitHub. You can look at the source here:
+
+ https://github.com/micheles/decorator
+
+Documentation
+---------------
+
+The documentation has been moved to https://github.com/micheles/decorator/blob/master/docs/documentation.md
+
+From there you can get a PDF version by simply using the print
+functionality of your browser.
+
+Here is the documentation for previous versions of the module:
+
+https://github.com/micheles/decorator/blob/4.3.2/docs/tests.documentation.rst
+https://github.com/micheles/decorator/blob/4.2.1/docs/tests.documentation.rst
+https://github.com/micheles/decorator/blob/4.1.2/docs/tests.documentation.rst
+https://github.com/micheles/decorator/blob/4.0.0/documentation.rst
+https://github.com/micheles/decorator/blob/3.4.2/documentation.rst
+
+For the impatient
+-----------------
+
+Here is an example of how to define a family of decorators tracing slow
+operations:
+
+.. code-block:: python
+
+   from decorator import decorator
+
+   @decorator
+   def warn_slow(func, timelimit=60, *args, **kw):
+       t0 = time.time()
+       result = func(*args, **kw)
+       dt = time.time() - t0
+       if dt > timelimit:
+           logging.warn('%s took %d seconds', func.__name__, dt)
+       else:
+           logging.info('%s took %d seconds', func.__name__, dt)
+       return result
+
+   @warn_slow  # warn if it takes more than 1 minute
+   def preprocess_input_files(inputdir, tempdir):
+       ...
+
+   @warn_slow(timelimit=600)  # warn if it takes more than 10 minutes
+   def run_calculation(tempdir, outdir):
+       ...
+
+Enjoy!

+ 13 - 0
desktop/core/ext-py/decorator-4.4.2/performance.sh

@@ -0,0 +1,13 @@
+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()"

+ 10 - 0
desktop/core/ext-py/decorator-4.4.2/setup.cfg

@@ -0,0 +1,10 @@
+[bdist_wheel]
+universal = 1
+
+[upload_docs]
+upload-dir = docs
+
+[egg_info]
+tag_build = 
+tag_date = 0
+

+ 42 - 0
desktop/core/ext-py/decorator-4.4.2/setup.py

@@ -0,0 +1,42 @@
+from setuptools import setup
+
+dic = dict(__file__=None)
+exec(open('src/decorator.py').read(), dic)  # extract the __version__
+VERSION = dic['__version__']
+
+
+if __name__ == '__main__':
+    setup(name='decorator',
+          version=VERSION,
+          description='Decorators for Humans',
+          long_description=open('README.rst').read(),
+          author='Michele Simionato',
+          author_email='michele.simionato@gmail.com',
+          url='https://github.com/micheles/decorator',
+          license="new BSD License",
+          package_dir={'': 'src'},
+          py_modules=['decorator'],
+          keywords="decorators generic utility",
+          platforms=["All"],
+          python_requires='>=2.6, !=3.0.*, !=3.1.*',
+          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 :: Implementation :: CPython',
+                       'Topic :: Software Development :: Libraries',
+                       'Topic :: Utilities'],
+          test_suite='tests',
+          zip_safe=False)

+ 454 - 0
desktop/core/ext-py/decorator-4.4.2/src/decorator.py

@@ -0,0 +1,454 @@
+# #########################     LICENSE     ############################ #
+
+# Copyright (c) 2005-2018, Michele Simionato
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   Redistributions in bytecode form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+"""
+Decorator module, see http://pypi.python.org/pypi/decorator
+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
+
+
+DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(')
+
+
+# basic functionality
+class FunctionMaker(object):
+    """
+    An object with the ability to create functions with a given signature.
+    It has attributes name, doc, module, signature, defaults, dict and
+    methods update and make.
+    """
+
+    # Atomic get-and-increment provided by the GIL
+    _compile_count = itertools.count()
+
+    # make pylint happy
+    args = varargs = varkw = defaults = kwonlyargs = kwonlydefaults = ()
+
+    def __init__(self, func=None, name=None, signature=None,
+                 defaults=None, doc=None, module=None, funcdict=None):
+        self.shortsignature = signature
+        if func:
+            # func can be a class or a callable, but not an instance method
+            self.name = func.__name__
+            if self.name == '<lambda>':  # small hack for lambda functions
+                self.name = '_lambda_'
+            self.doc = func.__doc__
+            self.module = func.__module__
+            if inspect.isfunction(func):
+                argspec = getfullargspec(func)
+                self.annotations = getattr(func, '__annotations__', {})
+                for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
+                          'kwonlydefaults'):
+                    setattr(self, a, getattr(argspec, a))
+                for i, arg in enumerate(self.args):
+                    setattr(self, 'arg%d' % i, arg)
+                allargs = list(self.args)
+                allshortargs = list(self.args)
+                if self.varargs:
+                    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:
+                    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:
+            self.name = name
+        if signature is not None:
+            self.signature = signature
+        if defaults:
+            self.defaults = defaults
+        if doc:
+            self.doc = doc
+        if module:
+            self.module = module
+        if funcdict:
+            self.dict = funcdict
+        # check existence required attributes
+        assert hasattr(self, 'name')
+        if not hasattr(self, 'signature'):
+            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"
+        func.__name__ = self.name
+        func.__doc__ = getattr(self, 'doc', None)
+        func.__dict__ = getattr(self, 'dict', {})
+        func.__defaults__ = self.defaults
+        func.__kwdefaults__ = self.kwonlydefaults or None
+        func.__annotations__ = getattr(self, 'annotations', None)
+        try:
+            frame = sys._getframe(3)
+        except AttributeError:  # for IronPython and similar implementations
+            callermodule = '?'
+        else:
+            callermodule = frame.f_globals.get('__name__', '?')
+        func.__module__ = getattr(self, 'module', callermodule)
+        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"
+        src = src_templ % vars(self)  # expand name and signature
+        evaldict = evaldict or {}
+        mo = DEF.search(src)
+        if mo is None:
+            raise SyntaxError('not a valid function template\n%s' % src)
+        name = mo.group(1)  # extract the function name
+        names = set([name] + [arg.strip(' *') for arg in
+                              self.shortsignature.split(',')])
+        for n in names:
+            if n in ('_func_', '_call_'):
+                raise NameError('%s is overridden in\n%s' % (n, src))
+
+        if not src.endswith('\n'):  # add a newline for old Pythons
+            src += '\n'
+
+        # Ensure each generated function has a unique filename for profilers
+        # (such as cProfile) that depend on the tuple of (<filename>,
+        # <definition line>, <function name>) being unique.
+        filename = '<decorator-gen-%d>' % next(self._compile_count)
+        try:
+            code = compile(src, filename, 'single')
+            exec(code, evaldict)
+        except Exception:
+            print('Error in generated code:', file=sys.stderr)
+            print(src, file=sys.stderr)
+            raise
+        func = evaldict[name]
+        if addsource:
+            attrs['__source__'] = src
+        self.update(func, **attrs)
+        return func
+
+    @classmethod
+    def create(cls, obj, body, evaldict, defaults=None,
+               doc=None, module=None, addsource=True, **attrs):
+        """
+        Create a function from the strings name, signature and body.
+        evaldict is the evaluation dictionary. If addsource is true an
+        attribute __source__ is added to the result. The attributes attrs
+        are added, if any.
+        """
+        if isinstance(obj, str):  # "name(signature)"
+            name, rest = obj.strip().split('(', 1)
+            signature = rest[:-1]  # strip a right parens
+            func = None
+        else:  # a function
+            name = None
+            signature = None
+            func = obj
+        self = cls(func, name, signature, defaults, doc, module)
+        ibody = '\n'.join('    ' + line for line in body.splitlines())
+        caller = evaldict.get('_call_')  # when called from `decorate`
+        if caller and iscoroutinefunction(caller):
+            body = ('async def %(name)s(%(signature)s):\n' + ibody).replace(
+                'return', 'return await')
+        else:
+            body = 'def %(name)s(%(signature)s):\n' + ibody
+        return self.make(body, evaldict, addsource, **attrs)
+
+
+def decorate(func, caller, extras=()):
+    """
+    decorate(func, caller) decorates a function using a caller.
+    If the caller is a generator function, the resulting function
+    will be a generator function.
+    """
+    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)
+    else:
+        fun = FunctionMaker.create(
+            func, "return _call_(_func_, %s%%(shortsignature)s)" % es,
+            evaldict, __wrapped__=func)
+    if hasattr(func, '__qualname__'):
+        fun.__qualname__ = func.__qualname__
+    return fun
+
+
+def decorator(caller, _func=None):
+    """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_'
+        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 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__
+
+_contextmanager = decorator(ContextManager)
+
+
+def contextmanager(func):
+    # Enable Pylint config: contextmanager-decorators=decorator.contextmanager
+    return _contextmanager(func)
+
+
+# ############################ dispatch_on ############################ #
+
+def append(a, vancestors):
+    """
+    Append ``a`` to the list of the virtual ancestors, unless it is already
+    included.
+    """
+    add = True
+    for j, va in enumerate(vancestors):
+        if issubclass(va, a):
+            add = False
+            break
+        if issubclass(a, va):
+            vancestors[j] = a
+            add = False
+    if add:
+        vancestors.append(a)
+
+
+# inspired from simplegeneric by P.J. Eby and functools.singledispatch
+def dispatch_on(*dispatch_args):
+    """
+    Factory of decorators turning a function into a generic function
+    dispatching on the given arguments.
+    """
+    assert dispatch_args, 'No dispatch args passed'
+    dispatch_str = '(%s,)' % ', '.join(dispatch_args)
+
+    def check(arguments, wrong=operator.ne, msg=''):
+        """Make sure one passes the expected number of arguments"""
+        if wrong(len(arguments), len(dispatch_args)):
+            raise TypeError('Expected %d arguments, got %d%s' %
+                            (len(dispatch_args), len(arguments), msg))
+
+    def gen_func_dec(func):
+        """Decorator turning a function into a generic function"""
+
+        # first check the dispatch arguments
+        argset = set(getfullargspec(func).args)
+        if not set(dispatch_args) <= argset:
+            raise NameError('Unknown dispatch arguments %s' % dispatch_str)
+
+        typemap = {}
+
+        def vancestors(*types):
+            """
+            Get a list of sets of virtual ancestors for the given types
+            """
+            check(types)
+            ras = [[] for _ in range(len(dispatch_args))]
+            for types_ in typemap:
+                for t, type_, ra in zip(types, types_, ras):
+                    if issubclass(t, type_) and type_ not in t.mro():
+                        append(type_, ra)
+            return [set(ra) for ra in ras]
+
+        def ancestors(*types):
+            """
+            Get a list of virtual MROs, one for each type
+            """
+            check(types)
+            lists = []
+            for t, vas in zip(types, vancestors(*types)):
+                n_vas = len(vas)
+                if n_vas > 1:
+                    raise RuntimeError(
+                        'Ambiguous dispatch for %s: %s' % (t, vas))
+                elif n_vas == 1:
+                    va, = vas
+                    mro = type('t', (t, va), {}).mro()[1:]
+                else:
+                    mro = t.mro()
+                lists.append(mro[:-1])  # discard t and object
+            return lists
+
+        def register(*types):
+            """
+            Decorator to register an implementation for the given types
+            """
+            check(types)
+
+            def dec(f):
+                check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__)
+                typemap[types] = f
+                return f
+            return dec
+
+        def dispatch_info(*types):
+            """
+            An utility to introspect the dispatch algorithm
+            """
+            check(types)
+            lst = []
+            for anc in itertools.product(*ancestors(*types)):
+                lst.append(tuple(a.__name__ for a in anc))
+            return lst
+
+        def _dispatch(dispatch_args, *args, **kw):
+            types = tuple(type(arg) for arg in dispatch_args)
+            try:  # fast path
+                f = typemap[types]
+            except KeyError:
+                pass
+            else:
+                return f(*args, **kw)
+            combinations = itertools.product(*ancestors(*types))
+            next(combinations)  # the first one has been already tried
+            for types_ in combinations:
+                f = typemap.get(types_)
+                if f is not None:
+                    return f(*args, **kw)
+
+            # else call the default implementation
+            return func(*args, **kw)
+
+        return FunctionMaker.create(
+            func, 'return _f_(%s, %%(shortsignature)s)' % dispatch_str,
+            dict(_f_=_dispatch), register=register, default=func,
+            typemap=typemap, vancestors=vancestors, ancestors=ancestors,
+            dispatch_info=dispatch_info, __wrapped__=func)
+
+    gen_func_dec.__name__ = 'dispatch_on' + dispatch_str
+    return gen_func_dec

+ 0 - 0
desktop/core/ext-py/decorator-4.4.2/src/tests/__init__.py


+ 1897 - 0
desktop/core/ext-py/decorator-4.4.2/src/tests/documentation.py

@@ -0,0 +1,1897 @@
+from __future__ import print_function
+import sys
+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,
+                       dispatch_on, __version__)
+
+doc = r"""Decorators for Humans
+----------------------------------
+
+|Author | Michele Simionato|
+|---|---|
+|E-mail | michele.simionato@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|
+|Download page| http://pypi.python.org/pypi/decorator/$VERSION|
+|Installation| ``pip install decorator``|
+|License | BSD license|
+
+Introduction
+-----------------------------------------
+
+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.
+
+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.
+  Even if you are a long-time user, you may want to revisit the docs, since
+  several examples have been improved.
+
+- **Packaging improvements**
+  The code is now also available in wheel format. Integration with
+  setuptools has improved and you can run the tests with the command
+  ``python setup.py test`` too.
+
+- **Code changes**
+  A new utility function ``decorate(func, caller)`` has been added.
+  It does the same job that was performed by the older
+  ``decorator(caller, func)``. The old functionality is now deprecated
+  and no longer documented, but still available for now.
+
+- **Multiple dispatch**
+  The decorator module now includes an implementation of generic
+  functions (sometimes called "multiple dispatch functions").
+  The API is designed to mimic ``functools.singledispatch`` (added
+  in Python 3.4), but the implementation is much simpler.
+  Moreover, all decorators involved preserve the signature of the
+  decorated functions. For now, this exists mostly to demonstrate
+  the power of the module. In the future it could be enhanced/optimized.
+  In any case, it is very short and compact (less then 100 lines), so you
+  can extract it for your own use. Take it as food for thought.
+
+- **Python 3.5 coroutines**
+  From version 4.1 it is possible to decorate coroutines, i.e. functions
+  defined with the `async def` syntax, and to maintain the
+  `inspect.iscoroutinefunction` check working for the decorated function.
+
+- **Decorator factories**
+  From version 4.2 there is facility to define factories of decorators in
+  a simple way, a feature requested by the users since a long time.
+
+Usefulness of decorators
+------------------------------------------------
+
+Python decorators are an interesting example of why syntactic sugar
+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
+idea since:
+
+* decorators help reducing boilerplate code;
+* decorators help separation of concerns;
+* decorators enhance readability and maintenability;
+* decorators are explicit.
+
+Still, as of now, writing custom decorators correctly requires
+some experience and it is not as easy as it could be. For instance,
+typical implementations of decorators involve nested functions, and
+we all know that flat is better than nested.
+
+The aim of the ``decorator`` module it to simplify the usage of
+decorators for the average programmer, and to popularize decorators by
+showing various non-trivial examples. Of course, as all techniques,
+decorators can be abused (I have seen that) and you should not try to
+solve every problem with a decorator, just because you can.
+
+You may find the source code for all the examples
+discussed here in the ``documentation.py`` file, which contains
+the documentation you are reading in the form of doctests.
+
+Definitions
+------------------------------------
+
+Technically speaking, any Python object which can be called with one argument
+can be used as a decorator. However, this definition is somewhat too large
+to be really useful. It is more convenient to split the generic class of
+decorators in two subclasses:
+
+1. **signature-preserving decorators**, callable objects which accept
+    a function as input and return a function as output, *with the
+    same signature*
+
+2. **signature-changing** decorators, i.e. decorators
+    which change the signature of their input function, or decorators
+    that return non-callable objects
+
+Signature-changing decorators have their use: for instance, the
+builtin classes ``staticmethod`` and ``classmethod`` are in this
+group. They take functions and return descriptor objects which
+are neither functions, nor callables.
+
+Still, signature-preserving decorators are more common, and easier
+to reason about. In particular, they can be composed together,
+whereas other decorators generally cannot.
+
+Writing signature-preserving decorators from scratch is not that
+obvious, especially if one wants to define proper decorators that
+can accept functions with any signature. A simple example will clarify
+the issue.
+
+Statement of the problem
+------------------------------
+
+A very common use case for decorators is the memoization of functions.
+A ``memoize`` decorator works by caching
+the result of the function call in a dictionary, so that the next time
+the function is called with the same input parameters the result is retrieved
+from the cache and not recomputed.
+
+There are many implementations of ``memoize`` in
+http://www.python.org/moin/PythonDecoratorLibrary,
+but they do not preserve the signature. In recent versions of
+Python you can find a sophisticated ``lru_cache`` decorator
+in the standard library's ``functools``. Here I am just
+interested in giving an example.
+
+Consider the following simple implementation (note that it is
+generally impossible to *correctly* memoize something
+that depends on non-hashable arguments):
+
+$$memoize_uw
+
+Here I used the functools.update_wrapper_ utility, which was added
+in Python 2.5 to simplify the writing of decorators.
+(Previously, you needed to manually copy the function attributes
+``__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*
+from the original.
+
+Consider for instance the following case:
+
+$$f1
+
+Here, the original function takes a single argument named ``x``,
+but the decorated function takes any number of arguments and
+keyword arguments:
+
+```python
+>>> from decorator 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:
+
+```python
+>>> f1(0, 1) # doctest: +IGNORE_EXCEPTION_DETAIL
+Traceback (most recent call last):
+   ...
+TypeError: f1() takes exactly 1 positional argument (2 given)
+
+```
+
+Notice that ``inspect.getfullargspec``
+will give the wrong signature, even in the latest Python, i.e. version 3.6
+at the time of writing.
+
+The solution
+-----------------------------------------
+
+The solution is to provide a generic factory of generators, which
+hides the complexity of making signature-preserving decorators
+from the application programmer. The ``decorate`` function in
+the ``decorator`` module is such a factory:
+
+```python
+>>> from decorator import decorate
+
+```
+
+``decorate`` takes two arguments:
+
+1. a caller function describing the functionality of the decorator, and
+
+2. a function to be decorated.
+
+The caller function must have signature ``(f, *args, **kw)``, and it
+must call the original function ``f`` with arguments ``args`` and ``kw``,
+implementing the wanted capability (in this case, memoization):
+
+$$_memoize
+
+Now, you can define your decorator as follows:
+
+$$memoize
+
+The difference from the nested function approach of ``memoize_uw``
+is that the decorator module forces you to lift the inner function
+to the outer level. Moreover, you are forced to explicitly pass the
+function you want to decorate; there are no closures.
+
+Here is a test of usage:
+
+```python
+>>> @memoize
+... def heavy_computation():
+...     time.sleep(2)
+...     return "done"
+
+>>> print(heavy_computation()) # the first time it will take 2 seconds
+done
+
+>>> print(heavy_computation()) # the second time it will be instantaneous
+done
+
+```
+
+The signature of ``heavy_computation`` is the one you would expect:
+
+```python
+>>> print(getfullargspec(heavy_computation))
+FullArgSpec(args=[], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
+
+```
+
+A ``trace`` decorator
+------------------------------------------------------
+
+Here is an example of how to define a simple ``trace`` decorator,
+which prints a message whenever the traced function is called:
+
+$$_trace
+
+$$trace
+
+Here is an example of usage:
+
+```python
+>>> @trace
+... def f1(x):
+...     pass
+
+```
+
+It is immediate to verify that ``f1`` works...
+
+```python
+>>> f1(0)
+calling f1 with args (0,), {}
+
+```
+
+...and it that it has the correct signature:
+
+```python
+>>> print(getfullargspec(f1))
+FullArgSpec(args=['x'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
+
+```
+
+The decorator works with functions of any signature:
+
+```python
+>>> @trace
+... def f(x, y=1, z=2, *args, **kw):
+...     pass
+
+>>> f(0, 3)
+calling f with args (0, 3, 2), {}
+
+>>> print(getfullargspec(f))
+FullArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={})
+
+```
+$FUNCTION_ANNOTATIONS
+
+``decorator.decorator``
+---------------------------------------------
+
+It can become tedious to write a caller function (like the above
+``_trace`` example) and then a trivial wrapper
+(``def trace(f): return decorate(f, _trace)``) every time.
+Not to worry!  The ``decorator`` module provides an easy shortcut
+to convert the caller function into a signature-preserving decorator.
+
+It is the ``decorator`` function:
+
+```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
+decorator, just like ``classmethod`` and ``staticmethod``.
+But ``classmethod`` and ``staticmethod`` return generic
+objects which are not callable. Instead, ``decorator`` returns
+signature-preserving decorators (i.e. functions with a single argument).
+
+For instance, you can write:
+
+```python
+>>> @decorator
+... def trace(f, *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 ``trace`` is now a decorator!
+
+```python
+>>> trace # doctest: +ELLIPSIS
+<function trace at 0x...>
+
+```
+
+Here is an example of usage:
+
+```python
+>>> @trace
+... def func(): pass
+
+>>> func()
+calling func with args (), {}
+
+```
+
+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:
+
+```python
+def decfactory(param1, param2, ...):
+    def caller(f, *args, **kw):
+        return somefunc(f, param1, param2, .., *args, **kw)
+    return decorator(caller)
+```
+
+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:
+
+```python
+def caller(f, param1=default1, param2=default2, ..., *args, **kw):
+    return somefunc(f, param1, param2, *args, **kw)
+decfactory = decorator(caller)
+```
+
+Notice that this simplified approach *only works with default arguments*,
+i.e. `param1`, `param2` etc must have known defaults. Thanks to this
+restriction, there exists an unique default decorator, i.e. the member
+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
+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:
+
+$$blocking
+
+Functions decorated with ``blocking`` will return a busy message if
+the resource is unavailable, and the intended result if the resource is
+available. For instance:
+
+```python
+>>> @blocking(msg="Please wait ...")
+... def read_data():
+...     time.sleep(3) # simulate a blocking resource
+...     return "some data"
+
+>>> print(read_data())  # data is not available yet
+Please wait ...
+
+>>> time.sleep(1)
+>>> print(read_data())  # data is not available yet
+Please wait ...
+
+>>> time.sleep(1)
+>>> print(read_data())  # data is not available yet
+Please wait ...
+
+>>> time.sleep(1.1)  # after 3.1 seconds, data is available
+>>> print(read_data())
+some data
+
+```
+
+Decorator factories are most useful to framework builders. Here is an example
+that gives an idea of how you could manage permissions in a framework:
+
+$$Action
+
+where ``restricted`` is a decorator factory defined as follows
+
+$$restricted
+
+Notice that if you forget to use the keyword argument notation, i.e. if you
+write ``restricted(User)`` instead of ``restricted(user_class=User)`` you
+will get an error
+
+```python
+TypeError: You are decorating a non function: <class '__main__.User'>
+
+```
+
+Be careful!
+
+``decorator(cls)``
+--------------------------------------------
+
+The ``decorator`` facility can also produce a decorator starting
+from a class with the signature of a caller. In such a case the
+produced generator is able to convert functions into factories
+to create instances of that class.
+
+As an example, here is a decorator which can convert a
+blocking function into an asynchronous function. When
+the function is called, it is executed in a separate thread.
+
+(This is similar to the approach used in the ``concurrent.futures`` package.
+But I don't recommend that you implement futures this way; this is just an
+example.)
+
+$$Future
+
+The decorated function returns a ``Future`` object. It has a ``.result()``
+method which blocks until the underlying thread finishes and returns
+the final result.
+
+Here is the minimalistic usage:
+
+```python
+>>> @decorator(Future)
+... def long_running(x):
+...     time.sleep(.5)
+...     return x
+
+>>> fut1 = long_running(1)
+>>> fut2 = long_running(2)
+>>> fut1.result() + fut2.result()
+3
+
+```
+
+contextmanager
+-------------------------------------
+
+Python's standard library has the ``contextmanager`` decorator,
+which converts a generator function into a ``GeneratorContextManager``
+factory. For instance, if you write this...
+
+```python
+>>> from contextlib import contextmanager
+>>> @contextmanager
+... def before_after(before, after):
+...     print(before)
+...     yield
+...     print(after)
+
+```
+
+...then ``before_after`` is a factory function that returns
+``GeneratorContextManager`` objects, which provide the
+use of the ``with`` statement:
+
+```python
+>>> with before_after('BEFORE', 'AFTER'):
+...     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, like so:
+
+```python
+>>> ba = before_after('BEFORE', 'AFTER')
+>>>
+>>> @ba # doctest: +SKIP
+... def hello():
+...     print('hello')
+...
+>>> hello() # doctest: +SKIP
+BEFORE
+hello
+AFTER
+
+```
+
+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.
+
+For these reasons, the `decorator` module, starting from release 3.4, offers a
+``decorator.contextmanager`` decorator that solves both problems,
+*and* works in all supported Python versions.  Its usage is identical,
+and factories decorated with ``decorator.contextmanager`` will return
+instances of ``ContextManager``, a subclass of the standard library's
+``contextlib.GeneratorContextManager`` class. The subclass includes
+an improved ``__call__`` method, which acts as a signature-preserving
+decorator.
+
+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
+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
+can be handy. You will see an example shortly--in
+the implementation of a cool decorator utility (``decorator_apply``).
+
+``FunctionMaker`` provides the ``.create`` classmethod, which
+accepts the *name*, *signature*, and *body* of the function
+you want to generate, as well as the execution environment
+where the function is generated by ``exec``.
+
+Here's an example:
+
+```python
+>>> def f(*args, **kw): # a function with a generic signature
+...     print(args, kw)
+
+>>> f1 = FunctionMaker.create('f1(a, b)', 'f(a, b)', dict(f=f))
+>>> f1(1,2)
+(1, 2) {}
+
+```
+
+It is important to notice that the function body is interpolated
+before being executed; **be careful** with the ``%`` sign!
+
+``FunctionMaker.create`` also accepts keyword arguments.
+The keyword arguments are attached to the generated function.
+This is useful if you want to set some function attributes
+(e.g., the docstring ``__doc__``).
+
+For debugging/introspection purposes, it may be useful to see
+the source code of the generated function. To do this, just
+pass ``addsource=True``, and the generated function will get
+a ``__source__`` attribute:
+
+```python
+>>> f1 = FunctionMaker.create(
+...     'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True)
+>>> print(f1.__source__)
+def f1(a, b):
+    f(a, b)
+<BLANKLINE>
+
+```
+
+The first argument to ``FunctionMaker.create`` can be a string (as above),
+or a function. This is the most common usage, since you typically decorate
+pre-existing functions.
+
+If you're writing a framework, however, you may want to use
+``FunctionMaker.create`` directly, rather than ``decorator``, because it gives
+you direct access to the body of the generated function.
+
+For instance, suppose you want to instrument the ``__init__`` methods of a
+set of classes, by preserving their signature.
+(This use case is not made up. This is done by SQAlchemy, and other frameworks,
+too.)
+Here is what happens:
+
+- 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``.)
+
+- For each item in ``args`` (a list of strings of the names of all required
+  arguments), an attribute ``arg0``, ``arg1``, ..., ``argN`` is also generated.
+
+- Finally, there is a ``signature`` attribute, which is a string with the
+  signature of the original function.
+
+**NOTE:** You should not pass signature strings with default arguments
+(e.g., something like ``'f1(a, b=None)'``). Just pass ``'f1(a, b)'``,
+followed by a tuple of defaults:
+
+```python
+>>> f1 = FunctionMaker.create(
+...     'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True, defaults=(None,))
+>>> print(getfullargspec(f1))
+FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
+
+```
+
+Getting the source code
+---------------------------------------------------
+
+Internally, ``FunctionMaker.create`` uses ``exec`` to generate the
+decorated function. Therefore ``inspect.getsource`` will not work for
+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:
+
+```python
+>>> print(inspect.getsource(factorial.__wrapped__))
+@tail_recursive
+def factorial(n, acc=1):
+    "The good old factorial"
+    if n == 0:
+        return acc
+    return factorial(n-1, n*acc)
+<BLANKLINE>
+
+```
+
+Dealing with third-party decorators
+-----------------------------------------------------------------
+
+Sometimes on the net you find some cool decorator that you would
+like to include in your code. However, more often than not, the cool
+decorator is not signature-preserving. What you need is an easy way to
+upgrade third party decorators to signature-preserving decorators...
+*without* having to rewrite them in terms of ``decorator``.
+
+You can use a ``FunctionMaker`` to implement that functionality as follows:
+
+$$decorator_apply
+
+``decorator_apply`` sets the generated function's ``__wrapped__`` attribute
+to the original function, so you can get the right source code.
+If you are using a Python later than 3.2, you should also set the
+``__qualname__`` attribute to preserve the qualified name of the original
+function.
+
+Notice that I am not providing this functionality in the ``decorator``
+module directly, since I think it is best to rewrite the decorator instead
+of adding another level of indirection. However, practicality
+beats purity, so you can add ``decorator_apply`` to your toolbox and
+use it if you need to.
+
+To give a good example for ``decorator_apply``, I will show a pretty slick
+decorator that converts a tail-recursive function into an iterative function.
+I have shamelessly stolen the core concept from Kay Schluehr's recipe
+in the Python Cookbook,
+http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691.
+
+$$TailRecursive
+
+Here the decorator is implemented as a class returning callable
+objects.
+
+$$tail_recursive
+
+Here is how you apply the upgraded decorator to the good old factorial:
+
+$$factorial
+
+```python
+>>> print(factorial(4))
+24
+
+```
+
+This decorator is pretty impressive, and should give you some food for
+thought! ;)
+
+Notice that there is no recursion limit now; you can easily compute
+``factorial(1001)`` (or larger) without filling the stack frame.
+
+Notice also that the decorator will *not* work on functions which
+are not tail recursive, such as the following:
+
+$$fact
+
+**Reminder:** A function is *tail recursive* if it does either of the
+following:
+
+- returns a value without making a recursive call; or,
+- returns directly the result of a recursive call.
+
+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.
+
+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
+write code like the following:
+
+```python
+import time
+import logging
+from asyncio import get_event_loop, sleep, wait
+from decorator import decorator
+
+ @decorator
+async def log_start_stop(coro, *args, **kwargs):
+    logging.info('Starting %s%s', coro.__name__, args)
+    t0 = time.time()
+    await coro(*args, **kwargs)
+    dt = time.time() - t0
+    logging.info('Ending %s%s after %d seconds', coro.__name__, args, dt)
+
+@log_start_stop
+async def make_task(n):
+    for i in range(n):
+        await sleep(1)
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO)
+    tasks = [make_task(3), make_task(2), make_task(1)]
+    get_event_loop().run_until_complete(wait(tasks))
+```
+
+and you will get an output like this:
+
+```bash
+INFO:root:Starting make_task(1,)
+INFO:root:Starting make_task(3,)
+INFO:root:Starting make_task(2,)
+INFO:root:Ending make_task(1,) after 1 seconds
+INFO:root:Ending make_task(2,) after 2 seconds
+INFO:root:Ending make_task(3,) after 3 seconds
+```
+
+This may be handy if you have trouble understanding what it going on
+with a particularly complex chain of coroutines. With a single line you
+can decorate the troubling coroutine function, understand what happens, fix the
+issue and then remove the decorator (or keep it if continuous monitoring
+of the coroutines makes sense). Notice that
+``inspect.iscoroutinefunction(make_task)``
+will return the right answer (i.e. ``True``).
+
+It is also possible to define decorators converting coroutine functions
+into regular functions, such as the following:
+
+```python
+@decorator
+def coro_to_func(coro, *args, **kw):
+    "Convert a coroutine into a function"
+     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;
+the caller in ``coro_to_func`` is a regular function and converts
+coroutines -> functions.
+
+Multiple dispatch
+-------------------------------------------
+
+There has been talk of implementing multiple dispatch functions
+(i.e. "generic functions") in Python for over ten years. Last year,
+something concrete was done for the first time. As of Python 3.4,
+we have the decorator ``functools.singledispatch`` to implement generic
+functions!
+
+As its name implies, it is limited to *single dispatch*; in other words,
+it is able to dispatch on the first argument of the function only.
+
+The ``decorator`` module provides the decorator factory ``dispatch_on``,
+which can be used to implement generic functions dispatching on *any* argument.
+Moreover, it can manage dispatching on more than one argument.
+(And, of course, it is signature-preserving.)
+
+Here is a concrete example (from a real-life use case) where it is desiderable
+to dispatch on the second argument.
+
+Suppose you have an ``XMLWriter`` class, which is instantiated
+with some configuration parameters, and has the ``.write`` method which
+serializes objects to XML:
+
+$$XMLWriter
+
+Here, you want to dispatch on the *second* argument; the first is already
+taken by ``self``. The ``dispatch_on`` decorator factory allows you to specify
+the dispatch argument simply by passing its name as a string. (Note
+that if you misspell the name you will get an error.)
+
+The decorated function `write` is turned into a generic function (
+`write` is a function at the idea it is decorated; it will be turned
+into a method later, at class instantiation time),
+and it is called if there are no more specialized implementations.
+
+Usually, default functions should raise a ``NotImplementedError``, thus
+forcing people to register some implementation.
+You can perform the registration with a decorator:
+
+$$writefloat
+
+Now ``XMLWriter`` can serialize floats:
+
+```python
+>>> writer = XMLWriter()
+>>> writer.write(2.3)
+'<float>2.3</float>'
+
+```
+
+I could give a down-to-earth example of situations in which it is desiderable
+to dispatch on more than one argument--for instance, I once implemented
+a database-access library where the first dispatching argument was the
+the database driver, and the second was the database record--but here
+I will follow tradition, and show the time-honored Rock-Paper-Scissors example:
+
+$$Rock
+$$Paper
+$$Scissors
+
+I have added an ordinal to the Rock-Paper-Scissors classes to simplify
+the implementation. The idea is to define a generic function (``win(a,
+b)``) of two arguments corresponding to the *moves* of the first and
+second players. The *moves* are instances of the classes
+Rock, Paper, and Scissors:
+
+- Paper wins over Rock
+- Scissors wins over Paper
+- Rock wins over Scissors
+
+The function will return +1 for a win, -1 for a loss, and 0 for parity.
+There are 9 combinations, but combinations with the same ordinal
+(i.e. the same class) return 0. Moreover, by exchanging the order of the
+arguments, the sign of the result changes. Therefore, it is sufficient to
+directly specify only 3 implementations:
+
+$$win
+$$winRockPaper
+$$winPaperScissors
+$$winRockScissors
+
+Here is the result:
+
+```python
+>>> win(Paper(), Rock())
+1
+>>> win(Scissors(), Paper())
+1
+>>> win(Rock(), Scissors())
+1
+>>> win(Paper(), Paper())
+0
+>>> win(Rock(), Rock())
+0
+>>> win(Scissors(), Scissors())
+0
+>>> win(Rock(), Paper())
+-1
+>>> win(Paper(), Scissors())
+-1
+>>> win(Scissors(), Rock())
+-1
+
+```
+
+The point of generic functions is that they play well with subclassing.
+For instance, suppose we define a ``StrongRock``, which does not lose against
+Paper:
+
+$$StrongRock
+$$winStrongRockPaper
+
+Then you do not need to define other implementations; they are
+inherited from the parent:
+
+```python
+>>> win(StrongRock(), Scissors())
+1
+
+```
+
+You can introspect the precedence used by the dispath algorithm by
+calling ``.dispatch_info(*types)``:
+
+```python
+>>> win.dispatch_info(StrongRock, Scissors)
+[('StrongRock', 'Scissors'), ('Rock', 'Scissors')]
+
+```
+
+Since there is no direct implementation for (``StrongRock``, ``Scissors``),
+the dispatcher will look at the implementation for (``Rock``, ``Scissors``)
+which is available. Internally, the algorithm is doing a cross
+product of the class precedence lists (or *Method Resolution Orders*,
+[MRO](http://www.python.org/2.3/mro.html) for short) of ``StrongRock``
+ and ``Scissors``, respectively.
+
+Generic functions and virtual ancestors
+-------------------------------------------------
+
+In Python, generic functions are complicated by the existence of
+"virtual ancestors": superclasses which are not in the class hierarchy.
+
+Consider this class:
+
+$$WithLength
+
+This class defines a ``__len__`` method, and is therefore
+considered to be a subclass of the abstract base class
+``collections.abc.Sized`` (``collections.Sized`` on Python 2):
+
+```python
+>>> issubclass(WithLength, collections.abc.Sized)
+True
+
+```
+
+However, ``collections.abc.Sized`` is not in the MRO_ of ``WithLength``; it
+is not a true ancestor. Any implementation of generic functions (even
+with single dispatch) must go through some contorsion to take into
+account the virtual ancestors.
+
+In particular, if we define a generic function...
+
+$$get_length
+
+...implemented on all classes with a length...
+
+$$get_length_sized
+
+...then ``get_length`` must be defined on ``WithLength`` instances...
+
+```python
+>>> get_length(WithLength())
+0
+
+```
+
+...even if ``collections.abc.Sized`` is not a true ancestor of ``WithLength``.
+
+Of course, this is a contrived example--you could just use the
+builtin ``len``--but you should get the idea.
+
+Since in Python it is possible to consider any instance of ``ABCMeta``
+as a virtual ancestor of any other class (it is enough to register it
+as ``ancestor.register(cls)``), any implementation of generic functions
+must be aware of the registration mechanism.
+
+For example, suppose you are using a third-party set-like class, like
+the following:
+
+$$SomeSet
+
+Here, the author of ``SomeSet`` made a mistake by inheriting from
+``collections.abc.Sized`` (instead of ``collections.abc.Set``).
+
+This is not a problem. You can register *a posteriori*
+``collections.abc.Set`` as a virtual ancestor of ``SomeSet``:
+
+```python
+>>> _ = collections.abc.Set.register(SomeSet)
+>>> issubclass(SomeSet, collections.abc.Set)
+True
+
+```
+
+Now, let's define an implementation of ``get_length`` specific to set:
+
+$$get_length_set
+
+The current implementation (and ``functools.singledispatch`` too)
+is able to discern that a ``Set`` is a ``Sized`` object, by looking at
+the class registry, so it uses the more specific implementation for ``Set``:
+
+```python
+>>> get_length(SomeSet())  # NB: the implementation for Sized would give 0
+1
+
+```
+
+Sometimes it is not clear how to dispatch. For instance, consider a
+class ``C`` registered both as ``collections.abc.Iterable`` and
+``collections.abc.Sized``, and defines a generic function ``g`` with
+implementations for both ``collections.abc.Iterable`` *and*
+``collections.abc.Sized``:
+
+$$singledispatch_example1
+
+It is impossible to decide which implementation to use, since the ancestors
+are independent. The following function will raise a ``RuntimeError``
+when called. This is consistent with the "refuse the temptation to guess"
+philosophy. ``functools.singledispatch`` would raise a similar error.
+
+It would be easy to rely on the order of registration to decide the
+precedence order. This is reasonable, but also fragile:
+
+- if, during some refactoring, you change the registration order by mistake,
+  a different implementation could be taken;
+- if implementations of the generic functions are distributed across modules,
+  and you change the import order, a different implementation could be taken.
+
+So the ``decorator`` module prefers to raise an error in the face of ambiguity.
+This is the same approach taken by the standard library.
+
+However, it should be noted that the *dispatch algorithm* used by the decorator
+module is different from the one used by the standard library, so in certain
+cases you will get different answers. The difference is that
+``functools.singledispatch`` tries to insert the virtual ancestors *before* the
+base classes, whereas ``decorator.dispatch_on`` tries to insert them *after*
+the base classes.
+
+Here's an example that shows the difference:
+
+$$singledispatch_example2
+
+If you play with this example and replace the ``singledispatch`` definition
+with ``functools.singledispatch``, the assertion will break: ``g`` will return
+``"container"`` instead of ``"s"``, because ``functools.singledispatch``
+will insert the ``Container`` class right before ``S``.
+
+Notice that here I am not making any bold claim such as "the standard
+library algorithm is wrong and my algorithm is right" or viceversa. It
+just point out that there are some subtle differences. The only way to
+understand what is really happening here is to scratch your head by
+looking at the implementations. I will just notice that
+``.dispatch_info`` is quite essential to see the class precedence
+list used by algorithm:
+
+```python
+>>> g, V = singledispatch_example2()
+>>> g.dispatch_info(V)
+[('V',), ('Sized',), ('S',), ('Container',)]
+
+```
+
+The current implementation does not implement any kind of cooperation
+between implementations. In other words, nothing is akin either to
+call-next-method in Lisp, or to ``super`` in Python.
+
+Finally, let me notice that the decorator module implementation does
+not use any cache, whereas the ``singledispatch`` implementation does.
+
+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/)
+project by Graeme Dumpleton.
+
+There is a strange quirk when decorating functions with keyword
+arguments, if one of the arguments has the same name used in the
+caller function for the first argument. The quirk was reported by
+David Goldstein.
+
+Here is an example where it is manifest:
+
+```python
+>>> @memoize
+... def getkeys(**kw):
+...     return kw.keys()
+
+>>> getkeys(func='a') # doctest: +ELLIPSIS
+Traceback (most recent call last):
+ ...
+TypeError: _memoize() got multiple values for ... 'func'
+
+```
+
+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.
+
+The solution is to change the name of the first argument in `_memoize`,
+or to change the implementation like so:
+
+```python
+
+def _memoize(*all_args, **kw):
+    func = all_args[0]
+    args = all_args[1:]
+    if kw:  # frozenset is used to ensure hashability
+        key = args, frozenset(kw.items())
+    else:
+        key = args
+    cache = func.cache  # attribute added by memoize
+    if key not in cache:
+        cache[key] = func(*args, **kw)
+    return cache[key]
+```
+
+This avoids the need to name the first argument, so the problem
+simply disappears. This is a technique that you should keep in mind
+when writing decorators for functions with keyword arguments. Also,
+notice that lately I have come to believe that decorating functions with
+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
+a (shallow) copy of the original function dictionary:
+
+```python
+>>> def f(): pass # the original function
+>>> f.attr1 = "something" # setting an attribute
+>>> f.attr2 = "something else" # setting another attribute
+
+>>> traced_f = trace(f) # the decorated function
+
+>>> traced_f.attr1
+'something'
+>>> traced_f.attr2 = "something different" # setting attr
+>>> f.attr2 # the original attribute did not change
+'something else'
+
+```
+
+LICENSE (2-clause BSD)
+---------------------------------------------
+
+Copyright (c) 2005-2020, Michele Simionato
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  Redistributions in bytecode form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+If you use this software and you are happy with it, consider sending me a
+note, just to gratify my ego. On the other hand, if you use this software and
+you are unhappy with it, send me a patch!
+"""
+
+function_annotations = """Function annotations
+---------------------------------------------
+
+Python 3 introduced the concept of [function annotations](
+http://www.python.org/dev/peps/pep-3107/): the ability
+to annotate the signature of a function with additional information,
+stored in a dictionary named ``__annotations__``. The ``decorator`` module
+(starting from release 3.3) will understand and preserve these annotations.
+
+Here is an example:
+
+```python
+>>> @trace
+... def f(x: 'the first argument', y: 'default argument'=1, z=2,
+...       *args: 'varargs', **kw: 'kwargs'):
+...     pass
+
+```
+
+In order to introspect functions with annotations, one needs the
+utility ``inspect.getfullargspec`` (introduced in Python 3, then
+deprecated in Python 3.5, then undeprecated in Python 3.6):
+
+```python
+>>> from inspect import getfullargspec
+>>> argspec = getfullargspec(f)
+>>> argspec.args
+['x', 'y', 'z']
+>>> argspec.varargs
+'args'
+>>> argspec.varkw
+'kw'
+>>> argspec.defaults
+(1, 2)
+>>> argspec.kwonlyargs
+[]
+>>> argspec.kwonlydefaults
+
+```
+
+You can check that the ``__annotations__`` dictionary is preserved:
+
+```python
+>>> f.__annotations__ is f.__wrapped__.__annotations__
+True
+
+```
+
+Here ``f.__wrapped__`` is the original undecorated function.
+This attribute exists for consistency with the behavior of
+``functools.update_wrapper``.
+
+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 = ''
+
+today = time.strftime('%Y-%m-%d')
+
+__doc__ = (doc.replace('$VERSION', __version__).replace('$DATE', today)
+           .replace('$FUNCTION_ANNOTATIONS', function_annotations))
+
+
+def decorator_apply(dec, func):
+    """
+    Decorate a function by preserving the signature even if dec
+    is not a signature-preserving decorator.
+    """
+    return FunctionMaker.create(
+        func, 'return decfunc(%(signature)s)',
+        dict(decfunc=dec(func)), __wrapped__=func)
+
+
+def _trace(f, *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):
+    return decorate(f, _trace)
+
+
+class Future(threading.Thread):
+    """
+    A class converting blocking functions into asynchronous
+    functions by using threads.
+    """
+    def __init__(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():
+            self._result = func(*args, **kw)
+        super(Future, self).__init__(target=func_wrapper, name=name)
+        self.start()
+
+    def result(self):
+        self.join()
+        return self._result
+
+
+def identity_dec(func):
+    def wrapper(*args, **kw):
+        return func(*args, **kw)
+    return wrapper
+
+
+@identity_dec
+def example():
+    pass
+
+
+def memoize_uw(func):
+    func.cache = {}
+
+    def memoize(*args, **kw):
+        if kw:  # frozenset is used to ensure hashability
+            key = args, frozenset(kw.items())
+        else:
+            key = args
+        if key not in func.cache:
+            func.cache[key] = func(*args, **kw)
+        return func.cache[key]
+    return functools.update_wrapper(memoize, func)
+
+
+@memoize_uw
+def f1(x):
+    "Simulate some long computation"
+    time.sleep(1)
+    return x
+
+
+def _memoize(func, *args, **kw):
+    if kw:  # frozenset is used to ensure hashability
+        key = args, frozenset(kw.items())
+    else:
+        key = args
+    cache = func.cache  # attribute added by memoize
+    if key not in cache:
+        cache[key] = func(*args, **kw)
+    return cache[key]
+
+
+def memoize(f):
+    """
+    A simple memoize implementation. It works by adding a .cache dictionary
+    to the decorated function. The cache will grow indefinitely, so it is
+    your responsibility to clear it, if needed.
+    """
+    f.cache = {}
+    return decorate(f, _memoize)
+
+
+@decorator
+def blocking(f, msg='blocking', *args, **kw):
+    if not hasattr(f, "thread"):  # no thread running
+        def set_result():
+            f.result = f(*args, **kw)
+        f.thread = threading.Thread(None, set_result)
+        f.thread.start()
+        return msg
+    elif f.thread.is_alive():
+        return msg
+    else:  # the thread is ended, return the stored result
+        del f.thread
+        return f.result
+
+
+class User(object):
+    "Will just be able to see a page"
+
+
+class PowerUser(User):
+    "Will be able to add new pages too"
+
+
+class Admin(PowerUser):
+    "Will be able to delete pages too"
+
+
+class PermissionError(Exception):
+    """
+    >>> a = Action()
+    >>> a.user = User()
+    >>> a.view() # ok
+    >>> a.insert() # doctest: +IGNORE_EXCEPTION_DETAIL
+    Traceback (most recent call last):
+       ...
+    PermissionError: User does not have the permission to run insert!
+    """
+
+
+@decorator
+def restricted(func, user_class=User, *args, **kw):
+    "Restrict access to a given class of users"
+    self = args[0]
+    if isinstance(self.user, user_class):
+        return func(*args, **kw)
+    else:
+        raise PermissionError(
+            '%s does not have the permission to run %s!'
+            % (self.user, func.__name__))
+
+
+class Action(object):
+    @restricted(user_class=User)
+    def view(self):
+        "Any user can view objects"
+
+    @restricted(user_class=PowerUser)
+    def insert(self):
+        "Only power users can insert objects"
+
+    @restricted(user_class=Admin)
+    def delete(self):
+        "Only the admin can delete objects"
+
+
+class TailRecursive(object):
+    """
+    tail_recursive decorator based on Kay Schluehr's recipe
+    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691
+    with improvements by me and George Sakkis.
+    """
+
+    def __init__(self, func):
+        self.func = func
+        self.firstcall = True
+        self.CONTINUE = object()  # sentinel
+
+    def __call__(self, *args, **kwd):
+        CONTINUE = self.CONTINUE
+        if self.firstcall:
+            func = self.func
+            self.firstcall = False
+            try:
+                while True:
+                    result = func(*args, **kwd)
+                    if result is CONTINUE:  # update arguments
+                        args, kwd = self.argskwd
+                    else:  # last call
+                        return result
+            finally:
+                self.firstcall = True
+        else:  # return the arguments of the tail call
+            self.argskwd = args, kwd
+            return CONTINUE
+
+
+def tail_recursive(func):
+    return decorator_apply(TailRecursive, func)
+
+
+@tail_recursive
+def factorial(n, acc=1):
+    "The good old factorial"
+    if n == 0:
+        return acc
+    return factorial(n-1, n*acc)
+
+
+def fact(n):  # this is not tail-recursive
+    if n == 0:
+        return 1
+    return n * fact(n-1)
+
+
+def a_test_for_pylons():
+    """
+    In version 3.1.0 decorator(caller) returned a nameless partial
+    object, thus breaking Pylons. That must not happen again.
+
+    >>> decorator(_memoize).__name__
+    '_memoize'
+
+    Here is another bug of version 3.1.1 missing the docstring:
+
+    >>> factorial.__doc__
+    'The good old factorial'
+    """
+
+
+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_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
+    """
+    print('hello %s' % user)
+
+
+# #######################  multiple dispatch ############################ #
+
+
+class XMLWriter(object):
+    def __init__(self, **config):
+        self.cfg = config
+
+    @dispatch_on('obj')
+    def write(self, obj):
+        raise NotImplementedError(type(obj))
+
+
+@XMLWriter.write.register(float)
+def writefloat(self, obj):
+    return '<float>%s</float>' % obj
+
+
+class Rock(object):
+    ordinal = 0
+
+
+class Paper(object):
+    ordinal = 1
+
+
+class Scissors(object):
+    ordinal = 2
+
+
+class StrongRock(Rock):
+    pass
+
+
+@dispatch_on('a', 'b')
+def win(a, b):
+    if a.ordinal == b.ordinal:
+        return 0
+    elif a.ordinal > b.ordinal:
+        return -win(b, a)
+    raise NotImplementedError((type(a), type(b)))
+
+
+@win.register(Rock, Paper)
+def winRockPaper(a, b):
+    return -1
+
+
+@win.register(Rock, Scissors)
+def winRockScissors(a, b):
+    return 1
+
+
+@win.register(Paper, Scissors)
+def winPaperScissors(a, b):
+    return -1
+
+
+@win.register(StrongRock, Paper)
+def winStrongRockPaper(a, b):
+    return 0
+
+
+class WithLength(object):
+    def __len__(self):
+        return 0
+
+
+class SomeSet(collections.abc.Sized):
+    # methods that make SomeSet set-like
+    # not shown ...
+    def __len__(self):
+        return 0
+
+
+@dispatch_on('obj')
+def get_length(obj):
+    raise NotImplementedError(type(obj))
+
+
+@get_length.register(collections.abc.Sized)
+def get_length_sized(obj):
+    return len(obj)
+
+
+@get_length.register(collections.abc.Set)
+def get_length_set(obj):
+    return 1
+
+
+class C(object):
+    "Registered as Sized and Iterable"
+
+
+collections.abc.Sized.register(C)
+collections.abc.Iterable.register(C)
+
+
+def singledispatch_example1():
+    singledispatch = dispatch_on('obj')
+
+    @singledispatch
+    def g(obj):
+        raise NotImplementedError(type(g))
+
+    @g.register(collections.abc.Sized)
+    def g_sized(object):
+        return "sized"
+
+    @g.register(collections.abc.Iterable)
+    def g_iterable(object):
+        return "iterable"
+
+    g(C())  # RuntimeError: Ambiguous dispatch: Iterable or Sized?
+
+
+def singledispatch_example2():
+    # adapted from functools.singledispatch test case
+    singledispatch = dispatch_on('arg')
+
+    class S(object):
+        pass
+
+    class V(c.Sized, S):
+        def __len__(self):
+            return 0
+
+    @singledispatch
+    def g(arg):
+        return "base"
+
+    @g.register(S)
+    def g_s(arg):
+        return "s"
+
+    @g.register(c.Container)
+    def g_container(arg):
+        return "container"
+
+    v = V()
+    assert g(v) == "s"
+    c.Container.register(V)  # add c.Container to the virtual mro of V
+    assert g(v) == "s"  # since the virtual mro is V, Sized, S, Container
+    return g, V
+
+
+@decorator
+def warn_slow(func, duration=0, *args, **kwargs):
+    t0 = time.time()
+    res = func(*args, **kwargs)
+    dt = time.time() - t0
+    if dt >= duration:
+        print('%s is slow' % func.__name__)
+    return res
+
+
+@warn_slow()  # with parens
+def operation1():
+    """
+    >>> operation1()
+    operation1 is slow
+    """
+    time.sleep(.1)
+
+
+@warn_slow  # without parens
+def operation2():
+    """
+    >>> operation2()
+    operation2 is slow
+    """
+    time.sleep(.1)
+
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()

+ 480 - 0
desktop/core/ext-py/decorator-4.4.2/src/tests/test.py

@@ -0,0 +1,480 @@
+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 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
+
+
+@contextmanager
+def assertRaises(etype):
+    """This works in Python 2.6 too"""
+    try:
+        yield
+    except etype:
+        pass
+    else:
+        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
+        self.assertTrue(inspect.iscoroutinefunction(coro))
+        out = get_event_loop().run_until_complete(coro('x'))
+        self.assertEqual(out, '<before>x<after>')
+
+    def test_coro_to_func(self):
+        @coro_to_func
+        async def coro(x):
+            return x
+        self.assertFalse(inspect.iscoroutinefunction(coro))
+        self.assertEqual(coro('x'), 'x')
+''')
+
+
+def gen123():
+    yield 1
+    yield 2
+    yield 3
+
+
+class GeneratorCallerTestCase(unittest.TestCase):
+    def test_gen123(self):
+        @decorator
+        def square(func, *args, **kw):
+            for x in gen123():
+                yield x * x
+        new = square(gen123)
+        self.assertTrue(inspect.isgeneratorfunction(new))
+        self.assertEqual(list(new()), [1, 4, 9])
+
+
+class DocumentationTestCase(unittest.TestCase):
+    def test(self):
+        err = doctest.testmod(doc)[0]
+        self.assertEqual(err, 0)
+
+    def test_singledispatch1(self):
+        if hasattr(functools, 'singledispatch'):
+            with assertRaises(RuntimeError):
+                doc.singledispatch_example1()
+
+    def test_singledispatch2(self):
+        if hasattr(functools, 'singledispatch'):
+            doc.singledispatch_example2()
+
+
+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__
+
+    def test_signature(self):
+        if hasattr(inspect, 'signature'):
+            sig = inspect.signature(doc.f1)
+            self.assertEqual(str(sig), '(x)')
+
+    def test_unique_filenames(self):
+        @decorator
+        def d1(f, *args, **kwargs):
+            return f(*args, **kwargs)
+
+        @decorator
+        def d2(f, *args, **kwargs):
+            return f(*args, **kwargs)
+
+        @d1
+        def f1(x, y, z):
+            pass
+
+        @d2
+        def f2(x, y, z):
+            pass
+
+        f1_orig = f1
+
+        @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)
+
+    def test_no_first_arg(self):
+        @decorator
+        def example(*args, **kw):
+            return args[0](*args[1:], **kw)
+
+        @example
+        def func(**kw):
+            return kw
+
+        # there is no confusion when passing args as a keyword argument
+        self.assertEqual(func(args='a'), {'args': 'a'})
+
+    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)
+
+    def test_add1(self):
+        # similar to what IPython is doing in traitlets.config.application
+        @decorator
+        def add(func, const=1, *args, **kwargs):
+            return const + func(*args, **kwargs)
+
+        def f(x):
+            return x
+        self.assertEqual(add(f, 2)(0), 2)
+
+
+# ################### test dispatch_on ############################# #
+# adapted from test_functools in Python 3.5
+singledispatch = dispatch_on('obj')
+
+
+class TestSingleDispatch(unittest.TestCase):
+    def test_simple_overloads(self):
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        @g.register(int)
+        def g_int(i):
+            return "integer"
+
+        self.assertEqual(g("str"), "base")
+        self.assertEqual(g(1), "integer")
+        self.assertEqual(g([1, 2, 3]), "base")
+
+    def test_mro(self):
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        class A(object):
+            pass
+
+        class C(A):
+            pass
+
+        class B(A):
+            pass
+
+        class D(C, B):
+            pass
+
+        @g.register(A)
+        def g_A(a):
+            return "A"
+
+        @g.register(B)
+        def g_B(b):
+            return "B"
+
+        self.assertEqual(g(A()), "A")
+        self.assertEqual(g(B()), "B")
+        self.assertEqual(g(C()), "A")
+        self.assertEqual(g(D()), "B")
+
+    def test_register_decorator(self):
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        @g.register(int)
+        def g_int(i):
+            return "int %s" % (i,)
+        self.assertEqual(g(""), "base")
+        self.assertEqual(g(12), "int 12")
+
+    def test_register_error(self):
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        with assertRaises(TypeError):
+            # wrong number of arguments
+            @g.register(int)
+            def g_int():
+                return "int"
+
+    def test_wrapping_attributes(self):
+        @singledispatch
+        def g(obj):
+            "Simple test"
+            return "Test"
+        self.assertEqual(g.__name__, "g")
+        if sys.flags.optimize < 2:
+            self.assertEqual(g.__doc__, "Simple test")
+
+    def test_c_classes(self):
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        @g.register(decimal.DecimalException)
+        def _(obj):
+            return obj.args
+        subn = decimal.Subnormal("Exponent < Emin")
+        rnd = decimal.Rounded("Number got rounded")
+        self.assertEqual(g(subn), ("Exponent < Emin",))
+        self.assertEqual(g(rnd), ("Number got rounded",))
+
+        @g.register(decimal.Subnormal)
+        def _g(obj):
+            return "Too small to care."
+        self.assertEqual(g(subn), "Too small to care.")
+        self.assertEqual(g(rnd), ("Number got rounded",))
+
+    def test_register_abc(self):
+        d = {"a": "b"}
+        l = [1, 2, 3]
+        s = set([object(), None])
+        f = frozenset(s)
+        t = (1, 2, 3)
+
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        self.assertEqual(g(d), "base")
+        self.assertEqual(g(l), "base")
+        self.assertEqual(g(s), "base")
+        self.assertEqual(g(f), "base")
+        self.assertEqual(g(t), "base")
+
+        g.register(c.Sized)(lambda obj: "sized")
+        self.assertEqual(g(d), "sized")
+        self.assertEqual(g(l), "sized")
+        self.assertEqual(g(s), "sized")
+        self.assertEqual(g(f), "sized")
+        self.assertEqual(g(t), "sized")
+
+        g.register(c.MutableMapping)(lambda obj: "mutablemapping")
+        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")
+
+        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(c.MutableSequence)(lambda obj: "mutablesequence")
+        self.assertEqual(g(d), "mutablemapping")
+        self.assertEqual(g(l), "mutablesequence")
+        self.assertEqual(g(s), "sized")
+        self.assertEqual(g(f), "sized")
+        self.assertEqual(g(t), "sized")
+
+        g.register(c.MutableSet)(lambda obj: "mutableset")
+        self.assertEqual(g(d), "mutablemapping")
+        self.assertEqual(g(l), "mutablesequence")
+        self.assertEqual(g(s), "mutableset")
+        self.assertEqual(g(f), "sized")
+        self.assertEqual(g(t), "sized")
+
+        g.register(c.Mapping)(lambda obj: "mapping")
+        self.assertEqual(g(d), "mutablemapping")  # not specific enough
+        self.assertEqual(g(l), "mutablesequence")
+        self.assertEqual(g(s), "mutableset")
+        self.assertEqual(g(f), "sized")
+        self.assertEqual(g(t), "sized")
+
+        g.register(c.Sequence)(lambda obj: "sequence")
+        self.assertEqual(g(d), "mutablemapping")
+        self.assertEqual(g(l), "mutablesequence")
+        self.assertEqual(g(s), "mutableset")
+        self.assertEqual(g(f), "sized")
+        self.assertEqual(g(t), "sequence")
+
+        g.register(c.Set)(lambda obj: "set")
+        self.assertEqual(g(d), "mutablemapping")
+        self.assertEqual(g(l), "mutablesequence")
+        self.assertEqual(g(s), "mutableset")
+        self.assertEqual(g(f), "set")
+        self.assertEqual(g(t), "sequence")
+
+        g.register(dict)(lambda obj: "dict")
+        self.assertEqual(g(d), "dict")
+        self.assertEqual(g(l), "mutablesequence")
+        self.assertEqual(g(s), "mutableset")
+        self.assertEqual(g(f), "set")
+        self.assertEqual(g(t), "sequence")
+
+        g.register(list)(lambda obj: "list")
+        self.assertEqual(g(d), "dict")
+        self.assertEqual(g(l), "list")
+        self.assertEqual(g(s), "mutableset")
+        self.assertEqual(g(f), "set")
+        self.assertEqual(g(t), "sequence")
+
+        g.register(set)(lambda obj: "concrete-set")
+        self.assertEqual(g(d), "dict")
+        self.assertEqual(g(l), "list")
+        self.assertEqual(g(s), "concrete-set")
+        self.assertEqual(g(f), "set")
+        self.assertEqual(g(t), "sequence")
+
+        g.register(frozenset)(lambda obj: "frozen-set")
+        self.assertEqual(g(d), "dict")
+        self.assertEqual(g(l), "list")
+        self.assertEqual(g(s), "concrete-set")
+        self.assertEqual(g(f), "frozen-set")
+        self.assertEqual(g(t), "sequence")
+
+        g.register(tuple)(lambda obj: "tuple")
+        self.assertEqual(g(d), "dict")
+        self.assertEqual(g(l), "list")
+        self.assertEqual(g(s), "concrete-set")
+        self.assertEqual(g(f), "frozen-set")
+        self.assertEqual(g(t), "tuple")
+
+    def test_mro_conflicts(self):
+        @singledispatch
+        def g(obj):
+            return "base"
+
+        class O(c.Sized):
+            def __len__(self):
+                return 0
+        o = O()
+        self.assertEqual(g(o), "base")
+        g.register(c.Iterable)(lambda arg: "iterable")
+        g.register(c.Container)(lambda arg: "container")
+        g.register(c.Sized)(lambda arg: "sized")
+        g.register(c.Set)(lambda arg: "set")
+        self.assertEqual(g(o), "sized")
+        c.Iterable.register(O)
+        self.assertEqual(g(o), "sized")
+        c.Container.register(O)
+        with assertRaises(RuntimeError):  # was "sized" because in mro
+            self.assertEqual(g(o), "sized")
+        c.Set.register(O)
+        self.assertEqual(g(o), "set")
+
+        class P(object):
+            pass
+        p = P()
+        self.assertEqual(g(p), "base")
+        c.Iterable.register(P)
+        self.assertEqual(g(p), "iterable")
+        c.Container.register(P)
+
+        with assertRaises(RuntimeError):
+            self.assertEqual(g(p), "iterable")
+
+        class Q(c.Sized):
+            def __len__(self):
+                return 0
+        q = Q()
+        self.assertEqual(g(q), "sized")
+        c.Iterable.register(Q)
+        self.assertEqual(g(q), "sized")
+        c.Set.register(Q)
+        self.assertEqual(g(q), "set")
+        # because c.Set is a subclass of c.Sized and c.Iterable
+
+        @singledispatch
+        def h(obj):
+            return "base"
+
+        @h.register(c.Sized)
+        def h_sized(arg):
+            return "sized"
+
+        @h.register(c.Container)
+        def h_container(arg):
+            return "container"
+        # Even though Sized and Container are explicit bases of MutableMapping,
+        # this ABC is implicitly registered on defaultdict which makes all of
+        # MutableMapping's bases implicit as well from defaultdict's
+        # perspective.
+        with assertRaises(RuntimeError):
+            self.assertEqual(h(defaultdict(lambda: 0)), "sized")
+
+        class R(defaultdict):
+            pass
+        c.MutableSequence.register(R)
+
+        @singledispatch
+        def i(obj):
+            return "base"
+
+        @i.register(c.MutableMapping)
+        def i_mapping(arg):
+            return "mapping"
+
+        @i.register(c.MutableSequence)
+        def i_sequence(arg):
+            return "sequence"
+        r = R()
+        with assertRaises(RuntimeError):  # was no error
+            self.assertEqual(i(r), "sequence")
+
+        class S(object):
+            pass
+
+        class T(S, c.Sized):
+            def __len__(self):
+                return 0
+        t = T()
+        self.assertEqual(h(t), "sized")
+        c.Container.register(T)
+        self.assertEqual(h(t), "sized")   # because it's explicitly in the MRO
+
+        class U(object):
+            def __len__(self):
+                return 0
+        u = U()
+        self.assertEqual(h(u), "sized")
+        # implicit Sized subclass inferred
+        # from the existence of __len__()
+
+        c.Container.register(U)
+        # There is no preference for registered versus inferred ABCs.
+        with assertRaises(RuntimeError):
+            h(u)
+
+
+if __name__ == '__main__':
+    unittest.main()