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

Warn against using yield and return x #2

Closed
untitaker opened this issue Sep 30, 2016 · 17 comments
Closed

Warn against using yield and return x #2

untitaker opened this issue Sep 30, 2016 · 17 comments

Comments

@untitaker
Copy link
Contributor

Python 3 allows mixing of return-with-value and yield in the same function. I got bitten by this behavior multiple times, so I want to write a flake8 plugin for it. I wonder if I should add the lint to this package instead of making a separate one. What do you think?

@ambv
Copy link
Member

ambv commented Sep 30, 2016

As Victor and Xiang noted on the original bug, this is a new feature of Python and not a bug. In this sense, linting against this would for sure create false positives. Even in your pull request you don't really suggest what the user should do (note that all other messages have suggestions). And if you suggested users to not use return-with-value, then that's wrong. Consider def broken2 in your example. This is perfectly valid asyncio code:

def old_style_coroutine():
  data = yield from get_data()
  return data.some_value

How did this "bite" you?

@untitaker
Copy link
Contributor Author

untitaker commented Sep 30, 2016

See the attached example in that bug. I wrote the return in an actual codebase (not intentionally using any async features) because I forgot that the function used yield further down, the function generated an empty sequence when the return was executed. This was completely surprising to me, I was used to Python 2 catching such errors with a SyntaxError. Of course it's valid code, but you can shoot yourself in the foot with it (I did at least, it took a while to debug this). That's why lints exist.

@ambv
Copy link
Member

ambv commented Sep 30, 2016

What we are trying to explain to you is that mere existence of yield/yield from and return-with-value in the body of a generator is not enough for a linter to generate a valid warning. In general, bugbear has two kinds of warnings now:

B0xx - downright bugs or design issues. No excuse having code like this.

B3xx - likely valid Python 2 code that will not work on Python 3. While these can have false positives, they would trip up a human reviewer in the same way.

Your proposed warning is in a different category of "it might sometimes be a problem for people unfamiliar with a new feature of the language". You would be better served type annotating your code and running a type checker against it. The generator annotation is specifically designed for the problem you are encountering, see here:

https://www.python.org/dev/peps/pep-0484/#annotating-generator-functions-and-coroutines

@untitaker
Copy link
Contributor Author

I'm aware that this falls into a different category. It's a quite opinionated check, and whether it has a place in a linter simply depends on what kind of linter the author wants to make. If you don't want it, that's totally fine.

Regarding type annotations -- I might as well use an actually statically typed language :)

@ambv ambv reopened this Sep 30, 2016
@ambv
Copy link
Member

ambv commented Sep 30, 2016

I was pondering adding a class of disabled-by-default guidance warnings. If you can figure out how we can introduce a warning that wouldn't be enabled by default unless specifically listed in your config, and creating a new class for them (say B9xx), I would be willing to merge your proposed warning.

@untitaker
Copy link
Contributor Author

Happy to hear that! I suspect the best way to go about this are options, unless there's a Flake8-specific API I'm not aware of. @sigmavirus24 is there a way to do disabled-by-default warnings in Flake8 plugins?

@ambv
Copy link
Member

ambv commented Sep 30, 2016

pycodestyle (formerly pep8) does have a bunch of disabled-by-default warning codes:
https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes

Check out how they do it.

@untitaker
Copy link
Contributor Author

untitaker commented Oct 1, 2016

pycodestyle is not a flake8 extension as far as I can see, i.e. flake8 hooks into pycodestyle, not the other way around. It comes with its own CLI and defines its own --ignore option there.

Anyway I updated my code in #3 by reading through flake8's sourcecode. I think the used methods are supposed to be used like that, but I'm not sure. I didn't find any documentation.

@sigmavirus24
Copy link
Member

So Flake8 2.4+ (I think it's 2.4) allows you to annotate a check with an off_by_default attribute that you can set to True. 3.0+ allows you to extend the default ignore list directly instead of doing that. Depending on your compatibility matrix, depends on your solution. =)

Sorry for the delay, I'm not quite well.

@untitaker
Copy link
Contributor Author

allows you to annotate a check with an off_by_default attribute that you can set to True

That appears to be per-plugin, we need a per-warning-code solution. Probably could still be used by defining multiple plugins + entrypoints in one package.

3.0+ allows you to extend the default ignore list directly instead of doing that.

You mean optmanager.extend_default_ignore? That's what I currently use.

So @ambv, do we need to support Flake8 < 3.0?

@untitaker
Copy link
Contributor Author

Also @sigmavirus24 I respond to some mail after two months, so... which delay? 😆

Get well though.

@sigmavirus24
Copy link
Member

That appears to be per-plugin, we need a per-warning-code solution. Probably could still be used by defining multiple plugins + entrypoints in one package.

Correct. Hacking presently uses it with multiple plugins in the one package.

You mean optmanager.extend_default_ignore? That's what I currently use.

I hadn't looked but that is exactly what I mean. =)

@ambv
Copy link
Member

ambv commented Oct 3, 2016

We don't need to support flake8 < 3.0, no.

@untitaker
Copy link
Contributor Author

Cool, I bumped the requirement in setup.py to flake8 >= 3.0, now I think it's done.

@ambv ambv closed this as completed in #3 Oct 3, 2016
@untitaker
Copy link
Contributor Author

untitaker commented Oct 4, 2016

Hmm, flake8==3.0.4 and the latest flake8-bugbear apparently don't have this new check disabled by default! Sorry, I should've checked this before asking for review.

At first glance I can't see anything in flake8-bugbear that would be the cause of this.

@ambv
Copy link
Member

ambv commented Oct 4, 2016

Are you sure? This is not my experience:

$ flake8 tests/b901.py
tests/b901.py:6:1: E302 expected 2 blank lines, found 1
$ flake8 --select=B tests/b901.py
$ flake8 --select=B901 tests/b901.py
tests/b901.py:8:9: B901: Using `yield` together with `return x`. Use native `async def` coroutines or put a `# noqa` comment on this line if this was intentional.
tests/b901.py:35:5: B901: Using `yield` together with `return x`. Use native `async def` coroutines or put a `# noqa` comment on this line if this was intentional.

The one thing that DOESN'T work is that selecting B9 still filters out B901 (you have to explicitly name each warning):

$ flake8 --select=B9 tests/b901.py
$

@untitaker
Copy link
Contributor Author

Yeah I'm a fool, forgot that I 1.) have a setup.cfg in my repo 2.) have a custom ignore option in there

Pierre-Sassoulas added a commit to pylint-dev/astroid that referenced this issue Aug 5, 2022
It's opinionated see PyCQA/flake8-bugbear#2
and every current warning is a false positive.
Pierre-Sassoulas added a commit to pylint-dev/astroid that referenced this issue Aug 8, 2022
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/asottile/pyupgrade: v2.37.2 → v2.37.3](asottile/pyupgrade@v2.37.2...v2.37.3)
- https://github.com/Pierre-Sassoulas/black-disable-checker/: v1.1.0 → v1.1.1
- [github.com/PyCQA/flake8: 4.0.1 → 5.0.3](PyCQA/flake8@4.0.1...5.0.3)

* Disable line too long and line break before binary operator

As there's a lot of the format and the latter is incompatible with black.

* [flake8] Deactivate the check for return and yield together

It's opinionated see PyCQA/flake8-bugbear#2
and every current warning is a false positive.

* Explain falke8 disables

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants