astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.
https://docs.astral.sh/ruff
MIT License
32.04k stars 1.07k forks source link

False Positive PT012 for async iterator #9730

Open nmzgnv opened 8 months ago

nmzgnv commented 8 months ago

What's wrong

I want to test that async iterator raises error.

with pytest.raises(KeyError, match='unknown'):
    async for _ in gpt.generate(gpt_request):
        pass

Receive unexpected error PT012 'pytest.raises()' block should contain a single simple statement, but the statement is already simple.

How it should work

not raise PT012 for simple async for loops as with empty context managers https://github.com/m-burst/flake8-pytest-style/blob/master/docs/rules/PT012.md

System information

charliermarsh commented 8 months ago

I agree this is reasonable.

charliermarsh commented 8 months ago

Is it possible to rewrite this with a single await asyncio.gather?

nmzgnv commented 8 months ago

I have no idea about asyncio.gather, but if error occures on the first iteration, you can use await anext(...):

async def async_gen():
    for i in range(10):
        raise ValueError('Hello')
        yield i

async def main():
    await anext(async_gen())

if an error occurs after many iterations, then you need to go through the iterator completely before the error occurs. Another tric:

async def main():
    _ = [elem async for elem in async_gen()]
charliermarsh commented 8 months ago

@RonnyPfannschmidt - Do you have an opinion on this one, before I consider changing the rule?

RonnyPfannschmidt commented 8 months ago

I'm a bit torn on this one

The most beautiful Syntax is the false positive

The listcomp makes the intent more clear

This is one of the cases where I wish thered be a consume helper