Skip to content

Commit c7e5b36

Browse files
committed
remove unreferenced imports
1 parent d57d904 commit c7e5b36

File tree

1 file changed

+78
-25
lines changed

1 file changed

+78
-25
lines changed

pyls/plugins/importmagic_lint.py

+78-25
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010

1111
SOURCE = 'importmagic'
1212
ADD_IMPORT_COMMAND = 'importmagic.addimport'
13+
REMOVE_IMPORT_COMMAND = 'importmagic.removeimport'
1314
MAX_COMMANDS = 4
1415
UNRES_RE = re.compile(r"Unresolved import '(?P<unresolved>[\w.]+)'")
16+
UNREF_RE = re.compile(r"Unreferenced import '(?P<unreferenced>[\w.]+)'")
1517

1618
_index_cache = {}
1719

@@ -31,9 +33,22 @@ def _get_index(sys_path):
3133
return _index_cache[key]
3234

3335

36+
def _get_imports_list(source, index=None):
37+
"""Get modules, functions and variables that are imported.
38+
"""
39+
if index is None:
40+
index = importmagic.SymbolIndex()
41+
imports = importmagic.Imports(index, source)
42+
imported = [i.name for i in list(imports._imports)]
43+
# Go over from imports
44+
for from_import in list(imports._imports_from.values()):
45+
imported.extend([i.name for i in list(from_import)])
46+
return imported
47+
48+
3449
@hookimpl
3550
def pyls_commands():
36-
return [ADD_IMPORT_COMMAND]
51+
return [ADD_IMPORT_COMMAND, REMOVE_IMPORT_COMMAND]
3752

3853

3954
@hookimpl
@@ -68,10 +83,6 @@ def pyls_lint(document):
6883

6984
# Annoyingly, we only get the text of an unresolved import, so we'll look for it ourselves
7085
for unres in unresolved:
71-
# TODO (youben): delete this test as it double execution time (next for loop will do the same)
72-
if unres not in document.source:
73-
continue
74-
7586
for line_no, line in enumerate(document.lines):
7687
pos = line.find(unres)
7788
if pos < 0:
@@ -93,10 +104,9 @@ def pyls_lint(document):
93104
if pos < 0:
94105
continue
95106

96-
# Find out if the unref is a module or a variable/func
97-
imports = importmagic.Imports(importmagic.SymbolIndex(), document.source)
98-
modules = [m.name for m in list(imports._imports)]
99-
if unref in modules:
107+
# Find out if the unref is an import or a variable/func
108+
imports = _get_imports_list(document.source)
109+
if unref in imports:
100110
message = "Unreferenced import '%s'" % unref
101111
else:
102112
message = "Unreferenced variable/function '%s'" % unref
@@ -119,7 +129,7 @@ def pyls_code_actions(config, document, context):
119129
"""Build a list of actions to be suggested to the user. Each action follow this format:
120130
{
121131
'title': 'importmagic',
122-
'command': command ('importmagic.add_import'),
132+
'command': command,
123133
'arguments':
124134
{
125135
'uri': document.uri,
@@ -136,31 +146,49 @@ def pyls_code_actions(config, document, context):
136146
log.debug("Got importmagic settings: %s", conf)
137147
importmagic.Imports.set_style(**{_utils.camel_to_underscore(k): v for k, v in conf.items()})
138148

149+
# Might be slow but is cached once built
150+
# TODO (youben): add project path for indexing
151+
index = _get_index(sys.path)
139152
actions = []
140153
diagnostics = context.get('diagnostics', [])
141154
for diagnostic in diagnostics:
142155
if diagnostic.get('source') != SOURCE:
143156
continue
144-
m = UNRES_RE.match(diagnostic['message'])
145-
if not m:
146-
continue
157+
message = diagnostic.get('message', '')
158+
if message.startswith('Unreferenced'):
159+
m = UNREF_RE.match(message)
160+
if not m:
161+
continue
162+
unref = m.group('unreferenced')
163+
actions.append(_generate_remove_action(document, index, unref))
164+
elif message.startswith('Unresolved'):
165+
m = UNRES_RE.match(message)
166+
if not m:
167+
continue
168+
unres = m.group('unresolved')
169+
actions.extend(_get_actions_for_unres(document, index, min_score, unres))
147170

148-
unres = m.group('unresolved')
149-
# Might be slow but is cached once built
150-
index = _get_index(sys.path) # TODO (youben): add project path for indexing
171+
return actions
151172

152-
for score, module, variable in sorted(index.symbol_scores(unres)[:MAX_COMMANDS], reverse=True):
153-
if score < min_score:
154-
# Skip low score results
155-
continue
156173

157-
actions.append(_generate_add_action(document, index, module, variable))
174+
def _get_actions_for_unres(document, index, min_score, unres):
175+
"""Get the list of possible actions to be applied to solve an unresolved symbol.
176+
Get a maximun of MAX_COMMANDS actions with the highest score, also filter low score actions
177+
using the min_score value.
178+
"""
179+
actions = []
180+
for score, module, variable in sorted(index.symbol_scores(unres)[:MAX_COMMANDS], reverse=True):
181+
if score < min_score:
182+
# Skip low score results
183+
continue
184+
actions.append(_generate_add_action(document, index, module, variable))
158185

159186
return actions
160187

161188

162189
def _generate_add_action(document, index, module, variable):
163-
# Generate the patch we would need to apply
190+
"""Generate the patch we would need to apply to import a module.
191+
"""
164192
imports = importmagic.Imports(index, document.source)
165193
if variable:
166194
imports.add_import_from(module, variable)
@@ -169,7 +197,7 @@ def _generate_add_action(document, index, module, variable):
169197
start_line, end_line, text = imports.get_update()
170198

171199
action = {
172-
'title': _command_title(variable, module),
200+
'title': _add_command_title(variable, module),
173201
'command': ADD_IMPORT_COMMAND,
174202
'arguments': [{
175203
'uri': document.uri,
@@ -182,9 +210,30 @@ def _generate_add_action(document, index, module, variable):
182210
return action
183211

184212

213+
def _generate_remove_action(document, index, unref):
214+
"""Generate the patch we would need to apply to remove an import.
215+
"""
216+
imports = importmagic.Imports(index, document.source)
217+
imports.remove(unref)
218+
start_line, end_line, text = imports.get_update()
219+
220+
action = {
221+
'title': _remove_command_title(unref),
222+
'command': REMOVE_IMPORT_COMMAND,
223+
'arguments': [{
224+
'uri': document.uri,
225+
'version': document.version,
226+
'startLine': start_line,
227+
'endLine': end_line,
228+
'newText': text
229+
}]
230+
}
231+
return action
232+
233+
185234
@hookimpl
186235
def pyls_execute_command(workspace, command, arguments):
187-
if command != ADD_IMPORT_COMMAND:
236+
if command not in [ADD_IMPORT_COMMAND, REMOVE_IMPORT_COMMAND]:
188237
return
189238

190239
args = arguments[0]
@@ -205,7 +254,11 @@ def pyls_execute_command(workspace, command, arguments):
205254
workspace.apply_edit(edit)
206255

207256

208-
def _command_title(variable, module):
257+
def _add_command_title(variable, module):
209258
if not variable:
210259
return 'Import "%s"' % module
211260
return 'Import "%s" from "%s"' % (variable, module)
261+
262+
263+
def _remove_command_title(import_name):
264+
return 'Remove import of "%s"' % import_name

0 commit comments

Comments
 (0)