@@ -147,6 +147,17 @@ def redefines(self, other):
147
147
return isinstance (other , Definition ) and self .name == other .name
148
148
149
149
150
+ class StarImportation (Importation ):
151
+ """A binding created by an 'from x import *' statement."""
152
+
153
+ def __init__ (self , name , source ):
154
+ super (StarImportation , self ).__init__ ('*' , source )
155
+ # Each star importation needs a unique name, and
156
+ # may not be the module name otherwise it will be deemed imported
157
+ self .name = name + '.*'
158
+ self .fullName = name
159
+
160
+
150
161
class Argument (Binding ):
151
162
"""
152
163
Represents binding a name as an argument.
@@ -358,17 +369,29 @@ def checkDeadScopes(self):
358
369
if isinstance (scope , ClassScope ):
359
370
continue
360
371
361
- if isinstance (scope .get ('__all__' ), ExportBinding ):
362
- all_names = set (scope ['__all__' ].names )
372
+ all_binding = scope .get ('__all__' )
373
+ if all_binding and not isinstance (all_binding , ExportBinding ):
374
+ all_binding = None
375
+
376
+ if all_binding :
377
+ all_names = set (all_binding .names )
378
+ undefined = all_names .difference (scope )
379
+ else :
380
+ all_names = undefined = []
381
+
382
+ if undefined :
363
383
if not scope .importStarred and \
364
384
os .path .basename (self .filename ) != '__init__.py' :
365
385
# Look for possible mistakes in the export list
366
- undefined = all_names .difference (scope )
367
386
for name in undefined :
368
387
self .report (messages .UndefinedExport ,
369
388
scope ['__all__' ].source , name )
370
- else :
371
- all_names = []
389
+
390
+ # mark all import '*' as used by the undefined in __all__
391
+ if scope .importStarred :
392
+ for binding in scope .values ():
393
+ if isinstance (binding , StarImportation ):
394
+ binding .used = all_binding
372
395
373
396
# Look for imported names that aren't used.
374
397
for value in scope .values ():
@@ -504,8 +527,24 @@ def handleNodeLoad(self, node):
504
527
in_generators = isinstance (scope , GeneratorScope )
505
528
506
529
# look in the built-ins
507
- if importStarred or name in self .builtIns :
530
+ if name in self .builtIns :
508
531
return
532
+
533
+ if importStarred :
534
+ from_list = []
535
+
536
+ for scope in self .scopeStack [- 1 ::- 1 ]:
537
+ for binding in scope .values ():
538
+ if isinstance (binding , StarImportation ):
539
+ # mark '*' imports as used for each scope
540
+ binding .used = (self .scope , node )
541
+ from_list .append (binding .fullName )
542
+
543
+ # report * usage, with a list of possible sources
544
+ from_list = ', ' .join (sorted (from_list ))
545
+ self .report (messages .ImportStarUsage , node , name , from_list )
546
+ return
547
+
509
548
if name == '__path__' and os .path .basename (self .filename ) == '__init__.py' :
510
549
# the special name __path__ is valid only in packages
511
550
return
@@ -976,17 +1015,19 @@ def IMPORTFROM(self, node):
976
1015
self .futuresAllowed = False
977
1016
978
1017
for alias in node .names :
1018
+ name = alias .asname or alias .name
979
1019
if alias .name == '*' :
980
1020
# Only Python 2, local import * is a SyntaxWarning
981
1021
if not PY2 and not isinstance (self .scope , ModuleScope ):
982
1022
self .report (messages .ImportStarNotPermitted ,
983
1023
node , node .module )
984
1024
continue
1025
+
985
1026
self .scope .importStarred = True
986
1027
self .report (messages .ImportStarUsed , node , node .module )
987
- continue
988
- name = alias . asname or alias . name
989
- importation = Importation (name , node )
1028
+ importation = StarImportation ( node . module , node )
1029
+ else :
1030
+ importation = Importation (name , node )
990
1031
if node .module == '__future__' :
991
1032
importation .used = (self .scope , node )
992
1033
self .addBinding (node , importation )
0 commit comments