-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
possibly-used-before-assignment doesn't understand negation of conditionals #9628
Comments
Thanks @chrisburr. This is actually working as designed. The last example where no message is emitted is because of the limited exception we added in #8581 for identical guards. We should update the docs for the message, because the discussion there of an example The rationale being that if You may want to disable this message if you rely on this pattern. Pylint itself disabled this message for the time being. |
Thanks for the prompt response (and more generally for the work on this really nice new lint rule)! I can definitely see why relying on a globals/callables/properties/inner functions with The reason I had for having the inverted condition was that my code is actually of the form: if xxx:
yyy = ...
if not xxx:
...
elif zzz:
print(yyy) In my case the code is contained inside of a function so there is no way def my_func(a: bool):
if a:
b = "1234"
if not a:
pass
else:
print(b) |
Right, but what about the following. def my_func(a: bool):
if a:
b = "1234"
a = not a
if not a:
pass
else:
print(b) |
Ah! I didn’t realise pylint didn’t have control flow knowledge. That probably kills this suggestion, or at least turns it into a feature suggestion which sounds like it would be non-trivial. I think it would be reasonable to say that if you mutate the variable in then conditional between invocations that it’s an expected that pylint looses track and gives a false result. Though as mentioned before, if that’s not possible then I totally agree with the current behaviour. |
If variable a = bool(input("Enter something or nothing: "))
if a:
b = "1234"
print(b)
else:
pass |
Yeah, that's kind of the rub. It may or may not be feasible if a complete redesign of the variables checker is ever attempted, but in the meantime, we were thinking it was an okay compromise to ship with the current behavior so long as we weasel worded it with "possibly". That does make this error kind of a cross between an error and a code-style warning. I edited your example which was safe to make it unsafe, and all I did was insert one line in the middle of a function. That seems likely to happen in real-life, and authors can defend against that possibility by doing what @nickdrozd suggests instead, which is more of a future-proofing code-style convention than an error if we choose to look at it that way. |
Yeah I can see that. For the safety of this pattern I think it depends on what the variable actually is. In the cases I've seen it's a flag that is passed in externally so there is no reasonable change of someone mutating it though I'm sure I could find examples to the contrary if I looked (like if it was a flag that is set in a loop).
As you've asked, the real case that prompted this issue was the use of |
That's a nice one! There is a similar function in the Pylint codebase that gets flagged with the same warning: https://github.com/pylint-dev/pylint/blob/main/pylint/checkers/similar.py#L579 I think it's safe to say that both functions are pretty nasty. A bunch of different flags floating around, multi-way branches, nested loops -- these are generally things to be avoided. Of course they have to be done from time to time. But probably it isn't a coincidence that these "false positives" tend to crop up as comorbidities. If it happens to work out okay at runtime, great. And if that's the case, silencing the warning locally seems like a fine approach. Another alternative would be to define the variable unconditionally with some kind of null value: replicas = _getReplicas(list(chain(*lfns.values()))) if with_pfns else {} # or [], None, whatever In any case, I don't think Pylint should attempt to accommodate this. The variable really is possibly undefined, in the sense that there are runtime circumstances that could lead to an undefined variable error. How would this pattern be handled in a language like Rust? |
Given: # pylint: disable=missing-module-docstring,missing-function-docstring
def make_bot(token):
assert token
return token.upper()
def function(token):
⋮
function('pass')
function('')
👍
👍
👍 — however:
👎 (as above) And:
👍 — however:
👎 I'm doing something like: if token:
try:
bot = make_bot(token)
except AssertionError:
token = None
if not token:
print('Instructions for generating a [valid] token.')
return
bot.dereference() and it is possible for me to mess the logic up at some point so that |
Thanks for the use cases here. Going to close as a duplicate of #9662, which has more discussion about the direction/effort involved here. |
Bug description
Configuration
No response
Command used
Pylint output
Expected behavior
Pylint should understand both
if a: ...
andif not a: pass; else: ...
Pylint version
OS / Environment
No response
Additional dependencies
No response
The text was updated successfully, but these errors were encountered: