summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/decorator.py11
-rw-r--r--src/tests/documentation.py19
-rw-r--r--src/tests/test.py13
3 files changed, 33 insertions, 10 deletions
diff --git a/src/decorator.py b/src/decorator.py
index aa09566..788f4bb 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -40,7 +40,7 @@ import operator
import itertools
import collections
-__version__ = '4.1.1'
+__version__ = '4.1.2'
if sys.version >= '3':
from inspect import getfullargspec
@@ -97,7 +97,6 @@ class FunctionMaker(object):
def __init__(self, func=None, name=None, signature=None,
defaults=None, doc=None, module=None, funcdict=None):
self.shortsignature = signature
- self.coro = False
if func:
# func can be a class or a callable, but not an instance method
self.name = func.__name__
@@ -106,7 +105,6 @@ class FunctionMaker(object):
self.doc = func.__doc__
self.module = func.__module__
if inspect.isfunction(func):
- self.coro = iscoroutinefunction(func)
argspec = getfullargspec(func)
self.annotations = getattr(func, '__annotations__', {})
for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
@@ -223,7 +221,8 @@ class FunctionMaker(object):
func = obj
self = cls(func, name, signature, defaults, doc, module)
ibody = '\n'.join(' ' + line for line in body.splitlines())
- if self.coro:
+ 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:
@@ -263,9 +262,9 @@ def decorator(caller, _func=None):
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)
+ evaldict = dict(_call=caller, _decorate_=decorate)
return FunctionMaker.create(
- '%s(func)' % name, 'return _decorate_(func, _call_)',
+ '%s(func)' % name, 'return _decorate_(func, _call)',
evaldict, doc=doc, module=caller.__module__,
__wrapped__=caller)
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index 3e1568a..e8fcc55 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -752,8 +752,23 @@ 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 then right answer (i.e. `True`).
+``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:
+
+.. code-block:: 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
-------------------------------------------
diff --git a/src/tests/test.py b/src/tests/test.py
index d882418..7eb8391 100644
--- a/src/tests/test.py
+++ b/src/tests/test.py
@@ -30,15 +30,25 @@ if sys.version >= '3.5':
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(self):
+ 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')
''')
@@ -92,7 +102,6 @@ class ExtraTestCase(unittest.TestCase):
@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,