Skip to content

Commit 3a324cd

Browse files
committed
updated rope
1 parent 602a1cb commit 3a324cd

5 files changed

Lines changed: 95 additions & 40 deletions

File tree

pythonFiles/rope/base/codeanalyze.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,17 @@ def __call__(self):
129129
i += 1
130130
return result
131131

132-
# Doesn't match quotes which are escaped
133-
_main_tokens = re.compile(r'((?<!\\)(\'\'\'|"""|\'|")|#|\[|\]|\{|\}|\(|\))')
132+
# Matches all backslashes before the token, to detect escaped quotes
133+
_main_tokens = re.compile(r'(\\*)((\'\'\'|"""|\'|")|#|\[|\]|\{|\}|\(|\))')
134134

135135
def _analyze_line(self, line):
136136
token = None
137137
for match in self._main_tokens.finditer(line):
138-
token = match.group()
138+
prefix = match.group(1)
139+
token = match.group(2)
140+
# Skip any tokens which are escaped
141+
if len(prefix) % 2 == 1:
142+
continue
139143
if token in ["'''", '"""', "'", '"']:
140144
if not self.in_string:
141145
self.in_string = token

pythonFiles/rope/base/oi/docstrings.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
from rope.base.exceptions import AttributeNotFoundError
2828
from rope.base.evaluate import ScopeNameFinder
29-
from rope.base.pyobjects import PyClass
29+
from rope.base.pyobjects import PyClass, PyFunction
3030

3131
PEP0484_PATTERNS = [
3232
re.compile(r'type:\s*([^\n, ]+)'),
@@ -111,9 +111,12 @@ def _get_superfunc(pyfunc):
111111

112112
for cls in _get_mro(pyfunc.parent)[1:]:
113113
try:
114-
return cls.get_attribute(pyfunc.get_name()).get_object()
114+
superfunc = cls.get_attribute(pyfunc.get_name()).get_object()
115115
except AttributeNotFoundError:
116116
pass
117+
else:
118+
if isinstance(superfunc, PyFunction):
119+
return superfunc
117120

118121

119122
def _get_mro(pyclass):

pythonFiles/rope/refactor/importutils/module_imports.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def force_single_imports(self):
162162
"""force a single import per statement"""
163163
for import_stmt in self.imports[:]:
164164
import_info = import_stmt.import_info
165-
if import_info.is_empty():
165+
if import_info.is_empty() or import_stmt.readonly:
166166
continue
167167
if len(import_info.names_and_aliases) > 1:
168168
for name_and_alias in import_info.names_and_aliases:

pythonFiles/rope/refactor/move.py

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ def create_move(project, resource, offset=None):
2222
return MoveModule(project, resource)
2323
this_pymodule = project.get_pymodule(resource)
2424
pyname = evaluate.eval_location(this_pymodule, offset)
25-
if pyname is None:
26-
raise exceptions.RefactoringError(
27-
'Move only works on classes, functions, modules and methods.')
28-
pyobject = pyname.get_object()
29-
if isinstance(pyobject, pyobjects.PyModule) or \
30-
isinstance(pyobject, pyobjects.PyPackage):
31-
return MoveModule(project, pyobject.get_resource())
32-
if isinstance(pyobject, pyobjects.PyFunction) and \
33-
isinstance(pyobject.parent, pyobjects.PyClass):
34-
return MoveMethod(project, resource, offset)
35-
if isinstance(pyobject, pyobjects.PyDefinedObject) and \
36-
isinstance(pyobject.parent, pyobjects.PyModule):
37-
return MoveGlobal(project, resource, offset)
25+
if pyname is not None:
26+
pyobject = pyname.get_object()
27+
if isinstance(pyobject, pyobjects.PyModule) or \
28+
isinstance(pyobject, pyobjects.PyPackage):
29+
return MoveModule(project, pyobject.get_resource())
30+
if isinstance(pyobject, pyobjects.PyFunction) and \
31+
isinstance(pyobject.parent, pyobjects.PyClass):
32+
return MoveMethod(project, resource, offset)
33+
if isinstance(pyobject, pyobjects.PyDefinedObject) and \
34+
isinstance(pyobject.parent, pyobjects.PyModule) or \
35+
isinstance(pyname, pynames.AssignedName):
36+
return MoveGlobal(project, resource, offset)
3837
raise exceptions.RefactoringError(
39-
'Move only works on global classes/functions, modules and methods.')
38+
'Move only works on global classes/functions/variables, modules and '
39+
'methods.')
4040

4141

4242
class MoveMethod(object):
@@ -203,42 +203,63 @@ def __init__(self, project, resource, offset):
203203
self.project = project
204204
this_pymodule = self.project.get_pymodule(resource)
205205
self.old_pyname = evaluate.eval_location(this_pymodule, offset)
206+
if self.old_pyname is None:
207+
raise exceptions.RefactoringError(
208+
'Move refactoring should be performed on a '
209+
'class/function/variable.')
210+
if self._is_variable(self.old_pyname):
211+
self.old_name = worder.get_name_at(resource, offset)
212+
pymodule = this_pymodule
213+
else:
214+
self.old_name = self.old_pyname.get_object().get_name()
215+
pymodule = self.old_pyname.get_object().get_module()
206216
self._check_exceptional_conditions()
207-
self.old_name = self.old_pyname.get_object().get_name()
208-
pymodule = self.old_pyname.get_object().get_module()
209217
self.source = pymodule.get_resource()
210218
self.tools = _MoveTools(self.project, self.source,
211219
self.old_pyname, self.old_name)
212220
self.import_tools = self.tools.import_tools
213221

