@@ -435,6 +435,7 @@ def __init__(self):
435
435
super (FunctionScope , self ).__init__ ()
436
436
# Simplify: manage the special locals as globals
437
437
self .globals = self .alwaysUsed .copy ()
438
+ self .global_names = []
438
439
self .returnValue = None # First non-empty return
439
440
self .isGenerator = False # Detect a generator
440
441
@@ -574,6 +575,9 @@ def _in_doctest(self):
574
575
return (len (self .scopeStack ) >= 2 and
575
576
isinstance (self .scopeStack [1 ], DoctestScope ))
576
577
578
+ def _global_scope (self ):
579
+ return self .scopeStack [1 if self ._in_doctest () else 0 ]
580
+
577
581
@property
578
582
def futuresAllowed (self ):
579
583
if not all (isinstance (scope , ModuleScope )
@@ -735,6 +739,11 @@ def addBinding(self, node, value):
735
739
elif isinstance (existing , Importation ) and value .redefines (existing ):
736
740
existing .redefined .append (node )
737
741
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
+
738
747
if value .name in self .scope :
739
748
# then assume the rebound name is used as a global or within a loop
740
749
value .used = self .scope [value .name ].used
@@ -757,6 +766,12 @@ def handleNodeLoad(self, node):
757
766
in_generators = None
758
767
importStarred = None
759
768
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
+
760
775
# try enclosing function scopes and global scope
761
776
for scope in self .scopeStack [- 1 ::- 1 ]:
762
777
if isinstance (scope , ClassScope ):
@@ -833,6 +848,10 @@ def handleNodeStore(self, node):
833
848
scope [name ].used [1 ], name , scope [name ].source )
834
849
break
835
850
851
+ if (isinstance (self .scope , FunctionScope ) and
852
+ name in self .scope .global_names ):
853
+ self .store_global_scope (name , Assignment (name , node ))
854
+
836
855
parent_stmt = self .getParent (node )
837
856
if isinstance (parent_stmt , (ast .For , ast .comprehension )) or (
838
857
parent_stmt != node .parent and
@@ -868,8 +887,15 @@ def on_conditional_branch():
868
887
# be executed.
869
888
return
870
889
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 )
873
899
else :
874
900
try :
875
901
del self .scope [name ]
@@ -1016,6 +1042,10 @@ def handleForwardAnnotation():
1016
1042
def ignore (self , node ):
1017
1043
pass
1018
1044
1045
+ def store_global_scope (self , name , value ):
1046
+ """This store name in global scope"""
1047
+ self ._global_scope ()[name ] = value
1048
+
1019
1049
# "stmt" type nodes
1020
1050
DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \
1021
1051
ASYNCWITH = ASYNCWITHITEM = TRYFINALLY = EXEC = \
@@ -1122,7 +1152,8 @@ def GLOBAL(self, node):
1122
1152
m .message_args [0 ] != node_name ]
1123
1153
1124
1154
# 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 )
1126
1157
1127
1158
# Bind name to non-global scopes, but as already "used".
1128
1159
node_value .used = (global_scope , node )
0 commit comments