flake8-return
Flake8 plugin that checks return values.
Flake8-return rule set is supported in ruff.
Installation
pip install flake8-return
Errors
- R501 do not explicitly return None in function if it is the only possible return value.
def x(y): if not y: return return None # error!
- R502 do not implicitly return None in function able to return non-None value.
def x(y): if not y: return # error! return 1
- R503 missing explicit return at the end of function able to return non-None value.
def x(y): if not y: return 1 # error!
- R504 unnecessary variable assignment before return statement.
def x(): a = 1 # some code that not using `a` print('test') return a # error!
- R505 unnecessary else after return statement.
def x(y, z): if y: # error! return 1 else: return z
- R506 unnecessary else after raise statement.
def x(y, z): if y: # error! raise Exception(y) else: raise Exception(z)
- R507 unnecessary else after continue statement.
def x(y, z): for i in y: if i < z: # error! continue else: a = 0
- R508 unnecessary else after break statement.
def x(y, z): for i in y: if i > z: # error! break else: a = 0
Returns in asyncio coroutines also supported.
For developers
Show help
Create venv and install deps
Install git precommit hook
Run linters, autoformat, tests etc
Bump new version
make bump_major
make bump_minor
make bump_patch
Change Log
Unreleased
- …
1.2.0 — 2022-10-28
- Port no-else-break, no-else-continue, no-else-raise, no-else-return from pylint (#122) Calum Young
- PEP 621: Migrate more config to pyproject.toml (#123) Christian Clauss
- Fix/116/R504-try-except (#120) Calum Young
- Update ci (#119) Calum Young
- Fix/47/Update-R504-for-assignment-value (#117) Calum Young
- Upgrade GitHub Actions (#113) Christian Clauss
- Add a space to avoid a typo in R503 (#98) Christian Clauss
- GitHub Action to lint Python code (#97) Christian Clauss
- Typo fixes (#92) Aarni Koskela
- Create codeql-analysis.yml Afonasev Evgeniy
- Bump flake8-plugin-utils from 1.1.1 to 1.3.2 (#87) dependabot
- Bump mypy from 0.812 to 0.971 (#114) dependabot
- Bump pytest-cov from 3.0.0 to 4.0.0 (#124) dependabot
- Bump pytest-cov from 2.11.1 to 3.0.0 (#102) dependabot
- Bump pytest-mock from 3.6.0 to 3.6.1 (#91) dependabot
- Bump pytest from 6.2.4 to 6.2.5 (#99) dependabot
- Bump pylint from 2.8.2 to 2.10.2 (#100) dependabot
- Bump pytest from 6.2.3 to 6.2.4 (#86) dependabot
1.1.3 — 2021-05-05
- Error clarifications (#77) Clément Robert
- fix linting (migrate to black 20.0b1) (#78) Clément Robert
1.1.2 — 2020-07-09
- Make R504 visitors handle while loops (#56) Frank Tackitt
- Rename allows-prereleases to allow-prereleases (#55) Frank Tackitt
- Fix typo: → haven’t (#24) Jon Dufresne
1.1.1 — 2019-09-21
- fixed #3 The R504 doesn’t detect that the variable is modified in loop
- fixed #4 False positive with R503 inside async with clause
1.1.0 — 2019-05-23
- update flask_plugin_utils version to 1.0
1.0.0 — 2019-05-13
- skip assign after unpacking while unnecessary assign checking «(x, y = my_obj)»
0.3.2 — 2019-04-01
- allow «assert False» as last function return
0.3.1 — 2019-03-11
- add pypi deploy into travis config
- add make bump_version command
0.3.0 — 2019-02-26
- skip functions that consist only
return None
- fix false positive when last return inner with statement
- add unnecessary assign error
- add support tuple in assign or return expressions
- add support asyncio coroutines
0.2.0 — 2019-02-21
- fix explicit/implicit
- add flake8-plugin-utils as dependency
- allow raise as last function return
- allow no return as last line in while block
- fix if/elif/else cases
0.1.1 — 2019-02-10
- fix error messages
0.1.0 — 2019-02-10
- initial
flake8-return
Flake8 plugin that checks return values.
Flake8-return rule set is supported in ruff.
Installation
pip install flake8-return
Errors
- R501 do not explicitly return None in function if it is the only possible return value.
def x(y): if not y: return return None # error!
- R502 do not implicitly return None in function able to return non-None value.
def x(y): if not y: return # error! return 1
- R503 missing explicit return at the end of function able to return non-None value.
def x(y): if not y: return 1 # error!
- R504 unnecessary variable assignment before return statement.
def x(): a = 1 # some code that not using `a` print('test') return a # error!
- R505 unnecessary else after return statement.
def x(y, z): if y: # error! return 1 else: return z
- R506 unnecessary else after raise statement.
def x(y, z): if y: # error! raise Exception(y) else: raise Exception(z)
- R507 unnecessary else after continue statement.
def x(y, z): for i in y: if i < z: # error! continue else: a = 0
- R508 unnecessary else after break statement.
def x(y, z): for i in y: if i > z: # error! break else: a = 0
Returns in asyncio coroutines also supported.
For developers
Show help
Create venv and install deps
Install git precommit hook
Run linters, autoformat, tests etc
Bump new version
make bump_major
make bump_minor
make bump_patch
Change Log
Unreleased
- …
1.2.0 — 2022-10-28
- Port no-else-break, no-else-continue, no-else-raise, no-else-return from pylint (#122) Calum Young
- PEP 621: Migrate more config to pyproject.toml (#123) Christian Clauss
- Fix/116/R504-try-except (#120) Calum Young
- Update ci (#119) Calum Young
- Fix/47/Update-R504-for-assignment-value (#117) Calum Young
- Upgrade GitHub Actions (#113) Christian Clauss
- Add a space to avoid a typo in R503 (#98) Christian Clauss
- GitHub Action to lint Python code (#97) Christian Clauss
- Typo fixes (#92) Aarni Koskela
- Create codeql-analysis.yml Afonasev Evgeniy
- Bump flake8-plugin-utils from 1.1.1 to 1.3.2 (#87) dependabot
- Bump mypy from 0.812 to 0.971 (#114) dependabot
- Bump pytest-cov from 3.0.0 to 4.0.0 (#124) dependabot
- Bump pytest-cov from 2.11.1 to 3.0.0 (#102) dependabot
- Bump pytest-mock from 3.6.0 to 3.6.1 (#91) dependabot
- Bump pytest from 6.2.4 to 6.2.5 (#99) dependabot
- Bump pylint from 2.8.2 to 2.10.2 (#100) dependabot
- Bump pytest from 6.2.3 to 6.2.4 (#86) dependabot
1.1.3 — 2021-05-05
- Error clarifications (#77) Clément Robert
- fix linting (migrate to black 20.0b1) (#78) Clément Robert
1.1.2 — 2020-07-09
- Make R504 visitors handle while loops (#56) Frank Tackitt
- Rename allows-prereleases to allow-prereleases (#55) Frank Tackitt
- Fix typo: → haven’t (#24) Jon Dufresne
1.1.1 — 2019-09-21
- fixed #3 The R504 doesn’t detect that the variable is modified in loop
- fixed #4 False positive with R503 inside async with clause
1.1.0 — 2019-05-23
- update flask_plugin_utils version to 1.0
1.0.0 — 2019-05-13
- skip assign after unpacking while unnecessary assign checking «(x, y = my_obj)»
0.3.2 — 2019-04-01
- allow «assert False» as last function return
0.3.1 — 2019-03-11
- add pypi deploy into travis config
- add make bump_version command
0.3.0 — 2019-02-26
- skip functions that consist only
return None
- fix false positive when last return inner with statement
- add unnecessary assign error
- add support tuple in assign or return expressions
- add support asyncio coroutines
0.2.0 — 2019-02-21
- fix explicit/implicit
- add flake8-plugin-utils as dependency
- allow raise as last function return
- allow no return as last line in while block
- fix if/elif/else cases
0.1.1 — 2019-02-10
- fix error messages
0.1.0 — 2019-02-10
- initial
1 Answer
Sorted by:
Reset to default
23
you have set ignore =
in your configuration — you should use extend-ignore =
W504
and W503
conflict with each other (and are both disabled by default) — by setting ignore
you’ve re-enabled them. extend-ignore
does not have this problem as it augments the default set of ignored codes
note that when working with black you’ll want to use black’s recommended settings: https://github.com/psf/black/blob/06ccb88bf2bd35a4dc5d591bb296b5b299d07323/docs/guides/using_black_with_other_tools.md#flake8
max-line-length = 88
extend-ignore = E203
disclaimer: I’m the current flake8 maintainer
answered Jun 29, 2021 at 3:08
anthony sottileanthony sottile
56.8k13 gold badges135 silver badges187 bronze badges
2
-
it also detects rule E501 and run the linter on the file doesn’t solve it
– Antonio Santoro
Jun 29, 2021 at 9:01
-
1
then add that to extend-ignore too (though the
max-line-length
is supposed to cover that)– anthony sottile
Jun 30, 2021 at 11:48
Add a comment
|
Your Answer
Sign up or log in
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Name
Required, but never shown
By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy
Not the answer you’re looking for? Browse other questions tagged
- python
- flake8
- python-black
or ask your own question.
Not the answer you’re looking for? Browse other questions tagged
- python
- flake8
- python-black
or ask your own question.
afonasev / flake8-return
Goto Github
PK
View Code? Open in Web Editor
NEW
3.0
48.0
165 KB
Flake8 plugin for return expressions checking.
License: MIT License
Makefile 3.10%
flake8-return’s Introduction
Flake8 plugin that checks return values.
Flake8-return rule set is supported in ruff.
Installation
pip install flake8-return
Errors
- R501 do not explicitly return None in function if it is the only possible return value.
def x(y): if not y: return return None # error!
- R502 do not implicitly return None in function able to return non-None value.
def x(y): if not y: return # error! return 1
- R503 missing explicit return at the end of function able to return non-None value.
def x(y): if not y: return 1 # error!
- R504 unnecessary variable assignment before return statement.
def x(): a = 1 # some code that not using `a` print('test') return a # error!
- R505 unnecessary else after return statement.
def x(y, z): if y: # error! return 1 else: return z
- R506 unnecessary else after raise statement.
def x(y, z): if y: # error! raise Exception(y) else: raise Exception(z)
- R507 unnecessary else after continue statement.
def x(y, z): for i in y: if i < z: # error! continue else: a = 0
- R508 unnecessary else after break statement.
def x(y, z): for i in y: if i > z: # error! break else: a = 0
Returns in asyncio coroutines also supported.
For developers
Show help
Create venv and install deps
Install git precommit hook
Run linters, autoformat, tests etc
Bump new version
make bump_major
make bump_minor
make bump_patch
Change Log
Unreleased
- …
1.2.0 — 2022-10-28
- Port no-else-break, no-else-continue, no-else-raise, no-else-return from pylint (#122) Calum Young
- PEP 621: Migrate more config to pyproject.toml (#123) Christian Clauss
- Fix/116/R504-try-except (#120) Calum Young
- Update ci (#119) Calum Young
- Fix/47/Update-R504-for-assignment-value (#117) Calum Young
- Upgrade GitHub Actions (#113) Christian Clauss
- Add a space to avoid a typo in R503 (#98) Christian Clauss
- GitHub Action to lint Python code (#97) Christian Clauss
- Typo fixes (#92) Aarni Koskela
- Create codeql-analysis.yml Afonasev Evgeniy
- Bump flake8-plugin-utils from 1.1.1 to 1.3.2 (#87) dependabot
- Bump mypy from 0.812 to 0.971 (#114) dependabot
- Bump pytest-cov from 3.0.0 to 4.0.0 (#124) dependabot
- Bump pytest-cov from 2.11.1 to 3.0.0 (#102) dependabot
- Bump pytest-mock from 3.6.0 to 3.6.1 (#91) dependabot
- Bump pytest from 6.2.4 to 6.2.5 (#99) dependabot
- Bump pylint from 2.8.2 to 2.10.2 (#100) dependabot
- Bump pytest from 6.2.3 to 6.2.4 (#86) dependabot
1.1.3 — 2021-05-05
- Error clarifications (#77) Clément Robert
- fix linting (migrate to black 20.0b1) (#78) Clément Robert
1.1.2 — 2020-07-09
- Make R504 visitors handle while loops (#56) Frank Tackitt
- Rename allows-prereleases to allow-prereleases (#55) Frank Tackitt
- Fix typo: → haven’t (#24) Jon Dufresne
1.1.1 — 2019-09-21
- fixed #3 The R504 doesn’t detect that the variable is modified in loop
- fixed #4 False positive with R503 inside async with clause
1.1.0 — 2019-05-23
- update flask_plugin_utils version to 1.0
1.0.0 — 2019-05-13
- skip assign after unpacking while unnecessary assign checking «(x, y = my_obj)»
0.3.2 — 2019-04-01
- allow «assert False» as last function return
0.3.1 — 2019-03-11
- add pypi deploy into travis config
- add make bump_version command
0.3.0 — 2019-02-26
- skip functions that consist only
return None
- fix false positive when last return inner with statement
- add unnecessary assign error
- add support tuple in assign or return expressions
- add support asyncio coroutines
0.2.0 — 2019-02-21
- fix explicit/implicit
- add flake8-plugin-utils as dependency
- allow raise as last function return
- allow no return as last line in while block
- fix if/elif/else cases
0.1.1 — 2019-02-10
- fix error messages
0.1.0 — 2019-02-10
- initial
flake8-return’s People
flake8-return’s Issues
Should allow raise at end of function, in addition to assert
flake8-return version 1.1.3 allows this construct
def myfunc(x):
if x == 5:
return None
assert False
but disallows this one
def myfunc(x):
if x == 5:
return None
raise NotImplementedError()
I think they should be treated the same?
False positive on R504
- Date you used flake8-return: 2019-05-16
- flake8-return version used, if any: 1.0.0
- Python version, if any: 3.7.1
- Operating System: Debian
Description
The R504 doesn’t detect that the variable is conditionally modified prior to return.
What I Did
$ flake8 test.py test.py:5:12: R504 you shouldn`t assign value to variable if it will be use only as return value $ cat test.py def foo(bar): value = [] if bar: value = value[:1] return value
R506 false positive when raise is used in elif
- Date you used flake8-return: 15th December 2022
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.9.2
- Operating System: Linux
Description
Linting following code:
def test_2(bar): if bar == 3: baz = 1 elif bar == 4: raise Exception() else: baz = 2 return baz
What I Did
$ flake8 test.py test.py:4:5: R506 unnecessary else after raise statement.
The else is necessary as there is additional if before which has side effects and removing else would overwrite that. The code is simplified from real-world code.
Incorrectly marks variables updated in a while loop
- Date you used flake8-return: Jul 6, 2020
- flake8-return version used, if any: 1.1.1
- Python version, if any: Python 3.8.3
- Operating System: Arch Linux on Linux 5.7.4
Description
flake8-return seemingly fails to detect changes to a variable modified in a while loop.
What I Did
def doit(): test = 1 i = 4 while i := i - 1: test = test + 1 return test class Node: def __init__(self, v, parent=None): self.v = v self.parent = parent self.child = Node(v - 1, parent=self) if v else None def __str__(self): name = f"Node<{self.v}>" node = self while node := node.parent: name = f"Node<{node.v}>.{name}" return name def tail(self): node = self while node.child: node = node.child return node print(Node(5).tail())
A R504 error is detected at each return there, in doit()
, Node.__str__
, and Node.tail
flake8-return wrongly indicates R504
- Date you used flake8-return: 2020-06-18
- flake8-return version used, if any: 1.1.1
- Python version: 3.8.0
- Operating System: Windows 10
Description
flake8-return wrongly indicates R504 for the following samples:
formatted = _USER_AGENT_FORMATTER.format(format_string, **values)
# clean up after any blank components
formatted = formatted.replace('()', '').replace(' ', ' ').strip()
return formatted # <<< wrongly indicated as R504 issue
def user_agent_username(username=None):
if not username:
return ''
username = username.replace(' ', '_') # Avoid spaces or %20.
try:
username.encode('ascii') # just test, but not actually use it
except UnicodeEncodeError:
username = quote(username.encode('utf-8'))
else:
# % is legal in the default $wgLegalTitleChars
# This is so that ops know the real pywikibot will not
# allow a useragent in the username to allow through a hand-coded
# percent-encoded value.
if '%' in username:
username = quote(username)
return username # <<< wrongly indicated as R504 issue
flake8-return does not recognize `assert False` as an implicit return.
- Date you used flake8-return: today
- flake8-return version used, if any: 0.3.1
- Python version, if any: Python 3.7.2
- Operating System: Linux
Description
We sometimes end a method with assert False, "some reason"
as a sanity check. The current version of flake8-return sees this as a violation of R503.
def some_method(parameter):
if some_test:
return some_value
elif another_test:
return another_value
else:
assert False, "parameter was not some_value nor another_value"
This assert False
is equivalent to raise AssertionError
which flake8-return does recognize. We would like to see flake8-return treat both statements as equivalent.
Invalid error reported for R505 simple if — elif pattern
- Date you used flake8-return: 2022-10-31
- flake8-return version used, if any: 1.2.0
- Python version, if any: Python 3.10.6
- Operating System: macOS
Description
Invalid error reported for R505 simple if — elif pattern
def get_name(name): if name == 'foo': return 'foo' elif name == 'bar': return 'bar' return 'baz'
What I Did
a.py:2:5: R505 unnecessary elif after return statement.
I think this pattern should be passed.
Initial Update
The bot created this issue to inform you that pyup.io has been set up on this repo.
Once you have closed it, the bot will open pull requests for updates as soon as they are available.
False positive with R503 inside with clause
- Date you used flake8-return: 8/16/2019
- flake8-return version used, if any: 1.1.0
- Python version, if any: 3.6.6
- Operating System: OSX
Description
With a function like the following:
async def function(): async with thing as foo: return foo.bar
This is valid because there can be no other return than the one inside the with context. If enter/exit raise then nothing after it will run. The one way this is not true is if you capture the exeption with a try/except around the async with clause.
Variable assignment inside try/except blocks is not handled properly
- Date you used flake8-return: 09-09-2022
- flake8-return version used, if any: 1.1.3
- Python version, if any: 3.10.6
- Operating System: macOS Monterey 12.5.1
Description
Describe what you were trying to get done. Tell us what happened, what went wrong, and what you expected to happen.
Consider the following functions
def no_exception_loop(): success = False for _ in range(10): try: success = True except Exception: print("exception") # noqa: T201 return success def no_exception(): success = False try: success = True except Exception: print("exception") # noqa: T201 return success def exception(): success = True try: print("raising") # noqa: T201 raise Exception except Exception: success = False return success
The variable success
is changed (or may be changed) inside try/except
blocks. However, running flake8 generates the following error: R504 unecessary variable assignement before return statement.
What I Did
$ poetry run flake8 --show-source debug.py Unable to find qualified name for module: debug.py debug.py:8:12: R504 unecessary variable assignement before return statement. return success ^ debug.py:17:12: R504 unecessary variable assignement before return statement. return success ^ debug.py:27:12: R504 unecessary variable assignement before return statement. return success ^
In some circumstances the error R506 can be dangerous if the `raise` will be changed later
- Date you used flake8-return: 28.10.2022
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.10.8
- Operating System: MacOS/Linux
Description
The error reported for R506 can be dangerous in fast changing development environment
What I Did
Let assume we have this piece of code
def main(): for a in range(10): # | 0 exception bad value try: # | 1 ordinary value if a % 5 == 0: # | 2 good value raise ValueError('bad value') # | 3 ordinary value elif a % 2 == 0: # | 4 good value print(a, 'good value') # | 5 exception bad value else: # | 6 good value print(a, 'ordinary value') # | 7 ordinary value except ValueError as e: # | 8 good value print(a, 'exception', e) # | 9 ordinary value if __name__ == '__main__': main()
The error reported is the following:
myfile.py:4:13: R506 unnecessary elif after raise statement. if a % 5 == 0:
Now let assume we change it according to the proposal, but after short period of time another developer come and changed the code slightly (because IF can be quite big and not intuitive), he removed raise and add the handling of situation inside and removed try...except
all together. Now let’s see the result:
def main(): # | 0 exception bad value for a in range(10): # | 0 good value if a % 5 == 0: # | 1 ordinary value print(a, 'exception', 'bad value') # | 2 good value if a % 2 == 0: # | 3 ordinary value print(a, 'good value') # | 4 good value else: # | 5 exception bad value print(a, 'ordinary value') # | 5 ordinary value # | 6 good value # | 7 ordinary value if __name__ == '__main__': # | 8 good value main() # | 9 ordinary value
As we can see the result is not what the developer expected, but… sometimes it is very difficult to notice such issues. As elif
has SOME MEANING behind, usually…
Incorrect error reporting R507 for `elif` + `continue` if after the `continue` statement `elif` is following
- Date you used flake8-return: 28.10.2022
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.10.8
- Operating System: MacOS/Linux
Description
Invalid error reported for R507 because of some complex context
What I Did
We have some if...elif...
clause like this:
def main(): for a in range(10): # | 0 div 4 if a % 4 == 0: # | 1 div nothing print(a, 'div', 4) # | 2 div 2 elif a % 3 == 0: # | 3 div 3 print(a, 'div', 3) # | 4 div 4 continue # | 5 div nothing elif a % 2 == 0: # | 6 div 3 print(a, 'div', 2) # | 7 div nothing else: # | 8 div 4 print(a, 'div', 'nothing') # | 9 div 3 return 0 if __name__ == '__main__': main()
For this case we are getting this error:
myfile.py:5:9: R507 unnecessary elif after continue statement. elif a % 3 == 0: ^
If we follow the suggestion and fix the issue, then we have different output:
def main(): # | 0 div 4 for a in range(10): # | 0 div 2 if a % 4 == 0: # | 1 div nothing print(a, 'div', 4) # | 2 div 2 elif a % 3 == 0: # | 3 div 3 print(a, 'div', 3) # | 4 div 4 continue # | 4 div 2 if a % 2 == 0: # | 5 div nothing print(a, 'div', 2) # | 6 div 3 else: # | 7 div nothing print(a, 'div', 'nothing') # | 8 div 4 return 0 # | 8 div 2 # | 9 div 3 if __name__ == '__main__': main()
Can we do something to this? I have tried to apply the suggested errors on our codebase and this issue appeared.
Possible False Positive for R504
- Date you used flake8-return: Oct 25th 2022
- flake8-return version used, if any: 1.1.3
- Python version, if any: 3.10.7
- Operating System: Linux
Description
I have a fixture that creates a mock object, patches a library to return that mock object for a specific method and then returns the mock object so that assertions can be made on it. It seems quite clear that I am in fact using the variable, not sure why it’s triggering the linting rule.
I was able to refactor the code to make the lint pass (the second example below), but that code is much less intuitive to me and messy.
What I Did
@pytest.fixture() def example_mock_fails_linting(mocker): mock = mocker.MagicMock() mocker.patch("path.to.mocked.method.that.returns.an.object").return_value = mock return mock # R504 triggers for this line @pytest.fixture() def example_mock_lints_clean(mocker): example = mocker.patch("path.to.mocked.method.that.returns.an.object") example.return_value = mocker.MagicMock() return example.return_value # R504 doesn't trigger for this line
Support match/case operator
- Date you used flake8-return: 26-08-22
- flake8-return version used, if any: 1.1.3
- Python version, if any: 3.10.2
- Operating System: MacOS 12.5.1
Description
match/case construction not supported
What I Did
def test(): a = 1 match a: # <---- D400 First line should end with a period case 0: return False case 1: return True case _*: return False
Feature request: taking type hints into account ?
- Date you used flake8-return: feb 6 2021
- flake8-return version used, if any: 1.1.2
- Python version, if any: 3.8.5
- Operating System: macOS
Description
I have a decorator that’s specifically designed to return either None or a function depending on the CPU rank so that only the root one exectutes the decoreated function. Here’s the gist of it
from functools import wraps def rootonly(func): @wraps(func) def check_parallel_rank(*args, **kwargs): global topcomm_parallel_rank if topcomm_parallel_rank > 0: return return func(*args, **kwargs) return check_parallel_rank
I’m getting a R502
error of course, so I tried adding type hints to avoid using noqas
from typing import Optional from types import FunctionType # ... def check_parallel_rank(*args, **kwargs) -> Optional[FunctionType]: # ...
but the error persists, though I’d argue it shouldn’t (in an ideal world).
I know that this is a sizeable feature to ask but is there any chance you’d consider taking type hints into account ?
In any case thanks for the tool, it’s worth using for 504 alone !
Bad `R504` for assignment in a loop body
Running flake8-return
with Python 3.7, I get an R504
error for the following code:
def close(self): any_failed = False for task in self.tasks: try: task() except BaseException: any_failed = True report(traceback.format_exc()) return any_failed # R504 you shouldn't assign value to variable if it will be use only as return value
While any_failed
is not used in any other expressions before being returned, it’s still important to run all cleanup tasks instead of returning immediately after the first error. Perhaps R504
should be disabled when the assignment is in a loop and the return statement is not?
Plugin crashes when used with stdin
- Date you used flake8-return: 27-11-2020
- flake8-return version used, if any: 1.1.2
- Python version, if any: Python 3.86
- Operating System: Ubuntu 20.4
Description
When emacs’ lsp-mode calls flake 8 on a file (in order to lint it), the command errors out. I strongly suspect the issue is the same as the one reported here: sco1/flake8-annotations#52
My reason for suspecting the error lies within this plugin is the fact that the error goes away when I remove this plugin.
What I Did
Opened the file, activated the virtual env, and started the language server (which called flake8)
What I expected
Flake8 gives results and the pyls lints my code
What I got
Stack trace below
2020-11-27 12:43:25,280 UTC - ERROR - pyls.plugins.flake8_lint - Error while running flake8 'Traceback (most recent call last): File "some_code/.venv/bin/flake8", line 8, in <module> sys.exit(main()) File "some_code/.venv/lib/python3.8/site-packages/flake8/main/cli.py", line 22, in main app.run(argv) File "some_code/.venv/lib/python3.8/site-packages/flake8/main/application.py", line 363, in run self._run(argv) File "some_code/.venv/lib/python3.8/site-packages/flake8/main/application.py", line 351, in _run self.run_checks() File "some_code/.venv/lib/python3.8/site-packages/flake8/main/application.py", line 264, in run_checks self.file_checker_manager.run() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 323, in run self.run_serial() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 307, in run_serial checker.run_checks() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 589, in run_checks self.run_ast_checks() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 494, in run_ast_checks for (line_number, offset, text, _) in runner: File "some_code/.venv/lib/python3.8/site-packages/flake8_plugin_utils/plugin.py", line 75, in run self._load_file() File "some_code/.venv/lib/python3.8/site-packages/flake8_plugin_utils/plugin.py", line 87, in _load_file with open(self._filename, 'rb') as f: FileNotFoundError: [Errno 2] No such file or directory: 'stdin' '
port no-else-break, no-else-continue, no-else-raise, no-else-return from pylint
Description
This fixes the extremely annoying construct:
ret = fn() if bad: raise BadThingHappenedError(msg) elif okish: return fixit(ret) else: return ret
to favour
ret = fn() if bad: raise BadThingHappenedError(msg) if okish: return fixit(ret) return ret
What I Did
this is a feature request
Create v1.1.3 tag
- Date you used flake8-return: 28/10/2022
- flake8-return version used, if any: Hoping to use v1.1.3
- Python version, if any: 3.8
- Operating System: WSL
Description
I was updating our pre-commit hooks to use flake8-return (rather than a forked version), but as the v1.1.3 tag has not been created on Github, the pre-commit hook does not make use of the changes introduced in v1.1.3 on PyPI.
@afonasev, please could you create a tag for v1.1.3 so that pre-commit makes use of the recent updates?
What I Did
The abridged pre-commit config used below throws a false positive for R504, which has been fixed in the version released on PyPI.
repos: ... - repo: https://github.com/PyCQA/flake8 rev: 5.0.4 hooks: - id: flake8 additional_dependencies: - flake8-return ... args: [--config, setup.cfg]
Recommend Projects
-
ReactA declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
TypescriptTypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlowAn Open Source Machine Learning Framework for Everyone
-
DjangoThe Web framework for perfectionists with deadlines.
-
LaravelA PHP framework for web artisans
-
D3Bring data to life with SVG, Canvas and HTML. 📊📈🎉
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
FacebookWe are working to build community through open source technology. NB: members must have two-factor auth.
-
MicrosoftOpen source projects and samples from Microsoft.
-
GoogleGoogle ❤️ Open Source for everyone.
-
AlibabaAlibaba Open Source for everyone
-
D3Data-Driven Documents codes.
-
TencentChina tencent open source team.
- Date you used flake8-return: 28.10.2022
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.10.8
- Operating System: MacOS/Linux
Description
The error reported for R506 can be dangerous in fast changing development environment
What I Did
Let assume we have this piece of code
def main(): for a in range(10): # | 0 exception bad value try: # | 1 ordinary value if a % 5 == 0: # | 2 good value raise ValueError('bad value') # | 3 ordinary value elif a % 2 == 0: # | 4 good value print(a, 'good value') # | 5 exception bad value else: # | 6 good value print(a, 'ordinary value') # | 7 ordinary value except ValueError as e: # | 8 good value print(a, 'exception', e) # | 9 ordinary value if __name__ == '__main__': main()
The error reported is the following:
myfile.py:4:13: R506 unnecessary elif after raise statement. if a % 5 == 0:
Now let assume we change it according to the proposal, but after short period of time another developer come and changed the code slightly (because IF can be quite big and not intuitive), he removed raise and add the handling of situation inside and removed try...except
all together. Now let’s see the result:
def main(): # | 0 exception bad value for a in range(10): # | 0 good value if a % 5 == 0: # | 1 ordinary value print(a, 'exception', 'bad value') # | 2 good value if a % 2 == 0: # | 3 ordinary value print(a, 'good value') # | 4 good value else: # | 5 exception bad value print(a, 'ordinary value') # | 5 ordinary value # | 6 good value # | 7 ordinary value if __name__ == '__main__': # | 8 good value main() # | 9 ordinary value
As we can see the result is not what the developer expected, but… sometimes it is very difficult to notice such issues. As elif
has SOME MEANING behind, usually…
- Date you used flake8-return: 2023/02/02
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.11.1
- Operating System: ubuntu linux
Description
Running through pre-commit with flake8-return listed as an additional dependency for the flake8 repo.
This function:
def get_service_for_object( obj: events.EventWrapper | markets.MarketWrapper, ) -> events.Service | markets.Service: """ Args: obj: The parsed ZF push object. Returns: Relevant service object for the type. """ match obj: case events.EventWrapper(): return events.Service(obj) case markets.MarketWrapper(): return markets.Service(obj) case _: # pragma: no cover raise RuntimeError("Unexpected object type.")
raises R503 missing explicit return at the end of function able to return non-None value.
- Date you used flake8-return: 15th December 2022
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.9.2
- Operating System: Linux
Description
Linting following code:
def test_2(bar): if bar == 3: baz = 1 elif bar == 4: raise Exception() else: baz = 2 return baz
What I Did
$ flake8 test.py test.py:4:5: R506 unnecessary else after raise statement.
The else is necessary as there is additional if before which has side effects and removing else would overwrite that. The code is simplified from real-world code.
- Date you used flake8-return: 28.10.2022
- flake8-return version used, if any: 1.2.0
- Python version, if any: 3.10.8
- Operating System: MacOS/Linux
Description
Invalid error reported for R507 because of some complex context
What I Did
We have some if...elif...
clause like this:
def main(): for a in range(10): # | 0 div 4 if a % 4 == 0: # | 1 div nothing print(a, 'div', 4) # | 2 div 2 elif a % 3 == 0: # | 3 div 3 print(a, 'div', 3) # | 4 div 4 continue # | 5 div nothing elif a % 2 == 0: # | 6 div 3 print(a, 'div', 2) # | 7 div nothing else: # | 8 div 4 print(a, 'div', 'nothing') # | 9 div 3 return 0 if __name__ == '__main__': main()
For this case we are getting this error:
myfile.py:5:9: R507 unnecessary elif after continue statement. elif a % 3 == 0: ^
If we follow the suggestion and fix the issue, then we have different output:
def main(): # | 0 div 4 for a in range(10): # | 0 div 2 if a % 4 == 0: # | 1 div nothing print(a, 'div', 4) # | 2 div 2 elif a % 3 == 0: # | 3 div 3 print(a, 'div', 3) # | 4 div 4 continue # | 4 div 2 if a % 2 == 0: # | 5 div nothing print(a, 'div', 2) # | 6 div 3 else: # | 7 div nothing print(a, 'div', 'nothing') # | 8 div 4 return 0 # | 8 div 2 # | 9 div 3 if __name__ == '__main__': main()
Can we do something to this? I have tried to apply the suggested errors on our codebase and this issue appeared.
- Date you used flake8-return: 2022-10-31
- flake8-return version used, if any: 1.2.0
- Python version, if any: Python 3.10.6
- Operating System: macOS
Description
Invalid error reported for R505 simple if — elif pattern
def get_name(name): if name == 'foo': return 'foo' elif name == 'bar': return 'bar' return 'baz'
What I Did
a.py:2:5: R505 unnecessary elif after return statement.
I think this pattern should be passed.
- Date you used flake8-return: 28/10/2022
- flake8-return version used, if any: Hoping to use v1.1.3
- Python version, if any: 3.8
- Operating System: WSL
Description
I was updating our pre-commit hooks to use flake8-return (rather than a forked version), but as the v1.1.3 tag has not been created on Github, the pre-commit hook does not make use of the changes introduced in v1.1.3 on PyPI.
@afonasev, please could you create a tag for v1.1.3 so that pre-commit makes use of the recent updates?
What I Did
The abridged pre-commit config used below throws a false positive for R504, which has been fixed in the version released on PyPI.
repos: ... - repo: https://github.com/PyCQA/flake8 rev: 5.0.4 hooks: - id: flake8 additional_dependencies: - flake8-return ... args: [--config, setup.cfg]
- Date you used flake8-return: Oct 25th 2022
- flake8-return version used, if any: 1.1.3
- Python version, if any: 3.10.7
- Operating System: Linux
Description
I have a fixture that creates a mock object, patches a library to return that mock object for a specific method and then returns the mock object so that assertions can be made on it. It seems quite clear that I am in fact using the variable, not sure why it’s triggering the linting rule.
I was able to refactor the code to make the lint pass (the second example below), but that code is much less intuitive to me and messy.
What I Did
@pytest.fixture() def example_mock_fails_linting(mocker): mock = mocker.MagicMock() mocker.patch("path.to.mocked.method.that.returns.an.object").return_value = mock return mock # R504 triggers for this line @pytest.fixture() def example_mock_lints_clean(mocker): example = mocker.patch("path.to.mocked.method.that.returns.an.object") example.return_value = mocker.MagicMock() return example.return_value # R504 doesn't trigger for this line
Description
This fixes the extremely annoying construct:
ret = fn() if bad: raise BadThingHappenedError(msg) elif okish: return fixit(ret) else: return ret
to favour
ret = fn() if bad: raise BadThingHappenedError(msg) if okish: return fixit(ret) return ret
What I Did
this is a feature request
- Date you used flake8-return: 09-09-2022
- flake8-return version used, if any: 1.1.3
- Python version, if any: 3.10.6
- Operating System: macOS Monterey 12.5.1
Description
Describe what you were trying to get done. Tell us what happened, what went wrong, and what you expected to happen.
Consider the following functions
def no_exception_loop(): success = False for _ in range(10): try: success = True except Exception: print("exception") # noqa: T201 return success def no_exception(): success = False try: success = True except Exception: print("exception") # noqa: T201 return success def exception(): success = True try: print("raising") # noqa: T201 raise Exception except Exception: success = False return success
The variable success
is changed (or may be changed) inside try/except
blocks. However, running flake8 generates the following error: R504 unecessary variable assignement before return statement.
What I Did
$ poetry run flake8 --show-source debug.py Unable to find qualified name for module: debug.py debug.py:8:12: R504 unecessary variable assignement before return statement. return success ^ debug.py:17:12: R504 unecessary variable assignement before return statement. return success ^ debug.py:27:12: R504 unecessary variable assignement before return statement. return success ^
Running flake8-return
with Python 3.7, I get an R504
error for the following code:
def close(self): any_failed = False for task in self.tasks: try: task() except BaseException: any_failed = True report(traceback.format_exc()) return any_failed # R504 you shouldn't assign value to variable if it will be use only as return value
While any_failed
is not used in any other expressions before being returned, it’s still important to run all cleanup tasks instead of returning immediately after the first error. Perhaps R504
should be disabled when the assignment is in a loop and the return statement is not?
- Date you used flake8-return: 2020-06-18
- flake8-return version used, if any: 1.1.1
- Python version: 3.8.0
- Operating System: Windows 10
Description
flake8-return wrongly indicates R504 for the following samples:
formatted = _USER_AGENT_FORMATTER.format(format_string, **values)
# clean up after any blank components
formatted = formatted.replace('()', '').replace(' ', ' ').strip()
return formatted # <<< wrongly indicated as R504 issue
def user_agent_username(username=None):
if not username:
return ''
username = username.replace(' ', '_') # Avoid spaces or %20.
try:
username.encode('ascii') # just test, but not actually use it
except UnicodeEncodeError:
username = quote(username.encode('utf-8'))
else:
# % is legal in the default $wgLegalTitleChars
# This is so that ops know the real pywikibot will not
# allow a useragent in the username to allow through a hand-coded
# percent-encoded value.
if '%' in username:
username = quote(username)
return username # <<< wrongly indicated as R504 issue
- Date you used flake8-return: 27-11-2020
- flake8-return version used, if any: 1.1.2
- Python version, if any: Python 3.86
- Operating System: Ubuntu 20.4
Description
When emacs’ lsp-mode calls flake 8 on a file (in order to lint it), the command errors out. I strongly suspect the issue is the same as the one reported here: sco1/flake8-annotations#52
My reason for suspecting the error lies within this plugin is the fact that the error goes away when I remove this plugin.
What I Did
Opened the file, activated the virtual env, and started the language server (which called flake8)
What I expected
Flake8 gives results and the pyls lints my code
What I got
Stack trace below
2020-11-27 12:43:25,280 UTC - ERROR - pyls.plugins.flake8_lint - Error while running flake8 'Traceback (most recent call last): File "some_code/.venv/bin/flake8", line 8, in <module> sys.exit(main()) File "some_code/.venv/lib/python3.8/site-packages/flake8/main/cli.py", line 22, in main app.run(argv) File "some_code/.venv/lib/python3.8/site-packages/flake8/main/application.py", line 363, in run self._run(argv) File "some_code/.venv/lib/python3.8/site-packages/flake8/main/application.py", line 351, in _run self.run_checks() File "some_code/.venv/lib/python3.8/site-packages/flake8/main/application.py", line 264, in run_checks self.file_checker_manager.run() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 323, in run self.run_serial() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 307, in run_serial checker.run_checks() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 589, in run_checks self.run_ast_checks() File "some_code/.venv/lib/python3.8/site-packages/flake8/checker.py", line 494, in run_ast_checks for (line_number, offset, text, _) in runner: File "some_code/.venv/lib/python3.8/site-packages/flake8_plugin_utils/plugin.py", line 75, in run self._load_file() File "some_code/.venv/lib/python3.8/site-packages/flake8_plugin_utils/plugin.py", line 87, in _load_file with open(self._filename, 'rb') as f: FileNotFoundError: [Errno 2] No such file or directory: 'stdin' '
- Date you used flake8-return: 26-08-22
- flake8-return version used, if any: 1.1.3
- Python version, if any: 3.10.2
- Operating System: MacOS 12.5.1
Description
match/case construction not supported
What I Did
def test(): a = 1 match a: # <---- D400 First line should end with a period case 0: return False case 1: return True case _*: return False
flake8-return version 1.1.3 allows this construct
def myfunc(x):
if x == 5:
return None
assert False
but disallows this one
def myfunc(x):
if x == 5:
return None
raise NotImplementedError()
I think they should be treated the same?
- Date you used flake8-return: feb 6 2021
- flake8-return version used, if any: 1.1.2
- Python version, if any: 3.8.5
- Operating System: macOS
Description
I have a decorator that’s specifically designed to return either None or a function depending on the CPU rank so that only the root one exectutes the decoreated function. Here’s the gist of it
from functools import wraps def rootonly(func): @wraps(func) def check_parallel_rank(*args, **kwargs): global topcomm_parallel_rank if topcomm_parallel_rank > 0: return return func(*args, **kwargs) return check_parallel_rank
I’m getting a R502
error of course, so I tried adding type hints to avoid using noqas
from typing import Optional from types import FunctionType # ... def check_parallel_rank(*args, **kwargs) -> Optional[FunctionType]: # ...
but the error persists, though I’d argue it shouldn’t (in an ideal world).
I know that this is a sizeable feature to ask but is there any chance you’d consider taking type hints into account ?
In any case thanks for the tool, it’s worth using for 504 alone !
- Date you used flake8-return: Jul 6, 2020
- flake8-return version used, if any: 1.1.1
- Python version, if any: Python 3.8.3
- Operating System: Arch Linux on Linux 5.7.4
Description
flake8-return seemingly fails to detect changes to a variable modified in a while loop.
What I Did
def doit(): test = 1 i = 4 while i := i - 1: test = test + 1 return test class Node: def __init__(self, v, parent=None): self.v = v self.parent = parent self.child = Node(v - 1, parent=self) if v else None def __str__(self): name = f"Node<{self.v}>" node = self while node := node.parent: name = f"Node<{node.v}>.{name}" return name def tail(self): node = self while node.child: node = node.child return node print(Node(5).tail())
A R504 error is detected at each return there, in doit()
, Node.__str__
, and Node.tail
- Date you used flake8-return: 2019-05-16
- flake8-return version used, if any: 1.0.0
- Python version, if any: 3.7.1
- Operating System: Debian
Description
The R504 doesn’t detect that the variable is conditionally modified prior to return.
What I Did
$ flake8 test.py test.py:5:12: R504 you shouldn`t assign value to variable if it will be use only as return value $ cat test.py def foo(bar): value = [] if bar: value = value[:1] return value
- Date you used flake8-return: 8/16/2019
- flake8-return version used, if any: 1.1.0
- Python version, if any: 3.6.6
- Operating System: OSX
Description
With a function like the following:
async def function(): async with thing as foo: return foo.bar
This is valid because there can be no other return than the one inside the with context. If enter/exit raise then nothing after it will run. The one way this is not true is if you capture the exeption with a try/except around the async with clause.
- Date you used flake8-return: today
- flake8-return version used, if any: 0.3.1
- Python version, if any: Python 3.7.2
- Operating System: Linux
Description
We sometimes end a method with assert False, "some reason"
as a sanity check. The current version of flake8-return sees this as a violation of R503.
def some_method(parameter):
if some_test:
return some_value
elif another_test:
return another_value
else:
assert False, "parameter was not some_value nor another_value"
This assert False
is equivalent to raise AssertionError
which flake8-return does recognize. We would like to see flake8-return treat both statements as equivalent.
The bot created this issue to inform you that pyup.io has been set up on this repo.
Once you have closed it, the bot will open pull requests for updates as soon as they are available.