@@ -250,10 +250,11 @@ class Binding:
250250 the node that this binding was last used.
251251 """
252252
253- def __init__ (self , name , source ):
253+ def __init__ (self , name , source , * , assigned = True ):
254254 self .name = name
255255 self .source = source
256256 self .used = False
257+ self .assigned = assigned
257258
258259 def __str__ (self ):
259260 return self .name
@@ -1007,6 +1008,12 @@ def addBinding(self, node, value):
10071008 break
10081009 existing = scope .get (value .name )
10091010
1011+ global_scope = self .scopeStack [- 1 ]
1012+ if (existing and global_scope .get (value .name ) == existing and
1013+ not existing .assigned ):
1014+ # make sure the variable is in the global scope before setting as assigned
1015+ existing .assigned = True
1016+
10101017 if (existing and not isinstance (existing , Builtin ) and
10111018 not self .differentForks (node , existing .source )):
10121019
@@ -1089,6 +1096,10 @@ def handleNodeLoad(self, node):
10891096 continue
10901097
10911098 binding = scope .get (name , None )
1099+
1100+ if binding and binding .assigned is False :
1101+ self .report (messages .UndefinedName , node , name )
1102+
10921103 if isinstance (binding , Annotation ) and not self ._in_postponed_annotation :
10931104 scope [name ].used = True
10941105 continue
@@ -1159,12 +1170,19 @@ def handleNodeStore(self, node):
11591170 continue
11601171 # if the name was defined in that scope, and the name has
11611172 # been accessed already in the current scope, and hasn't
1162- # been declared global
1173+ # been assigned globally
11631174 used = name in scope and scope [name ].used
11641175 if used and used [0 ] is self .scope and name not in self .scope .globals :
11651176 # then it's probably a mistake
11661177 self .report (messages .UndefinedLocal ,
11671178 scope [name ].used [1 ], name , scope [name ].source )
1179+
1180+ # and remove UndefinedName messages already reported for this name
1181+ self .messages = [
1182+ m for m in self .messages if not
1183+ isinstance (m , messages .UndefinedName ) or
1184+ m .message_args [0 ] != name ]
1185+
11681186 break
11691187
11701188 parent_stmt = self .getParent (node )
@@ -1836,7 +1854,7 @@ def ASSERT(self, node):
18361854 self .report (messages .AssertTuple , node )
18371855 self .handleChildren (node )
18381856
1839- def GLOBAL (self , node ):
1857+ def GLOBAL (self , node , assign_by_default = False ):
18401858 """
18411859 Keep track of globals declarations.
18421860 """
@@ -1848,11 +1866,9 @@ def GLOBAL(self, node):
18481866
18491867 # One 'global' statement can bind multiple (comma-delimited) names.
18501868 for node_name in node .names :
1851- node_value = Assignment (node_name , node )
1869+ node_value = Assignment (node_name , node , assigned = assign_by_default )
18521870
18531871 # Remove UndefinedName messages already reported for this name.
1854- # TODO: if the global is not used in this scope, it does not
1855- # become a globally defined name. See test_unused_global.
18561872 self .messages = [
18571873 m for m in self .messages if not
18581874 isinstance (m , messages .UndefinedName ) or
@@ -1866,7 +1882,11 @@ def GLOBAL(self, node):
18661882 for scope in self .scopeStack [global_scope_index + 1 :]:
18671883 scope [node_name ] = node_value
18681884
1869- NONLOCAL = GLOBAL
1885+ def NONLOCAL (self , node ):
1886+ for node_name in node .names :
1887+ if not any (node_name in scope for scope in self .scopeStack [:- 1 ]):
1888+ self .report (messages .NoBindingForNonlocal , node , node_name )
1889+ self .GLOBAL (node , assign_by_default = True )
18701890
18711891 def GENERATOREXP (self , node ):
18721892 self .pushScope (GeneratorScope )
0 commit comments