@@ -136,16 +136,83 @@ class Importation(Definition):
136
136
@type fullName: C{str}
137
137
"""
138
138
139
- def __init__ (self , name , source ):
140
- self .fullName = name
139
+ def __init__ (self , name , source , full_name = None ):
140
+ self .fullName = full_name or name
141
141
self .redefined = []
142
- name = name .split ('.' )[0 ]
143
142
super (Importation , self ).__init__ (name , source )
144
143
144
+ def redefines (self , other ):
145
+ return isinstance (other , Definition ) and self .name == other .name
146
+
147
+ def _has_alias (self ):
148
+ """Return whether importation needs an as clause."""
149
+ return not self .fullName .split ('.' )[- 1 ] == self .name
150
+
151
+ @property
152
+ def source_statement (self ):
153
+ """Generate a source statement equivalent to the import."""
154
+ if self ._has_alias ():
155
+ return 'import %s as %s' % (self .fullName , self .name )
156
+ else :
157
+ return 'import %s' % self .fullName
158
+
159
+ def __str__ (self ):
160
+ """Return import full name with alias."""
161
+ if self ._has_alias ():
162
+ return self .fullName + ' as ' + self .name
163
+ else :
164
+ return self .fullName
165
+
166
+
167
+ class SubmoduleImportation (Importation ):
168
+
169
+ def __init__ (self , name , source ):
170
+ # A dot should only appear in the name when it is a submodule import
171
+ # without an 'as' clause, which is a special type of import where the
172
+ # root module is implicitly imported, and the submodules are also
173
+ # accessible because Python does not restrict which attributes of the
174
+ # root module may be used.
175
+ assert '.' in name and (not source or isinstance (source , ast .Import ))
176
+ package_name = name .split ('.' )[0 ]
177
+ super (SubmoduleImportation , self ).__init__ (package_name , source )
178
+ self .fullName = name
179
+
145
180
def redefines (self , other ):
146
181
if isinstance (other , Importation ):
147
182
return self .fullName == other .fullName
148
- return isinstance (other , Definition ) and self .name == other .name
183
+ return super (SubmoduleImportation , self ).redefines (other )
184
+
185
+ def __str__ (self ):
186
+ return self .fullName
187
+
188
+ @property
189
+ def source_statement (self ):
190
+ return 'import ' + self .fullName
191
+
192
+
193
+ class ImportationFrom (Importation ):
194
+
195
+ def __init__ (self , name , source , module , real_name = None ):
196
+ self .module = module
197
+ self .real_name = real_name or name
198
+ full_name = module + '.' + self .real_name
199
+ super (ImportationFrom , self ).__init__ (name , source , full_name )
200
+
201
+ def __str__ (self ):
202
+ """Return import full name with alias."""
203
+ if self .real_name != self .name :
204
+ return self .fullName + ' as ' + self .name
205
+ else :
206
+ return self .fullName
207
+
208
+ @property
209
+ def source_statement (self ):
210
+ if self .real_name != self .name :
211
+ return 'from %s import %s as %s' % (self .module ,
212
+ self .real_name ,
213
+ self .name )
214
+ else :
215
+ return 'from %s import %s' % (self .module , self .name )
149
216
150
217
151
218
class StarImportation (Importation ):
@@ -158,16 +225,23 @@ def __init__(self, name, source):
158
225
self .name = name + '.*'
159
226
self .fullName = name
160
227
228
+ @property
229
+ def source_statement (self ):
230
+ return 'from ' + self .fullName + ' import *'
161
231
162
- class FutureImportation (Importation ):
232
+ def __str__ (self ):
233
+ return self .name
234
+
235
+
236
+ class FutureImportation (ImportationFrom ):
163
237
"""
164
238
A binding created by a from `__future__` import statement.
165
239
166
240
`__future__` imports are implicitly used.
167
241
"""
168
242
169
243
def __init__ (self , name , source , scope ):
170
- super (FutureImportation , self ).__init__ (name , source )
244
+ super (FutureImportation , self ).__init__ (name , source , '__future__' )
171
245
self .used = (scope , source )
172
246
173
247
@@ -430,7 +504,7 @@ def checkDeadScopes(self):
430
504
used = value .used or value .name in all_names
431
505
if not used :
432
506
messg = messages .UnusedImport
433
- self .report (messg , value .source , value . name )
507
+ self .report (messg , value .source , str ( value ) )
434
508
for node in value .redefined :
435
509
if isinstance (self .getParent (node ), ast .For ):
436
510
messg = messages .ImportShadowedByLoopVar
@@ -1039,8 +1113,11 @@ def TUPLE(self, node):
1039
1113
1040
1114
def IMPORT (self , node ):
1041
1115
for alias in node .names :
1042
- name = alias .asname or alias .name
1043
- importation = Importation (name , node )
1116
+ if '.' in alias .name and not alias .asname :
1117
+ importation = SubmoduleImportation (alias .name , node )
1118
+ else :
1119
+ name = alias .asname or alias .name
1120
+ importation = Importation (name , node , alias .name )
1044
1121
self .addBinding (node , importation )
1045
1122
1046
1123
def IMPORTFROM (self , node ):
@@ -1069,7 +1146,8 @@ def IMPORTFROM(self, node):
1069
1146
self .report (messages .ImportStarUsed , node , node .module )
1070
1147
importation = StarImportation (node .module , node )
1071
1148
else :
1072
- importation = Importation (name , node )
1149
+ importation = ImportationFrom (name , node ,
1150
+ node .module , alias .name )
1073
1151
self .addBinding (node , importation )
1074
1152
1075
1153
def TRY (self , node ):
0 commit comments