Repository: Textualize/rich
Pull request #2357 (2022-06-21 21:27:43)

Prepend "async def" to Inspect coroutine functions
## Type of changes

- [ ] Bug fix
- [X] New feature
- [ ] Documentation / docstrings
- [ ] Tests
- [ ] Other

## Checklist

- [X] I've run the latest [black](https://github.com/psf/black) with default args on new code.
- [X] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.
- [X] I've added tests for new code.
- [X] I accept that @\willmcgugan may be pedantic in the code review.

## Description

Adds a feature to prepend `async def` when `rich.inspect` is used on a 3.5+ style coroutine function, as demonstrated in the below screenshot.
3.4-style generator-based coroutines are left as-is.

![Terminal screenshot demonstrating new feature](https://user-images.githubusercontent.com/23347632/174899823-96847787-baae-47d0-890a-cb3c715c7c54.png)




Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b1148a0..78dd01c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 
 - Environment variables `JUPYTER_COLUMNS` and `JUPYTER_LINES` to control width and height of console in Jupyter
+- `inspect` will prefix coroutine functions with `async def`
 
 ### Changed
 
diff --git a/rich/_inspect.py b/rich/_inspect.py
index af440340..13b92f5c 100644
--- a/rich/_inspect.py
+++ b/rich/_inspect.py
@@ -107,11 +107,13 @@ class Inspect(JupyterMixin):
         # If obj is a module, there may be classes (which are callable) to display
         if inspect.isclass(obj):
             prefix = "class"
+        elif inspect.iscoroutinefunction(obj):
+            prefix = "async def"
         else:
             prefix = "def"
 
         qual_signature = Text.assemble(
-            (f"{prefix} ", f"inspect.{prefix}"),
+            (f"{prefix} ", f"inspect.{prefix.replace(' ', '_')}"),
             (qualname, "inspect.callable"),
             signature_text,
         )
diff --git a/rich/default_styles.py b/rich/default_styles.py
index 1969bb78..f04a8530 100644
--- a/rich/default_styles.py
+++ b/rich/default_styles.py
@@ -39,6 +39,7 @@ DEFAULT_STYLES: Dict[str, Style] = {
     "inspect.attr": Style(color="yellow", italic=True),
     "inspect.attr.dunder": Style(color="yellow", italic=True, dim=True),
     "inspect.callable": Style(bold=True, color="red"),
+    "inspect.async_def": Style(italic=True, color="bright_cyan"),
     "inspect.def": Style(italic=True, color="bright_cyan"),
     "inspect.class": Style(italic=True, color="bright_cyan"),
     "inspect.error": Style(bold=True, color="red"),


Test patch:
diff --git a/tests/test_inspect.py b/tests/test_inspect.py
index 8772070c..4e537f9c 100644
--- a/tests/test_inspect.py
+++ b/tests/test_inspect.py
@@ -142,6 +142,19 @@ def test_inspect_builtin_function():
     assert expected == render(print)
 
 
+@skip_pypy3
+def test_inspect_coroutine():
+    async def coroutine():
+        pass
+
+    expected = (
+        "╭─ <function test_inspect_coroutine.<locals>.cor─╮\n"
+        "│ async def                                      │\n"
+        "│ test_inspect_coroutine.<locals>.coroutine():   │\n"
+    )
+    assert render(coroutine).startswith(expected)
+
+
 @skip_py36
 def test_inspect_integer():
     expected = (