diff --git a/docs/changelog.md b/docs/changelog.md index 159307b..d870b3e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,10 @@ # Changelog +### 1.15.2 - bugfix + + - Fixed `SyntaxError` happening when the name of a native coroutine function to create contains `'return'`. + Fixes [#96](https://github.com/smarie/python-makefun/issues/96). + ### 1.15.1 - bugfixes - Fixed `ValueError: Invalid co_name` happening on python 2 when the name of a function to create starts or ends with diff --git a/src/makefun/main.py b/src/makefun/main.py index ffa389b..1e763e7 100644 --- a/src/makefun/main.py +++ b/src/makefun/main.py @@ -312,7 +312,7 @@ def create_function(func_signature, # type: Union[str, Signature] body = "def %s\n return _func_impl_(%s)\n" % (func_signature_str, params_str) if iscoroutinefunction(func_impl): - body = ("async " + body).replace('return', 'return await') + body = ("async " + body).replace('return _func_impl_', 'return await _func_impl_') # create the function by compiling code, mapping the `_func_impl_` symbol to `func_impl` protect_eval_dict(evaldict, func_name, params_names) diff --git a/tests/test_generators_coroutines.py b/tests/test_generators_coroutines.py index 7a9f13a..f9ec779 100644 --- a/tests/test_generators_coroutines.py +++ b/tests/test_generators_coroutines.py @@ -95,3 +95,25 @@ def test_native_coroutine(): from asyncio import get_event_loop out = get_event_loop().run_until_complete(dynamic_fun(0.1)) assert out == 0.1 + + +@pytest.mark.skipif(sys.version_info < (3, 5), reason="native coroutines with async/await require python3.6 or higher") +def test_issue_96(): + """Same as `test_native_coroutine` but tests that we can use 'return' in the coroutine name""" + + # define the handler that should be called + from tests._test_py35 import make_native_coroutine_handler + my_native_coroutine_handler = make_native_coroutine_handler() + + # create the dynamic function + dynamic_fun = create_function("foo_returns_bar(sleep_time=2)", my_native_coroutine_handler) + + # check that this is a coroutine for inspect and for asyncio + assert iscoroutinefunction(dynamic_fun) + from asyncio import iscoroutinefunction as is_native_co + assert is_native_co(dynamic_fun) + + # verify that the new function is a native coroutine and behaves correctly + from asyncio import get_event_loop + out = get_event_loop().run_until_complete(dynamic_fun(0.1)) + assert out == 0.1