@@ -417,6 +417,7 @@ def __init__(self):
417
417
super (FunctionScope , self ).__init__ ()
418
418
# Simplify: manage the special locals as globals
419
419
self .globals = self .alwaysUsed .copy ()
420
+ self .global_names = []
420
421
self .returnValue = None # First non-empty return
421
422
self .isGenerator = False # Detect a generator
422
423
@@ -959,6 +960,15 @@ def handleForwardAnnotation():
959
960
def ignore (self , node ):
960
961
pass
961
962
963
+ def store_global_scope (self , name ):
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 , alias ))
971
+
962
972
# "stmt" type nodes
963
973
DELETE = PRINT = FOR = ASYNCFOR = WHILE = IF = WITH = WITHITEM = \
964
974
ASYNCWITH = ASYNCWITHITEM = RAISE = TRYFINALLY = EXEC = \
@@ -1052,7 +1062,8 @@ def GLOBAL(self, node):
1052
1062
m .message_args [0 ] != node_name ]
1053
1063
1054
1064
# 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 )
1056
1067
1057
1068
# Bind name to non-global scopes, but as already "used".
1058
1069
node_value .used = (global_scope , node )
@@ -1074,17 +1085,33 @@ def NAME(self, node):
1074
1085
"""
1075
1086
Handle occurrence of Name (which can be a load/store/delete access.)
1076
1087
"""
1088
+ global_scope_index = 1 if self ._in_doctest () else 0
1089
+ global_scope = self .scopeStack [global_scope_index ]
1077
1090
# Locate the name in locals / function / globals scopes.
1078
1091
if isinstance (node .ctx , (ast .Load , ast .AugLoad )):
1079
1092
self .handleNodeLoad (node )
1080
1093
if (node .id == 'locals' and isinstance (self .scope , FunctionScope )
1081
1094
and isinstance (node .parent , ast .Call )):
1082
1095
# we are doing locals() call in current scope
1083
1096
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 )
1084
1101
elif isinstance (node .ctx , (ast .Store , ast .AugStore )):
1085
1102
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 ))
1086
1106
elif isinstance (node .ctx , ast .Del ):
1087
1107
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 )
1088
1115
else :
1089
1116
# must be a Param context -- this only happens for names in function
1090
1117
# arguments, but these aren't dispatched through here
@@ -1292,13 +1319,16 @@ def TUPLE(self, node):
1292
1319
1293
1320
def IMPORT (self , node ):
1294
1321
for alias in node .names :
1322
+ name = alias .name
1295
1323
if '.' in alias .name and not alias .asname :
1296
- importation = SubmoduleImportation (alias . name , node )
1324
+ importation = SubmoduleImportation (name , node )
1297
1325
else :
1298
1326
name = alias .asname or alias .name
1299
1327
importation = Importation (name , node , alias .name )
1300
1328
self .addBinding (node , importation )
1301
1329
1330
+ self .store_global_scope (name )
1331
+
1302
1332
def IMPORTFROM (self , node ):
1303
1333
if node .module == '__future__' :
1304
1334
if not self .futuresAllowed :
@@ -1331,6 +1361,8 @@ def IMPORTFROM(self, node):
1331
1361
module , alias .name )
1332
1362
self .addBinding (node , importation )
1333
1363
1364
+ self .store_global_scope (name )
1365
+
1334
1366
def TRY (self , node ):
1335
1367
handler_names = []
1336
1368
# List the exception handlers
0 commit comments