Repository: adamchainz/flake8-comprehensions (python)

Issue:
False positive in C416
Example file, `demo.py`
```python
import asyncio


async def ticker(delay, to):
    for i in range(to):
        yield i
        await asyncio.sleep(delay)


async def main():
    return [item async for item in ticker(1, 10)]

```

Error message,
```
demo.py:5:15: C416 Unnecessary list comprehension - rewrite using list()
```

I don't think we can rewrite asynchronous list/dict/set comprehensions (https://www.python.org/dev/peps/pep-0525/#asynchronous-list-dict-set-comprehensions) using `list()`, `dict()` or `set()`.

 

Pull request description:
Fix false positives in c416 for asynchronous comprehensions
Fixes #196.

Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 6a3fef9..d79d73e 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,6 +2,11 @@
 History
 =======
 
+Pending
+-------
+
+* Fix false positives in ``C416`` rule for asynchronous comprehensions.
+
 3.1.0 (2019-11-15)
 ------------------
 
diff --git a/src/flake8_comprehensions.py b/src/flake8_comprehensions.py
index 6d89e8f..5ca4e80 100644
--- a/src/flake8_comprehensions.py
+++ b/src/flake8_comprehensions.py
@@ -286,6 +286,7 @@ class ComprehensionChecker:
                 if (
                     len(node.generators) == 1
                     and not node.generators[0].ifs
+                    and not is_async_generator(node.generators[0])
                     and (
                         (
                             isinstance(node.elt, ast.Name)
@@ -321,3 +322,14 @@ def has_star_args(call_node):
 
 def has_keyword_args(call_node):
     return any(k.arg is None for k in call_node.keywords)
+
+
+if sys.version_info >= (3, 7):
+
+    def is_async_generator(node):
+        return node.is_async
+
+else:
+
+    def is_async_generator(node):
+        return False


Test patch:
diff --git a/tests/test_flake8_comprehensions.py b/tests/test_flake8_comprehensions.py
index 8871ce8..60c4e18 100644
--- a/tests/test_flake8_comprehensions.py
+++ b/tests/test_flake8_comprehensions.py
@@ -1,11 +1,16 @@
 import sys
 
+import pytest
+
 if sys.version_info >= (3, 8):
     from importlib.metadata import version
 else:
     from importlib_metadata import version
 
 
+python_3_7_plus = pytest.mark.skipif(sys.version_info < (3, 7), reason="Python 3.7+")
+
+
 def test_version(flake8dir):
     result = flake8dir.run_flake8(["--version"])
     version_string = "flake8-comprehensions: " + version("flake8-comprehensions")
@@ -929,6 +934,20 @@ def test_C416_pass_1(flake8dir):
     assert result.out_lines == []
 
 
+@python_3_7_plus
+def test_C416_pass_2_async_list(flake8dir):
+    flake8dir.make_example_py("[x async for x in range(5)]")
+    result = flake8dir.run_flake8()
+    assert result.out_lines == []
+
+
+@python_3_7_plus
+def test_C416_pass_2_async_set(flake8dir):
+    flake8dir.make_example_py("{x async for x in range(5)}")
+    result = flake8dir.run_flake8()
+    assert result.out_lines == []
+
+
 def test_C416_fail_1(flake8dir):
     flake8dir.make_example_py(
         """