@@ -405,7 +405,10 @@ def _has_locals_call_after_node(stmt, scope):
405
405
"E0601" : (
406
406
"Using variable %r before assignment" ,
407
407
"used-before-assignment" ,
408
- "Used when a local variable is accessed before its assignment." ,
408
+ "Emitted when a local variable is accessed before its assignment took place. "
409
+ "Assignments in try blocks are assumed not to have occurred when evaluating "
410
+ "associated except/finally blocks. Assignments in except blocks are assumed "
411
+ "not to have occurred when evaluating statements outside the block." ,
409
412
),
410
413
"E0602" : (
411
414
"Undefined variable %r" ,
@@ -580,12 +583,10 @@ def consumed(self):
580
583
def consumed_uncertain (self ) -> DefaultDict [str , List [nodes .NodeNG ]]:
581
584
"""
582
585
Retrieves nodes filtered out by get_next_to_consume() that may not
583
- have executed, such as statements in except blocks. Checkers that
584
- want to treat the statements as executed (e.g. for unused-variable)
585
- may need to add them back.
586
-
587
- TODO: A pending PR will extend this to nodes in try blocks when
588
- evaluating their corresponding except and finally blocks.
586
+ have executed, such as statements in except blocks, or statements
587
+ in try blocks (when evaluating their corresponding except and finally
588
+ blocks). Checkers that want to treat the statements as executed
589
+ (e.g. for unused-variable) may need to add them back.
589
590
"""
590
591
return self ._atomic .consumed_uncertain
591
592
@@ -617,6 +618,7 @@ def get_next_to_consume(self, node):
617
618
name = node .name
618
619
parent_node = node .parent
619
620
found_nodes = self .to_consume .get (name )
621
+ node_statement = node .statement (future = True )
620
622
if (
621
623
found_nodes
622
624
and isinstance (parent_node , nodes .Assign )
@@ -662,6 +664,44 @@ def get_next_to_consume(self, node):
662
664
self .consumed_uncertain [node .name ] += difference
663
665
found_nodes = filtered_nodes
664
666
667
+ # If this node is in a Finally block of a Try/Finally,
668
+ # filter out assignments in the try portion, assuming they may fail
669
+ if (
670
+ found_nodes
671
+ and isinstance (node_statement .parent , nodes .TryFinally )
672
+ and node_statement in node_statement .parent .finalbody
673
+ ):
674
+ filtered_nodes = [
675
+ n
676
+ for n in found_nodes
677
+ if not (
678
+ n .statement (future = True ).parent is node_statement .parent
679
+ and n .statement (future = True ) in n .statement (future = True ).parent .body
680
+ )
681
+ ]
682
+ filtered_nodes_set = set (filtered_nodes )
683
+ difference = [n for n in found_nodes if n not in filtered_nodes_set ]
684
+ self .consumed_uncertain [node .name ] += difference
685
+ found_nodes = filtered_nodes
686
+
687
+ # If this node is in an ExceptHandler,
688
+ # filter out assignments in the try portion, assuming they may fail
689
+ if found_nodes and isinstance (node_statement .parent , nodes .ExceptHandler ):
690
+ filtered_nodes = [
691
+ n
692
+ for n in found_nodes
693
+ if not (
694
+ isinstance (n .statement (future = True ).parent , nodes .TryExcept )
695
+ and n .statement (future = True ) in n .statement (future = True ).parent .body
696
+ and node_statement .parent
697
+ in n .statement (future = True ).parent .handlers
698
+ )
699
+ ]
700
+ filtered_nodes_set = set (filtered_nodes )
701
+ difference = [n for n in found_nodes if n not in filtered_nodes_set ]
702
+ self .consumed_uncertain [node .name ] += difference
703
+ found_nodes = filtered_nodes
704
+
665
705
return found_nodes
666
706
667
707
0 commit comments