python / python/mypy

Overzealous truthy-bool check in finally block

Open
#16,193 3 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

If a variable's type is narrowed from potentially-falsey to definitely-truthy during a try block, and that variable is truth-tested during a finally block, the truthy-bool check raises an error even though the variable could in fact be false (if an exception is raised in the try block before the narrowing occurs).

To Reproduce

class A:
    def __init__(self):
        import random
        if random.randint(0, 1):
            raise ValueError
    def close(self): pass

def fn() -> None:
    a: A | None = None
    try:
        a = A()
        print(a)
    finally:
        if a:
            a.close()

fn()

Expected Behavior

Since a might still be None (if A.__init__ raises ValueError) I would expect mypy to not flag the if statement as redundant.

Actual Behavior

$ mypy --enable-error-code=truthy-bool t.py
t.py:14: error: "a" has type "A" which does not implement __bool__ or __len__ so it could always be true in boolean context  [truthy-bool]
Found 1 error in 1 file (checked 1 source file)

If I add a reveal_type(a) line just before if a:, then I get two revealed types:

t.py:14: note: Revealed type is "Union[t.A, None]"
t.py:14: note: Revealed type is "t.A"

which makes me suspect this is an issue where finally statements are desugared into an after-try and an after-except, with different narrowings applied to each one, and truthy-bool is only complaining about one of those.

Your Environment

$ mypy --version
mypy 1.5.1 (compiled: yes)
$ python --version
Python 3.11.5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the provided example with mypy 1.5.1 and --enable-error-code=truthy-bool, then inspect the finally-block narrowing and truthy-bool check involved in the reported diagnostics. Done means the example no longer reports a redundant truthiness error while preserving correct narrowing and diagnostics for other finally cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.