nebius/SWE-bench-extra huggingface dataset:
Repository: asottile/covdefaults

Issue:
Class-level `if TYPE_CHECKING` is reported as uncovered
Example:

```python
from typing import TYPE_CHECKING

class Some:
   if TYPE_CHECKING:
      some_attr: str
```

Here `if TYPE_CHECKING:` is reported to be uncovered.

<img width="679" alt="Снимок экрана 2022-12-03 в 14 21 00" src="https://user-images.githubusercontent.com/4660275/205438416-b995b5a3-a8a1-4553-ba20-b4246650c26b.png">


While, other rules have `\s*` prefix. I have a PR ready.

Comments:

Patch:
diff --git a/README.md b/README.md
index 08a0078..2761af0 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@ exclude_lines =
     ^\s*raise$
 
     # typing-related code
-    ^if (False|TYPE_CHECKING):
+    ^\s*if (False|TYPE_CHECKING):
     : \.\.\.(\s*#.*)?$
     ^ +\.\.\.$
     -> ['"]?NoReturn['"]?:
diff --git a/covdefaults.py b/covdefaults.py
index 55a5120..09b40a9 100644
--- a/covdefaults.py
+++ b/covdefaults.py
@@ -93,7 +93,7 @@ EXTEND = (
             r'^\s*return NotImplemented\b',
             r'^\s*raise$',
             # typing-related code
-            r'^if (False|TYPE_CHECKING):',
+            r'^\s*if (False|TYPE_CHECKING):',
             r': \.\.\.(\s*#.*)?$',
             r'^ +\.\.\.$',
             r'-> [\'"]?NoReturn[\'"]?:',


Test patch:
diff --git a/tests/covdefaults_test.py b/tests/covdefaults_test.py
index 7d124ba..bc3f1bc 100644
--- a/tests/covdefaults_test.py
+++ b/tests/covdefaults_test.py
@@ -167,7 +167,9 @@ def test_exclude_lines_does_not_include_defaults(configured):
         '    return NotImplemented\n',
         '    raise\n',
         'if False:\n',
+        '    if False:\n',
         'if TYPE_CHECKING:\n',
+        '    if TYPE_CHECKING:\n',
         'def f(x: int) -> int: ...\n',
         'def f(x: int) -> int:\n    ...\n',
         'def f(x: int) -> C: ...# noqa: F821\n',
Repository: asottile/dead

Issue:
dead raises ValueError in case a file is deleted (since it remains listed with "git ls-files")
Hi,
Just hit this twice in a week. I'm using `dead` to clean up a large codebase and realized that as soon as you delete a file, `dead` starts complaining that it can't find that same file in subsequent run
```
Traceback (most recent call last):
  File "/home/***/.pyenv/versions/3.6.5/envs/cmp/bin/dead", line 8, in <module>
    sys.exit(main())
  File "/home/***/.pyenv/versions/3.6.5/envs/cmp/lib/python3.6/site-packages/dead.py", line 302, in main
    for filename, is_test in _filenames(files_re, exclude_re, tests_re):
  File "/home/***/.pyenv/versions/3.6.5/envs/cmp/lib/python3.6/site-packages/dead.py", line 213, in _filenames
    'python' not in tags_from_path(filename)
  File "/home/***/.pyenv/versions/3.6.5/envs/cmp/lib/python3.6/site-packages/identify/identify.py", line 38, in tags_from_path
    raise ValueError('{} does not exist.'.format(path))
ValueError: myapp/lib/helpers.py does not exist.
```
I quickly check and the problem is that it relies on `git ls-files`, which lists also the deleted files.
The workaround is to commit the change, then re-execute `dead` but I thought it is worth fixing this.

I havn't seen an option in `git ls-files` to lists everything except the deleted file but I see that I can list the deleted files with `git ls-files --deleted` so I guess we can use that to subtract the deleted files.

Let me know your thoughts and if that seems like a good approach, I'd be happy to implement it.

Comments:

Patch:
diff --git a/dead.py b/dead.py
index 969acac..03695bb 100644
--- a/dead.py
+++ b/dead.py
@@ -210,6 +210,7 @@ def _filenames(
         if (
                 not files_re.search(filename) or
                 exclude_re.search(filename) or
+                not os.path.exists(filename) or
                 'python' not in tags_from_path(filename)
         ):
             continue


Test patch:
diff --git a/tests/dead_test.py b/tests/dead_test.py
index 3dee231..15917bf 100644
--- a/tests/dead_test.py
+++ b/tests/dead_test.py
@@ -76,6 +76,14 @@ def test_is_marked_as_used(git_dir, capsys, s):
     assert not any(capsys.readouterr())
 
 
+def test_deleted_file_dont_raise_error(git_dir):
+    module = git_dir.join('test-module.py')
+    module.write('print(1)')
+    subprocess.check_call(('git', 'add', '.'))
+    module.remove()
+    assert not dead.main(())
+
+
 def test_setup_py_entrypoints_mark_as_used(git_dir, capsys):
     git_dir.join('setup.py').write(
         'from setuptools import setup\n'
Repository: asottile/dead

Issue:
Support posonlyargs
they are notably missing in [this code](https://github.com/asottile/dead/blob/8817aa412121e319fc45dd5e269b0d009e7c2c06/dead.py#L133-L140)

Comments:

Patch:
diff --git a/dead.py b/dead.py
index 5b3fdbc..a9f48c0 100644
--- a/dead.py
+++ b/dead.py
@@ -131,6 +131,7 @@ class Visitor(ast.NodeVisitor):
         with self.scope():
             if not self._is_stub_function(node):
                 for arg in (
+                        *getattr(node.args, 'posonlyargs', ()),
                         *node.args.args,
                         node.args.vararg,
                         *node.args.kwonlyargs,


Test patch:
diff --git a/tests/dead_test.py b/tests/dead_test.py
index 73aa8b2..9de3213 100644
--- a/tests/dead_test.py
+++ b/tests/dead_test.py
@@ -1,4 +1,5 @@
 import subprocess
+import sys
 
 import pytest
 
@@ -247,3 +248,16 @@ def test_ignored_arguments(git_dir):
     )
     subprocess.check_call(('git', 'add', '.'))
     assert not dead.main(())
+
+
+@pytest.mark.xfail(sys.version_info < (3, 8), reason='py38+')
+def test_unused_positional_only_argument(git_dir, capsys):  # pragma: no cover
+    git_dir.join('f.py').write(
+        'def f(unused, /):\n'
+        '    return 1\n'
+        'print(f)\n',
+    )
+    subprocess.check_call(('git', 'add', '.'))
+    assert dead.main(())
+    out, _ = capsys.readouterr()
+    assert out == 'unused is never read, defined in f.py:1\n'
Repository: asottile/pyupgrade

Issue:
raw-string rewrite with escaped newlines incorrect
```console
$ cat t.py
x = """\
foo\s
"""
print(x)
$ python t.py 
foo\s

$ pyupgrade t.py
Rewriting t.py
$ cat t.py
x = r"""\
foo\s
"""
print(x)
$ python t.py
\
foo\s

```

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index cdf8c14..f41fa13 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -429,7 +429,7 @@ ESCAPE_STARTS = frozenset((
     'N', 'u', 'U',
 ))
 ESCAPE_STARTS_BYTES = ESCAPE_STARTS - frozenset(('N', 'u', 'U'))
-ESCAPE_RE = re.compile(r'\\.')
+ESCAPE_RE = re.compile(r'\\.', re.DOTALL)
 
 
 def _fix_escape_sequences(contents_text):


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index 183903f..685571c 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -370,6 +370,10 @@ def test_fix_escape_sequences_noop(s):
         (r'"\8"', r'r"\8"'), (r'"\9"', r'r"\9"'),
         # explicit byte strings should not honor string-specific escapes
         ('b"\\u2603"', 'br"\\u2603"'),
+        # do not make a raw string for escaped newlines
+        ('"""\\\n\\q"""', '"""\\\n\\\\q"""'),
+        ('"""\\\r\n\\q"""', '"""\\\r\n\\\\q"""'),
+        ('"""\\\r\\q"""', '"""\\\r\\\\q"""'),
     ),
 )
 def test_fix_escape_sequences(s, expected):
Repository: asottile/pyupgrade

Issue:
unicode literal fixer `return'foo'`
Mistakenly does the following:

```diff
-    return'foo'
+    retrn'foo'
```

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index a9c6cd5..0dcc2e0 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -490,6 +490,10 @@ def _fix_octal(s):
         return '0o' + s[1:]
 
 
+def _is_string_prefix(token):
+    return token.name == 'NAME' and set(token.src.lower()) <= set('bfru')
+
+
 def _fix_tokens(contents_text, py3_plus):
     remove_u_prefix = py3_plus or _imports_unicode_literals(contents_text)
 
@@ -503,7 +507,7 @@ def _fix_tokens(contents_text, py3_plus):
         elif token.name == 'STRING':
             # when a string prefix is not recognized, the tokenizer produces a
             # NAME token followed by a STRING token
-            if i > 0 and tokens[i - 1].name == 'NAME':
+            if i > 0 and _is_string_prefix(tokens[i - 1]):
                 tokens[i] = token._replace(src=tokens[i - 1].src + token.src)
                 tokens[i - 1] = tokens[i - 1]._replace(src='')
 


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index 9c6db3d..4c56411 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -323,6 +323,14 @@ def test_imports_unicode_literals(s, expected):
         ),
         # Regression: string containing newline
         ('"""with newline\n"""', True, '"""with newline\n"""'),
+        pytest.param(
+            'def f():\n'
+            '    return"foo"\n',
+            True,
+            'def f():\n'
+            '    return"foo"\n',
+            id='Regression: no space between return and string',
+        ),
     ),
 )
 def test_unicode_literals(s, py3_plus, expected):
Repository: asottile/pyupgrade

Issue:
Syntax errors created when removing with_metaclass
Code such as 
```
class EventProcessorMeta(six.with_metaclass(abc.ABCMeta)):
```

is being rewritten as invalid Python
```
class EventProcessorMeta(, metaclass=abc.ABCMeta):
``` 

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index d3d7a55..6f2669b 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -914,7 +914,8 @@ SIX_CALLS = {
     'assertRegex': '{args[0]}.assertRegex({rest})',
 }
 SIX_B_TMPL = 'b{args[0]}'
-WITH_METACLASS_TMPL = '{rest}, metaclass={args[0]}'
+WITH_METACLASS_NO_BASES_TMPL = 'metaclass={args[0]}'
+WITH_METACLASS_BASES_TMPL = '{rest}, metaclass={args[0]}'
 SIX_RAISES = {
     'raise_from': 'raise {args[0]} from {rest}',
     'reraise': 'raise {args[1]}.with_traceback({args[2]})',
@@ -1221,7 +1222,11 @@ def _fix_py3_plus(contents_text):
         elif token.offset in visitor.six_with_metaclass:
             j = _find_open_paren(tokens, i)
             func_args, end = _parse_call_args(tokens, j)
-            _replace_call(tokens, i, end, func_args, WITH_METACLASS_TMPL)
+            if len(func_args) == 1:
+                tmpl = WITH_METACLASS_NO_BASES_TMPL
+            else:
+                tmpl = WITH_METACLASS_BASES_TMPL
+            _replace_call(tokens, i, end, func_args, tmpl)
         elif token.offset in visitor.super_calls:
             i = _find_open_paren(tokens, i)
             call = visitor.super_calls[token.offset]


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index 773ac80..b6988d7 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -1280,6 +1280,11 @@ def test_fix_six_noop(s):
             'from six import raise_from\nraise exc from exc_from',
             id='weird spacing raise_from',
         ),
+        (
+            'class C(six.with_metaclass(M)): pass',
+
+            'class C(metaclass=M): pass',
+        ),
         (
             'class C(six.with_metaclass(M, B)): pass',
Repository: asottile/pyupgrade

Issue:
Doesn't handle indexed format strings
The following code which I tried to reduce (which I had no idea was possible):
```python
thing = {'a': 1, 'b': 2}
print('{0[a]} and {0[b]}'.format(thing))
```
leads to 
```
Traceback (most recent call last):
  File "/home/ethan/venv/bin/pyupgrade", line 10, in <module>
    sys.exit(main())
  File "/home/ethan/venv/lib/python3.7/site-packages/pyupgrade.py", line 1396, in main
    ret |= fix_file(filename, args)
  File "/home/ethan/venv/lib/python3.7/site-packages/pyupgrade.py", line 1372, in fix_file
    contents_text = _fix_fstrings(contents_text)
  File "/home/ethan/venv/lib/python3.7/site-packages/pyupgrade.py", line 1348, in _fix_fstrings
    tokens[i] = token._replace(src=_to_fstring(token.src, node))
  File "/home/ethan/venv/lib/python3.7/site-packages/pyupgrade.py", line 1310, in _to_fstring
    name = ''.join((params[k or str(i)], dot, rest))
KeyError: '0[a]'
```

This is a very esoteric format string usage, but 🤷‍♂️

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index 6f2669b..bf04191 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -1279,6 +1279,9 @@ class FindSimpleFormats(ast.NodeVisitor):
                     # timid: could make the f-string longer
                     if candidate and candidate in seen:
                         break
+                    # timid: bracketed
+                    elif '[' in candidate:
+                        break
                     seen.add(candidate)
             else:
                 self.found[_ast_to_offset(node)] = node


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index b6988d7..dbf747a 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -1366,6 +1366,7 @@ def test_fix_classes_py3only(s, expected):
         'b"{} {}".format(a, b)',
         # for now, too difficult to rewrite correctly
         '"{:{}}".format(x, y)',
+        '"{a[b]}".format(a=a)',
     ),
 )
 def test_fix_fstrings_noop(s):
