Skip to content

Commit 335b4c4

Browse files
committed
remove unreferenced imports
1 parent d57d904 commit 335b4c4

File tree

1 file changed

+77
-25
lines changed

1 file changed

+77
-25
lines changed

pyls/plugins/importmagic_lint.py

+77-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,48 @@ 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+
index = _get_index(sys.path) # TODO (youben): add project path for indexing
139151
actions = []
140152
diagnostics = context.get('diagnostics', [])
141153
for diagnostic in diagnostics:
142154
if diagnostic.get('source') != SOURCE:
143155
continue
144-
m = UNRES_RE.match(diagnostic['message'])
145-
if not m:
146-
continue
156+
message = diagnostic.get('message', '')
157+
if message.startswith('Unreferenced'):
158+
m = UNREF_RE.match(message)
159+
if not m:
160+
continue
161+
unref = m.group('unreferenced')
162+
actions.append(_generate_remove_action(document, index, unref))
163+
elif message.startswith('Unresolved'):
164+
m = UNRES_RE.match(message)
165+
if not m:
166+
continue
167+
unres = m.group('unresolved')
168+
actions.extend(_get_actions_for_unres(document, index, min_score, unres))
147169

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
170+
return actions
151171

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
156172

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

159185
return actions
160186

161187

162188
def _generate_add_action(document, index, module, variable):
163-
# Generate the patch we would need to apply
189+
"""Generate the patch we would need to apply to import a module.
190+
"""
164191
imports = importmagic.Imports(index, document.source)
165192
if variable:
166193
imports.add_import_from(module, variable)
@@ -169,7 +196,7 @@ def _generate_add_action(document, index, module, variable):
169196
start_line, end_line, text = imports.get_update()
170197

171198
action = {
172-
'title': _command_title(variable, module),
199+
'title': _add_command_title(variable, module),
173200
'command': ADD_IMPORT_COMMAND,
174201
'arguments': [{
175202
'uri': document.uri,
@@ -182,9 +209,30 @@ def _generate_add_action(document, index, module, variable):
182209
return action
183210

184211

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

190238
args = arguments[0]
@@ -205,7 +253,11 @@ def pyls_execute_command(workspace, command, arguments):
205253
workspace.apply_edit(edit)
206254

207255

208-
def _command_title(variable, module):
256+
def _add_command_title(variable, module):
209257
if not variable:
210258
return 'Import "%s"' % module
211259
return 'Import "%s" from "%s"' % (variable, module)
260+
261+
262+
def _remove_command_title(import_name):
263+
return 'Remove import of "%s"' % import_name

0 commit comments

Comments
 (0)