@@ -435,6 +435,7 @@ def __init__(self):
435435 super (FunctionScope , self ).__init__ ()
436436 # Simplify: manage the special locals as globals
437437 self .globals = self .alwaysUsed .copy ()
438+ self .global_names = []
438439 self .returnValue = None # First non-empty return
439440 self .isGenerator = False # Detect a generator
440441
@@ -574,6 +575,9 @@ def _in_doctest(self):
574575 return (len (self .scopeStack ) >= 2 and
575576 isinstance (self .scopeStack [1 ], DoctestScope ))
576577
578+ def _global_scope (self ):
579+ return self .scopeStack [1 if self ._in_doctest () else 0 ]
580+
577581 @property
578582 def futuresAllowed (self ):
579583 if not all (isinstance (scope , ModuleScope )
@@ -735,6 +739,11 @@ def addBinding(self, node, value):
735739 elif isinstance (existing , Importation ) and value .redefines (existing ):
736740 existing .redefined .append (node )
737741
742+ if (isinstance (self .scope , FunctionScope ) and
743+ isinstance (value , Importation ) and
744+ value .name in self .scope .global_names ):
745+ self .store_global_scope (value .name , value )
746+
738747 if value .name in self .scope :
739748 # then assume the rebound name is used as a global or within a loop
740749 value .used = self .scope [value .name ].used
@@ -757,6 +766,12 @@ def handleNodeLoad(self, node):
757766 in_generators = None
758767 importStarred = None
759768
769+ if (isinstance (self .scope , FunctionScope ) and
770+ name in self .scope .global_names and
771+ name not in self ._global_scope ()):
772+ # report name declared with global statement but undefined
773+ self .report (messages .UndefinedName , node , name )
774+
760775 # try enclosing function scopes and global scope
761776 for scope in self .scopeStack [- 1 ::- 1 ]:
762777 if isinstance (scope , ClassScope ):
@@ -833,6 +848,10 @@ def handleNodeStore(self, node):
833848 scope [name ].used [1 ], name , scope [name ].source )
834849 break
835850
851+ if (isinstance (self .scope , FunctionScope ) and
852+ name in self .scope .global_names ):
853+ self .store_global_scope (name , Assignment (name , node ))
854+
836855 parent_stmt = self .getParent (node )
837856 if isinstance (parent_stmt , (ast .For , ast .comprehension )) or (
838857 parent_stmt != node .parent and
@@ -868,8 +887,15 @@ def on_conditional_branch():
868887 # be executed.
869888 return
870889
871- if isinstance (self .scope , FunctionScope ) and name in self .scope .globals :
872- self .scope .globals .remove (name )
890+ if isinstance (self .scope , FunctionScope ):
891+ if name in self .scope .globals :
892+ self .scope .globals .remove (name )
893+ if name in self .scope .global_names :
894+ self .scope .global_names .remove (name )
895+ try :
896+ del self ._global_scope ()[name ]
897+ except KeyError :
898+ self .report (messages .UndefinedName , node , name )
873899 else :
874900 try :
875901 del self .scope [name ]
@@ -1016,6 +1042,10 @@ def handleForwardAnnotation():
10161042 def ignore (self , node ):
10171043 pass
10181044
1045+ def store_global_scope (self , name , value ):
1046+ """This store name in global scope"""
1047+ self ._global_scope ()[name ] = value
1048+
10191049 # "stmt" type nodes
10201050 DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \
10211051 ASYNCWITH = ASYNCWITHITEM = TRYFINALLY = EXEC = \
@@ -1122,7 +1152,8 @@ def GLOBAL(self, node):
11221152 m .message_args [0 ] != node_name ]
11231153
11241154 # Bind name to global scope if it doesn't exist already.
1125- global_scope .setdefault (node_name , node_value )
1155+ if isinstance (self .scope , FunctionScope ):
1156+ self .scope .global_names .append (node_name )
11261157
11271158 # Bind name to non-global scopes, but as already "used".
11281159 node_value .used = (global_scope , node )
0 commit comments