Repository: asottile/pyupgrade

Issue:
IndexError with pytest's fixtures.py
```
% pyupgrade --py3-only --keep-percent-format src/_pytest/fixtures.py
Traceback (most recent call last):
  File "…/Vcs/pytest/.venv/bin/pyupgrade", line 11, in <module>
    sys.exit(main())
  File "…/Vcs/pytest/.venv/lib/python3.7/site-packages/pyupgrade.py", line 1428, in main
    ret |= fix_file(filename, args)
  File "…/Vcs/pytest/.venv/lib/python3.7/site-packages/pyupgrade.py", line 1402, in fix_file
    contents_text = _fix_py3_plus(contents_text)
  File "…/Vcs/pytest/.venv/lib/python3.7/site-packages/pyupgrade.py", line 1244, in _fix_py3_plus
    _replace_call(tokens, i, end, func_args, template)
  File "…/Vcs/pytest/.venv/lib/python3.7/site-packages/pyupgrade.py", line 1171, in _replace_call
    src = tmpl.format(args=arg_strs, rest=rest)
IndexError: list index out of range
```
`print(repr(tmpl), repr(arg_strs), repr(rest))` shows:

> 'raise {args[1]}.with_traceback({args[2]})' ['*err'] ''

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index 31a603e..b3c6f9c 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -1001,7 +1001,8 @@ class FindPy3Plus(ast.NodeVisitor):
         if (
                 len(node.bases) == 1 and
                 isinstance(node.bases[0], ast.Call) and
-                self._is_six(node.bases[0].func, ('with_metaclass',))
+                self._is_six(node.bases[0].func, ('with_metaclass',)) and
+                not _starargs(node.bases[0])
         ):
             self.six_with_metaclass.add(_ast_to_offset(node.bases[0]))
 
