From a1f1d0143af71b86f5428e48d61295e9a2254952 Mon Sep 17 00:00:00 2001 From: Evan Krall Date: Thu, 17 May 2018 14:54:49 -0700 Subject: [PATCH 1/2] Check if argument is a coroutine function before checking argument.func --- .gitignore | 1 + a_sync/a_sync.py | 4 ++-- requirements-dev.txt | 3 +++ tests/test_a_sync.py | 36 ++++++++++++++++++++++++++++++++++++ tox.ini | 9 +++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 requirements-dev.txt create mode 100644 tests/test_a_sync.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 72364f9..f9ecd6e 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,4 @@ ENV/ # Rope project settings .ropeproject +.pytest_cache/ diff --git a/a_sync/a_sync.py b/a_sync/a_sync.py index e30596e..92318fe 100644 --- a/a_sync/a_sync.py +++ b/a_sync/a_sync.py @@ -102,7 +102,7 @@ def to_async(blocking_func: AnyCallable) -> AnyCallable: * keep an async partial the same * validate that it doesn't matter if the loop is running. """ - if asyncio.iscoroutinefunction(getattr(blocking_func, 'func', blocking_func)): + if asyncio.iscoroutinefunction(blocking_func) or asyncio.iscoroutinefunction(getattr(blocking_func, 'func', None)): # caller messed up - this is already async async_func = blocking_func else: @@ -146,7 +146,7 @@ def to_blocking(async_func: AnyCallable) -> AnyCallable: * keep blocking partial the same * convert async partial """ - if not asyncio.iscoroutinefunction(getattr(async_func, 'func', async_func)): + if not asyncio.iscoroutinefunction(async_func) or asyncio.iscoroutinefunction(getattr(async_func, 'func', None)): # caller messed up - this is already blocking blocking = async_func else: diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..1dede35 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +pytest==3.5.1 +asynctest==0.12.0 +pytest-asyncio==0.8.0 \ No newline at end of file diff --git a/tests/test_a_sync.py b/tests/test_a_sync.py new file mode 100644 index 0000000..bba84c6 --- /dev/null +++ b/tests/test_a_sync.py @@ -0,0 +1,36 @@ +import a_sync +import asynctest + +import pytest + + +def test_block(): + async def async_func(): + return 5 + + def sync_func(): + return 4 + + assert a_sync.block(async_func) == 5 + assert a_sync.block(sync_func) == 4 + + +def test_block_works_with_CoroutineMock(): + assert 3 == a_sync.block(asynctest.CoroutineMock(return_value=3)) + + +@pytest.mark.asyncio +async def test_run(): + async def async_func(): + return 5 + + def sync_func(): + return 4 + + assert await a_sync.run(async_func) == 5 + assert await a_sync.run(sync_func) == 4 + + +@pytest.mark.asyncio +async def test_run_works_with_CoroutineMock(): + assert 3 == await a_sync.run(asynctest.CoroutineMock(return_value=3)) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..d28b9e1 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +envlist = py36 + +[testenv] +basepython = python3.6 +deps = + --requirement={toxinidir}/requirements-dev.txt +commands = + py.test {posargs:tests} \ No newline at end of file From cc2bc2799db9104eca9ca535884492b6114757cb Mon Sep 17 00:00:00 2001 From: Evan Krall Date: Thu, 17 May 2018 17:19:20 -0700 Subject: [PATCH 2/2] Fix boolean logic error with partials --- a_sync/a_sync.py | 2 +- tests/test_a_sync.py | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/a_sync/a_sync.py b/a_sync/a_sync.py index 92318fe..4851ca4 100644 --- a/a_sync/a_sync.py +++ b/a_sync/a_sync.py @@ -146,7 +146,7 @@ def to_blocking(async_func: AnyCallable) -> AnyCallable: * keep blocking partial the same * convert async partial """ - if not asyncio.iscoroutinefunction(async_func) or asyncio.iscoroutinefunction(getattr(async_func, 'func', None)): + if not (asyncio.iscoroutinefunction(async_func) or asyncio.iscoroutinefunction(getattr(async_func, 'func', None))): # caller messed up - this is already blocking blocking = async_func else: diff --git a/tests/test_a_sync.py b/tests/test_a_sync.py index bba84c6..6bc06ae 100644 --- a/tests/test_a_sync.py +++ b/tests/test_a_sync.py @@ -1,8 +1,10 @@ -import a_sync -import asynctest +import functools +import asynctest import pytest +import a_sync + def test_block(): async def async_func(): @@ -15,6 +17,20 @@ def sync_func(): assert a_sync.block(sync_func) == 4 +def test_block_partials(): + def sync_func_to_partial(retval): + return retval + + async def async_func_to_partial(retval): + return retval + + sync_partial = functools.partial(sync_func_to_partial, 5) + async_partial = functools.partial(async_func_to_partial, 4) + + assert a_sync.block(sync_partial) == 5 + assert a_sync.block(async_partial) == 4 + + def test_block_works_with_CoroutineMock(): assert 3 == a_sync.block(asynctest.CoroutineMock(return_value=3)) @@ -34,3 +50,18 @@ def sync_func(): @pytest.mark.asyncio async def test_run_works_with_CoroutineMock(): assert 3 == await a_sync.run(asynctest.CoroutineMock(return_value=3)) + + +@pytest.mark.asyncio +async def test_run_partials(): + def sync_func_to_partial(retval): + return retval + + async def async_func_to_partial(retval): + return retval + + sync_partial = functools.partial(sync_func_to_partial, 5) + async_partial = functools.partial(async_func_to_partial, 4) + + assert await a_sync.run(sync_partial) == 5 + assert await a_sync.run(async_partial) == 4