214222
def _import_filter(self, stmt):
215223
module_name = libutils.modname(self.source)
224+
216225
if isinstance(stmt.import_info, importutils.NormalImport):
226+
# Affect any statement that imports the source module
217227
return any(module_name == name
218228
for name, alias in stmt.import_info.names_and_aliases)
219229
elif isinstance(stmt.import_info, importutils.FromImport):
230+
# Affect statements importing from the source package
220231
if '.' in module_name:
221-
package_name = '.'.join(module_name.split('.')[:-1])
222-
if stmt.import_info.module_name == package_name:
232+
package_name, basename = module_name.rsplit('.', 1)
233+
if (stmt.import_info.module_name == package_name and
234+
any(basename == name
235+
for name, alias in stmt.import_info.names_and_aliases)):
223236
return True
224237
return stmt.import_info.module_name == module_name
225238
return False
226239

227240
def _check_exceptional_conditions(self):
228-
if self.old_pyname is None or \
229-
not isinstance(self.old_pyname.get_object(),
230-
pyobjects.PyDefinedObject):
231-
raise exceptions.RefactoringError(
232-
'Move refactoring should be performed on a class/function.')
233-
moving_pyobject = self.old_pyname.get_object()
234-
if not self._is_global(moving_pyobject):
235-
raise exceptions.RefactoringError(
236-
'Move refactoring should be performed ' +
237-
'on a global class/function.')
241+
if self._is_variable(self.old_pyname):
242+
pymodule = self.old_pyname.get_definition_location()[0]
243+
try:
244+
pymodule.get_scope().get_name(self.old_name)
245+
except exceptions.NameNotFoundError:
246+
self._raise_refactoring_error()
247+
elif not (isinstance(self.old_pyname.get_object(),
248+
pyobjects.PyDefinedObject) and
249+
self._is_global(self.old_pyname.get_object())):
250+
self._raise_refactoring_error()
251+
252+
def _raise_refactoring_error(self):
253+
raise exceptions.RefactoringError(
254+
'Move refactoring should be performed on a global class, function '
255+
'or variable.')
238256

239257
def _is_global(self, pyobject):
240258
return pyobject.get_scope().parent == pyobject.get_module().get_scope()
241259

260+
def _is_variable(self, pyname):
261+
return isinstance(pyname, pynames.AssignedName)
262+
242263
def get_changes(self, dest, resources=None,
243264
task_handle=taskhandle.NullTaskHandle()):
244265
if resources is None:
@@ -367,9 +388,23 @@ def _get_moving_element(self):
367388
def _get_moving_region(self):
368389
pymodule = self.project.get_pymodule(self.source)
369390
lines = pymodule.lines
370-
scope = self.old_pyname.get_object().get_scope()
371-
start = lines.get_line_start(scope.get_start())
372-
end_line = scope.get_end()
391+
if self._is_variable(self.old_pyname):
392+
logical_lines = pymodule.logical_lines
393+
lineno = logical_lines.logical_line_in(
394+
self.old_pyname.get_definition_location()[1])[0]
395+
start = lines.get_line_start(lineno)
396+
end_line = logical_lines.logical_line_in(lineno)[1]
397+
else:
398+
scope = self.old_pyname.get_object().get_scope()
399+
start = lines.get_line_start(scope.get_start())
400+
end_line = scope.get_end()
401+
402+
# Include comment lines before the definition
403+
start_line = lines.get_line_number(start)
404+
while start_line > 1 and lines.get_line(start_line - 1).startswith('#'):
405+
start_line -= 1
406+
start = lines.get_line_start(start_line)
407+
373408
while end_line < lines.length() and \
374409
lines.get_line(end_line + 1).strip() == '':
375410
end_line += 1
@@ -650,6 +685,17 @@ def _add_imports_to_module(import_tools, pymodule, new_imports):
650685
def moving_code_with_imports(project, resource, source):
651686
import_tools = importutils.ImportTools(project)
652687
pymodule = libutils.get_string_module(project, source, resource)
688+
689+
# Strip comment prefix, if any. These need to stay before the moving
690+
# section, but imports would be added between them.
691+
lines = codeanalyze.SourceLinesAdapter(source)
692+
start = 1
693+
while start < lines.length() and lines.get_line(start).startswith('#'):
694+
start += 1
695+
moving_prefix = source[:lines.get_line_start(start)]
696+
pymodule = libutils.get_string_module(
697+
project, source[lines.get_line_start(start):], resource)
698+
653699
origin = project.get_pymodule(resource)
654700

655701
imports = []
@@ -680,7 +726,9 @@ def moving_code_with_imports(project, resource, source):
680726
lines = codeanalyze.SourceLinesAdapter(source)
681727
while start < lines.length() and not lines.get_line(start).strip():
682728
start += 1
683-
moving = source[lines.get_line_start(start):]
729+
730+
# Reinsert the prefix which was removed at the beginning
731+
moving = moving_prefix + source[lines.get_line_start(start):]
684732
return moving, imports
685733

686734

pythonFiles/rope/refactor/patchedast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,8 +821,8 @@ def __getslice__(self, i, j):
821821

822822
def _get_number_pattern(self):
823823
# HACK: It is merely an approaximation and does the job
824-
integer = r'(0|0x)?[\da-fA-F]+[lL]?'
825-
return r'(%s(\.\d*)?|(\.\d+))([eE][-+]?\d*)?[jJ]?' % integer
824+
integer = r'\-?(0x[\da-fA-F]+|\d+)[lL]?'
825+
return r'(%s(\.\d*)?|(\.\d+))([eE][-+]?\d+)?[jJ]?' % integer
826826

827827
_string_pattern = None
828828
_number_pattern = None

0 commit comments

Comments
 (0)