@@ -1047,11 +1048,12 @@ class FindPy3Plus(ast.NodeVisitor):
             self.six_type_ctx[_ast_to_offset(node.args[1])] = node.args[1]
         elif self._is_six(node.func, ('b',)):
             self.six_b.add(_ast_to_offset(node))
-        elif self._is_six(node.func, SIX_CALLS):
+        elif self._is_six(node.func, SIX_CALLS) and not _starargs(node):
             self.six_calls[_ast_to_offset(node)] = node
         elif (
                 isinstance(self._previous_node, ast.Expr) and
-                self._is_six(node.func, SIX_RAISES)
+                self._is_six(node.func, SIX_RAISES) and
+                not _starargs(node)
         ):
             self.six_raises[_ast_to_offset(node)] = node
         elif (


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index 102e7b9..fcdb2ea 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -1098,6 +1098,9 @@ def test_fix_classes(s, expected):
         'print(six.b(   "123"))',
         # intentionally not handling this case due to it being a bug (?)
         'class C(six.with_metaclass(Meta, B), D): pass',
+        # cannot determine args to rewrite them
+        'six.reraise(*err)', 'six.b(*a)', 'six.u(*a)',
+        'class C(six.with_metaclass(*a)): pass',
     )
 )
 def test_fix_six_noop(s):
