]> granicus.if.org Git - python/commitdiff
bpo-36045: builtins.help() now prefixes `async` for async functions (GH-12010)
authorDan Rose <rotu@users.noreply.github.com>
Fri, 24 May 2019 11:38:01 +0000 (06:38 -0500)
committerMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 24 May 2019 11:38:01 +0000 (04:38 -0700)
Previously, it was hard to tell whether a function should be awaited. It was also incorrect (per PEP 484) to put this in the type hint for coroutine functions. Added this info to the output of builtins.help and pydoc.

https://bugs.python.org/issue36045

Lib/pydoc.py
Lib/test/test_pydoc.py
Misc/NEWS.d/next/Core and Builtins/2019-02-24-12-44-46.bpo-36045.RO20OV.rst [new file with mode: 0644]

index 679a596821f478ba222e2d21f82785e76f7c573e..9a22e56686f618822050da56867a07841fb12788 100644 (file)
@@ -951,6 +951,12 @@ class HTMLDoc(Doc):
                 else:
                     note = ' unbound %s method' % self.classlink(imclass,mod)
 
+        if (inspect.iscoroutinefunction(object) or
+                inspect.isasyncgenfunction(object)):
+            asyncqualifier = 'async '
+        else:
+            asyncqualifier = ''
+
         if name == realname:
             title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
         else:
@@ -979,8 +985,8 @@ class HTMLDoc(Doc):
         if not argspec:
             argspec = '(...)'
 
-        decl = title + self.escape(argspec) + (note and self.grey(
-               '<font face="helvetica, arial">%s</font>' % note))
+        decl = asyncqualifier + title + self.escape(argspec) + (note and
+               self.grey('<font face="helvetica, arial">%s</font>' % note))
 
         if skipdocs:
             return '<dl><dt>%s</dt></dl>\n' % decl
@@ -1382,6 +1388,12 @@ location listed above.
                 else:
                     note = ' unbound %s method' % classname(imclass,mod)
 
+        if (inspect.iscoroutinefunction(object) or
+                inspect.isasyncgenfunction(object)):
+            asyncqualifier = 'async '
+        else:
+            asyncqualifier = ''
+
         if name == realname:
             title = self.bold(realname)
         else:
@@ -1405,7 +1417,7 @@ location listed above.
                     argspec = argspec[1:-1] # remove parentheses
         if not argspec:
             argspec = '(...)'
-        decl = title + argspec + note
+        decl = asyncqualifier + title + argspec + note
 
         if skipdocs:
             return decl + '\n'
index 67c6c5d42d48b478c16e7802441d71c6a0660aff..6efdeb047c217de96dd5d6d453bf73d8de1695f5 100644 (file)
@@ -1288,6 +1288,29 @@ foo
     Custom descriptor
 """)
 
+    def test_async_annotation(self):
+        async def coro_function(ign) -> int:
+            return 1
+
+        text = pydoc.plain(pydoc.plaintext.document(coro_function))
+        self.assertIn('async coro_function', text)
+
+        html = pydoc.HTMLDoc().document(coro_function)
+        self.assertIn(
+            'async <a name="-coro_function"><strong>coro_function',
+            html)
+
+    def test_async_generator_annotation(self):
+        async def an_async_generator():
+            yield 1
+
+        text = pydoc.plain(pydoc.plaintext.document(an_async_generator))
+        self.assertIn('async an_async_generator', text)
+
+        html = pydoc.HTMLDoc().document(an_async_generator)
+        self.assertIn(
+            'async <a name="-an_async_generator"><strong>an_async_generator',
+            html)
 
 class PydocServerTest(unittest.TestCase):
     """Tests for pydoc._start_server"""
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-24-12-44-46.bpo-36045.RO20OV.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-24-12-44-46.bpo-36045.RO20OV.rst
new file mode 100644 (file)
index 0000000..7cab3ea
--- /dev/null
@@ -0,0 +1 @@
+builtins.help() now prefixes `async` for async functions