@@ -417,6 +417,7 @@ def __init__(self):
417417 super (FunctionScope , self ).__init__ ()
418418 # Simplify: manage the special locals as globals
419419 self .globals = self .alwaysUsed .copy ()
420+ self .global_names = []
420421 self .returnValue = None # First non-empty return
421422 self .isGenerator = False # Detect a generator
422423
@@ -959,6 +960,15 @@ def handleForwardAnnotation():
959960 def ignore (self , node ):
960961 pass
961962
963+ def store_global_scope (self , name , value ):
964+ """This store name in global scope if it is in global_names"""
965+ if isinstance (self .scope , FunctionScope ):
966+ global_scope_index = 1 if self ._in_doctest () else 0
967+ global_scope = self .scopeStack [global_scope_index ]
968+ if name in self .scope .global_names :
969+ global_scope .setdefault (name ,
970+ Assignment (name , value ))
971+
962972 # "stmt" type nodes
963973 DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \
964974 ASYNCWITH = ASYNCWITHITEM = RAISE = TRYFINALLY = EXEC = \
@@ -1052,7 +1062,8 @@ def GLOBAL(self, node):
10521062 m .message_args [0 ] != node_name ]
10531063
10541064 # Bind name to global scope if it doesn't exist already.
1055- global_scope .setdefault (node_name , node_value )
1065+ if isinstance (self .scope , FunctionScope ):
1066+ self .scope .global_names .append (node_name )
10561067
10571068 # Bind name to non-global scopes, but as already "used".
10581069 node_value .used = (global_scope , node )
@@ -1074,17 +1085,33 @@ def NAME(self, node):
10741085 """
10751086 Handle occurrence of Name (which can be a load/store/delete access.)
10761087 """
1088+ global_scope_index = 1 if self ._in_doctest () else 0
1089+ global_scope = self .scopeStack [global_scope_index ]
10771090 # Locate the name in locals / function / globals scopes.
10781091 if isinstance (node .ctx , (ast .Load , ast .AugLoad )):
10791092 self .handleNodeLoad (node )
10801093 if (node .id == 'locals' and isinstance (self .scope , FunctionScope )
10811094 and isinstance (node .parent , ast .Call )):
10821095 # we are doing locals() call in current scope
10831096 self .scope .usesLocals = True
1097+ if (isinstance (self .scope , FunctionScope ) and
1098+ node .id in self .scope .global_names ):
1099+ if node .id not in global_scope :
1100+ self .report (messages .UndefinedName , node , node .id )
10841101 elif isinstance (node .ctx , (ast .Store , ast .AugStore )):
10851102 self .handleNodeStore (node )
1103+ if (isinstance (self .scope , FunctionScope ) and
1104+ node .id in self .scope .global_names ):
1105+ global_scope .setdefault (node .id , Assignment (node .id , node ))
10861106 elif isinstance (node .ctx , ast .Del ):
10871107 self .handleNodeDelete (node )
1108+ if (isinstance (self .scope , FunctionScope ) and
1109+ node .id in self .scope .global_names ):
1110+ if node .id not in global_scope :
1111+ self .report (messages .UndefinedName , node , node .id )
1112+ else :
1113+ global_scope .pop (node .id , None )
1114+ self .scope .global_names .remove (node .id )
10881115 else :
10891116 # must be a Param context -- this only happens for names in function
10901117 # arguments, but these aren't dispatched through here
@@ -1292,13 +1319,16 @@ def TUPLE(self, node):
12921319
12931320 def IMPORT (self , node ):
12941321 for alias in node .names :
1322+ name = alias .name
12951323 if '.' in alias .name and not alias .asname :
1296- importation = SubmoduleImportation (alias . name , node )
1324+ importation = SubmoduleImportation (name , node )
12971325 else :
12981326 name = alias .asname or alias .name
12991327 importation = Importation (name , node , alias .name )
13001328 self .addBinding (node , importation )
13011329
1330+ self .store_global_scope (name , alias )
1331+
13021332 def IMPORTFROM (self , node ):
13031333 if node .module == '__future__' :
13041334 if not self .futuresAllowed :
@@ -1331,6 +1361,8 @@ def IMPORTFROM(self, node):
13311361 module , alias .name )
13321362 self .addBinding (node , importation )
13331363
1364+ self .store_global_scope (name , alias )
1365+
13341366 def TRY (self , node ):
13351367 handler_names = []
13361368 # List the exception handlers
0 commit comments