Repository: asottile/pyupgrade

Issue:
123L -> 123
Somewhere between python2.0 and python2.4 the L prefix became unnecessary for long literals

Comments:

Patch:
diff --git a/README.md b/README.md
index 7374c46..dd1fe44 100644
--- a/README.md
+++ b/README.md
@@ -65,6 +65,17 @@ u"foo"      # 'foo'
 u'''foo'''  # '''foo'''
 ```
 
+### Long literals
+
+Availability:
+- If `pyupgrade` is running in python 2.
+
+```python
+5L                            # 5
+5l                            # 5
+123456789123456789123456789L  # 123456789123456789123456789
+```
+
 
 ## Planned features
 
diff --git a/pyupgrade.py b/pyupgrade.py
index 5da90af..60ffda7 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -463,6 +463,14 @@ def _fix_unicode_literals(contents_text, py3_only):
     return untokenize_tokens(tokens)
 
 
+def _fix_long_literals(contents_text):
+    tokens = tokenize_src(contents_text)
+    for i, token in enumerate(tokens):
+        if token.name == 'NUMBER':
+            tokens[i] = token._replace(src=token.src.rstrip('lL'))
+    return untokenize_tokens(tokens)
+
+
 def fix_file(filename, args):
     with open(filename, 'rb') as f:
         contents_bytes = f.read()
@@ -477,6 +485,7 @@ def fix_file(filename, args):
     contents_text = _fix_sets(contents_text)
     contents_text = _fix_format_literals(contents_text)
     contents_text = _fix_unicode_literals(contents_text, args.py3_only)
+    contents_text = _fix_long_literals(contents_text)
 
     if contents_text != contents_text_orig:
         print('Rewriting {}'.format(filename))


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index 868d7a4..b594486 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -3,11 +3,13 @@ from __future__ import absolute_import
 from __future__ import unicode_literals
 
 import io
+import sys
 
 import pytest
 
 from pyupgrade import _fix_dictcomps
 from pyupgrade import _fix_format_literals
+from pyupgrade import _fix_long_literals
 from pyupgrade import _fix_sets
 from pyupgrade import _fix_unicode_literals
 from pyupgrade import _imports_unicode_literals
@@ -318,6 +320,19 @@ def test_unicode_literals(s, py3_only, expected):
     assert ret == expected
 
 
+@pytest.mark.xfail(sys.version_info >= (3,), reason='python2 "feature"')
+@pytest.mark.parametrize(
+    ('s', 'expected'),
+    (
+        ('5L', '5'),
+        ('5l', '5'),
+        ('123456789123456789123456789L', '123456789123456789123456789'),
+    ),
+)
+def test_long_literals(s, expected):
+    assert _fix_long_literals(s) == expected
+
+
 def test_main_trivial():
     assert main(()) == 0
Repository: asottile/pyupgrade

Issue:
`add_metaclass` rewrite indentation is strange when indented
Currently:

```diff
 if True:
