-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Looks like ruff ignores useless return statement in functions annotated to return not None #14377
Comments
Thanks for bringing this up! It appears the decision to skip the lint when the return annotation is present and not We should certainly update the documentation to reflect this. But if there is also some interest from the community in revisiting this decision, or perhaps even making it configurable, it'd be nice to hear more about what's most helpful here! |
Ruff's current behavior seems correct to me. The return isn't useless. It's just that the returned value doesn't match the annotated type. But that's more a type checker concern than a concern of the useless return rule. |
Is there currently any way of making ruff complain about such returns? If not, I would be happy if that was made possible. So revise the decision or add the other rule for this, please. Thank you for ruff! |
How are such returns not useless? What do you mean?
But ruff should not flag this?: def f() -> ...:
print()
return None |
I don't mind extending the documentation.
The return in the given example is incorrect: It returns
To my knowledge, there's currently no rule to catch this because catching that the returned value |
I don't know, I'm not sure if I'm fully on board with this interpretation. From my point of view, there are two separate things happening:
I think (1) is a question of style and (2) is a question for a type checker. It makes sense to me that one would want to enforce (1) uniformly in a project as a lint rule (really either way - to always have explicit returns or always implicit returns of None - just a style preference), and then separately have a type checker complain about the values being returned from your function and what type hint you used. Sorry for being difficult! I'm fine leaving it as is but just wanted to share this perspective. |
That interpretation makes sense to me. But to me, showing both PLR1711 and a violation that the returned value doesn't match the annotated type is confusing for users using a type checker. It's provided fix is may also be incorrect, depending on the situations. That's why I think it's better to not raise the violation at all. |
So I would answer yes to the question whether it should there should be an option to make ruff complain about such returns: def f() -> {not None}:
...
return None Because it might very well be that somebody wants this code to be valid: # returns some int
def f() -> int: ...
exec('redefine f. example: def f(): return 0')
r = f()
assert isinstance(r, int)
print(r) but get complains about the same code with: def f() -> int:
...
return None or with def f() -> int:
"""docs in the signature function, description..."""
return None Actually, ruff doesnt complain even about the following now (so does pylint): def f():
"""docs in the signature function, description..."""
return None I myself didn't know that functions with docstring and without return at the end are valid. And I can imagine how I could have ended up not knowing about it and working with some other developers who know that this is valid, use ruff, share the ruff config with their teammates, and want ruff to tell newbies that they are fine with: def f():
"""docs in the signature function, description...""" |
I think there is an underlying assumption in applying static program analysis to a highly dynamic language like Python that behavior involving |
What do I do if I want to allow exec and eval, and allow the definition of function signatures, but also get warnings when there is some return None that is not needed there? |
Yes I think that's a fair question (and orthogonal to the use of |
Examples of 'real world' code that contains useless return, but that ruff doesn't complain about (with abstractmethod, not exec or eval): from typing import Any
from abc import ABC, abstractmethod
class DataProcessor(ABC):
@abstractmethod
def process(self) -> Any:
...
return None from abc import ABC, abstractmethod
class DataProcessor(ABC):
@abstractmethod
def process(self):
"""processes the data"""
return None |
Today, I went to Ruff playground, enabled PLR1711 (useless-return) rule and pasted this code:
In Diagnostics tab I saw only
Everything is looking good!
.I then removed
-> int
for the code to be:and saw
Useless `return` statement at end of function (PLR1711) [Ln 3, Col 5]
.Ruff complained in the same way when I annotated function to return None:
All the same goes for cases with
return
instead ofreturn None
.Is this an intended behavior? If it is, I think the documentation on this rule should inform about this.
I have checked how pylint handles such cases by running cell with the following in fresh google colab runtime:
I got
How can I get ruff to complain about useless return statements in cases when function is not annotated to return None?
You can also help on StackOverflow
The text was updated successfully, but these errors were encountered: