From 3f1c0f831a61b48d0fb499214aacec589e90ba28 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 20 Nov 2025 13:21:17 -0500 Subject: [PATCH 1/4] Fix possibly-undefined false-positive with nesting Closes #14309 --- test-data/unit/check-possibly-undefined.test | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test-data/unit/check-possibly-undefined.test b/test-data/unit/check-possibly-undefined.test index ae277949c049..0dcfb1ced218 100644 --- a/test-data/unit/check-possibly-undefined.test +++ b/test-data/unit/check-possibly-undefined.test @@ -708,6 +708,17 @@ def f6() -> int: finally: a = x # E: Name "x" may be undefined return a + +def f7() -> int: + try: + if int(): + x = 1 + else: + raise BaseException + return x # E: Name "x" may be undefined + finally: + pass + return 0 [builtins fixtures/exception.pyi] [case testTryElse] From acb345af691f5f9b700daf4dec58cfb88eb98c32 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 20 Nov 2025 13:23:36 -0500 Subject: [PATCH 2/4] report errors in finally when in disable_branch_skip --- mypy/partially_defined.py | 9 ++++++++- test-data/unit/check-possibly-undefined.test | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mypy/partially_defined.py b/mypy/partially_defined.py index 38154cf697e1..3a6b880c07e8 100644 --- a/mypy/partially_defined.py +++ b/mypy/partially_defined.py @@ -206,11 +206,13 @@ def __init__(self) -> None: # disable_branch_skip is used to disable skipping a branch due to a return/raise/etc. This is useful # in things like try/except/finally statements. self.disable_branch_skip = False + self.in_finally = False def copy(self) -> DefinedVariableTracker: result = DefinedVariableTracker() result.scopes = [s.copy() for s in self.scopes] result.disable_branch_skip = self.disable_branch_skip + result.in_finally = self.in_finally return result def _scope(self) -> Scope: @@ -579,7 +581,9 @@ def process_try_stmt(self, o: TryStmt) -> None: self.tracker.end_branch_statement() if o.finally_body is not None: + self.tracker.in_finally = True o.finally_body.accept(self) + self.tracker.in_finally = False def visit_while_stmt(self, o: WhileStmt) -> None: o.expr.accept(self) @@ -620,7 +624,10 @@ def visit_starred_pattern(self, o: StarredPattern) -> None: def visit_name_expr(self, o: NameExpr) -> None: if o.name in self.builtins and self.tracker.in_scope(ScopeType.Global): return - if self.tracker.is_possibly_undefined(o.name): + if ( + self.tracker.is_possibly_undefined(o.name) + and self.tracker.in_finally == self.tracker.disable_branch_skip + ): # A variable is only defined in some branches. self.variable_may_be_undefined(o.name, o) # We don't want to report the error on the same variable multiple times. diff --git a/test-data/unit/check-possibly-undefined.test b/test-data/unit/check-possibly-undefined.test index 0dcfb1ced218..86c225fba835 100644 --- a/test-data/unit/check-possibly-undefined.test +++ b/test-data/unit/check-possibly-undefined.test @@ -678,7 +678,7 @@ def f3() -> int: pass finally: y = x # E: Name "x" may be undefined - return x + return x # E: Name "x" may be undefined def f4() -> int: try: @@ -715,7 +715,7 @@ def f7() -> int: x = 1 else: raise BaseException - return x # E: Name "x" may be undefined + return x # No error. finally: pass return 0 From 61b40dfe43c140574bf14430be905dbe4afe7866 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 23 Nov 2025 13:33:31 -0800 Subject: [PATCH 3/4] slightly more test --- test-data/unit/check-possibly-undefined.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-possibly-undefined.test b/test-data/unit/check-possibly-undefined.test index 86c225fba835..6e3390fa7dd6 100644 --- a/test-data/unit/check-possibly-undefined.test +++ b/test-data/unit/check-possibly-undefined.test @@ -628,7 +628,7 @@ def f7() -> int: x = 1 assert False except: - pass + y = x # E: Name "x" may be undefined return x # E: Name "x" may be undefined [builtins fixtures/exception.pyi] From a6c6c5135dcfb06a213a74fbbf497aeb4658d6af Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 23 Nov 2025 13:34:24 -0800 Subject: [PATCH 4/4] slightly more test --- test-data/unit/check-possibly-undefined.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-possibly-undefined.test b/test-data/unit/check-possibly-undefined.test index 6e3390fa7dd6..b0c19cbb7315 100644 --- a/test-data/unit/check-possibly-undefined.test +++ b/test-data/unit/check-possibly-undefined.test @@ -717,7 +717,7 @@ def f7() -> int: raise BaseException return x # No error. finally: - pass + y = x # E: Name "x" may be undefined return 0 [builtins fixtures/exception.pyi]