Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error trying to format line with parameter assignment and generator #2551

Closed
tabrezm opened this issue Oct 20, 2021 · 5 comments · Fixed by #3327
Closed

Error trying to format line with parameter assignment and generator #2551

tabrezm opened this issue Oct 20, 2021 · 5 comments · Fixed by #3327
Assignees
Labels
C: parser How we parse code. Or fail to parse it. T: bug Something isn't working

Comments

@tabrezm
Copy link

tabrezm commented Oct 20, 2021

Describe the bug

Black throws an error trying to format files containing a parameter assignment with a generator. This is valid Python code.

error: cannot format util.py: Cannot parse: 200:43:     if any(match := pattern_error.match(s) for s in buffer):
Oh no! 💥 💔 💥
1 file failed to reformat.

To Reproduce

Code sample:

    if any(match := pattern_error.match(s) for s in buffer):
        if match.group(2) == data_not_available:
            # Error OK to ignore.
            pass

Expected behavior

Black formats the file without errors. It seems to handle parameter assignment elsewhere just fine:

            if not (next_line := next(buffer_iter, None)):
                # Buffer is incomplete, so we return early and wait to be
                # reinvoked with a complete buffer.
                return status

Environment (please complete the following information):

  • Version: main
  • OS and Python version: Mac/Python 3.9.7

Does this bug also happen on main?

Yes

Additional context

None

@tabrezm tabrezm added the T: bug Something isn't working label Oct 20, 2021
@vbarbaresi
Copy link
Contributor

vbarbaresi commented Oct 24, 2021

I confirm this syntax seems valid in 3.9 (it wasn't in Python 3.8.6)

Though it looks like this syntax is not supported by the current CPython parser.
I looked into CPython parser unit tests:
https://github.com/python/cpython/blob/v3.9.10/Lib/lib2to3/tests/test_parser.py#L654-L655
The assignment in any() is wrapped in parentheses and it doesn't pass the tests if you remove the parentheses.
Maybe this should be fixed in CPython and/or black's lib2to3 fork?

By the way the documentation about the usage of parentheses in assignment expression is still a work in progress python/cpython#23291

To workaround the issue: wrap the assignment (match := pattern_error.match(s)) in parentheses, or define the generator expression in a variable.

@betafcc
Copy link

betafcc commented Oct 9, 2022

up for 2022-10-09 on black 22.10.0:

from typing import TypeVar, AsyncIterable

A = TypeVar("A")

async def enumerate(fa: AsyncIterable[A]) -> AsyncIterable[tuple[int, A]]:
    i = -1
    async for a in fa:
        yield i := i + 1, a

Result:

> black --version
black, 22.10.0 (compiled: yes)
Python (CPython) 3.10.6

> black dirty_bits/helpers/aitertools.py
error: cannot format dirty_bits/helpers/aitertools.py: Cannot parse: 165:15:         yield i:= i + 1, a

Oh no! 💥 💔 💥
1 file failed to reformat.

The parens workaround in #1898 does work:

async def enumerate(fa: AsyncIterable[A]) -> AsyncIterable[tuple[int, A]]:
    i = -1
    async for a in fa:
        yield (i := i + 1), a

@ichard26 ichard26 added the C: parser How we parse code. Or fail to parse it. label Oct 9, 2022
@ichard26
Copy link
Collaborator

ichard26 commented Oct 9, 2022

@isidentical would you be interested in taking a look at this issue?

@isidentical
Copy link
Collaborator

@isidentical would you be interested in taking a look at this issue?

Yep, will look into it! Thanks for CC'ing me.

@isidentical
Copy link
Collaborator

@betafcc, the example you have shared already fails with the standard Python parser since the named expression has to be wrapped with parens in that case. But the bug still persists for generator expressions passed as call arguments (any(x := y for _ in _)), so hopefully #3327 should fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: parser How we parse code. Or fail to parse it. T: bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants