mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 05:54:25 +08:00
Remove the old refactoring module
This commit is contained in:
@@ -4,7 +4,6 @@ omit =
|
|||||||
jedi/inference/compiled/subprocess/__main__.py
|
jedi/inference/compiled/subprocess/__main__.py
|
||||||
jedi/__main__.py
|
jedi/__main__.py
|
||||||
# For now this is not being used.
|
# For now this is not being used.
|
||||||
jedi/refactoring.py
|
|
||||||
|
|
||||||
[report]
|
[report]
|
||||||
# Regexes for lines to exclude from consideration
|
# Regexes for lines to exclude from consideration
|
||||||
|
|||||||
@@ -150,10 +150,10 @@ Docstrings (inference/docstrings.py)
|
|||||||
|
|
||||||
.. _refactoring:
|
.. _refactoring:
|
||||||
|
|
||||||
Refactoring (inference/refactoring.py)
|
Refactoring (inference/api/refactoring.py)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. automodule:: jedi.refactoring
|
.. automodule:: jedi.api.refactoring
|
||||||
|
|
||||||
|
|
||||||
.. _imports-modules:
|
.. _imports-modules:
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
"""
|
|
||||||
THIS is not in active development, please check
|
|
||||||
https://github.com/davidhalter/jedi/issues/667 first before editing.
|
|
||||||
|
|
||||||
Introduce some basic refactoring functions to |jedi|. This module is still in a
|
|
||||||
very early development stage and needs much testing and improvement.
|
|
||||||
|
|
||||||
.. warning:: I won't do too much here, but if anyone wants to step in, please
|
|
||||||
do. Refactoring is none of my priorities
|
|
||||||
|
|
||||||
It uses the |jedi| `API <api.html>`_ and supports currently the
|
|
||||||
following functions (sometimes bug-prone):
|
|
||||||
|
|
||||||
- rename
|
|
||||||
- extract variable
|
|
||||||
- inline variable
|
|
||||||
"""
|
|
||||||
import difflib
|
|
||||||
|
|
||||||
from parso import python_bytes_to_unicode, split_lines
|
|
||||||
from jedi.inference import helpers
|
|
||||||
|
|
||||||
|
|
||||||
class Refactoring(object):
|
|
||||||
def __init__(self, change_dct):
|
|
||||||
"""
|
|
||||||
:param change_dct: dict(old_path=(new_path, old_lines, new_lines))
|
|
||||||
"""
|
|
||||||
self.change_dct = change_dct
|
|
||||||
|
|
||||||
def old_files(self):
|
|
||||||
dct = {}
|
|
||||||
for old_path, (new_path, old_l, new_l) in self.change_dct.items():
|
|
||||||
dct[old_path] = '\n'.join(old_l)
|
|
||||||
return dct
|
|
||||||
|
|
||||||
def new_files(self):
|
|
||||||
dct = {}
|
|
||||||
for old_path, (new_path, old_l, new_l) in self.change_dct.items():
|
|
||||||
dct[new_path] = '\n'.join(new_l)
|
|
||||||
return dct
|
|
||||||
|
|
||||||
def diff(self):
|
|
||||||
texts = []
|
|
||||||
for old_path, (new_path, old_l, new_l) in self.change_dct.items():
|
|
||||||
if old_path:
|
|
||||||
udiff = difflib.unified_diff(old_l, new_l)
|
|
||||||
else:
|
|
||||||
udiff = difflib.unified_diff(old_l, new_l, old_path, new_path)
|
|
||||||
texts.append('\n'.join(udiff))
|
|
||||||
return '\n'.join(texts)
|
|
||||||
|
|
||||||
|
|
||||||
def rename(script, new_name):
|
|
||||||
""" The `args` / `kwargs` params are the same as in `api.Script`.
|
|
||||||
:param new_name: The new name of the script.
|
|
||||||
:param script: The source Script object.
|
|
||||||
:return: list of changed lines/changed files
|
|
||||||
"""
|
|
||||||
return Refactoring(_rename(script.get_references(), new_name))
|
|
||||||
|
|
||||||
|
|
||||||
def _rename(names, replace_str):
|
|
||||||
""" For both rename and inline. """
|
|
||||||
order = sorted(names, key=lambda x: (x.module_path, x.line, x.column),
|
|
||||||
reverse=True)
|
|
||||||
|
|
||||||
def process(path, old_lines, new_lines):
|
|
||||||
if new_lines is not None: # goto next file, save last
|
|
||||||
dct[path] = path, old_lines, new_lines
|
|
||||||
|
|
||||||
dct = {}
|
|
||||||
current_path = object()
|
|
||||||
new_lines = old_lines = None
|
|
||||||
for name in order:
|
|
||||||
if name.in_builtin_module():
|
|
||||||
continue
|
|
||||||
if current_path != name.module_path:
|
|
||||||
current_path = name.module_path
|
|
||||||
|
|
||||||
process(current_path, old_lines, new_lines)
|
|
||||||
if current_path is not None:
|
|
||||||
# None means take the source that is a normal param.
|
|
||||||
with open(current_path) as f:
|
|
||||||
source = f.read()
|
|
||||||
|
|
||||||
new_lines = split_lines(python_bytes_to_unicode(source))
|
|
||||||
old_lines = new_lines[:]
|
|
||||||
|
|
||||||
nr, indent = name.line, name.column
|
|
||||||
line = new_lines[nr - 1]
|
|
||||||
new_lines[nr - 1] = line[:indent] + replace_str + \
|
|
||||||
line[indent + len(name.name):]
|
|
||||||
process(current_path, old_lines, new_lines)
|
|
||||||
return dct
|
|
||||||
|
|
||||||
|
|
||||||
def extract(script, new_name):
|
|
||||||
""" The `args` / `kwargs` params are the same as in `api.Script`.
|
|
||||||
:param operation: The refactoring operation to execute.
|
|
||||||
:type operation: str
|
|
||||||
:type source: str
|
|
||||||
:return: list of changed lines/changed files
|
|
||||||
"""
|
|
||||||
new_lines = split_lines(python_bytes_to_unicode(script.source))
|
|
||||||
old_lines = new_lines[:]
|
|
||||||
|
|
||||||
user_stmt = script._parser.user_stmt()
|
|
||||||
|
|
||||||
# TODO care for multi-line extracts
|
|
||||||
dct = {}
|
|
||||||
if user_stmt:
|
|
||||||
pos = script._pos
|
|
||||||
line_index = pos[0] - 1
|
|
||||||
# Be careful here. 'array_for_pos' does not exist in 'helpers'.
|
|
||||||
arr, index = helpers.array_for_pos(user_stmt, pos)
|
|
||||||
if arr is not None:
|
|
||||||
start_pos = arr[index].start_pos
|
|
||||||
end_pos = arr[index].end_pos
|
|
||||||
|
|
||||||
# take full line if the start line is different from end line
|
|
||||||
e = end_pos[1] if end_pos[0] == start_pos[0] else None
|
|
||||||
start_line = new_lines[start_pos[0] - 1]
|
|
||||||
text = start_line[start_pos[1]:e]
|
|
||||||
for l in range(start_pos[0], end_pos[0] - 1):
|
|
||||||
text += '\n' + str(l)
|
|
||||||
if e is None:
|
|
||||||
end_line = new_lines[end_pos[0] - 1]
|
|
||||||
text += '\n' + end_line[:end_pos[1]]
|
|
||||||
|
|
||||||
# remove code from new lines
|
|
||||||
t = text.lstrip()
|
|
||||||
del_start = start_pos[1] + len(text) - len(t)
|
|
||||||
|
|
||||||
text = t.rstrip()
|
|
||||||
del_end = len(t) - len(text)
|
|
||||||
if e is None:
|
|
||||||
new_lines[end_pos[0] - 1] = end_line[end_pos[1] - del_end:]
|
|
||||||
e = len(start_line)
|
|
||||||
else:
|
|
||||||
e = e - del_end
|
|
||||||
start_line = start_line[:del_start] + new_name + start_line[e:]
|
|
||||||
new_lines[start_pos[0] - 1] = start_line
|
|
||||||
new_lines[start_pos[0]:end_pos[0] - 1] = []
|
|
||||||
|
|
||||||
# add parentheses in multi-line case
|
|
||||||
open_brackets = ['(', '[', '{']
|
|
||||||
close_brackets = [')', ']', '}']
|
|
||||||
if '\n' in text and not (text[0] in open_brackets and text[-1]
|
|
||||||
== close_brackets[open_brackets.index(text[0])]):
|
|
||||||
text = '(%s)' % text
|
|
||||||
|
|
||||||
# add new line before statement
|
|
||||||
indent = user_stmt.start_pos[1]
|
|
||||||
new = "%s%s = %s" % (' ' * indent, new_name, text)
|
|
||||||
new_lines.insert(line_index, new)
|
|
||||||
dct[script.path] = script.path, old_lines, new_lines
|
|
||||||
return Refactoring(dct)
|
|
||||||
|
|
||||||
|
|
||||||
def inline(script):
|
|
||||||
"""
|
|
||||||
:type script: api.Script
|
|
||||||
"""
|
|
||||||
new_lines = split_lines(python_bytes_to_unicode(script.source))
|
|
||||||
|
|
||||||
dct = {}
|
|
||||||
|
|
||||||
definitions = script.goto()
|
|
||||||
assert len(definitions) == 1
|
|
||||||
stmt = definitions[0]._definition
|
|
||||||
references = script.get_references()
|
|
||||||
inlines = [r for r in references
|
|
||||||
if not stmt.start_pos <= (r.line, r.column) <= stmt.end_pos]
|
|
||||||
inlines = sorted(inlines, key=lambda x: (x.module_path, x.line, x.column),
|
|
||||||
reverse=True)
|
|
||||||
expression_list = stmt.expression_list()
|
|
||||||
# don't allow multi-line refactorings for now.
|
|
||||||
assert stmt.start_pos[0] == stmt.end_pos[0]
|
|
||||||
index = stmt.start_pos[0] - 1
|
|
||||||
|
|
||||||
line = new_lines[index]
|
|
||||||
replace_str = line[expression_list[0].start_pos[1]:stmt.end_pos[1] + 1]
|
|
||||||
replace_str = replace_str.strip()
|
|
||||||
# tuples need parentheses
|
|
||||||
if expression_list and expression_list[0].type == 'TODO':
|
|
||||||
arr = expression_list[0]
|
|
||||||
if replace_str[0] not in ['(', '[', '{'] and len(arr) > 1:
|
|
||||||
replace_str = '(%s)' % replace_str
|
|
||||||
|
|
||||||
# if it's the only assignment, remove the statement
|
|
||||||
if len(stmt.get_defined_names()) == 1:
|
|
||||||
line = line[:stmt.start_pos[1]] + line[stmt.end_pos[1]:]
|
|
||||||
|
|
||||||
dct = _rename(inlines, replace_str)
|
|
||||||
# remove the empty line
|
|
||||||
new_lines = dct[script.path][2]
|
|
||||||
if line.strip():
|
|
||||||
new_lines[index] = line
|
|
||||||
else:
|
|
||||||
new_lines.pop(index)
|
|
||||||
|
|
||||||
return Refactoring(dct)
|
|
||||||
Reference in New Issue
Block a user