-    @six.add_metaclass(M)
-    class C: pass
+        class C(metaclass=M): pass
```

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index 8d11da1..ac8bd70 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -1114,6 +1114,8 @@ class FindPy3Plus(ast.NodeVisitor):
 def _remove_decorator(tokens, i):
     while tokens[i - 1].src != '@':
         i -= 1
+    if i > 1 and tokens[i - 2].name not in {'NEWLINE', 'NL'}:
+        i -= 1
     end = i + 1
     while tokens[end].name != 'NEWLINE':
         end += 1


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index 7c76a51..87ac751 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -1387,6 +1387,16 @@ def test_fix_six_noop(s):
 
             id='add_metaclass, weird base that contains a :',
         ),
+        pytest.param(
+            'if True:\n'
+            '    @six.add_metaclass(M)\n'
+            '    class C: pass\n',
+
+            'if True:\n'
+            '    class C(metaclass=M): pass\n',
+
+            id='add_metaclass, indented',
+        ),
     ),
 )
 def test_fix_six(s, expected):
Repository: asottile/pyupgrade

Issue:
function call rewrite broken when function is parenthesized
A bit of an edge case, I haven't seen this break in the wild but it's certainly possible

```python
(
    six
).text_type(x)
```

This should produce

```python
str(x)
```

But currently produces this broken syntax:

```python
(
    str(b)
```

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index 6e6051f..7313835 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -1541,6 +1541,9 @@ def _fix_py3_plus(contents_text):
         else:
             j = i
             while tokens[j].src != node.attr:
+                # timid: if we see a parenthesis here, skip it
+                if tokens[j].src == ')':
+                    return
                 j += 1
             tokens[i:j + 1] = [new_token]
 


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index d4b5bdc..ef78b95 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -1102,6 +1102,10 @@ def test_fix_classes(s, expected):
         'class C(six.with_metaclass(*a)): pass',
         '@six.add_metaclass(*a)\n'
         'class C: pass\n',
+        # parenthesized part of attribute
+        '(\n'
+        '    six\n'
+        ').text_type(u)\n',
     ),
 )
 def test_fix_six_noop(s):
Repository: asottile/pyupgrade

Issue:
Should not rewrite to `yield from` inside `async def`
oops, totally forgot about this.

Currently this is happening but this is forbidden by [PEP 525](https://www.python.org/dev/peps/pep-0525/#asynchronous-yield-from)

```diff
 async def f():
-    for x in y:
-        yield x
+    yield from y
```

Comments:

Patch:
diff --git a/pyupgrade.py b/pyupgrade.py
index 7313835..5a25ec8 100644
--- a/pyupgrade.py
+++ b/pyupgrade.py
@@ -1023,6 +1023,7 @@ class FindPy3Plus(ast.NodeVisitor):
         self._class_info_stack = []
         self._in_comp = 0
         self.super_calls = {}
+        self._in_async_def = False
         self.yield_from_fors = set()
 
     def _is_six(self, node, names):
@@ -1101,7 +1102,17 @@ class FindPy3Plus(ast.NodeVisitor):
         else:
             self.generic_visit(node)
 
-    visit_FunctionDef = visit_Lambda = _visit_func
+    def _visit_sync_func(self, node):
+        self._in_async_def, orig = False, self._in_async_def
+        self._visit_func(node)
+        self._in_async_def = orig
+
+    visit_FunctionDef = visit_Lambda = _visit_sync_func
+
+    def visit_AsyncFunctionDef(self, node):  # pragma: no cover (py35+)
+        self._in_async_def, orig = True, self._in_async_def
+        self._visit_func(node)
+        self._in_async_def = orig
 
     def _visit_comp(self, node):
         self._in_comp += 1
@@ -1235,6 +1246,7 @@ class FindPy3Plus(ast.NodeVisitor):
 
     def visit_For(self, node):  # type: (ast.For) -> None
         if (
+            not self._in_async_def and
             len(node.body) == 1 and
             isinstance(node.body[0], ast.Expr) and
             isinstance(node.body[0].value, ast.Yield) and


Test patch:
diff --git a/tests/pyupgrade_test.py b/tests/pyupgrade_test.py
index ef78b95..cfed404 100644
--- a/tests/pyupgrade_test.py
+++ b/tests/pyupgrade_test.py
@@ -1540,6 +1540,44 @@ def test_fix_yield_from(s, expected):
     assert _fix_py3_plus(s) == expected
 
 
+@pytest.mark.xfail(
+    sys.version_info < (3, 5),
+    reason='async introduced in python 3.5',
+)
+@pytest.mark.parametrize(
+    ('s', 'expected'),
+    (
+        (
+            'async def f():\n'
+            '    for x in [1, 2]:\n'
+            '        yield x\n'
+            '\n'
+            '    def g():\n'
+            '        for x in [1, 2, 3]:\n'
+            '            yield x\n'
+            '\n'
+            '    for x in [1, 2]:\n'
+            '        yield x\n'
+            '\n'
+            '    return g',
+            'async def f():\n'
+            '    for x in [1, 2]:\n'
+            '        yield x\n'
+            '\n'
+            '    def g():\n'
+            '        yield from [1, 2, 3]\n'
+            '\n'
+            '    for x in [1, 2]:\n'
+            '        yield x\n'
+            '\n'
+            '    return g',
+        ),
+    ),
+)
+def test_fix_async_yield_from(s, expected):
+    assert _fix_py3_plus(s) == expected
+
+
 @pytest.mark.parametrize(
     's',
     (