Repository: maxfischer2781/asyncstdlib

Issue:
Release 3.10
The [Python 3.10 release schedule](https://www.python.org/dev/peps/pep-0619/) assumes feature freeze for beta 1 @ Monday, 2021-05-03.

Comments:

Patch:
diff --git a/asyncstdlib/__init__.py b/asyncstdlib/__init__.py
index f972870..79ac930 100644
--- a/asyncstdlib/__init__.py
+++ b/asyncstdlib/__init__.py
@@ -35,7 +35,7 @@ from .itertools import (
 )
 from .asynctools import borrow, scoped_iter, await_each, apply, sync
 
-__version__ = "3.9.2"
+__version__ = "3.10.0"
 
 __all__ = [
     "anext",
diff --git a/asyncstdlib/asynctools.py b/asyncstdlib/asynctools.py
index 87b3c02..ee9b98f 100644
--- a/asyncstdlib/asynctools.py
+++ b/asyncstdlib/asynctools.py
@@ -326,7 +326,17 @@ async def apply(
     )
 
 
+@overload
+def sync(function: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
+    ...
+
+
+@overload
 def sync(function: Callable[..., T]) -> Callable[..., Awaitable[T]]:
+    ...
+
+
+def sync(function: Callable) -> Callable[..., Awaitable[T]]:
     r"""
     Wraps a callable to ensure its result can be ``await``\ ed
 
@@ -359,12 +369,13 @@ def sync(function: Callable[..., T]) -> Callable[..., Awaitable[T]]:
         raise TypeError("function argument should be Callable")
 
     if iscoroutinefunction(function):
-        return function  # type: ignore
+        return function
 
     @wraps(function)
     async def async_wrapped(*args, **kwargs):
         result = function(*args, **kwargs)
-
+        if isinstance(result, Awaitable):
+            return await result
         return result
 
     return async_wrapped
diff --git a/docs/conf.py b/docs/conf.py
index 57fc7bf..19b4d73 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -49,7 +49,6 @@ extensions = [
     'sphinx.ext.imgmath',
     'sphinx.ext.viewcode',
     'sphinxcontrib_trio',
-    'sphinxcontrib.contentui',
 ]
 
 # Add any paths that contain templates here, relative to this directory.
diff --git a/docs/source/api/asynctools.rst b/docs/source/api/asynctools.rst
index 31f774d..bac8931 100644
--- a/docs/source/api/asynctools.rst
+++ b/docs/source/api/asynctools.rst
@@ -23,8 +23,7 @@ Iterator lifetime
 Async transforming
 ==================
 
-.. autofunction:: sync(function:(...) -> T) -> (...) -> await T
-    :async:
+.. autofunction:: sync(function: (...) -> (await) T) -> (...) -> await T
 
     .. versionadded:: 3.9.3
 
diff --git a/docs/source/api/itertools.rst b/docs/source/api/itertools.rst
index 0a140ea..1685cf4 100644
--- a/docs/source/api/itertools.rst
+++ b/docs/source/api/itertools.rst
@@ -61,7 +61,7 @@ Iterator splitting
     :for: :(async iter T, ...)
 
 .. autofunction:: pairwise(iterable: (async) iter T)
-    :for: :(T, T)
+    :async-for: :(T, T)
 
     .. versionadded:: 3.10.0
 
diff --git a/pyproject.toml b/pyproject.toml
index 143b30a..7d3af30 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -29,7 +29,7 @@ test = [
     "pytest-cov",
     "mypy; implementation_name=='cpython'",
 ]
-doc = ["sphinx", "sphinxcontrib-contentui", "sphinxcontrib-trio"]
+doc = ["sphinx", "sphinxcontrib-trio"]
 
 [tool.flit.metadata.urls]
 Documentation = "https://asyncstdlib.readthedocs.io/en/latest/"


Test patch:
diff --git a/unittests/test_asynctools.py b/unittests/test_asynctools.py
index 088588c..fde3297 100644
--- a/unittests/test_asynctools.py
+++ b/unittests/test_asynctools.py
@@ -221,3 +221,17 @@ async def test_sync():
     assert t1 == 110
     assert t2 == 120
     assert t3 == 125
+
+
+@sync
+async def test_sync_awaitable():
+    """Test any (…) -> await T is recognised"""
+
+    @a.sync
+    def nocoro_async(value):
+        async def coro():
+            return value
+
+        return coro()
+
+    assert await nocoro_async(5) == 5