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

used-before-assignment when variable possibly defined in try, and used in finally #9639

Open
eli-schwartz opened this issue May 16, 2024 · 2 comments
Labels
C: used-before-assignment Issues related to 'used-before-assignment' check Needs decision 🔒 Needs a decision before implemention or rejection

Comments

@eli-schwartz
Copy link

eli-schwartz commented May 16, 2024

Bug description

import random

def may_raise():
    if random.choice([True, False]):
        raise RuntimeError('good luck!')

def func(arg):
    if arg:
        objfile = True
        may_raise()
    else:
        objfile = False
        may_raise()

    print(objfile)

def func2(arg):
    try:
        if arg:
            objfile = True
            may_raise()
        else:
            objfile = False
            may_raise()

    finally:
        print(objfile)


def func3(arg):
    try:
        objfile = True
        may_raise()

    finally:
        print(objfile)

Configuration

No response

Command used

pylint /tmp/test.py

Pylint output

************* Module test
/tmp/test.py:27:14: E0601: Using variable 'objfile' before assignment (used-before-assignment)
/tmp/test.py:36:14: E0601: Using variable 'objfile' before assignment (used-before-assignment)

Expected behavior

The variable is certainly assigned before use, in all cases unless an exception takes place -- this is why func() succeeds but func2() fails.

In the case of func3() the assignment could be hoisted out of the conditional, but in the case of func2() it cannot easily be. It's really func2() I am concerned about.

Real world code exhibiting func2()'s design: https://github.com/mesonbuild/meson/blob/7d28ff29396f9d7043204de8ddc52226b9903811/mesonbuild/compilers/detect.py#L1143-L1160

If I know that the assignment cannot fail -- but later parts of the try can fail -- then it is definitely not a used-before-assignment. So the lint violation should actually be possibly-used-before-assignment since pylint cannot know whether or not the assignment is exception-proof.

EDIT: ok I overlooked that in my real world code it does report "possibly", but while diagnosing it and writing a test case I got a "used-before-assignment" and forgot what the real code does. So maybe nothing need be for me... the test case is still interesting I guess.

Pylint version

pylint 3.2.0
astroid 3.2.0
Python 3.11.9 (main, Apr 27 2024, 23:35:49) [GCC 13.2.1 20240210]

OS / Environment

Gentoo Linux

Additional dependencies

No response

@eli-schwartz eli-schwartz added the Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling label May 16, 2024
@jacobtylerwalls
Copy link
Member

Thanks for the report. I think pylint's behavior here is surprising to you because you would like pylint to distinguish what can fail (may_raise()) from what cannot (objfile = True).

objfile = True sure looks safe in a minimal example, but this isn't really knowable in priniciple:

>>> try:
...   objfile = 1/0
... finally:
...   print(objfile)
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
NameError: name 'objfile' is not defined

I think the design choice here was to keep things simple and stupid by assuming that everything under a try can fail. If something under a try cannot fail, then it shouldn't be in a try.

I appreciate that the introduction of a possibly... flavor of the message suggests ways pylint could start using it in other cases where uncertainty also applies, but I hope this gives some sense of why we decided to leave things as is.

@jacobtylerwalls jacobtylerwalls closed this as not planned Won't fix, can't repro, duplicate, stale May 17, 2024
@jacobtylerwalls jacobtylerwalls added C: used-before-assignment Issues related to 'used-before-assignment' check Won't fix/not planned and removed Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling Won't fix/not planned labels May 17, 2024
@jacobtylerwalls
Copy link
Member

Sorry for the churn. I think the suggestion to use possibly... here makes some sense, as it's in agreement with the discussion on #2835 about what to do after a finally. Although I may need to check some discussion on other closed issues.

@jacobtylerwalls jacobtylerwalls added the Needs decision 🔒 Needs a decision before implemention or rejection label May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: used-before-assignment Issues related to 'used-before-assignment' check Needs decision 🔒 Needs a decision before implemention or rejection
Projects
None yet
Development

No branches or pull requests

2 participants