diff --git a/AUTHORS b/AUTHORS index c09fe72d..ef6d0bbc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -47,3 +47,4 @@ Contributors: * lee (loyalpartner); * nixon; * tramchamploo; +* Tyler Fenby (https://github.com/TFenby) diff --git a/pymode/libs2/rope/__init__.py b/pymode/libs2/rope/__init__.py index 19466380..c8e11f68 100644 --- a/pymode/libs2/rope/__init__.py +++ b/pymode/libs2/rope/__init__.py @@ -1,7 +1,7 @@ """rope, a python refactoring library""" INFO = __doc__ -VERSION = '0.9.4' +VERSION = '0.10.2' COPYRIGHT = """\ Copyright (C) 2006-2012 Ali Gholami Rudi Copyright (C) 2009-2012 Anton Gritsay diff --git a/pymode/libs2/rope/base/arguments.py b/pymode/libs2/rope/base/arguments.py index 342e2ae5..7ba43640 100644 --- a/pymode/libs2/rope/base/arguments.py +++ b/pymode/libs2/rope/base/arguments.py @@ -72,6 +72,8 @@ def get_pynames(self, parameters): def get_instance_pyname(self): return self.pynames[0] + + class MixedArguments(object): def __init__(self, pyname, arguments, scope): diff --git a/pymode/libs2/rope/base/builtins.py b/pymode/libs2/rope/base/builtins.py index 78e7afb0..5bb84859 100644 --- a/pymode/libs2/rope/base/builtins.py +++ b/pymode/libs2/rope/base/builtins.py @@ -149,8 +149,10 @@ def _get_builtin(*args): return cls._generated[args] return _get_builtin + def _create_builtin_getter(cls): type_getter = _create_builtin_type_getter(cls) + def _get_builtin(*args): return pyobjects.PyObject(type_getter(*args)) return _get_builtin @@ -233,7 +235,7 @@ def __call__(self, name, returned=None, function=None, except AttributeError: if check_existence: raise - builtin=None + builtin = None self.attributes[name] = BuiltinName( BuiltinFunction(returned=returned, function=function, argnames=argnames, builtin=builtin)) @@ -252,7 +254,8 @@ def __init__(self, holding=None): collector('__new__', function=self._new_list) # Adding methods - collector('append', function=self._list_add, argnames=['self', 'value']) + collector('append', function=self._list_add, + argnames=['self', 'value']) collector('__setitem__', function=self._list_add, argnames=['self', 'index', 'value']) collector('insert', function=self._list_add, @@ -306,7 +309,6 @@ class Dict(BuiltinClass): def __init__(self, keys=None, values=None): self.keys = keys self.values = values - item = get_tuple(self.keys, self.values) collector = _AttributeCollector(dict) collector('__new__', function=self._new_dict) collector('__setitem__', function=self._dict_add) @@ -327,7 +329,8 @@ def do_create(holding=None): if holding is None: return get_dict() type = holding.get_type() - if isinstance(type, Tuple) and len(type.get_holding_objects()) == 2: + if isinstance(type, Tuple) and \ + len(type.get_holding_objects()) == 2: return get_dict(*type.get_holding_objects()) return _create_builtin(args, do_create) @@ -384,7 +387,7 @@ def _self_set(self, context): if new_dict and isinstance(new_dict.get_object().get_type(), Dict): args = arguments.ObjectArguments([new_dict]) items = new_dict.get_object()['popitem'].\ - get_object().get_returned_object(args) + get_object().get_returned_object(args) context.save_per_name(items) else: holding = _infer_sequence_for_pyname(new_dict) @@ -405,7 +408,8 @@ def __init__(self, *objects): first = objects[0] attributes = { '__getitem__': BuiltinName(BuiltinFunction(first)), - '__getslice__': BuiltinName(BuiltinFunction(pyobjects.PyObject(self))), + '__getslice__': + BuiltinName(BuiltinFunction(pyobjects.PyObject(self))), '__new__': BuiltinName(BuiltinFunction(function=self._new_tuple)), '__iter__': BuiltinName(BuiltinFunction(get_iterator(first)))} super(Tuple, self).__init__(tuple, attributes) @@ -485,8 +489,9 @@ def __init__(self): self_methods = ['__getitem__', '__getslice__', 'capitalize', 'center', 'decode', 'encode', 'expandtabs', 'join', 'ljust', - 'lower', 'lstrip', 'replace', 'rjust', 'rstrip', 'strip', - 'swapcase', 'title', 'translate', 'upper', 'zfill'] + 'lower', 'lstrip', 'replace', 'rjust', 'rstrip', + 'strip', 'swapcase', 'title', 'translate', 'upper', + 'zfill'] for method in self_methods: collector(method, self_object) @@ -514,6 +519,7 @@ def get_object(self): def get_definition_location(self): return (None, None) + class Iterator(pyobjects.AbstractClass): def __init__(self, holding=None): @@ -539,7 +545,8 @@ def __init__(self, holding=None): self.holding = holding self.attributes = { 'next': BuiltinName(BuiltinFunction(self.holding)), - '__iter__': BuiltinName(BuiltinFunction(get_iterator(self.holding))), + '__iter__': BuiltinName(BuiltinFunction( + get_iterator(self.holding))), 'close': BuiltinName(BuiltinFunction()), 'send': BuiltinName(BuiltinFunction()), 'throw': BuiltinName(BuiltinFunction())} @@ -556,10 +563,10 @@ def get_returned_object(self, args): class File(BuiltinClass): def __init__(self): - self_object = pyobjects.PyObject(self) str_object = get_str() str_list = get_list(get_str()) attributes = {} + def add(name, returned=None, function=None): builtin = getattr(file, name, None) attributes[name] = BuiltinName( @@ -587,7 +594,8 @@ def __init__(self, fget=None, fset=None, fdel=None, fdoc=None): 'fget': BuiltinName(BuiltinFunction()), 'fset': BuiltinName(pynames.UnboundName()), 'fdel': BuiltinName(pynames.UnboundName()), - '__new__': BuiltinName(BuiltinFunction(function=_property_function))} + '__new__': BuiltinName( + BuiltinFunction(function=_property_function))} super(Property, self).__init__(property, attributes) def get_property_object(self, args): @@ -631,7 +639,7 @@ def get_attributes(self): return {} def get_name(self): - return 'lambda' + return 'lambda' def get_param_names(self, special_args=True): result = [node.id for node in self.arguments.args @@ -671,7 +679,7 @@ def _infer_sequence_for_pyname(pyname): iter = obj.get_returned_object(args) if iter is not None and 'next' in iter: holding = iter['next'].get_object().\ - get_returned_object(args) + get_returned_object(args) return holding @@ -690,12 +698,15 @@ def _create_builtin(args, creator): def _range_function(args): return get_list() + def _reversed_function(args): return _create_builtin(args, get_iterator) + def _sorted_function(args): return _create_builtin(args, get_list) + def _super_function(args): passed_class, passed_self = args.get_arguments(['type', 'self']) if passed_self is None: @@ -709,6 +720,7 @@ def _super_function(args): return pyobjects.PyObject(supers[0]) return passed_self + def _zip_function(args): args = args.get_pynames(['sequence']) objects = [] @@ -721,6 +733,7 @@ def _zip_function(args): tuple = get_tuple(*objects) return get_list(tuple) + def _enumerate_function(args): passed = args.get_pynames(['sequence'])[0] if passed is None: @@ -730,6 +743,7 @@ def _enumerate_function(args): tuple = get_tuple(None, holding) return get_iterator(tuple) + def _iter_function(args): passed = args.get_pynames(['sequence'])[0] if passed is None: @@ -738,6 +752,7 @@ def _iter_function(args): holding = _infer_sequence_for_pyname(passed) return get_iterator(holding) + def _input_function(args): return get_str() @@ -751,17 +766,25 @@ def _input_function(args): 'file': BuiltinName(get_file_type()), 'open': BuiltinName(get_file_type()), 'unicode': BuiltinName(get_str_type()), - 'range': BuiltinName(BuiltinFunction(function=_range_function, builtin=range)), - 'reversed': BuiltinName(BuiltinFunction(function=_reversed_function, builtin=reversed)), - 'sorted': BuiltinName(BuiltinFunction(function=_sorted_function, builtin=sorted)), - 'super': BuiltinName(BuiltinFunction(function=_super_function, builtin=super)), - 'property': BuiltinName(BuiltinFunction(function=_property_function, builtin=property)), + 'range': BuiltinName(BuiltinFunction(function=_range_function, + builtin=range)), + 'reversed': BuiltinName(BuiltinFunction(function=_reversed_function, + builtin=reversed)), + 'sorted': BuiltinName(BuiltinFunction(function=_sorted_function, + builtin=sorted)), + 'super': BuiltinName(BuiltinFunction(function=_super_function, + builtin=super)), + 'property': BuiltinName(BuiltinFunction(function=_property_function, + builtin=property)), 'zip': BuiltinName(BuiltinFunction(function=_zip_function, builtin=zip)), - 'enumerate': BuiltinName(BuiltinFunction(function=_enumerate_function, builtin=enumerate)), + 'enumerate': BuiltinName(BuiltinFunction(function=_enumerate_function, + builtin=enumerate)), 'object': BuiltinName(BuiltinObject()), 'type': BuiltinName(BuiltinType()), - 'iter': BuiltinName(BuiltinFunction(function=_iter_function, builtin=iter)), - 'raw_input': BuiltinName(BuiltinFunction(function=_input_function, builtin=raw_input)), - } + 'iter': BuiltinName(BuiltinFunction(function=_iter_function, + builtin=iter)), + 'raw_input': BuiltinName(BuiltinFunction(function=_input_function, + builtin=raw_input)), +} builtins = BuiltinModule('__builtin__', initial=_initial_builtins) diff --git a/pymode/libs2/rope/base/change.py b/pymode/libs2/rope/base/change.py index 8d19aac1..e9764484 100644 --- a/pymode/libs2/rope/base/change.py +++ b/pymode/libs2/rope/base/change.py @@ -2,7 +2,6 @@ import difflib import os import time -import warnings import rope.base.fscommands from rope.base import taskhandle, exceptions, utils @@ -17,13 +16,13 @@ class Change(object): def do(self, job_set=None): """Perform the change - + .. note:: Do use this directly. Use `Project.do()` instead. """ def undo(self, job_set=None): """Perform the change - + .. note:: Do use this directly. Use `History.undo()` instead. """ @@ -97,7 +96,8 @@ def __str__(self): date = datetime.datetime.fromtimestamp(self.time) if date.date() == datetime.date.today(): string_date = 'today' - elif date.date() == (datetime.date.today() - datetime.timedelta(1)): + elif date.date() == (datetime.date.today() - + datetime.timedelta(1)): string_date = 'yesterday' elif date.year == datetime.date.today().year: string_date = date.strftime('%b %d') @@ -257,7 +257,8 @@ class CreateFolder(CreateResource): """ def __init__(self, parent, name): - resource = parent.project.get_folder(self._get_child_path(parent, name)) + resource = parent.project.get_folder( + self._get_child_path(parent, name)) super(CreateFolder, self).__init__(resource) @@ -309,6 +310,7 @@ def count_changes(change): return result return 1 + def create_job_set(task_handle, change): return task_handle.create_jobset(str(change), count_changes(change)) diff --git a/pymode/libs2/rope/base/codeanalyze.py b/pymode/libs2/rope/base/codeanalyze.py index 3d2a2a45..87061912 100644 --- a/pymode/libs2/rope/base/codeanalyze.py +++ b/pymode/libs2/rope/base/codeanalyze.py @@ -18,6 +18,7 @@ def add_change(self, start, end, new_text=None): def get_changed(self): if not self.changes: return None + def compare_changes(change1, change2): return cmp(change1[:2], change2[:2]) self.changes.sort(compare_changes) @@ -131,6 +132,7 @@ def __call__(self): return result _main_chars = re.compile(r'[\'|"|#|\\|\[|\]|\{|\}|\(|\)]') + def _analyze_line(self, line): char = None for match in self._main_chars.finditer(line): @@ -142,8 +144,8 @@ def _analyze_line(self, line): if char * 3 == line[i:i + 3]: self.in_string = char * 3 elif self.in_string == line[i:i + len(self.in_string)] and \ - not (i > 0 and line[i - 1] == '\\' and - not (i > 1 and line[i - 2] == '\\')): + not (i > 0 and line[i - 1] == '\\' and + not (i > 1 and line[i - 2] == '\\')): self.in_string = '' if self.in_string: continue @@ -158,6 +160,7 @@ def _analyze_line(self, line): else: self.continuation = False + def custom_generator(lines): return _CustomGenerator(lines)() @@ -189,7 +192,6 @@ def generate_regions(self, start_line=1, end_line=None): # XXX: `block_start` should be at a better position! block_start = 1 readline = LinesToReadline(self.lines, block_start) - shifted = start_line - block_start + 1 try: for start, end in self._logical_lines(readline): real_start = start + block_start - 1 @@ -199,7 +201,7 @@ def generate_regions(self, start_line=1, end_line=None): real_end = end + block_start - 1 if real_start >= start_line: yield (real_start, real_end) - except tokenize.TokenError, e: + except tokenize.TokenError: pass def _block_logical_line(self, block_start, line_number): @@ -254,6 +256,7 @@ def __init__(self, lines, generate=custom_generator): self._generate = generate _starts = None + @property def starts(self): if self._starts is None: @@ -261,6 +264,7 @@ def starts(self): return self._starts _ends = None + @property def ends(self): if self._ends is None: @@ -326,6 +330,7 @@ def get_block_start(lines, lineno, maximum_indents=80): _block_start_pattern = None + def get_block_start_patterns(): global _block_start_pattern if not _block_start_pattern: @@ -350,9 +355,10 @@ def count_line_indents(line): def get_string_pattern(): start = r'(\b[uU]?[rR]?)?' longstr = r'%s"""(\\.|"(?!"")|\\\n|[^"\\])*"""' % start - shortstr = r'%s"(\\.|[^"\\\n])*"' % start + shortstr = r'%s"(\\.|\\\n|[^"\\])*"' % start return '|'.join([longstr, longstr.replace('"', "'"), shortstr, shortstr.replace('"', "'")]) + def get_comment_pattern(): return r'#[^\n]*' diff --git a/pymode/libs2/rope/base/default_config.py b/pymode/libs2/rope/base/default_config.py index ffebcd4f..0ee9937d 100644 --- a/pymode/libs2/rope/base/default_config.py +++ b/pymode/libs2/rope/base/default_config.py @@ -14,7 +14,7 @@ def set_prefs(prefs): # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', - '.hg', '.svn', '_svn', '.git'] + '.hg', '.svn', '_svn', '.git', '.tox'] # Specifies which files should be considered python files. It is # useful when you have scripts inside your project. Only files @@ -79,6 +79,16 @@ def set_prefs(prefs): # appear in the importing namespace. prefs['ignore_bad_imports'] = False + # If `True`, rope will transform a comma list of imports into + # multiple separate import statements when organizing + # imports. + prefs['split_imports'] = False + + # If `True`, rope will sort imports alphabetically by module name + # instead of alphabetically by import statement, with from imports + # after normal imports. + prefs['sort_imports_alphabetically'] = False + def project_opened(project): """This function is called after opening the project""" diff --git a/pymode/libs2/rope/base/evaluate.py b/pymode/libs2/rope/base/evaluate.py index 6736b2a9..faf09407 100644 --- a/pymode/libs2/rope/base/evaluate.py +++ b/pymode/libs2/rope/base/evaluate.py @@ -6,6 +6,7 @@ BadIdentifierError = exceptions.BadIdentifierError + def eval_location(pymodule, offset): """Find the pyname at the offset""" return eval_location2(pymodule, offset)[1] @@ -40,7 +41,8 @@ def eval_str2(holding_scope, name): # parenthesizing for handling cases like 'a_var.\nattr' node = ast.parse('(%s)' % name) except SyntaxError: - raise BadIdentifierError('Not a resolvable python identifier selected.') + raise BadIdentifierError( + 'Not a resolvable python identifier selected.') return eval_node2(holding_scope, node) @@ -81,7 +83,8 @@ def get_primary_and_pyname_at(self, offset): keyword_name = self.worder.get_word_at(offset) pyobject = self.get_enclosing_function(offset) if isinstance(pyobject, pyobjects.PyFunction): - return (None, pyobject.get_parameters().get(keyword_name, None)) + return (None, + pyobject.get_parameters().get(keyword_name, None)) # class body if self._is_defined_in_class_body(holding_scope, offset, lineno): class_scope = holding_scope @@ -93,7 +96,8 @@ def get_primary_and_pyname_at(self, offset): except rope.base.exceptions.AttributeNotFoundError: return (None, None) # function header - if self._is_function_name_in_function_header(holding_scope, offset, lineno): + if self._is_function_name_in_function_header(holding_scope, + offset, lineno): name = self.worder.get_primary_at(offset).strip() return (None, holding_scope.parent[name]) # from statement module @@ -118,7 +122,7 @@ def get_enclosing_function(self, offset): if isinstance(pyobject, pyobjects.AbstractFunction): return pyobject elif isinstance(pyobject, pyobjects.AbstractClass) and \ - '__init__' in pyobject: + '__init__' in pyobject: return pyobject['__init__'].get_object() elif '__call__' in pyobject: return pyobject['__call__'].get_object() @@ -157,6 +161,7 @@ def _Call(self, node): primary, pyobject = self._get_primary_and_object_for_node(node.func) if pyobject is None: return + def _get_returned(pyobject): args = arguments.create_arguments(primary, pyobject, node, self.scope) @@ -295,7 +300,8 @@ def _call_function(self, node, function_name, other_args=None): return if function_name in pyobject: called = pyobject[function_name].get_object() - if not called or not isinstance(called, pyobjects.AbstractFunction): + if not called or \ + not isinstance(called, pyobjects.AbstractFunction): return args = [node] if other_args: diff --git a/pymode/libs2/rope/base/fscommands.py b/pymode/libs2/rope/base/fscommands.py index 3bc22044..daf118a0 100644 --- a/pymode/libs2/rope/base/fscommands.py +++ b/pymode/libs2/rope/base/fscommands.py @@ -199,12 +199,14 @@ def unicode_to_file_data(contents, encoding=None): except UnicodeEncodeError: return contents.encode('utf-8') + def file_data_to_unicode(data, encoding=None): result = _decode_data(data, encoding) if '\r' in result: result = result.replace('\r\n', '\n').replace('\r', '\n') return result + def _decode_data(data, encoding): if isinstance(data, unicode): return data @@ -227,7 +229,6 @@ def read_file_coding(path): file = open(path, 'b') count = 0 result = [] - buffsize = 10 while True: current = file.read(10) if not current: diff --git a/pymode/libs2/rope/base/libutils.py b/pymode/libs2/rope/base/libutils.py index cb9381e3..4037f183 100644 --- a/pymode/libs2/rope/base/libutils.py +++ b/pymode/libs2/rope/base/libutils.py @@ -3,6 +3,8 @@ import rope.base.project import rope.base.pycore +from rope.base import pyobjectsdef +from rope.base import utils from rope.base import taskhandle @@ -17,7 +19,7 @@ def path_to_resource(project, path, type=None): `Project.get_file()`, and `Project.get_folder()` methods. """ - project_path = relative(project.address, path) + project_path = path_relative_to_project_root(project, path) if project_path is None: project_path = rope.base.project._realpath(path) project = rope.base.project.get_no_project() @@ -29,13 +31,19 @@ def path_to_resource(project, path, type=None): return project.get_folder(project_path) return None + +def path_relative_to_project_root(project, path): + return relative(project.address, path) + +@utils.deprecated() def relative(root, path): root = rope.base.project._realpath(root).replace(os.path.sep, '/') path = rope.base.project._realpath(path).replace(os.path.sep, '/') if path == root: - return '' + return '' if path.startswith(root + '/'): - return path[len(root) + 1:] + return path[len(root) + 1:] + def report_change(project, path, old_content): """Report that the contents of file at `path` was changed @@ -52,14 +60,63 @@ def report_change(project, path, old_content): rope.base.pycore.perform_soa_on_changed_scopes(project, resource, old_content) + +def analyze_module(project, resource): + """Perform static object analysis on a python file in the project + + Note that this might be really time consuming. + """ + project.pycore.analyze_module(resource) + + def analyze_modules(project, task_handle=taskhandle.NullTaskHandle()): """Perform static object analysis on all python files in the project Note that this might be really time consuming. """ - resources = project.pycore.get_python_files() + resources = project.get_python_files() job_set = task_handle.create_jobset('Analyzing Modules', len(resources)) for resource in resources: job_set.started_job(resource.path) - project.pycore.analyze_module(resource) + analyze_module(project, resource) job_set.finished_job() + + +def get_string_module(project, code, resource=None, force_errors=False): + """Returns a `PyObject` object for the given code + + If `force_errors` is `True`, `exceptions.ModuleSyntaxError` is + raised if module has syntax errors. This overrides + ``ignore_syntax_errors`` project config. + + """ + return pyobjectsdef.PyModule(project.pycore, code, resource, + force_errors=force_errors) + + +def get_string_scope(project, code, resource=None): + """Returns a `Scope` object for the given code""" + return get_string_module(project, code, resource).get_scope() + + +def is_python_file(project, resource): + return project.pycore.is_python_file(resource) + + +def modname(resource): + if resource.is_folder(): + module_name = resource.name + source_folder = resource.parent + elif resource.name == '__init__.py': + module_name = resource.parent.name + source_folder = resource.parent.parent + else: + module_name = resource.name[:-3] + source_folder = resource.parent + + while source_folder != source_folder.parent and \ + source_folder.has_child('__init__.py'): + module_name = source_folder.name + '.' + module_name + source_folder = source_folder.parent + + return module_name diff --git a/pymode/libs2/rope/base/oi/doa.py b/pymode/libs2/rope/base/oi/doa.py index 12f50553..1b2a00fc 100644 --- a/pymode/libs2/rope/base/oi/doa.py +++ b/pymode/libs2/rope/base/oi/doa.py @@ -25,11 +25,11 @@ def run(self): """Execute the process""" env = dict(os.environ) file_path = self.file.real_path - path_folders = self.pycore.get_source_folders() + \ - self.pycore.get_python_path_folders() + path_folders = self.pycore.project.get_source_folders() + \ + self.pycore.project.get_python_path_folders() env['PYTHONPATH'] = os.pathsep.join(folder.real_path for folder in path_folders) - runmod_path = self.pycore.find_module('rope.base.oi.runmod').real_path + runmod_path = self.pycore.project.find_module('rope.base.oi.runmod').real_path self.receiver = None self._init_data_receiving() send_info = '-' @@ -56,7 +56,8 @@ def _init_data_receiving(self): self.receiver = _SocketReceiver() else: self.receiver = _FIFOReceiver() - self.receiving_thread = threading.Thread(target=self._receive_information) + self.receiving_thread = threading.Thread( + target=self._receive_information) self.receiving_thread.setDaemon(True) self.receiving_thread.start() @@ -114,7 +115,7 @@ def __init__(self): try: self.server_socket.bind(('', self.data_port)) break - except socket.error, e: + except socket.error: self.data_port += 1 self.server_socket.listen(1) diff --git a/pymode/libs2/rope/base/oi/runmod.py b/pymode/libs2/rope/base/oi/runmod.py index 8170623c..e332d7e6 100644 --- a/pymode/libs2/rope/base/oi/runmod.py +++ b/pymode/libs2/rope/base/oi/runmod.py @@ -40,9 +40,9 @@ def send_data(self, data): def close(self): self.my_file.close() - def _cached(func): cache = {} + def newfunc(self, arg): if arg in cache: return cache[arg] @@ -76,7 +76,8 @@ def on_function_call(self, frame, event, arg): code = frame.f_code for argname in code.co_varnames[:code.co_argcount]: try: - args.append(self._object_to_persisted_form(frame.f_locals[argname])) + args.append(self._object_to_persisted_form( + frame.f_locals[argname])) except (TypeError, AttributeError): args.append(('unknown',)) try: @@ -94,17 +95,19 @@ def on_function_call(self, frame, event, arg): def _is_an_interesting_call(self, frame): #if frame.f_code.co_name in ['?', '']: # return False - #return not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code) + #return not frame.f_back or + # not self._is_code_inside_project(frame.f_back.f_code) if not self._is_code_inside_project(frame.f_code) and \ - (not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code)): + (not frame.f_back or + not self._is_code_inside_project(frame.f_back.f_code)): return False return True def _is_code_inside_project(self, code): source = self._path(code.co_filename) return source is not None and os.path.exists(source) and \ - _realpath(source).startswith(self.project_root) + _realpath(source).startswith(self.project_root) @_cached def _get_persisted_code(self, object_): @@ -128,7 +131,8 @@ def _get_persisted_builtin(self, object_): holding = None if len(object_) > 0: holding = object_[0] - return ('builtin', 'list', self._object_to_persisted_form(holding)) + return ('builtin', 'list', + self._object_to_persisted_form(holding)) if isinstance(object_, dict): keys = None values = None @@ -152,7 +156,8 @@ def _get_persisted_builtin(self, object_): for o in object_: holding = o break - return ('builtin', 'set', self._object_to_persisted_form(holding)) + return ('builtin', 'set', + self._object_to_persisted_form(holding)) return ('unknown',) def _object_to_persisted_form(self, object_): diff --git a/pymode/libs2/rope/base/oi/soa.py b/pymode/libs2/rope/base/oi/soa.py index 38cd5c9d..a34b970e 100644 --- a/pymode/libs2/rope/base/oi/soa.py +++ b/pymode/libs2/rope/base/oi/soa.py @@ -26,9 +26,11 @@ def _analyze_node(pycore, pydefined, should_analyze, new_followed_calls = max(0, followed_calls - 1) return_true = lambda pydefined: True return_false = lambda pydefined: False + def _follow(pyfunction): _analyze_node(pycore, pyfunction, return_true, return_false, new_followed_calls) + if not followed_calls: _follow = None visitor = SOAVisitor(pycore, pydefined, _follow) @@ -113,7 +115,8 @@ def _Assign(self, node): args_pynames.append(evaluate.eval_node(self.scope, subscript.slice.value)) value = rope.base.oi.soi._infer_assignment( - rope.base.pynames.AssignmentValue(node.value, levels), self.pymodule) + rope.base.pynames.AssignmentValue(node.value, levels), + self.pymodule) args_pynames.append(rope.base.pynames.UnboundName(value)) if instance is not None and value is not None: pyobject = instance.get_object() diff --git a/pymode/libs2/rope/base/oi/soi.py b/pymode/libs2/rope/base/oi/soi.py index bf40af90..5a11b5ef 100644 --- a/pymode/libs2/rope/base/oi/soi.py +++ b/pymode/libs2/rope/base/oi/soi.py @@ -30,6 +30,7 @@ def infer_returned_object(pyfunction, args): return result return object_info.get_returned(pyfunction, args) + @_ignore_inferred def infer_parameter_objects(pyfunction): """Infer the `PyObject`\s of parameters of this `PyFunction`""" @@ -40,6 +41,7 @@ def infer_parameter_objects(pyfunction): _handle_first_parameter(pyfunction, result) return result + def _handle_first_parameter(pyobject, parameters): kind = pyobject.get_kind() if parameters is None or kind not in ['method', 'classmethod']: @@ -53,6 +55,7 @@ def _handle_first_parameter(pyobject, parameters): if kind == 'classmethod': parameters[0] = pyobject.parent + @_ignore_inferred def infer_assigned_object(pyname): if not pyname.assignments: @@ -62,6 +65,7 @@ def infer_assigned_object(pyname): if result is not None: return result + def get_passed_objects(pyfunction, parameter_index): object_info = pyfunction.pycore.object_info result = object_info.get_passed_objects(pyfunction, @@ -72,6 +76,7 @@ def get_passed_objects(pyfunction, parameter_index): result.append(statically_inferred[parameter_index]) return result + def _infer_returned(pyobject, args): if args: # HACK: Setting parameter objects manually @@ -99,12 +104,14 @@ def _infer_returned(pyobject, args): except rope.base.pyobjects.IsBeingInferredError: pass + def _parameter_objects(pyobject): params = pyobject.get_param_names(special_args=False) return [rope.base.pyobjects.get_unknown()] * len(params) # handling `rope.base.pynames.AssignmentValue` + @_ignore_inferred def _infer_assignment(assignment, pymodule): result = _follow_pyname(assignment, pymodule) @@ -116,6 +123,7 @@ def _infer_assignment(assignment, pymodule): return None return _follow_levels(assignment, pyobject) + def _follow_levels(assignment, pyobject): for index in assignment.levels: if isinstance(pyobject.get_type(), rope.base.builtins.Tuple): @@ -132,6 +140,7 @@ def _follow_levels(assignment, pyobject): break return pyobject + @_ignore_inferred def _follow_pyname(assignment, pymodule, lineno=None): assign_node = assignment.ast_node @@ -149,6 +158,7 @@ def _follow_pyname(assignment, pymodule, lineno=None): arguments.ObjectArguments([arg])) return pyname, result + @_ignore_inferred def _follow_evaluations(assignment, pyname, pyobject): new_pyname = pyname @@ -181,6 +191,7 @@ def _get_lineno_for_node(assign_node): return assign_node.lineno return 1 + def _get_attribute(pyobject, name): if pyobject is not None and name in pyobject: return pyobject[name] diff --git a/pymode/libs2/rope/base/oi/transform.py b/pymode/libs2/rope/base/oi/transform.py index 5a9d600e..aa29c373 100644 --- a/pymode/libs2/rope/base/oi/transform.py +++ b/pymode/libs2/rope/base/oi/transform.py @@ -120,7 +120,6 @@ def transform(self, textual): return None def builtin_to_pyobject(self, textual): - name = textual[1] method = getattr(self, 'builtin_%s_to_pyobject' % textual[1], None) if method is not None: return method(textual) @@ -203,7 +202,7 @@ def instance_to_pyobject(self, textual): def _get_pymodule(self, path): resource = self.path_to_resource(path) if resource is not None: - return self.project.pycore.resource_to_pyobject(resource) + return self.project.get_pymodule(resource) def path_to_resource(self, path): try: @@ -221,7 +220,7 @@ def path_to_resource(self, path): class DOITextualToPyObject(TextualToPyObject): """For transforming textual form to `PyObject` - + The textual form DOI uses is different from rope's standard textual form. The reason is that we cannot find the needed information by analyzing live objects. This class can be @@ -253,7 +252,8 @@ def _class_to_pyobject(self, textual): isinstance(suspected, rope.base.pyobjects.PyClass): return suspected else: - lineno = self._find_occurrence(name, pymodule.get_resource().read()) + lineno = self._find_occurrence(name, + pymodule.get_resource().read()) if lineno is not None: inner_scope = module_scope.get_inner_scope_for_line(lineno) return inner_scope.pyobject @@ -278,8 +278,8 @@ def _find_occurrence(self, name, source): def path_to_resource(self, path): import rope.base.libutils - root = self.project.address - relpath = rope.base.libutils.relative(root, path) + relpath = rope.base.libutils.path_relative_to_project_root( + self.project, path) if relpath is not None: path = relpath return super(DOITextualToPyObject, self).path_to_resource(path) diff --git a/pymode/libs2/rope/base/prefs.py b/pymode/libs2/rope/base/prefs.py index 674a58ec..2ab45dac 100644 --- a/pymode/libs2/rope/base/prefs.py +++ b/pymode/libs2/rope/base/prefs.py @@ -27,7 +27,7 @@ def get(self, key, default=None): def add_callback(self, key, callback): """Add `key` preference with `callback` function - + Whenever `key` is set the callback is called with the given `value` as parameter. diff --git a/pymode/libs2/rope/base/project.py b/pymode/libs2/rope/base/project.py index 97d2dd3e..23597f8c 100644 --- a/pymode/libs2/rope/base/project.py +++ b/pymode/libs2/rope/base/project.py @@ -6,8 +6,9 @@ import rope.base.fscommands from rope.base import exceptions, taskhandle, prefs, history, pycore, utils -from rope.base.resourceobserver import * +import rope.base.resourceobserver as resourceobserver from rope.base.resources import File, Folder, _ResourceMatcher +from rope.base.exceptions import ModuleNotFoundError class _Project(object): @@ -17,6 +18,7 @@ def __init__(self, fscommands): self.fscommands = fscommands self.prefs = prefs.Prefs() self.data_files = _DataFiles(self) + self._custom_source_folders = [] def get_resource(self, resource_name): """Get a resource in a project. @@ -41,6 +43,40 @@ def get_resource(self, resource_name): raise exceptions.ResourceNotFoundError('Unknown resource ' + resource_name) + def get_module(self, name, folder=None): + """Returns a `PyObject` if the module was found.""" + # check if this is a builtin module + pymod = self.pycore.builtin_module(name) + if pymod is not None: + return pymod + module = self.find_module(name, folder) + if module is None: + raise ModuleNotFoundError('Module %s not found' % name) + return self.pycore.resource_to_pyobject(module) + + def get_python_path_folders(self): + result = [] + for src in self.prefs.get('python_path', []) + sys.path: + try: + src_folder = get_no_project().get_resource(src) + result.append(src_folder) + except exceptions.ResourceNotFoundError: + pass + return result + + # INFO: It was decided not to cache source folders, since: + # - Does not take much time when the root folder contains + # packages, that is most of the time + # - We need a separate resource observer; `self.observer` + # does not get notified about module and folder creations + def get_source_folders(self): + """Returns project source folders""" + if self.root is None: + return [] + result = list(self._custom_source_folders) + result.extend(self.pycore._find_source_folders(self.root)) + return result + def validate(self, folder): """Validate files and folders contained in this folder @@ -71,6 +107,9 @@ def do(self, changes, task_handle=taskhandle.NullTaskHandle()): """ self.history.do(changes, task_handle=task_handle) + def get_pymodule(self, resource, force_errors=False): + return self.pycore.resource_to_pyobject(resource, force_errors) + def get_pycore(self): return self.pycore @@ -82,12 +121,45 @@ def get_folder(self, path): """Get the folder with `path` (it may not exist)""" return Folder(self, path) - def is_ignored(self, resource): - return False - def get_prefs(self): return self.prefs + def get_relative_module(self, name, folder, level): + module = self.find_relative_module(name, folder, level) + if module is None: + raise ModuleNotFoundError('Module %s not found' % name) + return self.pycore.resource_to_pyobject(module) + + def find_module(self, modname, folder=None): + """Returns a resource corresponding to the given module + + returns None if it can not be found + """ + for src in self.get_source_folders(): + module = _find_module_in_folder(src, modname) + if module is not None: + return module + for src in self.get_python_path_folders(): + module = _find_module_in_folder(src, modname) + if module is not None: + return module + if folder is not None: + module = _find_module_in_folder(folder, modname) + if module is not None: + return module + return None + + def find_relative_module(self, modname, folder, level): + for i in range(level - 1): + folder = folder.parent + if modname == '': + return folder + else: + return _find_module_in_folder(folder, modname) + + def is_ignored(self, resource): + return False + def _get_resource_path(self, name): pass @@ -144,10 +216,22 @@ def __init__(self, projectroot, fscommands=None, if ropefolder is not None: self.prefs['ignored_resources'] = [ropefolder] self._init_prefs(prefs) + self._init_source_folders() + + @utils.deprecated('Delete once deprecated functions are gone') + def _init_source_folders(self): + for path in self.prefs.get('source_folders', []): + folder = self.get_resource(path) + self._custom_source_folders.append(folder) def get_files(self): return self.file_list.get_files() + def get_python_files(self): + """Returns all python files available in the project""" + return [resource for resource in self.get_files() + if self.pycore.is_python_file(resource)] + def _get_resource_path(self, name): return os.path.join(self._address, *name.split('/')) @@ -244,6 +328,9 @@ def get_resource(self, name): def get_files(self): return [] + def get_python_files(self): + return [] + _no_project = None @@ -258,7 +345,7 @@ class _FileListCacher(object): def __init__(self, project): self.project = project self.files = None - rawobserver = ResourceObserver( + rawobserver = resourceobserver.ResourceObserver( self._changed, self._invalid, self._invalid, self._invalid, self._invalid) self.project.add_observer(rawobserver) @@ -334,7 +421,7 @@ def write(self): def _can_compress(self): try: - import gzip + import gzip # noqa return True except ImportError: return False @@ -371,5 +458,24 @@ def _realpath(path): if sys.platform == 'cygwin': if path[1:3] == ':\\': return path + elif path[1:3] == ':/': + path = "/cygdrive/" + path[0] + path[2:] return os.path.abspath(os.path.expanduser(path)) return os.path.realpath(os.path.abspath(os.path.expanduser(path))) + + +def _find_module_in_folder(folder, modname): + module = folder + packages = modname.split('.') + for pkg in packages[:-1]: + if module.is_folder() and module.has_child(pkg): + module = module.get_child(pkg) + else: + return None + if module.is_folder(): + if module.has_child(packages[-1]) and \ + module.get_child(packages[-1]).is_folder(): + return module.get_child(packages[-1]) + elif module.has_child(packages[-1] + '.py') and \ + not module.get_child(packages[-1] + '.py').is_folder(): + return module.get_child(packages[-1] + '.py') diff --git a/pymode/libs2/rope/base/pycore.py b/pymode/libs2/rope/base/pycore.py index 32056a0f..c4c1195a 100644 --- a/pymode/libs2/rope/base/pycore.py +++ b/pymode/libs2/rope/base/pycore.py @@ -3,15 +3,19 @@ import sys import warnings +import rope.base.libutils +import rope.base.resourceobserver +import rope.base.resources import rope.base.oi.doa import rope.base.oi.objectinfo import rope.base.oi.soa -from rope.base import ast, exceptions, taskhandle, utils, stdmods -from rope.base.exceptions import ModuleNotFoundError -from rope.base.pyobjectsdef import PyModule, PyPackage, PyClass -import rope.base.resources -import rope.base.resourceobserver from rope.base import builtins +from rope.base import exceptions +from rope.base import stdmods +from rope.base import taskhandle +from rope.base import utils +from rope.base.exceptions import ModuleNotFoundError +from rope.base.pyobjectsdef import PyModule, PyPackage class PyCore(object): @@ -25,7 +29,6 @@ def __init__(self, project): self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project) self._init_python_files() self._init_automatic_soa() - self._init_source_folders() def _init_python_files(self): self.python_matcher = None @@ -38,15 +41,10 @@ def _init_resource_observer(self): callback = self._invalidate_resource_cache observer = rope.base.resourceobserver.ResourceObserver( changed=callback, moved=callback, removed=callback) - self.observer = rope.base.resourceobserver.FilteredResourceObserver(observer) + self.observer = \ + rope.base.resourceobserver.FilteredResourceObserver(observer) self.project.add_observer(self.observer) - def _init_source_folders(self): - self._custom_source_folders = [] - for path in self.project.prefs.get('source_folders', []): - folder = self.project.get_resource(path) - self._custom_source_folders.append(folder) - def _init_automatic_soa(self): if not self.automatic_soa: return @@ -62,7 +60,7 @@ def automatic_soa(self): def _file_changed_for_soa(self, resource, new_resource=None): old_contents = self.project.history.\ - contents_before_current_change(resource) + contents_before_current_change(resource) if old_contents is not None: perform_soa_on_changed_scopes(self.project, resource, old_contents) @@ -73,16 +71,10 @@ def is_python_file(self, resource): return resource.name.endswith('.py') return self.python_matcher.does_match(resource) + @utils.deprecated('Use `project.get_module` instead') def get_module(self, name, folder=None): """Returns a `PyObject` if the module was found.""" - # check if this is a builtin module - pymod = self._builtin_module(name) - if pymod is not None: - return pymod - module = self.find_module(name, folder) - if module is None: - raise ModuleNotFoundError('Module %s not found' % name) - return self.resource_to_pyobject(module) + return self.project.get_module(name, folder) def _builtin_submodules(self, modname): result = {} @@ -90,18 +82,17 @@ def _builtin_submodules(self, modname): if extension.startswith(modname + '.'): name = extension[len(modname) + 1:] if '.' not in name: - result[name] = self._builtin_module(extension) + result[name] = self.builtin_module(extension) return result - def _builtin_module(self, name): + def builtin_module(self, name): return self.extension_cache.get_pymodule(name) + @utils.deprecated('Use `project.get_relative_module` instead') def get_relative_module(self, name, folder, level): - module = self.find_relative_module(name, folder, level) - if module is None: - raise ModuleNotFoundError('Module %s not found' % name) - return self.resource_to_pyobject(module) + return self.project.get_relative_module(name, folder, level) + @utils.deprecated('Use `libutils.get_string_module` instead') def get_string_module(self, code, resource=None, force_errors=False): """Returns a `PyObject` object for the given code @@ -112,92 +103,48 @@ def get_string_module(self, code, resource=None, force_errors=False): """ return PyModule(self, code, resource, force_errors=force_errors) + @utils.deprecated('Use `libutils.get_string_scope` instead') def get_string_scope(self, code, resource=None): """Returns a `Scope` object for the given code""" - return self.get_string_module(code, resource).get_scope() + return rope.base.libutils.get_string_scope(code, resource) def _invalidate_resource_cache(self, resource, new_resource=None): for observer in self.cache_observers: observer(resource) - def _find_module_in_folder(self, folder, modname): - module = folder - packages = modname.split('.') - for pkg in packages[:-1]: - if module.is_folder() and module.has_child(pkg): - module = module.get_child(pkg) - else: - return None - if module.is_folder(): - if module.has_child(packages[-1]) and \ - module.get_child(packages[-1]).is_folder(): - return module.get_child(packages[-1]) - elif module.has_child(packages[-1] + '.py') and \ - not module.get_child(packages[-1] + '.py').is_folder(): - return module.get_child(packages[-1] + '.py') - + @utils.deprecated('Use `project.get_python_path_folders` instead') def get_python_path_folders(self): - import rope.base.project - result = [] - for src in self.project.prefs.get('python_path', []) + sys.path: - try: - src_folder = rope.base.project.get_no_project().get_resource(src) - result.append(src_folder) - except rope.base.exceptions.ResourceNotFoundError: - pass - return result + return self.project.get_python_path_folders() + @utils.deprecated('Use `project.find_module` instead') def find_module(self, modname, folder=None): """Returns a resource corresponding to the given module returns None if it can not be found """ - return self._find_module(modname, folder) + return self.project.find_module(modname, folder) + @utils.deprecated('Use `project.find_relative_module` instead') def find_relative_module(self, modname, folder, level): - for i in range(level - 1): - folder = folder.parent - if modname == '': - return folder - else: - return self._find_module_in_folder(folder, modname) - - def _find_module(self, modname, folder=None): - """Return `modname` module resource""" - for src in self.get_source_folders(): - module = self._find_module_in_folder(src, modname) - if module is not None: - return module - for src in self.get_python_path_folders(): - module = self._find_module_in_folder(src, modname) - if module is not None: - return module - if folder is not None: - module = self._find_module_in_folder(folder, modname) - if module is not None: - return module - return None + return self.project.find_relative_module(modname, folder, level) # INFO: It was decided not to cache source folders, since: # - Does not take much time when the root folder contains # packages, that is most of the time # - We need a separate resource observer; `self.observer` # does not get notified about module and folder creations + @utils.deprecated('Use `project.get_source_folders` instead') def get_source_folders(self): """Returns project source folders""" - if self.project.root is None: - return [] - result = list(self._custom_source_folders) - result.extend(self._find_source_folders(self.project.root)) - return result + return self.project.get_source_folders() def resource_to_pyobject(self, resource, force_errors=False): return self.module_cache.get_pymodule(resource, force_errors) + @utils.deprecated('Use `project.get_python_files` instead') def get_python_files(self): """Returns all python files available in the project""" - return [resource for resource in self.project.get_files() - if self.is_python_file(resource)] + return self.project.get_python_files() def _is_package(self, folder): if folder.has_child('__init__.py') and \ @@ -270,22 +217,9 @@ def get_classes(self, task_handle=taskhandle.NullTaskHandle()): def __str__(self): return str(self.module_cache) + str(self.object_info) + @utils.deprecated('Use `libutils.modname` instead') def modname(self, resource): - if resource.is_folder(): - module_name = resource.name - source_folder = resource.parent - elif resource.name == '__init__.py': - module_name = resource.parent.name - source_folder = resource.parent.parent - else: - module_name = resource.name[:-3] - source_folder = resource.parent - - while source_folder != source_folder.parent and \ - source_folder.has_child('__init__.py'): - module_name = source_folder.name + '.' + module_name - source_folder = source_folder.parent - return module_name + return rope.base.libutils.modname(resource) @property @utils.cacheit @@ -355,9 +289,11 @@ def perform_soa_on_changed_scopes(project, resource, old_contents): new_contents = resource.read() # detecting changes in new_contents relative to old_contents detector = _TextChangeDetector(new_contents, old_contents) + def search_subscopes(pydefined): scope = pydefined.get_scope() return detector.is_changed(scope.get_start(), scope.get_end()) + def should_analyze(pydefined): scope = pydefined.get_scope() start = scope.get_start() diff --git a/pymode/libs2/rope/base/pynames.py b/pymode/libs2/rope/base/pynames.py index 79bba156..5d489814 100644 --- a/pymode/libs2/rope/base/pynames.py +++ b/pymode/libs2/rope/base/pynames.py @@ -57,7 +57,7 @@ def __init__(self, ast_node, levels=None, evaluation='', """ self.ast_node = ast_node - if levels == None: + if levels is None: self.levels = [] else: self.levels = levels @@ -112,15 +112,16 @@ def _get_pymodule(self): if self.pymodule.get() is None: pycore = self.importing_module.pycore if self.resource is not None: - self.pymodule.set(pycore.resource_to_pyobject(self.resource)) + self.pymodule.set(pycore.project.get_pymodule(self.resource)) elif self.module_name is not None: try: if self.level == 0: - pymodule = pycore.get_module(self.module_name, - self._current_folder()) + pymodule = pycore.project.get_module( + self.module_name, self._current_folder()) else: - pymodule = pycore.get_relative_module( - self.module_name, self._current_folder(), self.level) + pymodule = pycore.project.get_relative_module( + self.module_name, self._current_folder(), + self.level) self.pymodule.set(pymodule) except exceptions.ModuleNotFoundError: pass @@ -172,6 +173,7 @@ def _circular_inference(): raise rope.base.pyobjects.IsBeingInferredError( 'Circular Object Inference') + class _Inferred(object): def __init__(self, get_inferred, concluded=None): diff --git a/pymode/libs2/rope/base/pyobjectsdef.py b/pymode/libs2/rope/base/pyobjectsdef.py index 50b24360..a738b4de 100644 --- a/pymode/libs2/rope/base/pyobjectsdef.py +++ b/pymode/libs2/rope/base/pyobjectsdef.py @@ -3,16 +3,17 @@ import rope.base.builtins import rope.base.oi.soi import rope.base.pyscopes +import rope.base.libutils from rope.base import (pynamesdef as pynames, exceptions, ast, astutils, pyobjects, fscommands, arguments, utils) -from rope.base.pyobjects import * class PyFunction(pyobjects.PyFunction): def __init__(self, pycore, ast_node, parent): - AbstractFunction.__init__(self) - PyDefinedObject.__init__(self, pycore, ast_node, parent) + rope.base.pyobjects.AbstractFunction.__init__(self) + rope.base.pyobjects.PyDefinedObject.__init__( + self, pycore, ast_node, parent) self.arguments = self.ast_node.args self.parameter_pyobjects = pynames._Inferred( self._infer_parameters, self.get_module()._get_concluded_data()) @@ -109,8 +110,9 @@ class PyClass(pyobjects.PyClass): def __init__(self, pycore, ast_node, parent): self.visitor_class = _ClassVisitor - AbstractClass.__init__(self) - PyDefinedObject.__init__(self, pycore, ast_node, parent) + rope.base.pyobjects.AbstractClass.__init__(self) + rope.base.pyobjects.PyDefinedObject.__init__( + self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() @@ -134,8 +136,9 @@ def _get_bases(self): base = rope.base.evaluate.eval_node(self.parent.get_scope(), base_name) if base is not None and \ - base.get_object().get_type() == get_base_type('Type'): - result.append(base.get_object()) + base.get_object().get_type() == \ + rope.base.pyobjects.get_base_type('Type'): + result.append(base.get_object()) return result def _create_scope(self): @@ -213,7 +216,7 @@ def __init__(self, pycore, resource=None, force_errors=False): self.resource = resource init_dot_py = self._get_init_dot_py() if init_dot_py is not None: - ast_node = pycore.resource_to_pyobject( + ast_node = pycore.project.get_pymodule( init_dot_py, force_errors=force_errors).get_ast() else: ast_node = ast.parse('\n') @@ -221,7 +224,7 @@ def __init__(self, pycore, resource=None, force_errors=False): def _create_structural_attributes(self): result = {} - modname = self.pycore.modname(self.resource) + modname = rope.base.libutils.modname(self.resource) extension_submodules = self.pycore._builtin_submodules(modname) for name, module in extension_submodules.iteritems(): result[name] = rope.base.builtins.BuiltinName(module) @@ -235,7 +238,7 @@ def _create_concluded_attributes(self): result = {} init_dot_py = self._get_init_dot_py() if init_dot_py: - init_object = self.pycore.resource_to_pyobject(init_dot_py) + init_object = self.pycore.project.get_pymodule(init_dot_py) result.update(init_object.get_attributes()) return result @@ -245,13 +248,14 @@ def _get_child_resources(self): if child.is_folder(): result[child.name] = child elif child.name.endswith('.py') and \ - child.name != '__init__.py': + child.name != '__init__.py': name = child.name[:-3] result[name] = child return result def _get_init_dot_py(self): - if self.resource is not None and self.resource.has_child('__init__.py'): + if self.resource is not None and \ + self.resource.has_child('__init__.py'): return self.resource.get_child('__init__.py') else: return None @@ -262,7 +266,7 @@ def _create_scope(self): def get_module(self): init_dot_py = self._get_init_dot_py() if init_dot_py: - return self.pycore.resource_to_pyobject(init_dot_py) + return self.pycore.project.get_pymodule(init_dot_py) return self @@ -329,7 +333,9 @@ def _FunctionDef(self, node): if isinstance(decorator, ast.Name) and decorator.id == 'property': if isinstance(self, _ClassVisitor): type_ = rope.base.builtins.Property(pyfunction) - arg = pynames.UnboundName(PyObject(self.owner_object)) + arg = pynames.UnboundName( + rope.base.pyobjects.PyObject(self.owner_object)) + def _eval(type_=type_, arg=arg): return type_.get_property_object( arguments.ObjectArguments([arg])) @@ -347,7 +353,7 @@ def _AugAssign(self, node): pass def _For(self, node): - names = self._update_evaluated(node.target, node.iter, + names = self._update_evaluated(node.target, node.iter, # noqa '.__iter__().next()') for child in node.body + node.orelse: ast.walk(child, self) @@ -362,7 +368,7 @@ def _assigned(self, name, assignment): self.names[name] = pyname def _update_evaluated(self, targets, assigned, - evaluation= '', eval_type=False): + evaluation='', eval_type=False): result = {} names = astutils.get_name_levels(targets) for name, levels in names: @@ -430,7 +436,8 @@ def _ImportFrom(self, node): def _is_ignored_import(self, imported_module): if not self.pycore.project.prefs.get('ignore_bad_imports', False): return False - return not isinstance(imported_module.get_object(), AbstractModule) + return not isinstance(imported_module.get_object(), + rope.base.pyobjects.AbstractModule) def _Global(self, node): module = self.get_module() diff --git a/pymode/libs2/rope/base/pyscopes.py b/pymode/libs2/rope/base/pyscopes.py index a00381b7..0bed19a9 100644 --- a/pymode/libs2/rope/base/pyscopes.py +++ b/pymode/libs2/rope/base/pyscopes.py @@ -230,8 +230,8 @@ def get_holding_scope(self, module_scope, lineno, line_indents=None): current_scope = module_scope new_scope = current_scope while new_scope is not None and \ - (new_scope.get_kind() == 'Module' or - self._get_scope_indents(new_scope) <= line_indents): + (new_scope.get_kind() == 'Module' or + self._get_scope_indents(new_scope) <= line_indents): current_scope = new_scope if current_scope.get_start() == lineno and \ current_scope.get_kind() != 'Module': @@ -268,7 +268,7 @@ def find_scope_end(self, scope): else: body_indents = self._get_body_indents(scope) for l in self.logical_lines.generate_starts( - min(end + 1, self.lines.length()), self.lines.length() + 1): + min(end + 1, self.lines.length()), self.lines.length() + 1): if not self._is_empty_line(l): if self.get_indents(l) < body_indents: return end @@ -288,6 +288,7 @@ def code(self): def logical_lines(self): return self.pymodule.logical_lines + class TemporaryScope(Scope): """Currently used for list comprehensions and generator expressions diff --git a/pymode/libs2/rope/base/resourceobserver.py b/pymode/libs2/rope/base/resourceobserver.py index 6d1accbc..7c0937d5 100644 --- a/pymode/libs2/rope/base/resourceobserver.py +++ b/pymode/libs2/rope/base/resourceobserver.py @@ -231,7 +231,8 @@ def _search_resource_changes(self, resource): def _is_changed(self, resource): if self.resources[resource] is None: return False - return self.resources[resource] != self.timekeeper.get_indicator(resource) + return self.resources[resource] != \ + self.timekeeper.get_indicator(resource) def _calculate_new_resource(self, main, new_main, resource): if new_main is None: diff --git a/pymode/libs2/rope/base/resources.py b/pymode/libs2/rope/base/resources.py index 46beadb0..aac755f0 100644 --- a/pymode/libs2/rope/base/resources.py +++ b/pymode/libs2/rope/base/resources.py @@ -1,9 +1,37 @@ +"""Files and folders in a project are represented as resource objects. + +Files and folders are access through `Resource` objects. `Resource` has +two subclasses: `File` and `Folder`. What we care about is that +refactorings and `rope.base.change.Change`s use resources. + +There are two options to create a `Resource` for a path in a project. +Note that in these examples `path` is the path to a file or folder +relative to the project's root. A project's root folder is represented +by an empty string. + + 1) Use the `rope.base.Project.get_resource()` method. E.g.: + + myresource = myproject.get_resource(path) + + + 2) Use the `rope.base.libutils` module. `libutils` has a function + named `path_to_resource()`. It takes a project and a path: + + from rope.base import libutils + + myresource = libutils.path_to_resource(myproject, path) + +Once we have a `Resource`, we can retrieve information from it, like +getting the path relative to the project's root (via `path`), reading +from and writing to the resource, moving the resource, etc. +""" + import os import re -import rope.base.change -import rope.base.fscommands +from rope.base import change from rope.base import exceptions +from rope.base import fscommands class Resource(object): @@ -15,12 +43,12 @@ def __init__(self, project, path): def move(self, new_location): """Move resource to `new_location`""" - self._perform_change(rope.base.change.MoveResource(self, new_location), + self._perform_change(change.MoveResource(self, new_location), 'Moving <%s> to <%s>' % (self.path, new_location)) def remove(self): """Remove resource from the project""" - self._perform_change(rope.base.change.RemoveResource(self), + self._perform_change(change.RemoveResource(self), 'Removing <%s>' % self.path) def is_folder(self): @@ -66,7 +94,7 @@ def __hash__(self): return hash(self.path) def _perform_change(self, change_, description): - changes = rope.base.change.ChangeSet(description) + changes = change.ChangeSet(description) changes.add_change(change_) self.project.do(changes) @@ -80,7 +108,7 @@ def __init__(self, project, name): def read(self): data = self.read_bytes() try: - return rope.base.fscommands.file_data_to_unicode(data) + return fscommands.file_data_to_unicode(data) except UnicodeDecodeError, e: raise exceptions.ModuleDecodeError(self.path, e.reason) @@ -93,7 +121,7 @@ def write(self, contents): return except IOError: pass - self._perform_change(rope.base.change.ChangeContents(self, contents), + self._perform_change(change.ChangeContents(self, contents), 'Writing file <%s>' % self.path) def is_folder(self): @@ -114,8 +142,12 @@ def is_folder(self): def get_children(self): """Return the children of this folder""" + try: + children = os.listdir(self.real_path) + except OSError: + return [] result = [] - for name in os.listdir(self.real_path): + for name in children: try: child = self.get_child(name) except exceptions.ResourceNotFoundError: @@ -126,13 +158,13 @@ def get_children(self): def create_file(self, file_name): self._perform_change( - rope.base.change.CreateFile(self, file_name), + change.CreateFile(self, file_name), 'Creating file <%s>' % self._get_child_path(file_name)) return self.get_child(file_name) def create_folder(self, folder_name): self._perform_change( - rope.base.change.CreateFolder(self, folder_name), + change.CreateFolder(self, folder_name), 'Creating folder <%s>' % self._get_child_path(folder_name)) return self.get_child(folder_name) @@ -187,8 +219,8 @@ def set_patterns(self, patterns): def _add_pattern(self, pattern): re_pattern = pattern.replace('.', '\\.').\ - replace('*', '[^/]*').replace('?', '[^/]').\ - replace('//', '/(.*/)?') + replace('*', '[^/]*').replace('?', '[^/]').\ + replace('//', '/(.*/)?') re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$' self.compiled_patterns.append(re.compile(re_pattern)) diff --git a/pymode/libs2/rope/base/stdmods.py b/pymode/libs2/rope/base/stdmods.py index b6c9839b..457a4fac 100644 --- a/pymode/libs2/rope/base/stdmods.py +++ b/pymode/libs2/rope/base/stdmods.py @@ -6,12 +6,15 @@ def _stdlib_path(): import distutils.sysconfig - return distutils.sysconfig.get_python_lib(standard_lib=True) + return distutils.sysconfig.get_python_lib(standard_lib=True, + plat_specific=True) + @utils.cached(1) def standard_modules(): return python_modules() | dynload_modules() + @utils.cached(1) def python_modules(): result = set() @@ -27,6 +30,7 @@ def python_modules(): result.add(name[:-3]) return result + @utils.cached(1) def dynload_modules(): result = set(sys.builtin_module_names) @@ -35,6 +39,8 @@ def dynload_modules(): for name in os.listdir(dynload_path): path = os.path.join(dynload_path, name) if os.path.isfile(path): - if name.endswith('.so') or name.endswith('.dll'): + if name.endswith('.dll'): result.add(os.path.splitext(name)[0]) + if name.endswith('.so'): + result.add(os.path.splitext(name)[0].replace('module', '')) return result diff --git a/pymode/libs2/rope/base/taskhandle.py b/pymode/libs2/rope/base/taskhandle.py index 6d4ed856..c1f01b98 100644 --- a/pymode/libs2/rope/base/taskhandle.py +++ b/pymode/libs2/rope/base/taskhandle.py @@ -1,5 +1,3 @@ -import warnings - from rope.base import exceptions diff --git a/pymode/libs2/rope/base/utils.py b/pymode/libs2/rope/base/utils.py index e35ecbf3..11556c13 100644 --- a/pymode/libs2/rope/base/utils.py +++ b/pymode/libs2/rope/base/utils.py @@ -5,6 +5,7 @@ def saveit(func): """A decorator that caches the return value of a function""" name = '_' + func.__name__ + def _wrapper(self, *args, **kwds): if not hasattr(self, name): setattr(self, name, func(self, *args, **kwds)) @@ -13,10 +14,12 @@ def _wrapper(self, *args, **kwds): cacheit = saveit + def prevent_recursion(default): """A decorator that returns the return value of `default` in recursions""" def decorator(func): name = '_calling_%s_' % func.__name__ + def newfunc(self, *args, **kwds): if getattr(self, name, False): return default() @@ -46,6 +49,7 @@ def deprecated(message=None): def _decorator(func, message=message): if message is None: message = '%s is deprecated' % func.__name__ + def newfunc(*args, **kwds): warnings.warn(message, DeprecationWarning, stacklevel=2) return func(*args, **kwds) @@ -59,6 +63,7 @@ def decorator(func): return _Cached(func, count) return decorator + class _Cached(object): def __init__(self, func, count): diff --git a/pymode/libs2/rope/base/worder.py b/pymode/libs2/rope/base/worder.py index 08d75f34..c85c6b36 100644 --- a/pymode/libs2/rope/base/worder.py +++ b/pymode/libs2/rope/base/worder.py @@ -257,8 +257,10 @@ def get_splitted_primary_before(self, offset): return (self.raw[real_start:end], '', offset) last_dot_position = word_start if self.code[word_start] != '.': - last_dot_position = self._find_last_non_space_char(word_start - 1) - last_char_position = self._find_last_non_space_char(last_dot_position - 1) + last_dot_position = \ + self._find_last_non_space_char(word_start - 1) + last_char_position = \ + self._find_last_non_space_char(last_dot_position - 1) if self.code[word_start].isspace(): word_start = offset return (self.raw[real_start:last_char_position + 1], @@ -304,8 +306,8 @@ def is_a_function_being_called(self, offset): word_end = self._find_word_end(offset) + 1 next_char = self._find_first_non_space_char(word_end) return next_char < len(self.code) and \ - self.code[next_char] == '(' and \ - not self.is_a_class_or_function_name_in_header(offset) + self.code[next_char] == '(' and \ + not self.is_a_class_or_function_name_in_header(offset) def _find_import_end(self, start): return self._get_line_end(start) @@ -337,7 +339,7 @@ def is_from_statement_module(self, offset): def is_a_name_after_from_import(self, offset): try: - if len(self.code) > offset and self.code[offset] == '\n': + if len(self.code) > offset and self.code[offset] == '\n': line_start = self._get_line_start(offset - 1) else: line_start = self._get_line_start(offset) @@ -405,7 +407,6 @@ def is_on_function_call_keyword(self, offset): def find_parens_start_from_inside(self, offset): stop = self._get_line_start(offset) - opens = 1 while offset > stop: if self.code[offset] == '(': break @@ -501,7 +502,7 @@ def is_assigned_in_a_tuple_assignment(self, offset): parens_start = self.find_parens_start_from_inside(offset) # XXX: only handling (x, y) = value return offset < equals_offset and \ - self.code[start:parens_start].strip() == '' + self.code[start:parens_start].strip() == '' def get_function_and_args_in_header(self, offset): offset = self.find_function_offset(offset) @@ -518,7 +519,7 @@ def find_function_offset(self, offset, definition='def '): return self._find_first_non_space_char(def_) def get_lambda_and_args(self, offset): - offset = self.find_function_offset(offset, definition = 'lambda ') - lparens, rparens = self.get_word_parens_range(offset, opening=' ', closing=':') + offset = self.find_function_offset(offset, definition='lambda ') + lparens, rparens = self.get_word_parens_range(offset, opening=' ', + closing=':') return self.raw[offset:rparens + 1] - diff --git a/pymode/libs2/rope/contrib/autoimport.py b/pymode/libs2/rope/contrib/autoimport.py index 4b7b5b05..9670080c 100644 --- a/pymode/libs2/rope/contrib/autoimport.py +++ b/pymode/libs2/rope/contrib/autoimport.py @@ -1,7 +1,13 @@ import re -from rope.base import (exceptions, pynames, resourceobserver, - taskhandle, pyobjects, builtins, resources) +from rope.base import builtins +from rope.base import exceptions +from rope.base import libutils +from rope.base import pynames +from rope.base import pyobjects +from rope.base import resources +from rope.base import resourceobserver +from rope.base import taskhandle from rope.refactor import importutils @@ -65,11 +71,10 @@ def get_all_names(self): def get_name_locations(self, name): """Return a list of ``(resource, lineno)`` tuples""" result = [] - pycore = self.project.pycore for module in self.names: if name in self.names[module]: try: - pymodule = pycore.get_module(module) + pymodule = self.project.get_module(module) if name in pymodule: pyname = pymodule[name] module, lineno = pyname.get_definition_location() @@ -91,7 +96,7 @@ def generate_cache(self, resources=None, underlined=None, """ if resources is None: - resources = self.project.pycore.get_python_files() + resources = self.project.get_python_files() job_set = task_handle.create_jobset( 'Generatig autoimport cache', len(resources)) for file in resources: @@ -107,7 +112,7 @@ def generate_modules_cache(self, modules, underlined=None, for modname in modules: job_set.started_job('Working on <%s>' % modname) if modname.endswith('.*'): - mod = self.project.pycore.find_module(modname[:-2]) + mod = self.project.find_module(modname[:-2]) if mod: for sub in submodules(mod): self.update_resource(sub, underlined) @@ -130,13 +135,13 @@ def find_insertion_line(self, code): if match is not None: code = code[:match.start()] try: - pymodule = self.project.pycore.get_string_module(code) + pymodule = libutils.get_string_module(self.project, code) except exceptions.ModuleSyntaxError: return 1 testmodname = '__rope_testmodule_rope' importinfo = importutils.NormalImport(((testmodname, None),)) - module_imports = importutils.get_module_imports( - self.project.pycore, pymodule) + module_imports = importutils.get_module_imports(self.project, + pymodule) module_imports.add_import(importinfo) code = module_imports.get_changed_source() offset = code.index(testmodname) @@ -146,7 +151,7 @@ def find_insertion_line(self, code): def update_resource(self, resource, underlined=None): """Update the cache for global names in `resource`""" try: - pymodule = self.project.pycore.resource_to_pyobject(resource) + pymodule = self.project.get_pymodule(resource) modname = self._module_name(resource) self._add_names(pymodule, modname, underlined) except exceptions.ModuleSyntaxError: @@ -158,13 +163,13 @@ def update_module(self, modname, underlined=None): `modname` is the name of a module. """ try: - pymodule = self.project.pycore.get_module(modname) + pymodule = self.project.get_module(modname) self._add_names(pymodule, modname, underlined) except exceptions.ModuleNotFoundError: pass def _module_name(self, resource): - return self.project.pycore.modname(resource) + return libutils.modname(resource) def _add_names(self, pymodule, modname, underlined): if underlined is None: diff --git a/pymode/libs2/rope/contrib/codeassist.py b/pymode/libs2/rope/contrib/codeassist.py index 37433c2a..48b4a813 100644 --- a/pymode/libs2/rope/contrib/codeassist.py +++ b/pymode/libs2/rope/contrib/codeassist.py @@ -4,8 +4,15 @@ import rope.base.codeanalyze import rope.base.evaluate -from rope.base import pyobjects, pyobjectsdef, pynames, builtins, exceptions, worder -from rope.base.codeanalyze import SourceLinesAdapter +from rope.base import builtins +from rope.base import exceptions +from rope.base import libutils +from rope.base import pynames +from rope.base import pynamesdef +from rope.base import pyobjects +from rope.base import pyobjectsdef +from rope.base import pyscopes +from rope.base import worder from rope.contrib import fixsyntax from rope.refactor import functionutils @@ -53,9 +60,7 @@ def starting_offset(source_code, offset): def get_doc(project, source_code, offset, resource=None, maxfixes=1): """Get the pydoc""" - fixer = fixsyntax.FixSyntax(project.pycore, source_code, - resource, maxfixes) - pymodule = fixer.get_pymodule() + fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes) pyname = fixer.pyname_at(offset) if pyname is None: return None @@ -88,9 +93,7 @@ def get_calltip(project, source_code, offset, resource=None, If `remove_self` is `True`, the first parameter whose name is self will be removed for methods. """ - fixer = fixsyntax.FixSyntax(project.pycore, source_code, - resource, maxfixes) - pymodule = fixer.get_pymodule() + fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes) pyname = fixer.pyname_at(offset) if pyname is None: return None @@ -108,9 +111,7 @@ def get_definition_location(project, source_code, offset, location cannot be determined ``(None, None)`` is returned. """ - fixer = fixsyntax.FixSyntax(project.pycore, source_code, - resource, maxfixes) - pymodule = fixer.get_pymodule() + fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes) pyname = fixer.pyname_at(offset) if pyname is not None: module, lineno = pyname.get_definition_location() @@ -126,6 +127,64 @@ def find_occurrences(*args, **kwds): return rope.contrib.findit.find_occurrences(*args, **kwds) +def get_canonical_path(project, resource, offset): + """Get the canonical path to an object. + + Given the offset of the object, this returns a list of + (name, name_type) tuples representing the canonical path to the + object. For example, the 'x' in the following code: + + class Foo(object): + def bar(self): + class Qux(object): + def mux(self, x): + pass + + we will return: + + [('Foo', 'CLASS'), ('bar', 'FUNCTION'), ('Qux', 'CLASS'), + ('mux', 'FUNCTION'), ('x', 'PARAMETER')] + + `resource` is a `rope.base.resources.Resource` object. + + `offset` is the offset of the pyname you want the path to. + + """ + # Retrieve the PyName. + pymod = project.get_pymodule(resource) + pyname = rope.base.evaluate.eval_location(pymod, offset) + + # Now get the location of the definition and its containing scope. + defmod, lineno = pyname.get_definition_location() + if not defmod: + return None + scope = defmod.get_scope().get_inner_scope_for_line(lineno) + + # Start with the name of the object we're interested in. + names = [] + if isinstance(pyname, pynamesdef.ParameterName): + names = [(worder.get_name_at(pymod.get_resource(), offset), + 'PARAMETER') ] + elif isinstance(pyname, pynamesdef.AssignedName): + names = [(worder.get_name_at(pymod.get_resource(), offset), + 'VARIABLE')] + + # Collect scope names. + while scope.parent: + if isinstance(scope, pyscopes.FunctionScope): + scope_type = 'FUNCTION' + elif isinstance(scope, pyscopes.ClassScope): + scope_type = 'CLASS' + else: + scope_type = None + names.append((scope.pyobject.get_name(), scope_type)) + scope = scope.parent + + names.append((defmod.get_resource().real_path, 'MODULE')) + names.reverse() + return names + + class CompletionProposal(object): """A completion proposal @@ -184,15 +243,14 @@ def type(self): if isinstance(pyobject, builtins.BuiltinFunction): return 'function' elif isinstance(pyobject, builtins.BuiltinClass): - clsobj = pyobject.builtin return 'class' elif isinstance(pyobject, builtins.BuiltinObject) or \ - isinstance(pyobject, builtins.BuiltinName): + isinstance(pyobject, builtins.BuiltinName): return 'instance' elif isinstance(pyname, pynames.ImportedModule): return 'module' elif isinstance(pyname, pynames.ImportedName) or \ - isinstance(pyname, pynames.DefinedName): + isinstance(pyname, pynames.DefinedName): pyobject = pyname.get_object() if isinstance(pyobject, pyobjects.AbstractFunction): return 'function' @@ -222,7 +280,7 @@ def get_doc(self): @property def kind(self): - warnings.warn("the proposal's `kind` property is deprecated, " \ + warnings.warn("the proposal's `kind` property is deprecated, " "use `scope` instead") return self.scope @@ -294,7 +352,6 @@ class _PythonCodeAssist(object): def __init__(self, project, source_code, offset, resource=None, maxfixes=1, later_locals=True): self.project = project - self.pycore = self.project.pycore self.code = source_code self.resource = resource self.maxfixes = maxfixes @@ -309,7 +366,7 @@ def _find_starting_offset(self, source_code, offset): current_offset = offset - 1 while current_offset >= 0 and (source_code[current_offset].isalnum() or source_code[current_offset] in '_'): - current_offset -= 1; + current_offset -= 1 return current_offset + 1 def _matching_keywords(self, starting): @@ -339,11 +396,12 @@ def _dotted_completions(self, module_scope, holding_scope): compl_scope = 'imported' for name, pyname in element.get_attributes().items(): if name.startswith(self.starting): - result[name] = CompletionProposal(name, compl_scope, pyname) + result[name] = CompletionProposal(name, compl_scope, + pyname) return result def _undotted_completions(self, scope, result, lineno=None): - if scope.parent != None: + if scope.parent is not None: self._undotted_completions(scope.parent, result) if lineno is None: names = scope.get_propagated_names() @@ -388,7 +446,7 @@ def _is_defined_after(self, scope, pyname, lineno): def _code_completions(self): lineno = self.code.count('\n', 0, self.offset) + 1 - fixer = fixsyntax.FixSyntax(self.pycore, self.code, + fixer = fixsyntax.FixSyntax(self.project, self.code, self.resource, self.maxfixes) pymodule = fixer.get_pymodule() module_scope = pymodule.get_scope() @@ -413,24 +471,21 @@ def _keyword_parameters(self, pymodule, scope): if offset == 0: return {} word_finder = worder.Worder(self.code, True) - lines = SourceLinesAdapter(self.code) - lineno = lines.get_line_number(offset) if word_finder.is_on_function_call_keyword(offset - 1): - name_finder = rope.base.evaluate.ScopeNameFinder(pymodule) function_parens = word_finder.\ find_parens_start_from_inside(offset - 1) primary = word_finder.get_primary_at(function_parens - 1) try: function_pyname = rope.base.evaluate.\ eval_str(scope, primary) - except exceptions.BadIdentifierError, e: + except exceptions.BadIdentifierError: return {} if function_pyname is not None: pyobject = function_pyname.get_object() if isinstance(pyobject, pyobjects.AbstractFunction): pass elif isinstance(pyobject, pyobjects.AbstractClass) and \ - '__init__' in pyobject: + '__init__' in pyobject: pyobject = pyobject['__init__'].get_object() elif '__call__' in pyobject: pyobject = pyobject['__call__'].get_object() @@ -455,12 +510,12 @@ def __init__(self, code_assist_proposals, scopepref=None, typepref=None): self.proposals = code_assist_proposals if scopepref is None: scopepref = ['parameter_keyword', 'local', 'global', 'imported', - 'attribute', 'builtin', 'keyword'] + 'attribute', 'builtin', 'keyword'] self.scopepref = scopepref if typepref is None: typepref = ['class', 'function', 'instance', 'module', None] self.typerank = dict((type, index) - for index, type in enumerate(typepref)) + for index, type in enumerate(typepref)) def get_sorted_proposal_list(self): """Return a list of `CodeAssistProposal`""" @@ -471,7 +526,7 @@ def get_sorted_proposal_list(self): for scope in self.scopepref: scope_proposals = proposals.get(scope, []) scope_proposals = [proposal for proposal in scope_proposals - if proposal.type in self.typerank] + if proposal.type in self.typerank] scope_proposals.sort(self._proposal_cmp) result.extend(scope_proposals) return result @@ -526,7 +581,8 @@ def get_calltip(self, pyobject, ignore_unknown=False, remove_self=False): def _get_class_docstring(self, pyclass): contents = self._trim_docstring(pyclass.get_doc(), 2) supers = [super.get_name() for super in pyclass.get_superclasses()] - doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) + contents + doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) \ + + contents if '__init__' in pyclass: init = pyclass['__init__'].get_object() @@ -544,7 +600,7 @@ def _get_function_docstring(self, pyfunction): def _is_method(self, pyfunction): return isinstance(pyfunction, pyobjects.PyFunction) and \ - isinstance(pyfunction.parent, pyobjects.PyClass) + isinstance(pyfunction.parent, pyobjects.PyClass) def _get_single_function_docstring(self, pyfunction): signature = self._get_function_signature(pyfunction) @@ -579,7 +635,6 @@ def _location(self, pyobject, add_module=False): parent = parent.parent if add_module: if isinstance(pyobject, pyobjects.PyFunction): - module = pyobject.get_module() location.insert(0, self._get_module(pyobject)) if isinstance(parent, builtins.BuiltinModule): location.insert(0, parent.get_name() + '.') @@ -590,7 +645,7 @@ def _get_module(self, pyfunction): if module is not None: resource = module.get_resource() if resource is not None: - return pyfunction.pycore.modname(resource) + '.' + return libutils.modname(resource) + '.' return '' def _trim_docstring(self, docstring, indents=0): diff --git a/pymode/libs2/rope/contrib/finderrors.py b/pymode/libs2/rope/contrib/finderrors.py index c8cf7e15..9ee7dd15 100644 --- a/pymode/libs2/rope/contrib/finderrors.py +++ b/pymode/libs2/rope/contrib/finderrors.py @@ -31,7 +31,7 @@ def find_errors(project, resource): It returns a list of `Error`\s. """ - pymodule = project.pycore.resource_to_pyobject(resource) + pymodule = project.get_pymodule(resource) finder = _BadAccessFinder(pymodule) ast.walk(pymodule.get_ast(), finder) return finder.errors diff --git a/pymode/libs2/rope/contrib/findit.py b/pymode/libs2/rope/contrib/findit.py index e8ddd7e5..93eb01a8 100644 --- a/pymode/libs2/rope/contrib/findit.py +++ b/pymode/libs2/rope/contrib/findit.py @@ -7,7 +7,8 @@ def find_occurrences(project, resource, offset, unsure=False, resources=None, - in_hierarchy=False, task_handle=taskhandle.NullTaskHandle()): + in_hierarchy=False, + task_handle=taskhandle.NullTaskHandle()): """Return a list of `Location`\s If `unsure` is `True`, possible matches are returned, too. You @@ -18,16 +19,17 @@ def find_occurrences(project, resource, offset, unsure=False, resources=None, """ name = worder.get_name_at(resource, offset) - this_pymodule = project.pycore.resource_to_pyobject(resource) + this_pymodule = project.get_pymodule(resource) primary, pyname = rope.base.evaluate.eval_location2( this_pymodule, offset) + def is_match(occurrence): return unsure finder = occurrences.create_finder( - project.pycore, name, pyname, unsure=is_match, + project, name, pyname, unsure=is_match, in_hierarchy=in_hierarchy, instance=primary) if resources is None: - resources = project.pycore.get_python_files() + resources = project.get_python_files() job_set = task_handle.create_jobset('Finding Occurrences', count=len(resources)) return _find_locations(finder, resources, job_set) @@ -41,7 +43,7 @@ def find_implementations(project, resource, offset, resources=None, `Location`\s. """ name = worder.get_name_at(resource, offset) - this_pymodule = project.pycore.resource_to_pyobject(resource) + this_pymodule = project.get_pymodule(resource) pyname = rope.base.evaluate.eval_location(this_pymodule, offset) if pyname is not None: pyobject = pyname.get_object() @@ -50,17 +52,19 @@ def find_implementations(project, resource, offset, resources=None, raise exceptions.BadIdentifierError('Not a method!') else: raise exceptions.BadIdentifierError('Cannot resolve the identifier!') + def is_defined(occurrence): if not occurrence.is_defined(): return False + def not_self(occurrence): if occurrence.get_pyname().get_object() == pyname.get_object(): return False filters = [is_defined, not_self, occurrences.InHierarchyFilter(pyname, True)] - finder = occurrences.Finder(project.pycore, name, filters=filters) + finder = occurrences.Finder(project, name, filters=filters) if resources is None: - resources = project.pycore.get_python_files() + resources = project.get_python_files() job_set = task_handle.create_jobset('Finding Implementations', count=len(resources)) return _find_locations(finder, resources, job_set) @@ -72,19 +76,19 @@ def find_definition(project, code, offset, resource=None, maxfixes=1): A `Location` object is returned if the definition location can be determined, otherwise ``None`` is returned. """ - fixer = fixsyntax.FixSyntax(project.pycore, code, resource, maxfixes) - main_module = fixer.get_pymodule() + fixer = fixsyntax.FixSyntax(project, code, resource, maxfixes) pyname = fixer.pyname_at(offset) if pyname is not None: module, lineno = pyname.get_definition_location() name = rope.base.worder.Worder(code).get_word_at(offset) if lineno is not None: start = module.lines.get_line_start(lineno) + def check_offset(occurrence): if occurrence.offset < start: return False pyname_filter = occurrences.PyNameFilter(pyname) - finder = occurrences.Finder(project.pycore, name, + finder = occurrences.Finder(project, name, [check_offset, pyname_filter]) for occurrence in finder.find_occurrences(pymodule=module): return Location(occurrence) diff --git a/pymode/libs2/rope/contrib/fixmodnames.py b/pymode/libs2/rope/contrib/fixmodnames.py index 7092f131..d8bd3da1 100644 --- a/pymode/libs2/rope/contrib/fixmodnames.py +++ b/pymode/libs2/rope/contrib/fixmodnames.py @@ -15,7 +15,7 @@ argument. """ -from rope.base import change, taskhandle +from rope.base import taskhandle from rope.contrib import changestack from rope.refactor import rename @@ -57,7 +57,7 @@ def _count_fixes(self, fixer): return len(list(self._tobe_fixed(fixer))) def _tobe_fixed(self, fixer): - for resource in self.project.pycore.get_python_files(): + for resource in self.project.get_python_files(): modname = self._name(resource) if modname != fixer(modname): yield resource diff --git a/pymode/libs2/rope/contrib/fixsyntax.py b/pymode/libs2/rope/contrib/fixsyntax.py index 870046c8..aab5c78c 100644 --- a/pymode/libs2/rope/contrib/fixsyntax.py +++ b/pymode/libs2/rope/contrib/fixsyntax.py @@ -1,13 +1,16 @@ import rope.base.codeanalyze import rope.base.evaluate -from rope.base import worder, exceptions, utils +from rope.base import exceptions +from rope.base import libutils +from rope.base import utils +from rope.base import worder from rope.base.codeanalyze import ArrayLinesAdapter, LogicalLineFinder class FixSyntax(object): - def __init__(self, pycore, code, resource, maxfixes=1): - self.pycore = pycore + def __init__(self, project, code, resource, maxfixes=1): + self.project = project self.code = code self.resource = resource self.maxfixes = maxfixes @@ -22,10 +25,11 @@ def get_pymodule(self): try: if tries == 0 and self.resource is not None and \ self.resource.read() == code: - return self.pycore.resource_to_pyobject(self.resource, - force_errors=True) - return self.pycore.get_string_module( - code, resource=self.resource, force_errors=True) + return self.project.get_pymodule(self.resource, + force_errors=True) + return libutils.get_string_module( + self.project, code, resource=self.resource, + force_errors=True) except exceptions.ModuleSyntaxError, e: if msg is None: msg = '%s:%s %s' % (e.filename, e.lineno, e.message_) @@ -34,7 +38,9 @@ def get_pymodule(self): self.commenter.comment(e.lineno) code = '\n'.join(self.commenter.lines) else: - raise exceptions.ModuleSyntaxError(e.filename, e.lineno, msg) + raise exceptions.ModuleSyntaxError( + e.filename, e.lineno, + 'Failed to fix error: {}'.format(msg)) @property @utils.saveit @@ -43,6 +49,7 @@ def commenter(self): def pyname_at(self, offset): pymodule = self.get_pymodule() + def old_pyname(): word_finder = worder.Worder(self.code, True) expression = word_finder.get_primary_at(offset) @@ -51,6 +58,7 @@ def old_pyname(): scope = pymodule.get_scope().get_inner_scope_for_line(lineno) return rope.base.evaluate.eval_str(scope, expression) new_code = pymodule.source_code + def new_pyname(): newoffset = self.commenter.transfered_offset(offset) return rope.base.evaluate.eval_location(pymodule, newoffset) @@ -108,7 +116,6 @@ def _get_block_end(self, lineno): return end_line def _get_stmt_end(self, lineno): - end_line = lineno base_indents = _get_line_indents(self.lines[lineno]) for i in range(lineno + 1, len(self.lines)): if _get_line_indents(self.lines[i]) <= base_indents: @@ -117,7 +124,7 @@ def _get_stmt_end(self, lineno): def _fix_incomplete_try_blocks(self, lineno, indents): block_start = lineno - last_indents = current_indents = indents + last_indents = indents while block_start > 0: block_start = rope.base.codeanalyze.get_block_start( ArrayLinesAdapter(self.lines), block_start) - 1 @@ -155,6 +162,7 @@ def _insert(self, lineno, line): self.origs.insert(lineno, self.origs[lineno]) self.lines.insert(lineno, line) + def _logical_start(lines, lineno, check_prev=False): logical_finder = LogicalLineFinder(ArrayLinesAdapter(lines)) if check_prev: diff --git a/pymode/libs2/rope/contrib/generate.py b/pymode/libs2/rope/contrib/generate.py index 4d850da0..825f26d6 100644 --- a/pymode/libs2/rope/contrib/generate.py +++ b/pymode/libs2/rope/contrib/generate.py @@ -1,5 +1,7 @@ import rope.base.evaluate -from rope.base import change, pyobjects, exceptions, pynames, worder, codeanalyze +from rope.base import libutils +from rope.base import (change, pyobjects, exceptions, pynames, worder, + codeanalyze) from rope.refactor import sourceutils, importutils, functionutils, suites @@ -24,6 +26,7 @@ def create_module(project, name, sourcefolder=None): parent = parent.get_child(package) return parent.create_file(packages[-1] + '.py') + def create_package(project, name, sourcefolder=None): """Creates a package and returns a `rope.base.resources.Folder`""" if sourcefolder is None: @@ -55,14 +58,16 @@ def _check_exceptional_conditions(self): 'Element <%s> already exists.' % self.name) if not self.info.primary_is_found(): raise exceptions.RefactoringError( - 'Cannot determine the scope <%s> should be defined in.' % self.name) + 'Cannot determine the scope <%s> should be defined in.' % + self.name) def get_changes(self): changes = change.ChangeSet('Generate %s <%s>' % (self._get_element_kind(), self.name)) indents = self.info.get_scope_indents() blanks = self.info.get_blank_lines() - base_definition = sourceutils.fix_indentation(self._get_element(), indents) + base_definition = sourceutils.fix_indentation(self._get_element(), + indents) definition = '\n' * blanks[0] + base_definition + '\n' * blanks[1] resource = self.info.get_insertion_resource() @@ -130,18 +135,19 @@ class GenerateModule(_Generate): def get_changes(self): package = self.info.get_package() changes = change.ChangeSet('Generate Module <%s>' % self.name) - new_resource = self.project.get_file('%s/%s.py' % (package.path, self.name)) + new_resource = self.project.get_file('%s/%s.py' % + (package.path, self.name)) if new_resource.exists(): raise exceptions.RefactoringError( 'Module <%s> already exists' % new_resource.path) changes.add_change(change.CreateResource(new_resource)) changes.add_change(_add_import_to_module( - self.project.pycore, self.resource, new_resource)) + self.project, self.resource, new_resource)) return changes def get_location(self): package = self.info.get_package() - return (package.get_child('%s.py' % self.name) , 1) + return (package.get_child('%s.py' % self.name), 1) class GeneratePackage(_Generate): @@ -149,13 +155,14 @@ class GeneratePackage(_Generate): def get_changes(self): package = self.info.get_package() changes = change.ChangeSet('Generate Package <%s>' % self.name) - new_resource = self.project.get_folder('%s/%s' % (package.path, self.name)) + new_resource = self.project.get_folder('%s/%s' % + (package.path, self.name)) if new_resource.exists(): raise exceptions.RefactoringError( 'Package <%s> already exists' % new_resource.path) changes.add_change(change.CreateResource(new_resource)) changes.add_change(_add_import_to_module( - self.project.pycore, self.resource, new_resource)) + self.project, self.resource, new_resource)) child = self.project.get_folder(package.path + '/' + self.name) changes.add_change(change.CreateFile(child, '__init__.py')) return changes @@ -163,14 +170,14 @@ def get_changes(self): def get_location(self): package = self.info.get_package() child = package.get_child(self.name) - return (child.get_child('__init__.py') , 1) + return (child.get_child('__init__.py'), 1) -def _add_import_to_module(pycore, resource, imported): - pymodule = pycore.resource_to_pyobject(resource) - import_tools = importutils.ImportTools(pycore) +def _add_import_to_module(project, resource, imported): + pymodule = project.get_pymodule(resource) + import_tools = importutils.ImportTools(project) module_imports = import_tools.module_imports(pymodule) - module_name = pycore.modname(imported) + module_name = libutils.modname(imported) new_import = importutils.NormalImport(((module_name, None), )) module_imports.add_import(new_import) return change.ChangeContents(resource, module_imports.get_changed_source()) @@ -182,7 +189,7 @@ def __init__(self, pycore, resource, offset): self.pycore = pycore self.resource = resource self.offset = offset - self.source_pymodule = self.pycore.resource_to_pyobject(resource) + self.source_pymodule = self.pycore.project.get_pymodule(resource) finder = rope.base.evaluate.ScopeNameFinder(self.source_pymodule) self.primary, self.pyname = finder.get_primary_and_pyname_at(offset) self._init_fields() @@ -264,7 +271,7 @@ def get_blank_lines(self): def get_package(self): primary = self.primary if self.primary is None: - return self.pycore.get_source_folders()[0] + return self.pycore.project.get_source_folders()[0] if isinstance(primary.get_object(), pyobjects.PyPackage): return primary.get_object().get_resource() raise exceptions.RefactoringError( @@ -304,15 +311,15 @@ def element_already_exists(self): def is_static_method(self): return self.primary is not None and \ - isinstance(self.primary.get_object(), pyobjects.PyClass) + isinstance(self.primary.get_object(), pyobjects.PyClass) def is_method(self): return self.primary is not None and \ - isinstance(self.primary.get_object().get_type(), pyobjects.PyClass) + isinstance(self.primary.get_object().get_type(), pyobjects.PyClass) def is_constructor(self): return self.pyname is not None and \ - isinstance(self.pyname.get_object(), pyobjects.PyClass) + isinstance(self.pyname.get_object(), pyobjects.PyClass) def is_instance(self): if self.pyname is None: diff --git a/pymode/libs2/rope/refactor/__init__.py b/pymode/libs2/rope/refactor/__init__.py index 10d734c3..4ef67513 100644 --- a/pymode/libs2/rope/refactor/__init__.py +++ b/pymode/libs2/rope/refactor/__init__.py @@ -45,8 +45,8 @@ monitoring the progress of refactorings. """ -from rope.refactor.importutils import ImportOrganizer -from rope.refactor.topackage import ModuleToPackage +from rope.refactor.importutils import ImportOrganizer # noqa +from rope.refactor.topackage import ModuleToPackage # noqa __all__ = ['rename', 'move', 'inline', 'extract', 'restructure', 'topackage', diff --git a/pymode/libs2/rope/refactor/change_signature.py b/pymode/libs2/rope/refactor/change_signature.py index a8c50d71..4279d9cf 100644 --- a/pymode/libs2/rope/refactor/change_signature.py +++ b/pymode/libs2/rope/refactor/change_signature.py @@ -1,7 +1,12 @@ import copy import rope.base.exceptions -from rope.base import pyobjects, taskhandle, evaluate, worder, codeanalyze, utils +from rope.base import codeanalyze +from rope.base import evaluate +from rope.base import pyobjects +from rope.base import taskhandle +from rope.base import utils +from rope.base import worder from rope.base.change import ChangeContents, ChangeSet from rope.refactor import occurrences, functionutils @@ -9,7 +14,7 @@ class ChangeSignature(object): def __init__(self, project, resource, offset): - self.pycore = project.pycore + self.project = project self.resource = resource self.offset = offset self._set_name_and_pyname() @@ -20,7 +25,7 @@ def __init__(self, project, resource, offset): def _set_name_and_pyname(self): self.name = worder.get_name_at(self.resource, self.offset) - this_pymodule = self.pycore.resource_to_pyobject(self.resource) + this_pymodule = self.project.get_pymodule(self.resource) self.primary, self.pyname = evaluate.eval_location2( this_pymodule, self.offset) if self.pyname is None: @@ -42,21 +47,21 @@ def _set_name_and_pyname(self): def _change_calls(self, call_changer, in_hierarchy=None, resources=None, handle=taskhandle.NullTaskHandle()): if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() changes = ChangeSet('Changing signature of <%s>' % self.name) job_set = handle.create_jobset('Collecting Changes', len(resources)) finder = occurrences.create_finder( - self.pycore, self.name, self.pyname, instance=self.primary, + self.project, self.name, self.pyname, instance=self.primary, in_hierarchy=in_hierarchy and self.is_method()) if self.others: name, pyname = self.others constructor_finder = occurrences.create_finder( - self.pycore, name, pyname, only_calls=True) + self.project, name, pyname, only_calls=True) finder = _MultipleFinders([finder, constructor_finder]) for file in resources: job_set.started_job(file.path) change_calls = _ChangeCallsInModule( - self.pycore, finder, file, call_changer) + self.project, finder, file, call_changer) changed_file = change_calls.get_changed_module() if changed_file is not None: changes.add_change(ChangeContents(file, changed_file)) @@ -160,12 +165,15 @@ def change_definition(self, call): def change_call(self, primary, pyname, call): call_info = functionutils.CallInfo.read( primary, pyname, self.definition_info, call) - mapping = functionutils.ArgumentMapping(self.definition_info, call_info) + mapping = functionutils.ArgumentMapping(self.definition_info, + call_info) - for definition_info, changer in zip(self.changed_definition_infos, self.changers): + for definition_info, changer in zip(self.changed_definition_infos, + self.changers): changer.change_argument_mapping(definition_info, mapping) - return mapping.to_call_info(self.changed_definition_infos[-1]).to_string() + return mapping.to_call_info( + self.changed_definition_infos[-1]).to_string() class _ArgumentChanger(object): @@ -190,12 +198,14 @@ def change_definition_info(self, call_info): if self.index < len(call_info.args_with_defaults): del call_info.args_with_defaults[self.index] elif self.index == len(call_info.args_with_defaults) and \ - call_info.args_arg is not None: + call_info.args_arg is not None: call_info.args_arg = None elif (self.index == len(call_info.args_with_defaults) and - call_info.args_arg is None and call_info.keywords_arg is not None) or \ - (self.index == len(call_info.args_with_defaults) + 1 and - call_info.args_arg is not None and call_info.keywords_arg is not None): + call_info.args_arg is None and + call_info.keywords_arg is not None) or \ + (self.index == len(call_info.args_with_defaults) + 1 and + call_info.args_arg is not None and + call_info.keywords_arg is not None): call_info.keywords_arg = None def change_argument_mapping(self, definition_info, mapping): @@ -282,8 +292,8 @@ def change_definition_info(self, definition_info): class _ChangeCallsInModule(object): - def __init__(self, pycore, occurrence_finder, resource, call_changer): - self.pycore = pycore + def __init__(self, project, occurrence_finder, resource, call_changer): + self.project = project self.occurrence_finder = occurrence_finder self.resource = resource self.call_changer = call_changer @@ -291,11 +301,13 @@ def __init__(self, pycore, occurrence_finder, resource, call_changer): def get_changed_module(self): word_finder = worder.Worder(self.source) change_collector = codeanalyze.ChangeCollector(self.source) - for occurrence in self.occurrence_finder.find_occurrences(self.resource): + for occurrence in self.occurrence_finder.find_occurrences( + self.resource): if not occurrence.is_called() and not occurrence.is_defined(): continue start, end = occurrence.get_primary_range() - begin_parens, end_parens = word_finder.get_word_parens_range(end - 1) + begin_parens, end_parens = word_finder.\ + get_word_parens_range(end - 1) if occurrence.is_called(): primary, pyname = occurrence.get_primary_and_pyname() changed_call = self.call_changer.change_call( @@ -310,7 +322,7 @@ def get_changed_module(self): @property @utils.saveit def pymodule(self): - return self.pycore.resource_to_pyobject(self.resource) + return self.project.get_pymodule(self.resource) @property @utils.saveit diff --git a/pymode/libs2/rope/refactor/encapsulate_field.py b/pymode/libs2/rope/refactor/encapsulate_field.py index af8d3ccf..32cb7a95 100644 --- a/pymode/libs2/rope/refactor/encapsulate_field.py +++ b/pymode/libs2/rope/refactor/encapsulate_field.py @@ -1,4 +1,10 @@ -from rope.base import pynames, taskhandle, evaluate, exceptions, worder, utils +from rope.base import evaluate +from rope.base import exceptions +from rope.base import libutils +from rope.base import pynames +from rope.base import taskhandle +from rope.base import utils +from rope.base import worder from rope.base.change import ChangeSet, ChangeContents from rope.refactor import sourceutils, occurrences @@ -6,9 +12,9 @@ class EncapsulateField(object): def __init__(self, project, resource, offset): - self.pycore = project.pycore + self.project = project self.name = worder.get_name_at(resource, offset) - this_pymodule = self.pycore.resource_to_pyobject(resource) + this_pymodule = self.project.get_pymodule(resource) self.pyname = evaluate.eval_location(this_pymodule, offset) if not self._is_an_attribute(self.pyname): raise exceptions.RefactoringError( @@ -30,7 +36,7 @@ def get_changes(self, getter=None, setter=None, resources=None, """ if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() changes = ChangeSet('Encapsulate field <%s>' % self.name) job_set = task_handle.create_jobset('Collecting Changes', len(resources)) @@ -39,7 +45,7 @@ def get_changes(self, getter=None, setter=None, resources=None, if setter is None: setter = 'set_' + self.name renamer = GetterSetterRenameInModule( - self.pycore, self.name, self.pyname, getter, setter) + self.project, self.name, self.pyname, getter, setter) for file in resources: job_set.started_job(file.path) if file == self.resource: @@ -61,7 +67,7 @@ def _is_an_attribute(self, pyname): if pyname is not None and isinstance(pyname, pynames.AssignedName): pymodule, lineno = self.pyname.get_definition_location() scope = pymodule.get_scope().\ - get_inner_scope_for_line(lineno) + get_inner_scope_for_line(lineno) if scope.get_kind() == 'Class': return pyname in scope.get_names().values() parent = scope.parent @@ -80,7 +86,7 @@ def _get_defining_scope(self): return pymodule.get_scope().get_inner_scope_for_line(line) def _change_holding_module(self, changes, renamer, getter, setter): - pymodule = self.pycore.resource_to_pyobject(self.resource) + pymodule = self.project.get_pymodule(self.resource) class_scope = self._get_defining_class_scope() defining_object = self._get_defining_scope().pyobject start, end = sourceutils.get_body_region(defining_object) @@ -88,10 +94,11 @@ def _change_holding_module(self, changes, renamer, getter, setter): new_source = renamer.get_changed_module(pymodule=pymodule, skip_start=start, skip_end=end) if new_source is not None: - pymodule = self.pycore.get_string_module(new_source, self.resource) + pymodule = libutils.get_string_module( + self.project, new_source, self.resource) class_scope = pymodule.get_scope().\ - get_inner_scope_for_line(class_scope.get_start()) - indents = sourceutils.get_indent(self.pycore) * ' ' + get_inner_scope_for_line(class_scope.get_start()) + indents = sourceutils.get_indent(self.project) * ' ' getter = 'def %s(self):\n%sreturn self.%s' % \ (getter, indents, self.name) setter = 'def %s(self, value):\n%sself.%s = value' % \ @@ -103,10 +110,10 @@ def _change_holding_module(self, changes, renamer, getter, setter): class GetterSetterRenameInModule(object): - def __init__(self, pycore, name, pyname, getter, setter): - self.pycore = pycore + def __init__(self, project, name, pyname, getter, setter): + self.project = project self.name = name - self.finder = occurrences.create_finder(pycore, name, pyname) + self.finder = occurrences.create_finder(project, name, pyname) self.getter = getter self.setter = setter @@ -120,7 +127,7 @@ def get_changed_module(self, resource=None, pymodule=None, class _FindChangesForModule(object): def __init__(self, finder, resource, pymodule, skip_start, skip_end): - self.pycore = finder.pycore + self.project = finder.project self.finder = finder.finder self.getter = finder.getter self.setter = finder.setter @@ -155,7 +162,7 @@ def get_changed_module(self): + ' %s ' % assignment_type[:-1]) current_line = self.lines.get_line_number(start) start_line, end_line = self.pymodule.logical_lines.\ - logical_line_in(current_line) + logical_line_in(current_line) self.last_set = self.lines.get_line_end(end_line) end = self.source.index('=', end) + 1 self.set_index = len(result) @@ -193,7 +200,7 @@ def source(self): @utils.saveit def lines(self): if self.pymodule is None: - self.pymodule = self.pycore.resource_to_pyobject(self.resource) + self.pymodule = self.project.get_pymodule(self.resource) return self.pymodule.lines @property diff --git a/pymode/libs2/rope/refactor/extract.py b/pymode/libs2/rope/refactor/extract.py index 3e7a619c..be541bb5 100644 --- a/pymode/libs2/rope/refactor/extract.py +++ b/pymode/libs2/rope/refactor/extract.py @@ -12,7 +12,7 @@ # # _ExtractInfo: holds information about the refactoring; it is passed # to the parts that need to have information about the refactoring -# +# # _ExtractCollector: merely saves all of the information necessary for # performing the refactoring. # @@ -36,7 +36,6 @@ class _ExtractRefactoring(object): def __init__(self, project, resource, start_offset, end_offset, variable=False): self.project = project - self.pycore = project.pycore self.resource = resource self.start_offset = self._fix_start(resource.read(), start_offset) self.end_offset = self._fix_end(resource.read(), end_offset) @@ -95,9 +94,9 @@ class _ExtractInfo(object): def __init__(self, project, resource, start, end, new_name, variable, similar, make_global): - self.pycore = project.pycore + self.project = project self.resource = resource - self.pymodule = self.pycore.resource_to_pyobject(resource) + self.pymodule = project.get_pymodule(resource) self.global_scope = self.pymodule.get_scope() self.source = self.pymodule.source_code self.lines = self.pymodule.lines @@ -153,8 +152,8 @@ def _choose_closest_line_end(self, offset, end=False): @property def one_line(self): return self.region != self.lines_region and \ - (self.logical_lines.logical_line_in(self.region_lines[0]) == - self.logical_lines.logical_line_in(self.region_lines[1])) + (self.logical_lines.logical_line_in(self.region_lines[0]) == + self.logical_lines.logical_line_in(self.region_lines[1])) @property def global_(self): @@ -163,7 +162,7 @@ def global_(self): @property def method(self): return self.scope.parent is not None and \ - self.scope.parent.get_kind() == 'Class' + self.scope.parent.get_kind() == 'Class' @property def indents(self): @@ -182,6 +181,7 @@ def extracted(self): return self.source[self.region[0]:self.region[1]] _returned = None + @property def returned(self): """Does the extracted piece contain return statement""" @@ -273,7 +273,8 @@ def _where_to_search(self): if self.info.variable: return [self.info.scope_region] else: - return [self.info._get_scope_region(self.info.scope.parent)] + return [self.info._get_scope_region( + self.info.scope.parent)] else: return [self.info.region] @@ -391,8 +392,9 @@ def multi_line_conditions(self, info): 'contain complete statements.') def _is_region_on_a_word(self, info): - if info.region[0] > 0 and self._is_on_a_word(info, info.region[0] - 1) or \ - self._is_on_a_word(info, info.region[1] - 1): + if info.region[0] > 0 and \ + self._is_on_a_word(info, info.region[0] - 1) or \ + self._is_on_a_word(info, info.region[1] - 1): return True def _is_on_a_word(self, info, offset): @@ -436,7 +438,7 @@ def _get_body(self): return result def _find_temps(self): - return usefunction.find_temps(self.info.pycore.project, + return usefunction.find_temps(self.info.project, self._get_body()) def get_checks(self): @@ -468,7 +470,7 @@ def _get_function_definition(self): result.append('@staticmethod\n') result.append('def %s:\n' % self._get_function_signature(args)) unindented_body = self._get_unindented_function_body(returns) - indents = sourceutils.get_indent(self.info.pycore) + indents = sourceutils.get_indent(self.info.project) function_body = sourceutils.indent_lines(unindented_body, indents) result.append(function_body) definition = ''.join(result) @@ -487,11 +489,11 @@ def _get_function_signature(self, args): args.remove(self_name) args.insert(0, self_name) return prefix + self.info.new_name + \ - '(%s)' % self._get_comma_form(args) + '(%s)' % self._get_comma_form(args) def _extracting_method(self): return self.info.method and not self.info.make_global and \ - _get_function_kind(self.info.scope) == 'method' + _get_function_kind(self.info.scope) == 'method' def _get_self_name(self): param_names = self.info.scope.pyobject.get_param_names() @@ -503,7 +505,7 @@ def _get_function_call(self, args): if self.info.method and not self.info.make_global: if _get_function_kind(self.info.scope) == 'method': self_name = self._get_self_name() - if self_name in args: + if self_name in args: args.remove(self_name) prefix = self_name + '.' else: @@ -557,7 +559,7 @@ def _find_function_returns(self): if self.info.one_line or self.info.returned: return [] written = self.info_collector.written | \ - self.info_collector.maybe_written + self.info_collector.maybe_written return list(written & self.info_collector.postread) def _get_unindented_function_body(self, returns): @@ -577,7 +579,7 @@ def __init__(self, info): def get_definition(self): result = self.info.new_name + ' = ' + \ - _join_lines(self.info.extracted) + '\n' + _join_lines(self.info.extracted) + '\n' return result def get_body_pattern(self): @@ -671,7 +673,6 @@ def _For(self, node): self._handle_conditional_node(node) - def _get_argnames(arguments): result = [node.id for node in arguments.args if isinstance(node, ast.Name)] @@ -770,6 +771,7 @@ def has_errors(code): ast.walk(node, visitor) return visitor.error + def _get_function_kind(scope): return scope.pyobject.get_kind() @@ -779,6 +781,7 @@ def _parse_text(body): node = ast.parse(body) return node + def _join_lines(code): lines = [] for line in code.splitlines(): diff --git a/pymode/libs2/rope/refactor/functionutils.py b/pymode/libs2/rope/refactor/functionutils.py index a653b9db..58baf917 100644 --- a/pymode/libs2/rope/refactor/functionutils.py +++ b/pymode/libs2/rope/refactor/functionutils.py @@ -32,9 +32,6 @@ def arguments_to_string(self, from_index=0): @staticmethod def _read(pyfunction, code): - scope = pyfunction.get_scope() - parent = scope.parent - parameter_names = pyfunction.get_param_names() kind = pyfunction.get_kind() is_method = kind == 'method' is_lambda = kind == 'lambda' @@ -89,7 +86,8 @@ def to_string(self): if self.args[start:]: params.extend(self.args[start:]) if self.keywords: - params.extend(['%s=%s' % (name, value) for name, value in self.keywords]) + params.extend(['%s=%s' % (name, value) + for name, value in self.keywords]) if self.args_arg is not None: params.append('*' + self.args_arg) if self.keywords_arg: @@ -120,15 +118,15 @@ def read(primary, pyname, definition_info, code): @staticmethod def _is_method_call(primary, pyname): return primary is not None and \ - isinstance(primary.get_object().get_type(), - rope.base.pyobjects.PyClass) and \ - CallInfo._is_method(pyname) + isinstance(primary.get_object().get_type(), + rope.base.pyobjects.PyClass) and \ + CallInfo._is_method(pyname) @staticmethod def _is_class(pyname): return pyname is not None and \ - isinstance(pyname.get_object(), - rope.base.pyobjects.PyClass) + isinstance(pyname.get_object(), + rope.base.pyobjects.PyClass) @staticmethod def _is_method(pyname): @@ -184,7 +182,8 @@ def to_call_info(self, definition_info): keywords.extend(self.keyword_args) return CallInfo(self.call_info.function_name, args, keywords, self.call_info.args_arg, self.call_info.keywords_arg, - self.call_info.implicit_arg, self.call_info.constructor) + self.call_info.implicit_arg, + self.call_info.constructor) class _FunctionParser(object): @@ -197,7 +196,8 @@ def __init__(self, call, implicit_arg, is_lambda=False): self.last_parens = self.call.rindex(':') else: self.last_parens = self.call.rindex(')') - self.first_parens = self.word_finder._find_parens_start(self.last_parens) + self.first_parens = self.word_finder._find_parens_start( + self.last_parens) def get_parameters(self): args, keywords = self.word_finder.get_parameters(self.first_parens, diff --git a/pymode/libs2/rope/refactor/importutils/__init__.py b/pymode/libs2/rope/refactor/importutils/__init__.py index 2a86edb0..4871faf3 100644 --- a/pymode/libs2/rope/refactor/importutils/__init__.py +++ b/pymode/libs2/rope/refactor/importutils/__init__.py @@ -5,6 +5,7 @@ """ import rope.base.evaluate +from rope.base import libutils from rope.base.change import ChangeSet, ChangeContents from rope.refactor import occurrences, rename from rope.refactor.importutils import module_imports, actions @@ -21,8 +22,7 @@ class ImportOrganizer(object): def __init__(self, project): self.project = project - self.pycore = project.pycore - self.import_tools = ImportTools(self.pycore) + self.import_tools = ImportTools(self.project) def organize_imports(self, resource, offset=None): return self._perform_command_on_import_tools( @@ -45,7 +45,7 @@ def handle_long_imports(self, resource, offset=None): self.import_tools.handle_long_imports, resource, offset) def _perform_command_on_import_tools(self, method, resource, offset): - pymodule = self.pycore.resource_to_pyobject(resource) + pymodule = self.project.get_pymodule(resource) before_performing = pymodule.source_code import_filter = None if offset is not None: @@ -66,26 +66,26 @@ def import_filter(import_stmt): class ImportTools(object): - def __init__(self, pycore): - self.pycore = pycore + def __init__(self, project): + self.project = project def get_import(self, resource): """The import statement for `resource`""" - module_name = self.pycore.modname(resource) + module_name = libutils.modname(resource) return NormalImport(((module_name, None), )) def get_from_import(self, resource, name): """The from import statement for `name` in `resource`""" - module_name = self.pycore.modname(resource) + module_name = libutils.modname(resource) names = [] if isinstance(name, list): names = [(imported, None) for imported in name] else: - names = [(name, None),] + names = [(name, None), ] return FromImport(module_name, 0, tuple(names)) def module_imports(self, module, imports_filter=None): - return module_imports.ModuleImports(self.pycore, module, + return module_imports.ModuleImports(self.project, module, imports_filter) def froms_to_imports(self, pymodule, import_filter=None): @@ -103,7 +103,8 @@ def froms_to_imports(self, pymodule, import_filter=None): if not import_stmt.readonly and \ self._is_transformable_to_normal(import_stmt.import_info): import_stmt.import_info = \ - NormalImport(((import_stmt.import_info.module_name, None),)) + NormalImport(((import_stmt.import_info.module_name, + None),)) module_imports.remove_duplicates() return module_imports.get_changed_source() @@ -121,12 +122,13 @@ def _from_to_normal(self, pymodule, import_stmt): if alias is not None: imported = alias occurrence_finder = occurrences.create_finder( - self.pycore, imported, pymodule[imported], imports=False) + self.project, imported, pymodule[imported], imports=False) source = rename.rename_in_module( occurrence_finder, module_name + '.' + name, pymodule=pymodule, replace_primary=True) if source is not None: - pymodule = self.pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module( + self.project, source, resource) return pymodule def _clean_up_imports(self, pymodule, import_filter): @@ -135,17 +137,20 @@ def _clean_up_imports(self, pymodule, import_filter): module_with_imports.expand_stars() source = module_with_imports.get_changed_source() if source is not None: - pymodule = self.pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module( + self.project, source, resource) source = self.relatives_to_absolutes(pymodule) if source is not None: - pymodule = self.pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module( + self.project, source, resource) module_with_imports = self.module_imports(pymodule, import_filter) module_with_imports.remove_duplicates() module_with_imports.remove_unused_imports() source = module_with_imports.get_changed_source() if source is not None: - pymodule = self.pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module( + self.project, source, resource) return pymodule def relatives_to_absolutes(self, pymodule, import_filter=None): @@ -172,12 +177,14 @@ def organize_imports(self, pymodule, module_imports = self.module_imports(pymodule, import_filter) if unused: module_imports.remove_unused_imports() + if self.project.prefs.get("split_imports"): + module_imports.force_single_imports() if duplicates: module_imports.remove_duplicates() source = module_imports.get_changed_source() if source is not None: - pymodule = self.pycore.get_string_module( - source, pymodule.get_resource()) + pymodule = libutils.get_string_module( + self.project, source, pymodule.get_resource()) if selfs: pymodule = self._remove_self_imports(pymodule, import_filter) if sort: @@ -187,10 +194,12 @@ def organize_imports(self, pymodule, def _remove_self_imports(self, pymodule, import_filter=None): module_imports = self.module_imports(pymodule, import_filter) - to_be_fixed, to_be_renamed = module_imports.get_self_import_fix_and_rename_list() + to_be_fixed, to_be_renamed = \ + module_imports.get_self_import_fix_and_rename_list() for name in to_be_fixed: try: - pymodule = self._rename_in_module(pymodule, name, '', till_dot=True) + pymodule = self._rename_in_module(pymodule, name, '', + till_dot=True) except ValueError: # There is a self import with direct access to it return pymodule @@ -200,16 +209,18 @@ def _remove_self_imports(self, pymodule, import_filter=None): module_imports.get_self_import_fix_and_rename_list() source = module_imports.get_changed_source() if source is not None: - pymodule = self.pycore.get_string_module(source, pymodule.get_resource()) + pymodule = libutils.get_string_module( + self.project, source, pymodule.get_resource()) return pymodule def _rename_in_module(self, pymodule, name, new_name, till_dot=False): old_name = name.split('.')[-1] old_pyname = rope.base.evaluate.eval_str(pymodule.get_scope(), name) occurrence_finder = occurrences.create_finder( - self.pycore, old_name, old_pyname, imports=False) + self.project, old_name, old_pyname, imports=False) changes = rope.base.codeanalyze.ChangeCollector(pymodule.source_code) - for occurrence in occurrence_finder.find_occurrences(pymodule=pymodule): + for occurrence in occurrence_finder.find_occurrences( + pymodule=pymodule): start, end = occurrence.get_primary_range() if till_dot: new_end = pymodule.source_code.index('.', end) + 1 @@ -222,7 +233,8 @@ def _rename_in_module(self, pymodule, name, new_name, till_dot=False): changes.add_change(start, end, new_name) source = changes.get_changed() if source is not None: - pymodule = self.pycore.get_string_module(source, pymodule.get_resource()) + pymodule = libutils.get_string_module( + self.project, source, pymodule.get_resource()) return pymodule def sort_imports(self, pymodule, import_filter=None): @@ -237,8 +249,8 @@ def handle_long_imports(self, pymodule, maxdots=2, maxlength=27, module_imports = self.module_imports(pymodule, import_filter) to_be_fixed = module_imports.handle_long_imports(maxdots, maxlength) # performing the renaming - pymodule = self.pycore.get_string_module( - module_imports.get_changed_source(), + pymodule = libutils.get_string_module( + self.project, module_imports.get_changed_source(), resource=pymodule.get_resource()) for name in to_be_fixed: pymodule = self._rename_in_module(pymodule, name, @@ -248,22 +260,22 @@ def handle_long_imports(self, pymodule, maxdots=2, maxlength=27, import_filter=import_filter) -def get_imports(pycore, pydefined): +def get_imports(project, pydefined): """A shortcut for getting the `ImportInfo`\s used in a scope""" pymodule = pydefined.get_module() - module = module_imports.ModuleImports(pycore, pymodule) + module = module_imports.ModuleImports(project, pymodule) if pymodule == pydefined: return [stmt.import_info for stmt in module.imports] return module.get_used_imports(pydefined) -def get_module_imports(pycore, pymodule): +def get_module_imports(project, pymodule): """A shortcut for creating a `module_imports.ModuleImports` object""" - return module_imports.ModuleImports(pycore, pymodule) + return module_imports.ModuleImports(project, pymodule) -def add_import(pycore, pymodule, module_name, name=None): - imports = get_module_imports(pycore, pymodule) +def add_import(project, pymodule, module_name, name=None): + imports = get_module_imports(project, pymodule) candidates = [] names = [] # from mod import name @@ -288,7 +300,7 @@ def add_import(pycore, pymodule, module_name, name=None): candidates.append(normal_import) - visitor = actions.AddingVisitor(pycore, candidates) + visitor = actions.AddingVisitor(project, candidates) selected_import = normal_import for import_statement in imports.imports: if import_statement.accept(visitor): diff --git a/pymode/libs2/rope/refactor/importutils/actions.py b/pymode/libs2/rope/refactor/importutils/actions.py index 4851d02f..fd0f7054 100644 --- a/pymode/libs2/rope/refactor/importutils/actions.py +++ b/pymode/libs2/rope/refactor/importutils/actions.py @@ -1,6 +1,4 @@ -import os -import sys - +from rope.base import libutils from rope.base import pyobjects, exceptions, stdmods from rope.refactor import occurrences from rope.refactor.importutils import importinfo @@ -28,24 +26,25 @@ def visitFromImport(self, import_stmt, import_info): class RelativeToAbsoluteVisitor(ImportInfoVisitor): - def __init__(self, pycore, current_folder): + def __init__(self, project, current_folder): self.to_be_absolute = [] - self.pycore = pycore + self.project = project self.folder = current_folder - self.context = importinfo.ImportContext(pycore, current_folder) + self.context = importinfo.ImportContext(project, current_folder) def visitNormalImport(self, import_stmt, import_info): - self.to_be_absolute.extend(self._get_relative_to_absolute_list(import_info)) + self.to_be_absolute.extend( + self._get_relative_to_absolute_list(import_info)) new_pairs = [] for name, alias in import_info.names_and_aliases: - resource = self.pycore.find_module(name, folder=self.folder) + resource = self.project.find_module(name, folder=self.folder) if resource is None: new_pairs.append((name, alias)) continue - absolute_name = self.pycore.modname(resource) + absolute_name = libutils.modname(resource) new_pairs.append((absolute_name, alias)) if not import_info._are_name_and_alias_lists_equal( - new_pairs, import_info.names_and_aliases): + new_pairs, import_info.names_and_aliases): import_stmt.import_info = importinfo.NormalImport(new_pairs) def _get_relative_to_absolute_list(self, import_info): @@ -53,10 +52,10 @@ def _get_relative_to_absolute_list(self, import_info): for name, alias in import_info.names_and_aliases: if alias is not None: continue - resource = self.pycore.find_module(name, folder=self.folder) + resource = self.project.find_module(name, folder=self.folder) if resource is None: continue - absolute_name = self.pycore.modname(resource) + absolute_name = libutils.modname(resource) if absolute_name != name: result.append((name, absolute_name)) return result @@ -65,7 +64,7 @@ def visitFromImport(self, import_stmt, import_info): resource = import_info.get_imported_resource(self.context) if resource is None: return None - absolute_name = self.pycore.modname(resource) + absolute_name = libutils.modname(resource) if import_info.module_name != absolute_name: import_stmt.import_info = importinfo.FromImport( absolute_name, 0, import_info.names_and_aliases) @@ -73,11 +72,11 @@ def visitFromImport(self, import_stmt, import_info): class FilteringVisitor(ImportInfoVisitor): - def __init__(self, pycore, folder, can_select): + def __init__(self, project, folder, can_select): self.to_be_absolute = [] - self.pycore = pycore + self.project = project self.can_select = self._transform_can_select(can_select) - self.context = importinfo.ImportContext(pycore, folder) + self.context = importinfo.ImportContext(project, folder) def _transform_can_select(self, can_select): def can_select_name_and_alias(name, alias): @@ -113,10 +112,10 @@ def visitFromImport(self, import_stmt, import_info): class RemovingVisitor(ImportInfoVisitor): - def __init__(self, pycore, folder, can_select): + def __init__(self, project, folder, can_select): self.to_be_absolute = [] - self.pycore = pycore - self.filtering = FilteringVisitor(pycore, folder, can_select) + self.project = project + self.filtering = FilteringVisitor(project, folder, can_select) def dispatch(self, import_): result = self.filtering.dispatch(import_) @@ -133,8 +132,8 @@ class AddingVisitor(ImportInfoVisitor): """ - def __init__(self, pycore, import_list): - self.pycore = pycore + def __init__(self, project, import_list): + self.project = project self.import_list = import_list self.import_info = None @@ -162,7 +161,8 @@ def visitNormalImport(self, import_stmt, import_info): # Multiple imports using a single import statement is discouraged # so we won't bother adding them. if self.import_info._are_name_and_alias_lists_equal( - import_info.names_and_aliases, self.import_info.names_and_aliases): + import_info.names_and_aliases, + self.import_info.names_and_aliases): return True def visitFromImport(self, import_stmt, import_info): @@ -174,6 +174,9 @@ def visitFromImport(self, import_stmt, import_info): if self.import_info.is_star_import(): import_stmt.import_info = self.import_info return True + if self.project.prefs.get("split_imports"): + return self.import_info.names_and_aliases == \ + import_info.names_and_aliases new_pairs = list(import_info.names_and_aliases) for pair in self.import_info.names_and_aliases: if pair not in new_pairs: @@ -185,10 +188,10 @@ def visitFromImport(self, import_stmt, import_info): class ExpandStarsVisitor(ImportInfoVisitor): - def __init__(self, pycore, folder, can_select): - self.pycore = pycore - self.filtering = FilteringVisitor(pycore, folder, can_select) - self.context = importinfo.ImportContext(pycore, folder) + def __init__(self, project, folder, can_select): + self.project = project + self.filtering = FilteringVisitor(project, folder, can_select) + self.context = importinfo.ImportContext(project, folder) def visitNormalImport(self, import_stmt, import_info): self.filtering.dispatch(import_stmt) @@ -208,18 +211,18 @@ def visitFromImport(self, import_stmt, import_info): class SelfImportVisitor(ImportInfoVisitor): - def __init__(self, pycore, current_folder, resource): - self.pycore = pycore + def __init__(self, project, current_folder, resource): + self.project = project self.folder = current_folder self.resource = resource self.to_be_fixed = set() self.to_be_renamed = set() - self.context = importinfo.ImportContext(pycore, current_folder) + self.context = importinfo.ImportContext(project, current_folder) def visitNormalImport(self, import_stmt, import_info): new_pairs = [] for name, alias in import_info.names_and_aliases: - resource = self.pycore.find_module(name, folder=self.folder) + resource = self.project.find_module(name, folder=self.folder) if resource is not None and resource == self.resource: imported = name if alias is not None: @@ -228,7 +231,7 @@ def visitNormalImport(self, import_stmt, import_info): else: new_pairs.append((name, alias)) if not import_info._are_name_and_alias_lists_equal( - new_pairs, import_info.names_and_aliases): + new_pairs, import_info.names_and_aliases): import_stmt.import_info = importinfo.NormalImport(new_pairs) def visitFromImport(self, import_stmt, import_info): @@ -238,7 +241,7 @@ def visitFromImport(self, import_stmt, import_info): if resource == self.resource: self._importing_names_from_self(import_info, import_stmt) return - pymodule = self.pycore.resource_to_pyobject(resource) + pymodule = self.project.get_pymodule(resource) new_pairs = [] for name, alias in import_info.names_and_aliases: try: @@ -254,7 +257,7 @@ def visitFromImport(self, import_stmt, import_info): except exceptions.AttributeNotFoundError: new_pairs.append((name, alias)) if not import_info._are_name_and_alias_lists_equal( - new_pairs, import_info.names_and_aliases): + new_pairs, import_info.names_and_aliases): import_stmt.import_info = importinfo.FromImport( import_info.module_name, import_info.level, new_pairs) @@ -268,19 +271,19 @@ def _importing_names_from_self(self, import_info, import_stmt): class SortingVisitor(ImportInfoVisitor): - def __init__(self, pycore, current_folder): - self.pycore = pycore + def __init__(self, project, current_folder): + self.project = project self.folder = current_folder self.standard = set() self.third_party = set() self.in_project = set() self.future = set() - self.context = importinfo.ImportContext(pycore, current_folder) + self.context = importinfo.ImportContext(project, current_folder) def visitNormalImport(self, import_stmt, import_info): if import_info.names_and_aliases: name, alias = import_info.names_and_aliases[0] - resource = self.pycore.find_module( + resource = self.project.find_module( name, folder=self.folder) self._check_imported_resource(import_stmt, resource, name) @@ -291,7 +294,7 @@ def visitFromImport(self, import_stmt, import_info): def _check_imported_resource(self, import_stmt, resource, imported_name): info = import_stmt.import_info - if resource is not None and resource.project == self.pycore.project: + if resource is not None and resource.project == self.project: self.in_project.add(import_stmt) elif _is_future(info): self.future.add(import_stmt) @@ -303,16 +306,15 @@ def _check_imported_resource(self, import_stmt, resource, imported_name): class LongImportVisitor(ImportInfoVisitor): - def __init__(self, current_folder, pycore, maxdots, maxlength): + def __init__(self, current_folder, project, maxdots, maxlength): self.maxdots = maxdots self.maxlength = maxlength self.to_be_renamed = set() self.current_folder = current_folder - self.pycore = pycore + self.project = project self.new_imports = [] def visitNormalImport(self, import_stmt, import_info): - new_pairs = [] for name, alias in import_info.names_and_aliases: if alias is None and self._is_long(name): self.to_be_renamed.add(name) @@ -324,15 +326,15 @@ def visitNormalImport(self, import_stmt, import_info): def _is_long(self, name): return name.count('.') > self.maxdots or \ - ('.' in name and len(name) > self.maxlength) + ('.' in name and len(name) > self.maxlength) class RemovePyNameVisitor(ImportInfoVisitor): - def __init__(self, pycore, pymodule, pyname, folder): + def __init__(self, project, pymodule, pyname, folder): self.pymodule = pymodule self.pyname = pyname - self.context = importinfo.ImportContext(pycore, folder) + self.context = importinfo.ImportContext(project, folder) def visitFromImport(self, import_stmt, import_info): new_pairs = [] @@ -356,4 +358,4 @@ def dispatch(self, import_): def _is_future(info): return isinstance(info, importinfo.FromImport) and \ - info.module_name == '__future__' + info.module_name == '__future__' diff --git a/pymode/libs2/rope/refactor/importutils/importinfo.py b/pymode/libs2/rope/refactor/importutils/importinfo.py index 25c8e813..114080aa 100644 --- a/pymode/libs2/rope/refactor/importutils/importinfo.py +++ b/pymode/libs2/rope/refactor/importutils/importinfo.py @@ -84,7 +84,7 @@ def _are_name_and_alias_lists_equal(self, list1, list2): def __eq__(self, obj): return isinstance(obj, self.__class__) and \ - self.get_import_statement() == obj.get_import_statement() + self.get_import_statement() == obj.get_import_statement() def __ne__(self, obj): return not self.__eq__(obj) @@ -147,10 +147,10 @@ def get_imported_resource(self, context): Returns `None` if module was not found. """ if self.level == 0: - return context.pycore.find_module( + return context.project.find_module( self.module_name, folder=context.folder) else: - return context.pycore.find_relative_module( + return context.project.find_relative_module( self.module_name, context.folder, self.level) def get_imported_module(self, context): @@ -160,10 +160,10 @@ def get_imported_module(self, context): could not be found. """ if self.level == 0: - return context.pycore.get_module( + return context.project.get_module( self.module_name, context.folder) else: - return context.pycore.get_relative_module( + return context.project.get_relative_module( self.module_name, context.folder, self.level) def get_import_statement(self): @@ -180,7 +180,7 @@ def is_empty(self): def is_star_import(self): return len(self.names_and_aliases) > 0 and \ - self.names_and_aliases[0][0] == '*' + self.names_and_aliases[0][0] == '*' class EmptyImport(ImportInfo): @@ -196,6 +196,6 @@ def get_imported_primaries(self, context): class ImportContext(object): - def __init__(self, pycore, folder): - self.pycore = pycore + def __init__(self, project, folder): + self.project = project self.folder = folder diff --git a/pymode/libs2/rope/refactor/importutils/module_imports.py b/pymode/libs2/rope/refactor/importutils/module_imports.py index 874213f2..b96eebc4 100644 --- a/pymode/libs2/rope/refactor/importutils/module_imports.py +++ b/pymode/libs2/rope/refactor/importutils/module_imports.py @@ -1,13 +1,14 @@ -import rope.base.pynames -from rope.base import ast, utils -from rope.refactor.importutils import importinfo +from rope.base import ast +from rope.base import pynames +from rope.base import utils from rope.refactor.importutils import actions +from rope.refactor.importutils import importinfo class ModuleImports(object): - def __init__(self, pycore, pymodule, import_filter=None): - self.pycore = pycore + def __init__(self, project, pymodule, import_filter=None): + self.project = project self.pymodule = pymodule self.separating_lines = 0 self.filter = import_filter @@ -15,7 +16,7 @@ def __init__(self, pycore, pymodule, import_filter=None): @property @utils.saveit def imports(self): - finder = _GlobalImportFinder(self.pymodule, self.pycore) + finder = _GlobalImportFinder(self.pymodule) result = finder.find_import_statements() self.separating_lines = finder.get_separating_line_count() if self.filter is not None: @@ -32,15 +33,16 @@ def _get_unbound_names(self, defined_pyobject): def remove_unused_imports(self): can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule)) visitor = actions.RemovingVisitor( - self.pycore, self._current_folder(), can_select) + self.project, self._current_folder(), can_select) for import_statement in self.imports: import_statement.accept(visitor) def get_used_imports(self, defined_pyobject): result = [] - can_select = _OneTimeSelector(self._get_unbound_names(defined_pyobject)) + can_select = _OneTimeSelector( + self._get_unbound_names(defined_pyobject)) visitor = actions.FilteringVisitor( - self.pycore, self._current_folder(), can_select) + self.project, self._current_folder(), can_select) for import_statement in self.imports: new_import = import_statement.accept(visitor) if new_import is not None and not new_import.is_empty(): @@ -48,11 +50,18 @@ def get_used_imports(self, defined_pyobject): return result def get_changed_source(self): - imports = self.imports - after_removing = self._remove_imports(imports) - imports = [stmt for stmt in imports + # Make sure we forward a removed import's preceding blank + # lines count to the following import statement. + prev_stmt = None + for stmt in self.imports: + if prev_stmt is not None and prev_stmt.import_info.is_empty(): + stmt.blank_lines = max(prev_stmt.blank_lines, stmt.blank_lines) + prev_stmt = stmt + # The new list of imports. + imports = [stmt for stmt in self.imports if not stmt.import_info.is_empty()] + after_removing = self._remove_imports(self.imports) first_non_blank = self._first_non_blank_line(after_removing, 0) first_import = self._first_import_line() - 1 result = [] @@ -61,7 +70,6 @@ def get_changed_source(self): # Writing imports sorted_imports = sorted(imports, self._compare_import_locations) for stmt in sorted_imports: - start = self._get_import_location(stmt) if stmt != sorted_imports[0]: result.append('\n' * stmt.blank_lines) result.append(stmt.get_import_statement() + '\n') @@ -111,7 +119,7 @@ def _first_non_blank_line(self, lines, lineno): return result def add_import(self, import_info): - visitor = actions.AddingVisitor(self.pycore, [import_info]) + visitor = actions.AddingVisitor(self.project, [import_info]) for import_statement in self.imports: if import_statement.accept(visitor): break @@ -132,21 +140,21 @@ def _get_new_import_lineno(self): def filter_names(self, can_select): visitor = actions.RemovingVisitor( - self.pycore, self._current_folder(), can_select) + self.project, self._current_folder(), can_select) for import_statement in self.imports: import_statement.accept(visitor) def expand_stars(self): can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule)) visitor = actions.ExpandStarsVisitor( - self.pycore, self._current_folder(), can_select) + self.project, self._current_folder(), can_select) for import_statement in self.imports: import_statement.accept(visitor) def remove_duplicates(self): added_imports = [] for import_stmt in self.imports: - visitor = actions.AddingVisitor(self.pycore, + visitor = actions.AddingVisitor(self.project, [import_stmt.import_info]) for added_import in added_imports: if added_import.accept(visitor): @@ -154,17 +162,34 @@ def remove_duplicates(self): else: added_imports.append(import_stmt) + def force_single_imports(self): + """force a single import per statement""" + for import_stmt in self.imports[:]: + import_info = import_stmt.import_info + if import_info.is_empty(): + continue + if len(import_info.names_and_aliases) > 1: + for name_and_alias in import_info.names_and_aliases: + if hasattr(import_info, "module_name"): + new_import = importinfo.FromImport( + import_info.module_name, import_info.level, + [name_and_alias]) + else: + new_import = importinfo.NormalImport([name_and_alias]) + self.add_import(new_import) + import_stmt.empty_import() + def get_relative_to_absolute_list(self): - visitor = rope.refactor.importutils.actions.RelativeToAbsoluteVisitor( - self.pycore, self._current_folder()) + visitor = actions.RelativeToAbsoluteVisitor( + self.project, self._current_folder()) for import_stmt in self.imports: if not import_stmt.readonly: import_stmt.accept(visitor) return visitor.to_be_absolute def get_self_import_fix_and_rename_list(self): - visitor = rope.refactor.importutils.actions.SelfImportVisitor( - self.pycore, self._current_folder(), self.pymodule.get_resource()) + visitor = actions.SelfImportVisitor( + self.project, self._current_folder(), self.pymodule.get_resource()) for import_stmt in self.imports: if not import_stmt.readonly: import_stmt.accept(visitor) @@ -174,15 +199,19 @@ def _current_folder(self): return self.pymodule.get_resource().parent def sort_imports(self): + if self.project.prefs.get("sort_imports_alphabetically"): + sort_kwargs = dict(key=self._get_import_name) + else: + sort_kwargs = dict(cmp=self._compare_imports) + # IDEA: Sort from import list - visitor = actions.SortingVisitor(self.pycore, self._current_folder()) + visitor = actions.SortingVisitor(self.project, self._current_folder()) for import_statement in self.imports: import_statement.accept(visitor) - in_projects = sorted(visitor.in_project, self._compare_imports) - third_party = sorted(visitor.third_party, self._compare_imports) - standards = sorted(visitor.standard, self._compare_imports) - future = sorted(visitor.future, self._compare_imports) - blank_lines = 0 + in_projects = sorted(visitor.in_project, **sort_kwargs) + third_party = sorted(visitor.third_party, **sort_kwargs) + standards = sorted(visitor.standard, **sort_kwargs) + future = sorted(visitor.future, **sort_kwargs) last_index = self._first_import_line() last_index = self._move_imports(future, last_index, 0) last_index = self._move_imports(standards, last_index, 1) @@ -208,6 +237,14 @@ def _first_import_line(self): break return lineno + def _get_import_name(self, import_stmt): + import_info = import_stmt.import_info + if hasattr(import_info, "module_name"): + return "%s.%s" % (import_info.module_name, + import_info.names_and_aliases[0][0]) + else: + return import_info.names_and_aliases[0][0] + def _compare_imports(self, stmt1, stmt2): str1 = stmt1.get_import_statement() str2 = stmt2.get_import_statement() @@ -229,7 +266,7 @@ def _move_imports(self, imports, index, blank_lines): def handle_long_imports(self, maxdots, maxlength): visitor = actions.LongImportVisitor( - self._current_folder(), self.pycore, maxdots, maxlength) + self._current_folder(), self.project, maxdots, maxlength) for import_statement in self.imports: if not import_statement.readonly: import_statement.accept(visitor) @@ -239,7 +276,7 @@ def handle_long_imports(self, maxdots, maxlength): def remove_pyname(self, pyname): """Removes pyname when imported in ``from mod import x``""" - visitor = actions.RemovePyNameVisitor(self.pycore, self.pymodule, + visitor = actions.RemovePyNameVisitor(self.project, self.pymodule, pyname, self._current_folder()) for import_stmt in self.imports: import_stmt.accept(visitor) @@ -277,7 +314,7 @@ def __init__(self, pyobject): def _visit_child_scope(self, node): pyobject = self.pyobject.get_module().get_scope().\ - get_inner_scope_for_line(node.lineno).pyobject + get_inner_scope_for_line(node.lineno).pyobject visitor = _LocalUnboundNameFinder(pyobject, self) for child in ast.get_child_nodes(node): ast.walk(child, visitor) @@ -324,8 +361,8 @@ def __init__(self, pymodule, wanted_pyobject): self.unbound = set() self.names = set() for name, pyname in pymodule._get_structural_attributes().items(): - if not isinstance(pyname, (rope.base.pynames.ImportedName, - rope.base.pynames.ImportedModule)): + if not isinstance(pyname, (pynames.ImportedName, + pynames.ImportedModule)): self.names.add(name) wanted_scope = wanted_pyobject.get_scope() self.start = wanted_scope.get_start() @@ -374,12 +411,11 @@ def add_unbound(self, name): class _GlobalImportFinder(object): - def __init__(self, pymodule, pycore): + def __init__(self, pymodule): self.current_folder = None if pymodule.get_resource(): self.current_folder = pymodule.get_resource().parent self.pymodule = pymodule - self.pycore = pycore self.imports = [] self.pymodule = pymodule self.lines = self.pymodule.lines @@ -428,13 +464,14 @@ def visit_from(self, node, end_line): if node.level: level = node.level import_info = importinfo.FromImport( - node.module or '', # see comment at rope.base.ast.walk + node.module or '', # see comment at rope.base.ast.walk level, self._get_names(node.names)) start_line = node.lineno self.imports.append(importinfo.ImportStatement( import_info, node.lineno, end_line, self._get_text(start_line, end_line), - blank_lines=self._count_empty_lines_before(start_line))) + blank_lines= + self._count_empty_lines_before(start_line))) def _get_names(self, alias_names): result = [] diff --git a/pymode/libs2/rope/refactor/inline.py b/pymode/libs2/rope/refactor/inline.py index cfd64a7e..0ae1f8f4 100644 --- a/pymode/libs2/rope/refactor/inline.py +++ b/pymode/libs2/rope/refactor/inline.py @@ -21,17 +21,19 @@ import rope.base.exceptions import rope.refactor.functionutils from rope.base import (pynames, pyobjects, codeanalyze, - taskhandle, evaluate, worder, utils) + taskhandle, evaluate, worder, utils, libutils) from rope.base.change import ChangeSet, ChangeContents from rope.refactor import (occurrences, rename, sourceutils, importutils, move, change_signature) + def unique_prefix(): n = 0 while True: yield "__" + str(n) + "__" n += 1 + def create_inline(project, resource, offset): """Create a refactoring object for inlining @@ -39,8 +41,7 @@ def create_inline(project, resource, offset): `InlineMethod`, `InlineVariable` or `InlineParameter`. """ - pycore = project.pycore - pyname = _get_pyname(pycore, resource, offset) + pyname = _get_pyname(project, resource, offset) message = 'Inline refactoring should be performed on ' \ 'a method, local variable or parameter.' if pyname is None: @@ -61,9 +62,8 @@ class _Inliner(object): def __init__(self, project, resource, offset): self.project = project - self.pycore = project.pycore - self.pyname = _get_pyname(self.pycore, resource, offset) - range_finder = worder.Worder(resource.read()) + self.pyname = _get_pyname(project, resource, offset) + range_finder = worder.Worder(resource.read(), True) self.region = range_finder.get_primary_range(offset) self.name = range_finder.get_word_at(offset) self.offset = offset @@ -84,7 +84,7 @@ def __init__(self, *args, **kwds): self.pymodule = self.pyfunction.get_module() self.resource = self.pyfunction.get_module().get_resource() self.occurrence_finder = occurrences.create_finder( - self.pycore, self.name, self.pyname) + self.project, self.name, self.pyname) self.normal_generator = _DefinitionGenerator(self.project, self.pyfunction) self._init_imports() @@ -92,7 +92,7 @@ def __init__(self, *args, **kwds): def _init_imports(self): body = sourceutils.get_body(self.pyfunction) body, imports = move.moving_code_with_imports( - self.pycore, self.resource, body) + self.project, self.resource, body) self.imports = imports self.others_generator = _DefinitionGenerator( self.project, self.pyfunction, body=body) @@ -100,7 +100,6 @@ def _init_imports(self): def _get_scope_range(self): scope = self.pyfunction.get_scope() lines = self.pymodule.lines - logicals = self.pymodule.logical_lines start_line = scope.get_start() if self.pyfunction.decorators: decorators = self.pyfunction.decorators @@ -121,7 +120,7 @@ def get_changes(self, remove=True, only_current=False, resources=None, """ changes = ChangeSet('Inline method <%s>' % self.name) if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() if only_current: resources = [self.original] if remove: @@ -132,20 +131,20 @@ def get_changes(self, remove=True, only_current=False, resources=None, job_set.started_job(file.path) if file == self.resource: changes.add_change(self._defining_file_changes( - changes, remove=remove, only_current=only_current)) + changes, remove=remove, only_current=only_current)) else: aim = None if only_current and self.original == file: aim = self.offset handle = _InlineFunctionCallsForModuleHandle( - self.pycore, file, self.others_generator, aim) + self.project, file, self.others_generator, aim) result = move.ModuleSkipRenamer( self.occurrence_finder, file, handle).get_changed_module() if result is not None: - result = _add_imports(self.pycore, result, + result = _add_imports(self.project, result, file, self.imports) if remove: - result = _remove_from(self.pycore, self.pyname, + result = _remove_from(self.project, self.pyname, result, file) changes.add_change(ChangeContents(file, result)) job_set.finished_job() @@ -154,8 +153,6 @@ def get_changes(self, remove=True, only_current=False, resources=None, def _get_removed_range(self): scope = self.pyfunction.get_scope() lines = self.pymodule.lines - logical = self.pymodule.logical_lines - start_line = scope.get_start() start, end = self._get_scope_range() end_line = scope.get_end() for i in range(end_line + 1, lines.length()): @@ -177,7 +174,7 @@ def _defining_file_changes(self, changes, remove, only_current): # we don't want to change any of them aim = len(self.resource.read()) + 100 handle = _InlineFunctionCallsForModuleHandle( - self.pycore, self.resource, + self.project, self.resource, self.normal_generator, aim_offset=aim) replacement = None if remove: @@ -200,7 +197,6 @@ def _is_the_last_method_of_a_class(self): return False class_start, class_end = sourceutils.get_body_region(pyclass) source = self.pymodule.source_code - lines = self.pymodule.lines func_start, func_end = self._get_scope_range() if source[class_start:func_start].strip() == '' and \ source[func_end:class_end].strip() == '': @@ -226,12 +222,12 @@ def _check_exceptional_conditions(self): 'Local variable should be assigned once for inlining.') def get_changes(self, remove=True, only_current=False, resources=None, - task_handle=taskhandle.NullTaskHandle()): + docs=False, task_handle=taskhandle.NullTaskHandle()): if resources is None: if rename._is_local(self.pyname): resources = [self.resource] else: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() if only_current: resources = [self.original] if remove and self.original != self.resource: @@ -243,28 +239,29 @@ def get_changes(self, remove=True, only_current=False, resources=None, for resource in resources: jobset.started_job(resource.path) if resource == self.resource: - source = self._change_main_module(remove, only_current) + source = self._change_main_module(remove, only_current, docs) changes.add_change(ChangeContents(self.resource, source)) else: result = self._change_module(resource, remove, only_current) if result is not None: - result = _add_imports(self.pycore, result, + result = _add_imports(self.project, result, resource, self.imports) changes.add_change(ChangeContents(resource, result)) jobset.finished_job() return changes - def _change_main_module(self, remove, only_current): + def _change_main_module(self, remove, only_current, docs): region = None if only_current and self.original == self.resource: region = self.region - return _inline_variable(self.pycore, self.pymodule, self.pyname, - self.name, remove=remove, region=region) + return _inline_variable(self.project, self.pymodule, self.pyname, + self.name, remove=remove, region=region, + docs=docs) def _init_imports(self): vardef = _getvardef(self.pymodule, self.pyname) self.imported, self.imports = move.moving_code_with_imports( - self.pycore, self.resource, vardef) + self.project, self.resource, vardef) def _change_module(self, resource, remove, only_current): filters = [occurrences.NoImportsFilter(), @@ -275,11 +272,12 @@ def check_aim(occurrence): if self.offset < start or end < self.offset: return False filters.insert(0, check_aim) - finder = occurrences.Finder(self.pycore, self.name, filters=filters) + finder = occurrences.Finder(self.project, self.name, filters=filters) changed = rename.rename_in_module( finder, self.imported, resource=resource, replace_primary=True) if changed and remove: - changed = _remove_from(self.pycore, self.pyname, changed, resource) + changed = _remove_from(self.project, self.pyname, + changed, resource) return changed def get_kind(self): @@ -329,8 +327,9 @@ def _join_lines(lines): class _DefinitionGenerator(object): unique_prefix = unique_prefix() + def __init__(self, project, pyfunction, body=None): - self.pycore = project.pycore + self.project = project self.pyfunction = pyfunction self.pymodule = pyfunction.get_module() self.resource = self.pymodule.get_resource() @@ -360,10 +359,11 @@ def _get_definition_params(self): def get_function_name(self): return self.pyfunction.get_name() - def get_definition(self, primary, pyname, call, host_vars=[],returns=False): + def get_definition(self, primary, pyname, call, host_vars=[], + returns=False): # caching already calculated definitions return self._calculate_definition(primary, pyname, call, - host_vars, returns) + host_vars, returns) def _calculate_header(self, primary, pyname, call): # A header is created which initializes parameters @@ -377,10 +377,6 @@ def _calculate_header(self, primary, pyname, call): paramdict[param_name] = value header = '' to_be_inlined = [] - mod = self.pycore.get_string_module(self.body) - all_names = mod.get_scope().get_names() - assigned_names = [name for name in all_names if - isinstance(all_names[name], rope.base.pynamesdef.AssignedName)] for name, value in paramdict.items(): if name != value and value is not None: header += name + ' = ' + value.replace('\n', ' ') + '\n' @@ -392,32 +388,36 @@ def _calculate_definition(self, primary, pyname, call, host_vars, returns): header, to_be_inlined = self._calculate_header(primary, pyname, call) source = header + self.body - mod = self.pycore.get_string_module(source) + mod = libutils.get_string_module(self.project, source) name_dict = mod.get_scope().get_names() - all_names = [x for x in name_dict if - not isinstance(name_dict[x], rope.base.builtins.BuiltinName)] + all_names = [x for x in name_dict if + not isinstance(name_dict[x], + rope.base.builtins.BuiltinName)] # If there is a name conflict, all variable names # inside the inlined function are renamed if len(set(all_names).intersection(set(host_vars))) > 0: prefix = _DefinitionGenerator.unique_prefix.next() - guest = self.pycore.get_string_module(source, self.resource) + guest = libutils.get_string_module(self.project, source, + self.resource) - to_be_inlined = [prefix+item for item in to_be_inlined] + to_be_inlined = [prefix + item for item in to_be_inlined] for item in all_names: pyname = guest[item] - occurrence_finder = occurrences.create_finder( - self.pycore, item, pyname) + occurrence_finder = occurrences.create_finder(self.project, + item, pyname) source = rename.rename_in_module(occurrence_finder, - prefix+item, pymodule=guest) - guest = self.pycore.get_string_module(source, self.resource) + prefix + item, pymodule=guest) + guest = libutils.get_string_module( + self.project, source, self.resource) #parameters not reassigned inside the functions are now inlined. for name in to_be_inlined: - pymodule = self.pycore.get_string_module(source, self.resource) + pymodule = libutils.get_string_module( + self.project, source, self.resource) pyname = pymodule[name] - source = _inline_variable(self.pycore, pymodule, pyname, name) + source = _inline_variable(self.project, pymodule, pyname, name) return self._replace_returns_with(source, returns) @@ -425,19 +425,22 @@ def _replace_returns_with(self, source, returns): result = [] returned = None last_changed = 0 - for match in _DefinitionGenerator._get_return_pattern().finditer(source): + for match in _DefinitionGenerator._get_return_pattern().finditer( + source): for key, value in match.groupdict().items(): if value and key == 'return': result.append(source[last_changed:match.start('return')]) if returns: self._check_nothing_after_return(source, match.end('return')) + beg_idx = match.end('return') returned = _join_lines( - source[match.end('return'): len(source)].splitlines()) + source[beg_idx:len(source)].splitlines()) last_changed = len(source) else: current = match.end('return') - while current < len(source) and source[current] in ' \t': + while current < len(source) and \ + source[current] in ' \t': current += 1 last_changed = current if current == len(source) or source[current] == '\n': @@ -452,7 +455,8 @@ def _check_nothing_after_return(self, source, offset): lineno = logical_lines.logical_line_in(lineno)[1] if source[lines.get_line_end(lineno):len(source)].strip() != '': raise rope.base.exceptions.RefactoringError( - 'Cannot inline functions with statements after return statement.') + 'Cannot inline functions with statements ' + + 'after return statement.') @classmethod def _get_return_pattern(cls): @@ -471,7 +475,7 @@ def named_pattern(name, list_): class _InlineFunctionCallsForModuleHandle(object): - def __init__(self, pycore, resource, + def __init__(self, project, resource, definition_generator, aim_offset=None): """Inlines occurrences @@ -479,7 +483,7 @@ def __init__(self, pycore, resource, `aim` offset will be inlined. """ - self.pycore = pycore + self.project = project self.generator = definition_generator self.resource = resource self.aim = aim_offset @@ -504,24 +508,24 @@ def occurred_outside_skip(self, change_collector, occurrence): end_parens = self._find_end_parens(self.source, end - 1) lineno = self.lines.get_line_number(start) start_line, end_line = self.pymodule.logical_lines.\ - logical_line_in(lineno) + logical_line_in(lineno) line_start = self.lines.get_line_start(start_line) line_end = self.lines.get_line_end(end_line) - returns = self.source[line_start:start].strip() != '' or \ - self.source[end_parens:line_end].strip() != '' + self.source[end_parens:line_end].strip() != '' indents = sourceutils.get_indents(self.lines, start_line) primary, pyname = occurrence.get_primary_and_pyname() - host = self.pycore.resource_to_pyobject(self.resource) + host = self.pymodule scope = host.scope.get_inner_scope_for_line(lineno) definition, returned = self.generator.get_definition( - primary, pyname, self.source[start:end_parens], scope.get_names(), returns=returns) + primary, pyname, self.source[start:end_parens], scope.get_names(), + returns=returns) end = min(line_end + 1, len(self.source)) - change_collector.add_change(line_start, end, - sourceutils.fix_indentation(definition, indents)) + change_collector.add_change( + line_start, end, sourceutils.fix_indentation(definition, indents)) if returns: name = returned if name is None: @@ -537,7 +541,7 @@ def _find_end_parens(self, source, offset): @property @utils.saveit def pymodule(self): - return self.pycore.resource_to_pyobject(self.resource) + return self.project.get_pymodule(self.resource) @property @utils.saveit @@ -553,12 +557,13 @@ def lines(self): return self.pymodule.lines -def _inline_variable(pycore, pymodule, pyname, name, - remove=True, region=None): +def _inline_variable(project, pymodule, pyname, name, + remove=True, region=None, docs=False): definition = _getvardef(pymodule, pyname) start, end = _assigned_lineno(pymodule, pyname) - occurrence_finder = occurrences.create_finder(pycore, name, pyname) + occurrence_finder = occurrences.create_finder(project, name, pyname, + docs=docs) changed_source = rename.rename_in_module( occurrence_finder, definition, pymodule=pymodule, replace_primary=True, writes=False, region=region) @@ -567,11 +572,12 @@ def _inline_variable(pycore, pymodule, pyname, name, if remove: lines = codeanalyze.SourceLinesAdapter(changed_source) source = changed_source[:lines.get_line_start(start)] + \ - changed_source[lines.get_line_end(end) + 1:] + changed_source[lines.get_line_end(end) + 1:] else: source = changed_source return source + def _getvardef(pymodule, pyname): assignment = pyname.assignments[0] lines = pymodule.lines @@ -581,35 +587,39 @@ def _getvardef(pymodule, pyname): if assignment.levels: raise rope.base.exceptions.RefactoringError( 'Cannot inline tuple assignments.') - definition = definition_with_assignment[definition_with_assignment.\ + definition = definition_with_assignment[definition_with_assignment. index('=') + 1:].strip() return definition + def _assigned_lineno(pymodule, pyname): definition_line = pyname.assignments[0].ast_node.lineno return pymodule.logical_lines.logical_line_in(definition_line) -def _add_imports(pycore, source, resource, imports): + +def _add_imports(project, source, resource, imports): if not imports: return source - pymodule = pycore.get_string_module(source, resource) - module_import = importutils.get_module_imports(pycore, pymodule) + pymodule = libutils.get_string_module(project, source, resource) + module_import = importutils.get_module_imports(project, pymodule) for import_info in imports: module_import.add_import(import_info) source = module_import.get_changed_source() - pymodule = pycore.get_string_module(source, resource) - import_tools = importutils.ImportTools(pycore) + pymodule = libutils.get_string_module(project, source, resource) + import_tools = importutils.ImportTools(project) return import_tools.organize_imports(pymodule, unused=False, sort=False) -def _get_pyname(pycore, resource, offset): - pymodule = pycore.resource_to_pyobject(resource) + +def _get_pyname(project, resource, offset): + pymodule = project.get_pymodule(resource) pyname = evaluate.eval_location(pymodule, offset) if isinstance(pyname, pynames.ImportedName): pyname = pyname._get_imported_pyname() return pyname -def _remove_from(pycore, pyname, source, resource): - pymodule = pycore.get_string_module(source, resource) - module_import = importutils.get_module_imports(pycore, pymodule) + +def _remove_from(project, pyname, source, resource): + pymodule = libutils.get_string_module(project, source, resource) + module_import = importutils.get_module_imports(project, pymodule) module_import.remove_pyname(pyname) return module_import.get_changed_source() diff --git a/pymode/libs2/rope/refactor/introduce_factory.py b/pymode/libs2/rope/refactor/introduce_factory.py index 5a885587..7532e361 100644 --- a/pymode/libs2/rope/refactor/introduce_factory.py +++ b/pymode/libs2/rope/refactor/introduce_factory.py @@ -1,5 +1,6 @@ import rope.base.exceptions import rope.base.pyobjects +from rope.base import libutils from rope.base import taskhandle, evaluate from rope.base.change import (ChangeSet, ChangeContents) from rope.refactor import rename, occurrences, sourceutils, importutils @@ -8,13 +9,14 @@ class IntroduceFactory(object): def __init__(self, project, resource, offset): - self.pycore = project.pycore + self.project = project self.offset = offset - this_pymodule = self.pycore.resource_to_pyobject(resource) + this_pymodule = self.project.get_pymodule(resource) self.old_pyname = evaluate.eval_location(this_pymodule, offset) - if self.old_pyname is None or not isinstance(self.old_pyname.get_object(), - rope.base.pyobjects.PyClass): + if self.old_pyname is None or \ + not isinstance(self.old_pyname.get_object(), + rope.base.pyobjects.PyClass): raise rope.base.exceptions.RefactoringError( 'Introduce factory should be performed on a class.') self.old_name = self.old_pyname.get_object().get_name() @@ -35,7 +37,7 @@ def get_changes(self, factory_name, global_factory=False, resources=None, """ if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() changes = ChangeSet('Introduce factory method <%s>' % factory_name) job_set = task_handle.create_jobset('Collecting Changes', len(resources)) @@ -64,11 +66,11 @@ def _change_module(self, resources, changes, global_) if changed_code is not None: if global_: - new_pymodule = self.pycore.get_string_module(changed_code, - self.resource) - modname = self.pycore.modname(self.resource) + new_pymodule = libutils.get_string_module( + self.project, changed_code, self.resource) + modname = libutils.modname(self.resource) changed_code, imported = importutils.add_import( - self.pycore, new_pymodule, modname, factory_name) + self.project, new_pymodule, modname, factory_name) changed_code = changed_code.replace(replacement, imported) changes.add_change(ChangeContents(file_, changed_code)) job_set.finished_job() @@ -81,8 +83,8 @@ def _change_resource(self, changes, factory_name, global_): if source_code is None: source_code = self.pymodule.source_code else: - self.pymodule = self.pycore.get_string_module( - source_code, resource=self.resource) + self.pymodule = libutils.get_string_module( + self.project, source_code, resource=self.resource) lines = self.pymodule.lines start = self._get_insertion_offset(class_scope, lines) result = source_code[:start] @@ -100,7 +102,7 @@ def _get_insertion_offset(self, class_scope, lines): def _get_factory_method(self, lines, class_scope, factory_name, global_): - unit_indents = ' ' * sourceutils.get_indent(self.pycore) + unit_indents = ' ' * sourceutils.get_indent(self.project) if global_: if self._get_scope_indents(lines, class_scope) > 0: raise rope.base.exceptions.RefactoringError( @@ -111,7 +113,7 @@ def _get_factory_method(self, lines, class_scope, ('@staticmethod\ndef %s(*args, **kwds):\n' % factory_name + '%sreturn %s(*args, **kwds)\n' % (unit_indents, self.old_name)) indents = self._get_scope_indents(lines, class_scope) + \ - sourceutils.get_indent(self.pycore) + sourceutils.get_indent(self.project) return '\n' + sourceutils.indent_lines(unindented_factory, indents) def _get_scope_indents(self, lines, scope): @@ -124,7 +126,7 @@ def _new_function_name(self, factory_name, global_): return self.old_name + '.' + factory_name def _rename_occurrences(self, file_, changed_name, global_factory): - finder = occurrences.create_finder(self.pycore, self.old_name, + finder = occurrences.create_finder(self.project, self.old_name, self.old_pyname, only_calls=True) result = rename.rename_in_module(finder, changed_name, resource=file_, replace_primary=global_factory) diff --git a/pymode/libs2/rope/refactor/introduce_parameter.py b/pymode/libs2/rope/refactor/introduce_parameter.py index 312c61aa..43d6f755 100644 --- a/pymode/libs2/rope/refactor/introduce_parameter.py +++ b/pymode/libs2/rope/refactor/introduce_parameter.py @@ -35,10 +35,10 @@ def f(p=a.var): """ def __init__(self, project, resource, offset): - self.pycore = project.pycore + self.project = project self.resource = resource self.offset = offset - self.pymodule = self.pycore.resource_to_pyobject(self.resource) + self.pymodule = self.project.get_pymodule(self.resource) scope = self.pymodule.get_scope().get_inner_scope_for_offset(offset) if scope.get_kind() != 'Function': raise exceptions.RefactoringError( @@ -79,7 +79,7 @@ def _get_header_offsets(self): lines = self.pymodule.lines start_line = self.pyfunction.get_scope().get_start() end_line = self.pymodule.logical_lines.\ - logical_line_in(start_line)[1] + logical_line_in(start_line)[1] start = lines.get_line_start(start_line) end = lines.get_line_end(end_line) start = self.pymodule.source_code.find('def', start) + 4 @@ -88,7 +88,8 @@ def _get_header_offsets(self): def _change_function_occurances(self, collector, function_start, function_end, new_name): - finder = occurrences.create_finder(self.pycore, self.name, self.pyname) + finder = occurrences.create_finder(self.project, self.name, + self.pyname) for occurrence in finder.find_occurrences(resource=self.resource): start, end = occurrence.get_primary_range() if function_start <= start < function_end: diff --git a/pymode/libs2/rope/refactor/localtofield.py b/pymode/libs2/rope/refactor/localtofield.py index 532d4c9e..f276070f 100644 --- a/pymode/libs2/rope/refactor/localtofield.py +++ b/pymode/libs2/rope/refactor/localtofield.py @@ -6,13 +6,12 @@ class LocalToField(object): def __init__(self, project, resource, offset): self.project = project - self.pycore = project.pycore self.resource = resource self.offset = offset def get_changes(self): name = worder.get_name_at(self.resource, self.offset) - this_pymodule = self.pycore.resource_to_pyobject(self.resource) + this_pymodule = self.project.get_pymodule(self.resource) pyname = evaluate.eval_location(this_pymodule, self.offset) if not self._is_a_method_local(pyname): raise exceptions.RefactoringError( @@ -26,7 +25,7 @@ def get_changes(self): new_name = self._get_field_name(function_scope.pyobject, name) changes = Rename(self.project, self.resource, self.offset).\ - get_changes(new_name, resources=[self.resource]) + get_changes(new_name, resources=[self.resource]) return changes def _check_redefinition(self, name, function_scope): @@ -45,6 +44,6 @@ def _is_a_method_local(self, pyname): holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) parent = holding_scope.parent return isinstance(pyname, pynames.AssignedName) and \ - pyname in holding_scope.get_names().values() and \ - holding_scope.get_kind() == 'Function' and \ - parent is not None and parent.get_kind() == 'Class' + pyname in holding_scope.get_names().values() and \ + holding_scope.get_kind() == 'Function' and \ + parent is not None and parent.get_kind() == 'Class' diff --git a/pymode/libs2/rope/refactor/method_object.py b/pymode/libs2/rope/refactor/method_object.py index b3dd6bdd..29ce429d 100644 --- a/pymode/libs2/rope/refactor/method_object.py +++ b/pymode/libs2/rope/refactor/method_object.py @@ -1,5 +1,6 @@ import warnings +from rope.base import libutils from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze from rope.refactor import sourceutils, occurrences, rename @@ -7,8 +8,8 @@ class MethodObject(object): def __init__(self, project, resource, offset): - self.pycore = project.pycore - this_pymodule = self.pycore.resource_to_pyobject(resource) + self.project = project + this_pymodule = self.project.get_pymodule(resource) pyname = evaluate.eval_location(this_pymodule, offset) if pyname is None or not isinstance(pyname.get_object(), pyobjects.PyFunction): @@ -21,10 +22,10 @@ def __init__(self, project, resource, offset): def get_new_class(self, name): body = sourceutils.fix_indentation( - self._get_body(), sourceutils.get_indent(self.pycore) * 2) + self._get_body(), sourceutils.get_indent(self.project) * 2) return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \ (name, self._get_init(), - ' ' * sourceutils.get_indent(self.pycore), body) + ' ' * sourceutils.get_indent(self.project), body) def get_changes(self, classname=None, new_class_name=None): if new_class_name is not None: @@ -36,14 +37,15 @@ def get_changes(self, classname=None, new_class_name=None): start, end = sourceutils.get_body_region(self.pyfunction) indents = sourceutils.get_indents( self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \ - sourceutils.get_indent(self.pycore) + sourceutils.get_indent(self.project) new_contents = ' ' * indents + 'return %s(%s)()\n' % \ (classname, ', '.join(self._get_parameter_names())) collector.add_change(start, end, new_contents) insertion = self._get_class_insertion_point() collector.add_change(insertion, insertion, '\n\n' + self.get_new_class(classname)) - changes = change.ChangeSet('Replace method with method object refactoring') + changes = change.ChangeSet( + 'Replace method with method object refactoring') changes.add_change(change.ChangeContents(self.resource, collector.get_changed())) return changes @@ -59,9 +61,10 @@ def _get_body(self): body = sourceutils.get_body(self.pyfunction) for param in self._get_parameter_names(): body = param + ' = None\n' + body - pymod = self.pycore.get_string_module(body, self.resource) + pymod = libutils.get_string_module( + self.project, body, self.resource) pyname = pymod[param] - finder = occurrences.create_finder(self.pycore, param, pyname) + finder = occurrences.create_finder(self.project, param, pyname) result = rename.rename_in_module(finder, 'self.' + param, pymodule=pymod) body = result[result.index('\n') + 1:] @@ -69,7 +72,7 @@ def _get_body(self): def _get_init(self): params = self._get_parameter_names() - indents = ' ' * sourceutils.get_indent(self.pycore) + indents = ' ' * sourceutils.get_indent(self.project) if not params: return '' header = indents + 'def __init__(self' diff --git a/pymode/libs2/rope/refactor/move.py b/pymode/libs2/rope/refactor/move.py index c8761011..60df493e 100644 --- a/pymode/libs2/rope/refactor/move.py +++ b/pymode/libs2/rope/refactor/move.py @@ -4,9 +4,11 @@ based on inputs. """ -from rope.base import pyobjects, codeanalyze, exceptions, pynames, taskhandle, evaluate, worder +from rope.base import (pyobjects, codeanalyze, exceptions, pynames, + taskhandle, evaluate, worder, libutils) from rope.base.change import ChangeSet, ChangeContents, MoveResource -from rope.refactor import importutils, rename, occurrences, sourceutils, functionutils +from rope.refactor import importutils, rename, occurrences, sourceutils, \ + functionutils def create_move(project, resource, offset=None): @@ -18,7 +20,7 @@ def create_move(project, resource, offset=None): """ if offset is None: return MoveModule(project, resource) - this_pymodule = project.pycore.resource_to_pyobject(resource) + this_pymodule = project.get_pymodule(resource) pyname = evaluate.eval_location(this_pymodule, offset) if pyname is None: raise exceptions.RefactoringError( @@ -48,8 +50,7 @@ class MoveMethod(object): def __init__(self, project, resource, offset): self.project = project - self.pycore = project.pycore - this_pymodule = self.pycore.resource_to_pyobject(resource) + this_pymodule = self.project.get_pymodule(resource) pyname = evaluate.eval_location(this_pymodule, offset) self.method_name = worder.get_name_at(resource, offset) self.pyfunction = pyname.get_object() @@ -73,7 +74,7 @@ def get_changes(self, dest_attr, new_name=None, resources=None, """ changes = ChangeSet('Moving method <%s>' % self.method_name) if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() if new_name is None: new_name = self.get_method_name() resource1, start1, end1, new_content1 = \ @@ -89,11 +90,11 @@ def get_changes(self, dest_attr, new_name=None, resources=None, collector2 = codeanalyze.ChangeCollector(resource2.read()) collector2.add_change(start2, end2, new_content2) result = collector2.get_changed() - import_tools = importutils.ImportTools(self.pycore) + import_tools = importutils.ImportTools(self.project) new_imports = self._get_used_imports(import_tools) if new_imports: - goal_pymodule = self.pycore.get_string_module(result, - resource2) + goal_pymodule = libutils.get_string_module( + self.project, result, resource2) result = _add_imports_to_module( import_tools, goal_pymodule, new_imports) if resource2 in resources: @@ -108,13 +109,13 @@ def get_method_name(self): return self.method_name def _get_used_imports(self, import_tools): - return importutils.get_imports(self.pycore, self.pyfunction) + return importutils.get_imports(self.project, self.pyfunction) def _get_changes_made_by_old_class(self, dest_attr, new_name): pymodule = self.pyfunction.get_module() indents = self._get_scope_indents(self.pyfunction) - body = 'return self.%s.%s(%s)\n' % (dest_attr, new_name, - self._get_passed_arguments_string()) + body = 'return self.%s.%s(%s)\n' % ( + dest_attr, new_name, self._get_passed_arguments_string()) region = sourceutils.get_body_region(self.pyfunction) return (pymodule.get_resource(), region[0], region[1], sourceutils.fix_indentation(body, indents)) @@ -123,7 +124,7 @@ def _get_scope_indents(self, pyobject): pymodule = pyobject.get_module() return sourceutils.get_indents( pymodule.lines, pyobject.get_scope().get_start()) + \ - sourceutils.get_indent(self.pycore) + sourceutils.get_indent(self.project) def _get_changes_made_by_new_class(self, dest_attr, new_name): old_pyclass = self.pyfunction.parent @@ -150,7 +151,7 @@ def get_new_method(self, name): return '%s\n%s' % ( self._get_new_header(name), sourceutils.fix_indentation(self._get_body(), - sourceutils.get_indent(self.pycore))) + sourceutils.get_indent(self.project))) def _get_unchanged_body(self): return sourceutils.get_body(self.pyfunction) @@ -158,9 +159,9 @@ def _get_unchanged_body(self): def _get_body(self, host='host'): self_name = self._get_self_name() body = self_name + ' = None\n' + self._get_unchanged_body() - pymodule = self.pycore.get_string_module(body) + pymodule = libutils.get_string_module(self.project, body) finder = occurrences.create_finder( - self.pycore, self_name, pymodule[self_name]) + self.project, self_name, pymodule[self_name]) result = rename.rename_in_module(finder, host, pymodule=pymodule) if result is None: result = body @@ -199,26 +200,28 @@ class MoveGlobal(object): """For moving global function and classes""" def __init__(self, project, resource, offset): - self.pycore = project.pycore - this_pymodule = self.pycore.resource_to_pyobject(resource) + self.project = project + this_pymodule = self.project.get_pymodule(resource) self.old_pyname = evaluate.eval_location(this_pymodule, offset) self.old_name = self.old_pyname.get_object().get_name() pymodule = self.old_pyname.get_object().get_module() self.source = pymodule.get_resource() - self.tools = _MoveTools(self.pycore, self.source, + self.tools = _MoveTools(self.project, self.source, self.old_pyname, self.old_name) self.import_tools = self.tools.import_tools self._check_exceptional_conditions() def _check_exceptional_conditions(self): if self.old_pyname is None or \ - not isinstance(self.old_pyname.get_object(), pyobjects.PyDefinedObject): + not isinstance(self.old_pyname.get_object(), + pyobjects.PyDefinedObject): raise exceptions.RefactoringError( 'Move refactoring should be performed on a class/function.') moving_pyobject = self.old_pyname.get_object() if not self._is_global(moving_pyobject): raise exceptions.RefactoringError( - 'Move refactoring should be performed on a global class/function.') + 'Move refactoring should be performed ' + + 'on a global class/function.') def _is_global(self, pyobject): return pyobject.get_scope().parent == pyobject.get_module().get_scope() @@ -226,7 +229,7 @@ def _is_global(self, pyobject): def get_changes(self, dest, resources=None, task_handle=taskhandle.NullTaskHandle()): if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() if dest is None or not dest.exists(): raise exceptions.RefactoringError( 'Move destination does not exist.') @@ -251,7 +254,7 @@ def _calculate_changes(self, dest, resources, task_handle): elif file_ == dest: changes.add_change(self._dest_module_changes(dest)) elif self.tools.occurs_in_module(resource=file_): - pymodule = self.pycore.resource_to_pyobject(file_) + pymodule = self.project.get_pymodule(file_) # Changing occurrences placeholder = '__rope_renaming_%s_' % self.old_name source = self.tools.rename_in_module(placeholder, @@ -264,7 +267,8 @@ def _calculate_changes(self, dest, resources, task_handle): if should_import: pymodule = self.tools.new_pymodule(pymodule, source) source, imported = importutils.add_import( - self.pycore, pymodule, self._new_modname(dest), self.old_name) + self.project, pymodule, self._new_modname(dest), + self.old_name) source = source.replace(placeholder, imported) source = self.tools.new_source(pymodule, source) if source != file_.read(): @@ -276,25 +280,26 @@ def _source_module_changes(self, dest): placeholder = '__rope_moving_%s_' % self.old_name handle = _ChangeMoveOccurrencesHandle(placeholder) occurrence_finder = occurrences.create_finder( - self.pycore, self.old_name, self.old_pyname) + self.project, self.old_name, self.old_pyname) start, end = self._get_moving_region() renamer = ModuleSkipRenamer(occurrence_finder, self.source, handle, start, end) source = renamer.get_changed_module() if handle.occurred: - pymodule = self.pycore.get_string_module(source, self.source) + pymodule = libutils.get_string_module( + self.project, source, self.source) # Adding new import source, imported = importutils.add_import( - self.pycore, pymodule, self._new_modname(dest), self.old_name) + self.project, pymodule, self._new_modname(dest), self.old_name) source = source.replace(placeholder, imported) return ChangeContents(self.source, source) def _new_modname(self, dest): - return self.pycore.modname(dest) + return libutils.modname(dest) def _dest_module_changes(self, dest): # Changing occurrences - pymodule = self.pycore.resource_to_pyobject(dest) + pymodule = self.project.get_pymodule(dest) source = self.tools.rename_in_module(self.old_name, pymodule) pymodule = self.tools.new_pymodule(pymodule, source) @@ -310,7 +315,8 @@ def _dest_module_changes(self, dest): lineno = module_with_imports.imports[-1].end_line - 1 else: while lineno < pymodule.lines.length() and \ - pymodule.lines.get_line(lineno + 1).lstrip().startswith('#'): + pymodule.lines.get_line(lineno + 1).\ + lstrip().startswith('#'): lineno += 1 if lineno > 0: cut = pymodule.lines.get_line_end(lineno) + 1 @@ -320,17 +326,18 @@ def _dest_module_changes(self, dest): # Organizing imports source = result - pymodule = self.pycore.get_string_module(source, dest) + pymodule = libutils.get_string_module(self.project, source, dest) source = self.import_tools.organize_imports(pymodule, sort=False, unused=False) return ChangeContents(dest, source) def _get_moving_element_with_imports(self): return moving_code_with_imports( - self.pycore, self.source, self._get_moving_element()) + self.project, self.source, self._get_moving_element()) def _get_module_with_imports(self, source_code, resource): - pymodule = self.pycore.get_string_module(source_code, resource) + pymodule = libutils.get_string_module( + self.project, source_code, resource) return self.import_tools.module_imports(pymodule) def _get_moving_element(self): @@ -339,13 +346,13 @@ def _get_moving_element(self): return moving.rstrip() + '\n' def _get_moving_region(self): - pymodule = self.pycore.resource_to_pyobject(self.source) + pymodule = self.project.get_pymodule(self.source) lines = pymodule.lines scope = self.old_pyname.get_object().get_scope() start = lines.get_line_start(scope.get_start()) end_line = scope.get_end() while end_line < lines.length() and \ - lines.get_line(end_line + 1).strip() == '': + lines.get_line(end_line + 1).strip() == '': end_line += 1 end = min(lines.get_line_end(end_line) + 1, len(pymodule.source_code)) return start, end @@ -356,7 +363,8 @@ def _add_imports2(self, pymodule, new_imports): return pymodule, False else: resource = pymodule.get_resource() - pymodule = self.pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module( + self.project, source, resource) return pymodule, True @@ -365,13 +373,12 @@ class MoveModule(object): def __init__(self, project, resource): self.project = project - self.pycore = project.pycore if not resource.is_folder() and resource.name == '__init__.py': resource = resource.parent if resource.is_folder() and not resource.has_child('__init__.py'): raise exceptions.RefactoringError( 'Cannot move non-package folder.') - dummy_pymodule = self.pycore.get_string_module('') + dummy_pymodule = libutils.get_string_module(self.project, '') self.old_pyname = pynames.ImportedModule(dummy_pymodule, resource=resource) self.source = self.old_pyname.get_object().get_resource() @@ -379,15 +386,14 @@ def __init__(self, project, resource): self.old_name = self.source.name else: self.old_name = self.source.name[:-3] - self.tools = _MoveTools(self.pycore, self.source, + self.tools = _MoveTools(self.project, self.source, self.old_pyname, self.old_name) self.import_tools = self.tools.import_tools def get_changes(self, dest, resources=None, task_handle=taskhandle.NullTaskHandle()): - moving_pyobject = self.old_pyname.get_object() if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() if dest is None or not dest.is_folder(): raise exceptions.RefactoringError( 'Move destination for modules should be packages.') @@ -412,7 +418,7 @@ def _calculate_changes(self, dest, resources, task_handle): return changes def _new_modname(self, dest): - destname = self.pycore.modname(dest) + destname = libutils.modname(dest) if destname: return destname + '.' + self.old_name return self.old_name @@ -422,7 +428,7 @@ def _new_import(self, dest): def _change_moving_module(self, changes, dest): if not self.source.is_folder(): - pymodule = self.pycore.resource_to_pyobject(self.source) + pymodule = self.project.get_pymodule(self.source) source = self.import_tools.relatives_to_absolutes(pymodule) pymodule = self.tools.new_pymodule(pymodule, source) source = self._change_occurrences_in_module(dest, pymodule) @@ -436,11 +442,24 @@ def _change_occurrences_in_module(self, dest, pymodule=None, resource=resource): return if pymodule is None: - pymodule = self.pycore.resource_to_pyobject(resource) + pymodule = self.project.get_pymodule(resource) new_name = self._new_modname(dest) + module_imports = importutils.get_module_imports(self.project, pymodule) + changed = False + + source = None + if libutils.modname(dest): + changed = self._change_import_statements(dest, new_name, + module_imports) + if changed: + source = module_imports.get_changed_source() + source = self.tools.new_source(pymodule, source) + pymodule = self.tools.new_pymodule(pymodule, source) + new_import = self._new_import(dest) source = self.tools.rename_in_module( - new_name, imports=True, pymodule=pymodule, resource=resource) + new_name, imports=True, pymodule=pymodule, + resource=resource if not changed else None) should_import = self.tools.occurs_in_module( pymodule=pymodule, resource=resource, imports=False) pymodule = self.tools.new_pymodule(pymodule, source) @@ -449,8 +468,75 @@ def _change_occurrences_in_module(self, dest, pymodule=None, pymodule = self.tools.new_pymodule(pymodule, source) source = self.tools.add_imports(pymodule, [new_import]) source = self.tools.new_source(pymodule, source) - if source != pymodule.resource.read(): + if source is not None and source != pymodule.resource.read(): return source + return None + + + def _change_import_statements(self, dest, new_name, module_imports): + moving_module = self.source + parent_module = moving_module.parent + + changed = False + for import_stmt in module_imports.imports: + if not any(name_and_alias[0] == self.old_name + for name_and_alias in + import_stmt.import_info.names_and_aliases) and \ + not any(name_and_alias[0] == libutils.modname(self.source) + for name_and_alias in + import_stmt.import_info.names_and_aliases): + continue + + # Case 1: Look for normal imports of the moving module. + if isinstance(import_stmt.import_info, importutils.NormalImport): + continue + + # Case 2: The moving module is from-imported. + changed = self._handle_moving_in_from_import_stmt( + dest, import_stmt, module_imports, parent_module) or changed + + # Case 3: Names are imported from the moving module. + context = importutils.importinfo.ImportContext(self.project, None) + if not import_stmt.import_info.is_empty() and \ + import_stmt.import_info.get_imported_resource(context) == \ + moving_module: + import_stmt.import_info = importutils.FromImport( + new_name, import_stmt.import_info.level, + import_stmt.import_info.names_and_aliases) + changed = True + + return changed + + def _handle_moving_in_from_import_stmt(self, dest, import_stmt, + module_imports, parent_module): + changed = False + context = importutils.importinfo.ImportContext(self.project, None) + if import_stmt.import_info.get_imported_resource(context) == \ + parent_module: + imports = import_stmt.import_info.names_and_aliases + new_imports = [] + for name, alias in imports: + # The moving module was imported. + if name == self.old_name: + changed = True + new_import = importutils.FromImport( + libutils.modname(dest), 0, + [(self.old_name, alias)]) + module_imports.add_import(new_import) + else: + new_imports.append((name, alias)) + + # Update the imports if the imported names were changed. + if new_imports != imports: + changed = True + if new_imports: + import_stmt.import_info = importutils.FromImport( + import_stmt.import_info.module_name, + import_stmt.import_info.level, + new_imports) + else: + import_stmt.empty_import() + return changed class _ChangeMoveOccurrencesHandle(object): @@ -470,20 +556,22 @@ def occurred_outside_skip(self, change_collector, occurrence): class _MoveTools(object): - def __init__(self, pycore, source, pyname, old_name): - self.pycore = pycore + def __init__(self, project, source, pyname, old_name): + self.project = project self.source = source self.old_pyname = pyname self.old_name = old_name - self.import_tools = importutils.ImportTools(self.pycore) + self.import_tools = importutils.ImportTools(self.project) def remove_old_imports(self, pymodule): old_source = pymodule.source_code module_with_imports = self.import_tools.module_imports(pymodule) + class CanSelect(object): changed = False old_name = self.old_name old_pyname = self.old_pyname + def __call__(self, name): try: if name == self.old_name and \ @@ -501,7 +589,7 @@ def __call__(self, name): return new_source def rename_in_module(self, new_name, pymodule=None, - imports=False, resource=None): + imports=False, resource=None): occurrence_finder = self._create_finder(imports) source = rename.rename_in_module( occurrence_finder, new_name, replace_primary=True, @@ -516,13 +604,13 @@ def occurs_in_module(self, pymodule=None, resource=None, imports=True): return False def _create_finder(self, imports): - return occurrences.create_finder(self.pycore, self.old_name, + return occurrences.create_finder(self.project, self.old_name, self.old_pyname, imports=imports) def new_pymodule(self, pymodule, source): if source is not None: - return self.pycore.get_string_module( - source, pymodule.get_resource()) + return libutils.get_string_module( + self.project, source, pymodule.get_resource()) return pymodule def new_source(self, pymodule, source): @@ -541,10 +629,10 @@ def _add_imports_to_module(import_tools, pymodule, new_imports): return module_with_imports.get_changed_source() -def moving_code_with_imports(pycore, resource, source): - import_tools = importutils.ImportTools(pycore) - pymodule = pycore.get_string_module(source, resource) - origin = pycore.resource_to_pyobject(resource) +def moving_code_with_imports(project, resource, source): + import_tools = importutils.ImportTools(project) + pymodule = libutils.get_string_module(project, source, resource) + origin = project.get_pymodule(resource) imports = [] for stmt in import_tools.module_imports(origin).imports: @@ -557,12 +645,12 @@ def moving_code_with_imports(pycore, resource, source): imports.append(import_tools.get_from_import(resource, back_names)) source = _add_imports_to_module(import_tools, pymodule, imports) - pymodule = pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module(project, source, resource) source = import_tools.relatives_to_absolutes(pymodule) - pymodule = pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module(project, source, resource) source = import_tools.organize_imports(pymodule, selfs=False) - pymodule = pycore.get_string_module(source, resource) + pymodule = libutils.get_string_module(project, source, resource) # extracting imports after changes module_imports = import_tools.module_imports(pymodule) @@ -610,7 +698,7 @@ def __init__(self, occurrence_finder, resource, handle=None, self.replacement = replacement self.handle = handle if self.handle is None: - self.handle = ModuleSkipHandle() + self.handle = ModuleSkipRenamerHandle() def get_changed_module(self): source = self.resource.read() @@ -618,7 +706,8 @@ def get_changed_module(self): if self.replacement is not None: change_collector.add_change(self.skip_start, self.skip_end, self.replacement) - for occurrence in self.occurrence_finder.find_occurrences(self.resource): + for occurrence in self.occurrence_finder.find_occurrences( + self.resource): start, end = occurrence.get_primary_range() if self.skip_start <= start < self.skip_end: self.handle.occurred_inside_skip(change_collector, occurrence) diff --git a/pymode/libs2/rope/refactor/multiproject.py b/pymode/libs2/rope/refactor/multiproject.py index 6a85d2a2..ac243bda 100644 --- a/pymode/libs2/rope/refactor/multiproject.py +++ b/pymode/libs2/rope/refactor/multiproject.py @@ -1,11 +1,11 @@ """This module can be used for performing cross-project refactorings -See the "cross-project refactorings" section of ``docs/library.txt`` +See the "cross-project refactorings" section of ``docs/library.rst`` file. """ -from rope.base import resources, project, libutils +from rope.base import resources, libutils class MultiProjectRefactoring(object): @@ -33,7 +33,7 @@ def __init__(self, refactoring, other_projects, addpath, self.refactoring = refactoring self.projects = [project] + other_projects for other_project in other_projects: - for folder in self.project.pycore.get_source_folders(): + for folder in self.project.get_source_folders(): other_project.get_prefs().add('python_path', folder.real_path) self.refactorings = [] for other in self.projects: @@ -57,7 +57,7 @@ def _resources_for_args(self, project, args, kwds): newkwds = dict((name, self._change_project_resource(project, value)) for name, value in kwds.items()) return newargs, newkwds - + def _change_project_resource(self, project, obj): if isinstance(obj, resources.Resource) and \ obj.project != project: diff --git a/pymode/libs2/rope/refactor/occurrences.py b/pymode/libs2/rope/refactor/occurrences.py index 2808ed2c..14a2d7de 100644 --- a/pymode/libs2/rope/refactor/occurrences.py +++ b/pymode/libs2/rope/refactor/occurrences.py @@ -1,7 +1,46 @@ +"""Find occurrences of a name in a project. + +This module consists of a `Finder` that finds all occurrences of a name +in a project. The `Finder.find_occurrences()` method is a generator that +yields `Occurrence` instances for each occurrence of the name. To create +a `Finder` object, use the `create_finder()` function: + + finder = occurrences.create_finder(project, 'foo', pyname) + for occurrence in finder.find_occurrences(): + pass + +It's possible to filter the occurrences. They can be specified when +calling the `create_finder()` function. + + * `only_calls`: If True, return only those instances where the name is + a function that's being called. + + * `imports`: If False, don't return instances that are in import + statements. + + * `unsure`: If a prediate function, return instances where we don't + know what the name references. It also filters based on the + predicate function. + + * `docs`: If True, it will search for occurrences in regions normally + ignored. E.g., strings and comments. + + * `in_hierarchy`: If True, it will find occurrences if the name is in + the class's hierarchy. + + * `instance`: Used only when you want implicit interfaces to be + considered. +""" + import re -import rope.base.pynames -from rope.base import pynames, pyobjects, codeanalyze, evaluate, exceptions, utils, worder +from rope.base import codeanalyze +from rope.base import evaluate +from rope.base import exceptions +from rope.base import pynames +from rope.base import pyobjects +from rope.base import utils +from rope.base import worder class Finder(object): @@ -19,8 +58,8 @@ class Finder(object): """ - def __init__(self, pycore, name, filters=[lambda o: True], docs=False): - self.pycore = pycore + def __init__(self, project, name, filters=[lambda o: True], docs=False): + self.project = project self.name = name self.docs = docs self.filters = filters @@ -28,7 +67,7 @@ def __init__(self, pycore, name, filters=[lambda o: True], docs=False): def find_occurrences(self, resource=None, pymodule=None): """Generate `Occurrence` instances""" - tools = _OccurrenceToolsCreator(self.pycore, resource=resource, + tools = _OccurrenceToolsCreator(self.project, resource=resource, pymodule=pymodule, docs=self.docs) for offset in self._textual_finder.find_offsets(tools.source_code): occurrence = Occurrence(tools, offset) @@ -41,7 +80,7 @@ def find_occurrences(self, resource=None, pymodule=None): break -def create_finder(pycore, name, pyname, only_calls=False, imports=True, +def create_finder(project, name, pyname, only_calls=False, imports=True, unsure=None, docs=False, instance=None, in_hierarchy=False): """A factory for `Finder` @@ -50,25 +89,25 @@ def create_finder(pycore, name, pyname, only_calls=False, imports=True, considered. """ - pynames = set([pyname]) + pynames_ = set([pyname]) filters = [] if only_calls: filters.append(CallsFilter()) if not imports: filters.append(NoImportsFilter()) - if isinstance(instance, rope.base.pynames.ParameterName): + if isinstance(instance, pynames.ParameterName): for pyobject in instance.get_objects(): try: - pynames.add(pyobject[name]) + pynames_.add(pyobject[name]) except exceptions.AttributeNotFoundError: pass - for pyname in pynames: + for pyname in pynames_: filters.append(PyNameFilter(pyname)) if in_hierarchy: filters.append(InHierarchyFilter(pyname)) if unsure: filters.append(UnsureFilter(unsure)) - return Finder(pycore, name, filters=filters, docs=docs) + return Finder(project, name, filters=filters, docs=docs) class Occurrence(object): @@ -96,7 +135,8 @@ def get_pyname(self): @utils.saveit def get_primary_and_pyname(self): try: - return self.tools.name_finder.get_primary_and_pyname_at(self.offset) + return self.tools.name_finder.get_primary_and_pyname_at( + self.offset) except exceptions.BadIdentifierError: pass @@ -109,11 +149,13 @@ def is_called(self): return self.tools.word_finder.is_a_function_being_called(self.offset) def is_defined(self): - return self.tools.word_finder.is_a_class_or_function_name_in_header(self.offset) + return self.tools.word_finder.is_a_class_or_function_name_in_header( + self.offset) def is_a_fixed_primary(self): - return self.tools.word_finder.is_a_class_or_function_name_in_header(self.offset) or \ - self.tools.word_finder.is_a_name_after_from_import(self.offset) + return self.tools.word_finder.is_a_class_or_function_name_in_header( + self.offset) or \ + self.tools.word_finder.is_a_name_after_from_import(self.offset) def is_written(self): return self.tools.word_finder.is_assigned_here(self.offset) @@ -134,11 +176,14 @@ def same_pyname(expected, pyname): return False if expected == pyname: return True - if type(expected) not in (pynames.ImportedModule, pynames.ImportedName) and \ - type(pyname) not in (pynames.ImportedModule, pynames.ImportedName): + if type(expected) not in (pynames.ImportedModule, pynames.ImportedName) \ + and type(pyname) not in \ + (pynames.ImportedModule, pynames.ImportedName): return False - return expected.get_definition_location() == pyname.get_definition_location() and \ - expected.get_object() == pyname.get_object() + return expected.get_definition_location() == \ + pyname.get_definition_location() and \ + expected.get_object() == pyname.get_object() + def unsure_pyname(pyname, unbound=True): """Return `True` if we don't know what this name references""" @@ -151,7 +196,7 @@ def unsure_pyname(pyname, unbound=True): class PyNameFilter(object): - """For finding occurrences of a name""" + """For finding occurrences of a name.""" def __init__(self, pyname): self.pyname = pyname @@ -162,7 +207,7 @@ def __call__(self, occurrence): class InHierarchyFilter(object): - """For finding occurrences of a name""" + """Finds the occurrence if the name is in the class's hierarchy.""" def __init__(self, pyname, implementations_only=False): self.pyname = pyname @@ -203,6 +248,7 @@ def _get_root_classes(self, pyclass, name): class UnsureFilter(object): + """Occurrences where we don't knoow what the name references.""" def __init__(self, unsure): self.unsure = unsure @@ -213,6 +259,7 @@ def __call__(self, occurrence): class NoImportsFilter(object): + """Don't include import statements as occurrences.""" def __call__(self, occurrence): if occurrence.is_in_import_statement(): @@ -220,6 +267,7 @@ def __call__(self, occurrence): class CallsFilter(object): + """Filter out non-call occurrences.""" def __call__(self, occurrence): if not occurrence.is_called(): @@ -258,8 +306,10 @@ def _normal_search(self, source): try: found = source.index(self.name, current) current = found + len(self.name) - if (found == 0 or not self._is_id_char(source[found - 1])) and \ - (current == len(source) or not self._is_id_char(source[current])): + if (found == 0 or + not self._is_id_char(source[found - 1])) and \ + (current == len(source) or + not self._is_id_char(source[current])): yield found except ValueError: break @@ -282,7 +332,7 @@ def _get_source(self, resource, pymodule): def _get_occurrence_pattern(self, name): occurrence_pattern = _TextualFinder.any('occurrence', - ['\\b' + name + '\\b']) + ['\\b' + name + '\\b']) pattern = re.compile(occurrence_pattern + '|' + self.comment_pattern + '|' + self.string_pattern) return pattern @@ -294,8 +344,8 @@ def any(name, list_): class _OccurrenceToolsCreator(object): - def __init__(self, pycore, resource=None, pymodule=None, docs=False): - self.pycore = pycore + def __init__(self, project, resource=None, pymodule=None, docs=False): + self.project = project self.__resource = resource self.__pymodule = pymodule self.docs = docs @@ -331,4 +381,4 @@ def resource(self): def pymodule(self): if self.__pymodule is not None: return self.__pymodule - return self.pycore.resource_to_pyobject(self.resource) + return self.project.get_pymodule(self.resource) diff --git a/pymode/libs2/rope/refactor/patchedast.py b/pymode/libs2/rope/refactor/patchedast.py index 88fa4d85..28d36d5a 100644 --- a/pymode/libs2/rope/refactor/patchedast.py +++ b/pymode/libs2/rope/refactor/patchedast.py @@ -68,6 +68,7 @@ def __init__(self, source, children=False): Number = object() String = object() + semicolon_or_as_in_except = object() def __call__(self, node): method = getattr(self, '_' + node.__class__.__name__, None) @@ -111,6 +112,10 @@ def _handle(self, node, base_children, eat_parens=False, eat_spaces=False): elif child == '!=': # INFO: This has been added to handle deprecated ``<>`` region = self.source.consume_not_equal() + elif child == self.semicolon_or_as_in_except: + # INFO: This has been added to handle deprecated + # semicolon in except + region = self.source.consume_except_as_or_semicolon() else: region = self.source.consume(child) child = self.source[region[0]:region[1]] @@ -205,16 +210,17 @@ def _find_next_statement_start(self): for child in children: if isinstance(child, ast.stmt): return child.col_offset \ - + self.lines.get_line_start(child.lineno) + + self.lines.get_line_start(child.lineno) return len(self.source.source) - _operators = {'And': 'and', 'Or': 'or', 'Add': '+', 'Sub': '-', 'Mult': '*', - 'Div': '/', 'Mod': '%', 'Pow': '**', 'LShift': '<<', - 'RShift': '>>', 'BitOr': '|', 'BitAnd': '&', 'BitXor': '^', - 'FloorDiv': '//', 'Invert': '~', 'Not': 'not', 'UAdd': '+', - 'USub': '-', 'Eq': '==', 'NotEq': '!=', 'Lt': '<', - 'LtE': '<=', 'Gt': '>', 'GtE': '>=', 'Is': 'is', - 'IsNot': 'is not', 'In': 'in', 'NotIn': 'not in'} + _operators = {'And': 'and', 'Or': 'or', 'Add': '+', 'Sub': '-', + 'Mult': '*', 'Div': '/', 'Mod': '%', 'Pow': '**', + 'LShift': '<<', 'RShift': '>>', 'BitOr': '|', 'BitAnd': '&', + 'BitXor': '^', 'FloorDiv': '//', 'Invert': '~', + 'Not': 'not', 'UAdd': '+', 'USub': '-', 'Eq': '==', + 'NotEq': '!=', 'Lt': '<', 'LtE': '<=', 'Gt': '>', + 'GtE': '>=', 'Is': 'is', 'IsNot': 'is not', 'In': 'in', + 'NotIn': 'not in'} def _get_op(self, node): return self._operators[node.__class__.__name__].split(' ') @@ -351,7 +357,8 @@ def _ImportFrom(self, node): children = ['from'] if node.level: children.append('.' * node.level) - children.extend([node.module or '', # see comment at rope.base.ast.walk + # see comment at rope.base.ast.walk + children.extend([node.module or '', 'import']) children.extend(self._child_nodes(node.names, ',')) self._handle(node, children) @@ -380,7 +387,8 @@ def _FunctionDef(self, node): def _arguments(self, node): children = [] args = list(node.args) - defaults = [None] * (len(args) - len(node.defaults)) + list(node.defaults) + defaults = [None] * (len(args) - len(node.defaults)) + \ + list(node.defaults) for index, (arg, default) in enumerate(zip(args, defaults)): if index > 0: children.append(',') @@ -568,13 +576,16 @@ def _ExceptHandler(self, node): self._excepthandler(node) def _excepthandler(self, node): + # self._handle(node, [self.semicolon_or_as_in_except]) children = ['except'] if node.type: children.append(node.type) if node.name: - children.extend([',', node.name]) + children.append(self.semicolon_or_as_in_except) + children.append(node.name) children.append(':') children.extend(node.body) + self._handle(node, children) def _Tuple(self, node): @@ -663,6 +674,10 @@ def consume_not_equal(self): repattern = _Source._not_equals_pattern return self._consume_pattern(repattern) + def consume_except_as_or_semicolon(self): + repattern = re.compile(r'as|,') + return self._consume_pattern(repattern) + def _good_token(self, token, offset, start=None): """Checks whether consumed token is in comments""" if start is None: diff --git a/pymode/libs2/rope/refactor/rename.py b/pymode/libs2/rope/refactor/rename.py index 65e6e1d5..3f1f5b7e 100644 --- a/pymode/libs2/rope/refactor/rename.py +++ b/pymode/libs2/rope/refactor/rename.py @@ -1,8 +1,9 @@ import warnings -from rope.base import exceptions, pyobjects, pynames, taskhandle, evaluate, worder, codeanalyze +from rope.base import (exceptions, pyobjects, pynames, taskhandle, + evaluate, worder, codeanalyze, libutils) from rope.base.change import ChangeSet, ChangeContents, MoveResource -from rope.refactor import occurrences, sourceutils +from rope.refactor import occurrences class Rename(object): @@ -16,11 +17,10 @@ class Rename(object): def __init__(self, project, resource, offset=None): """If `offset` is None, the `resource` itself will be renamed""" self.project = project - self.pycore = project.pycore self.resource = resource if offset is not None: self.old_name = worder.get_name_at(self.resource, offset) - this_pymodule = self.pycore.resource_to_pyobject(self.resource) + this_pymodule = self.project.get_pymodule(self.resource) self.old_instance, self.old_pyname = \ evaluate.eval_location2(this_pymodule, offset) if self.old_pyname is None: @@ -30,7 +30,7 @@ def __init__(self, project, resource, offset=None): else: if not resource.is_folder() and resource.name == '__init__.py': resource = resource.parent - dummy_pymodule = self.pycore.get_string_module('') + dummy_pymodule = libutils.get_string_module(self.project, '') self.old_instance = None self.old_pyname = pynames.ImportedModule(dummy_pymodule, resource=resource) @@ -70,6 +70,7 @@ def get_changes(self, new_name, in_file=None, in_hierarchy=False, warnings.warn( 'unsure parameter should be a function that returns ' 'True or False', DeprecationWarning, stacklevel=2) + def unsure_func(value=unsure): return value unsure = unsure_func @@ -82,14 +83,15 @@ def unsure_func(value=unsure): if _is_local(self.old_pyname): resources = [self.resource] if resources is None: - resources = self.pycore.get_python_files() + resources = self.project.get_python_files() changes = ChangeSet('Renaming <%s> to <%s>' % (self.old_name, new_name)) finder = occurrences.create_finder( - self.pycore, self.old_name, self.old_pyname, unsure=unsure, + self.project, self.old_name, self.old_pyname, unsure=unsure, docs=docs, instance=self.old_instance, in_hierarchy=in_hierarchy and self.is_method()) - job_set = task_handle.create_jobset('Collecting Changes', len(resources)) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) for file_ in resources: job_set.started_job(file_.path) new_content = rename_in_module(finder, new_name, resource=file_) @@ -119,8 +121,8 @@ def _is_renaming_a_module(self): def is_method(self): pyname = self.old_pyname return isinstance(pyname, pynames.DefinedName) and \ - isinstance(pyname.get_object(), pyobjects.PyFunction) and \ - isinstance(pyname.get_object().parent, pyobjects.PyClass) + isinstance(pyname.get_object(), pyobjects.PyFunction) and \ + isinstance(pyname.get_object().parent, pyobjects.PyClass) def _rename_module(self, resource, new_name, changes): if not resource.is_folder(): @@ -147,11 +149,11 @@ class ChangeOccurrences(object): """ def __init__(self, project, resource, offset): - self.pycore = project.pycore + self.project = project self.resource = resource self.offset = offset self.old_name = worder.get_name_at(resource, offset) - self.pymodule = self.pycore.resource_to_pyobject(self.resource) + self.pymodule = project.get_pymodule(self.resource) self.old_pyname = evaluate.eval_location(self.pymodule, offset) def get_old_name(self): @@ -161,7 +163,7 @@ def get_old_name(self): def _get_scope_offset(self): lines = self.pymodule.lines scope = self.pymodule.get_scope().\ - get_inner_scope_for_line(lines.get_line_number(self.offset)) + get_inner_scope_for_line(lines.get_line_number(self.offset)) start = lines.get_line_start(scope.get_start()) end = lines.get_line_end(scope.get_end()) return start, end @@ -171,7 +173,7 @@ def get_changes(self, new_name, only_calls=False, reads=True, writes=True): (self.old_name, new_name)) scope_start, scope_end = self._get_scope_offset() finder = occurrences.create_finder( - self.pycore, self.old_name, self.old_pyname, + self.project, self.old_name, self.old_pyname, imports=False, only_calls=only_calls) new_contents = rename_in_module( finder, new_name, pymodule=self.pymodule, replace_primary=True, @@ -181,8 +183,9 @@ def get_changes(self, new_name, only_calls=False, reads=True, writes=True): return changes -def rename_in_module(occurrences_finder, new_name, resource=None, pymodule=None, - replace_primary=False, region=None, reads=True, writes=True): +def rename_in_module(occurrences_finder, new_name, resource=None, + pymodule=None, replace_primary=False, region=None, + reads=True, writes=True): """Returns the changed source or `None` if there is no changes""" if resource is not None: source_code = resource.read() @@ -203,6 +206,7 @@ def rename_in_module(occurrences_finder, new_name, resource=None, pymodule=None, change_collector.add_change(start, end, new_name) return change_collector.get_changed() + def _is_local(pyname): module, lineno = pyname.get_definition_location() if lineno is None: @@ -212,5 +216,5 @@ def _is_local(pyname): scope.get_kind() in ('Function', 'Class'): scope = scope.parent return scope.get_kind() == 'Function' and \ - pyname in scope.get_names().values() and \ - isinstance(pyname, pynames.AssignedName) + pyname in scope.get_names().values() and \ + isinstance(pyname, pynames.AssignedName) diff --git a/pymode/libs2/rope/refactor/restructure.py b/pymode/libs2/rope/refactor/restructure.py index 1573c2fe..98a11e3d 100644 --- a/pymode/libs2/rope/refactor/restructure.py +++ b/pymode/libs2/rope/refactor/restructure.py @@ -1,6 +1,7 @@ import warnings from rope.base import change, taskhandle, builtins, ast, codeanalyze +from rope.base import libutils from rope.refactor import patchedast, similarfinder, sourceutils from rope.refactor.importutils import module_imports @@ -52,7 +53,6 @@ class Restructure(object): from rope.contrib import generate args - pycore: type=rope.base.pycore.PyCore project: type=rope.base.project.Project Example #4:: @@ -79,7 +79,7 @@ def __init__(self, project, pattern, goal, args=None, See class pydoc for more info about the arguments. """ - self.pycore = project.pycore + self.project = project self.pattern = pattern self.goal = goal self.args = args @@ -132,13 +132,13 @@ def get_changes(self, checks=None, imports=None, resources=None, (self.pattern, self.goal)) if resources is not None: files = [resource for resource in resources - if self.pycore.is_python_file(resource)] + if libutils.is_python_file(self.project, resource)] else: - files = self.pycore.get_python_files() + files = self.project.get_python_files() job_set = task_handle.create_jobset('Collecting Changes', len(files)) for resource in files: job_set.started_job(resource.path) - pymodule = self.pycore.resource_to_pyobject(resource) + pymodule = self.project.get_pymodule(resource) finder = similarfinder.SimilarFinder(pymodule, wildcards=self.wildcards) matches = list(finder.get_matches(self.pattern, self.args)) @@ -161,16 +161,16 @@ def _add_imports(self, resource, source, imports): if not imports: return source import_infos = self._get_import_infos(resource, imports) - pymodule = self.pycore.get_string_module(source, resource) - imports = module_imports.ModuleImports(self.pycore, pymodule) + pymodule = libutils.get_string_module(self.project, source, resource) + imports = module_imports.ModuleImports(self.project, pymodule) for import_info in import_infos: imports.add_import(import_info) return imports.get_changed_source() def _get_import_infos(self, resource, imports): - pymodule = self.pycore.get_string_module('\n'.join(imports), - resource) - imports = module_imports.ModuleImports(self.pycore, pymodule) + pymodule = libutils.get_string_module( + self.project, '\n'.join(imports), resource) + imports = module_imports.ModuleImports(self.project, pymodule) return [imports.import_info for imports in imports.imports] @@ -183,7 +183,7 @@ def make_checks(self, string_checks): checks = {} for key, value in string_checks.items(): is_pyname = not key.endswith('.object') and \ - not key.endswith('.type') + not key.endswith('.type') evaluated = self._evaluate(value, is_pyname=is_pyname) if evaluated is not None: checks[key] = evaluated @@ -198,7 +198,7 @@ def get_attribute(self, name): return builtins.builtins[name] pyobject = _BuiltinsStub() else: - pyobject = self.pycore.get_module(attributes[0]) + pyobject = self.project.get_module(attributes[0]) for attribute in attributes[1:]: pyname = pyobject[attribute] if pyname is None: diff --git a/pymode/libs2/rope/refactor/similarfinder.py b/pymode/libs2/rope/refactor/similarfinder.py index fc71abfa..f1a7d42d 100644 --- a/pymode/libs2/rope/refactor/similarfinder.py +++ b/pymode/libs2/rope/refactor/similarfinder.py @@ -2,9 +2,11 @@ import re import rope.refactor.wildcards -from rope.base import codeanalyze, evaluate, exceptions, ast, builtins -from rope.refactor import (patchedast, sourceutils, occurrences, - wildcards, importutils) +from rope.base import libutils +from rope.base import codeanalyze, exceptions, ast, builtins +from rope.refactor import (patchedast, wildcards) + +from rope.refactor.patchedast import MismatchedTokenError class BadNameInCheckError(exceptions.RefactoringError): @@ -22,8 +24,12 @@ class SimilarFinder(object): def __init__(self, pymodule, wildcards=None): """Construct a SimilarFinder""" self.source = pymodule.source_code - self.raw_finder = RawSimilarFinder( - pymodule.source_code, pymodule.get_ast(), self._does_match) + try: + self.raw_finder = RawSimilarFinder( + pymodule.source_code, pymodule.get_ast(), self._does_match) + except MismatchedTokenError: + print "in file %s" % pymodule.resource.path + raise self.pymodule = pymodule if wildcards is None: self.wildcards = {} @@ -41,7 +47,7 @@ def get_matches(self, code, args={}, start=0, end=None): if 'skip' in args.get('', {}): resource, region = args['']['skip'] if resource == self.pymodule.get_resource(): - skip_region = region + skip_region = region return self.raw_finder.get_matches(code, start=start, end=end, skip=skip_region) @@ -97,7 +103,7 @@ def get_matches(self, code, start=0, end=None, skip=None): if start <= match_start and match_end <= end: if skip is not None and (skip[0] < match_end and skip[1] > match_start): - continue + continue yield match def _get_matched_asts(self, code): @@ -175,8 +181,8 @@ def __check_stmt_list(self, nodes): def _match_nodes(self, expected, node, mapping): if isinstance(expected, ast.Name): - if self.ropevar.is_var(expected.id): - return self._match_wildcard(expected, node, mapping) + if self.ropevar.is_var(expected.id): + return self._match_wildcard(expected, node, mapping) if not isinstance(expected, ast.AST): return expected == node if expected.__class__ != node.__class__: @@ -296,8 +302,8 @@ def substitute(self, mapping): def _get_pattern(cls): if cls._match_pattern is None: pattern = codeanalyze.get_comment_pattern() + '|' + \ - codeanalyze.get_string_pattern() + '|' + \ - r'(?P\$\{[^\s\$\}]*\})' + codeanalyze.get_string_pattern() + '|' + \ + r'(?P\$\{[^\s\$\}]*\})' cls._match_pattern = re.compile(pattern) return cls._match_pattern @@ -339,6 +345,7 @@ def _is_var(self, name): def make_pattern(code, variables): variables = set(variables) collector = codeanalyze.ChangeCollector(code) + def does_match(node, name): return isinstance(node, ast.Name) and node.id == name finder = RawSimilarFinder(code, does_match=does_match) @@ -352,11 +359,12 @@ def does_match(node, name): def _pydefined_to_str(pydefined): address = [] - if isinstance(pydefined, (builtins.BuiltinClass, builtins.BuiltinFunction)): + if isinstance(pydefined, + (builtins.BuiltinClass, builtins.BuiltinFunction)): return '__builtins__.' + pydefined.get_name() else: while pydefined.parent is not None: address.insert(0, pydefined.get_name()) pydefined = pydefined.parent - module_name = pydefined.pycore.modname(pydefined.resource) + module_name = libutils.modname(pydefined.resource) return '.'.join(module_name.split('.') + address) diff --git a/pymode/libs2/rope/refactor/sourceutils.py b/pymode/libs2/rope/refactor/sourceutils.py index f64213db..9b842906 100644 --- a/pymode/libs2/rope/refactor/sourceutils.py +++ b/pymode/libs2/rope/refactor/sourceutils.py @@ -1,4 +1,4 @@ -from rope.base import ast, codeanalyze +from rope.base import codeanalyze def get_indents(lines, lineno): @@ -48,7 +48,7 @@ def add_methods(pymodule, class_scope, methods_sources): methods = '\n\n' + '\n\n'.join(methods_sources) indented_methods = fix_indentation( methods, get_indents(lines, class_scope.get_start()) + - get_indent(pymodule.pycore)) + get_indent(pymodule.pycore.project)) result = [] result.append(source_code[:insertion_offset]) result.append(indented_methods) @@ -58,7 +58,7 @@ def add_methods(pymodule, class_scope, methods_sources): def get_body(pyfunction): """Return unindented function body""" - scope = pyfunction.get_scope() + # FIXME scope = pyfunction.get_scope() pymodule = pyfunction.get_module() start, end = get_body_region(pyfunction) return fix_indentation(pymodule.source_code[start:end], 0) @@ -87,6 +87,5 @@ def get_body_region(defined): return start, end -def get_indent(pycore): - project = pycore.project +def get_indent(project): return project.prefs.get('indent_size', 4) diff --git a/pymode/libs2/rope/refactor/suites.py b/pymode/libs2/rope/refactor/suites.py index d955c819..4f9a8c71 100644 --- a/pymode/libs2/rope/refactor/suites.py +++ b/pymode/libs2/rope/refactor/suites.py @@ -14,6 +14,7 @@ def find_visible_for_suite(root, lines): line2 = find_visible_for_suite(root, lines[1:]) suite1 = root.find_suite(line1) suite2 = root.find_suite(line2) + def valid(suite): return suite is not None and not suite.ignored if valid(suite1) and not valid(suite2): diff --git a/pymode/libs2/rope/refactor/topackage.py b/pymode/libs2/rope/refactor/topackage.py index b7113979..f36a6d52 100644 --- a/pymode/libs2/rope/refactor/topackage.py +++ b/pymode/libs2/rope/refactor/topackage.py @@ -1,12 +1,12 @@ import rope.refactor.importutils -from rope.base.change import ChangeSet, ChangeContents, MoveResource, CreateFolder +from rope.base.change import ChangeSet, ChangeContents, MoveResource, \ + CreateFolder class ModuleToPackage(object): def __init__(self, project, resource): self.project = project - self.pycore = project.pycore self.resource = resource def get_changes(self): @@ -27,6 +27,6 @@ def get_changes(self): return changes def _transform_relatives_to_absolute(self, resource): - pymodule = self.pycore.resource_to_pyobject(resource) - import_tools = rope.refactor.importutils.ImportTools(self.pycore) + pymodule = self.project.get_pymodule(resource) + import_tools = rope.refactor.importutils.ImportTools(self.project) return import_tools.relatives_to_absolutes(pymodule) diff --git a/pymode/libs2/rope/refactor/usefunction.py b/pymode/libs2/rope/refactor/usefunction.py index b0621525..85896a98 100644 --- a/pymode/libs2/rope/refactor/usefunction.py +++ b/pymode/libs2/rope/refactor/usefunction.py @@ -1,6 +1,7 @@ from rope.base import (change, taskhandle, evaluate, exceptions, pyobjects, pynames, ast) -from rope.refactor import restructure, sourceutils, similarfinder, importutils +from rope.base import libutils +from rope.refactor import restructure, sourceutils, similarfinder class UseFunction(object): @@ -9,7 +10,7 @@ class UseFunction(object): def __init__(self, project, resource, offset): self.project = project self.offset = offset - this_pymodule = project.pycore.resource_to_pyobject(resource) + this_pymodule = project.get_pymodule(resource) pyname = evaluate.eval_location(this_pymodule, offset) if pyname is None: raise exceptions.RefactoringError('Unresolvable name selected') @@ -37,7 +38,7 @@ def _check_returns(self): def get_changes(self, resources=None, task_handle=taskhandle.NullTaskHandle()): if resources is None: - resources = self.project.pycore.get_python_files() + resources = self.project.get_python_files() changes = change.ChangeSet('Using function <%s>' % self.pyfunction.get_name()) if self.resource in resources: @@ -55,7 +56,6 @@ def get_function_name(self): return self.pyfunction.get_name() def _restructure(self, resources, task_handle, others=True): - body = self._get_body() pattern = self._make_pattern() goal = self._make_goal(import_=others) imports = None @@ -75,7 +75,7 @@ def _find_temps(self): return find_temps(self.project, self._get_body()) def _module_name(self): - return self.project.pycore.modname(self.resource) + return libutils.modname(self.resource) def _make_pattern(self): params = self.pyfunction.get_param_names() @@ -123,7 +123,7 @@ def _is_expression(self): def find_temps(project, code): code = 'def f():\n' + sourceutils.indent_lines(code, 4) - pymodule = project.pycore.get_string_module(code) + pymodule = libutils.get_string_module(project, code) result = [] function_scope = pymodule.get_scope().get_scopes()[0] for name, pyname in function_scope.get_names().items(): @@ -135,16 +135,19 @@ def find_temps(project, code): def _returns_last(node): return node.body and isinstance(node.body[-1], ast.Return) + def _yield_count(node): visitor = _ReturnOrYieldFinder() visitor.start_walking(node) return visitor.yields + def _return_count(node): visitor = _ReturnOrYieldFinder() visitor.start_walking(node) return visitor.returns + class _ReturnOrYieldFinder(object): def __init__(self): diff --git a/pymode/libs2/rope/refactor/wildcards.py b/pymode/libs2/rope/refactor/wildcards.py index 6c487a2a..90040c79 100644 --- a/pymode/libs2/rope/refactor/wildcards.py +++ b/pymode/libs2/rope/refactor/wildcards.py @@ -100,7 +100,7 @@ def __call__(self, pymodule, node): pyname = self._evaluate_node(pymodule, node) if pyname is None or self.expected is None: return self.unsure - if self._unsure_pyname(pyname, unbound=self.kind=='name'): + if self._unsure_pyname(pyname, unbound=self.kind == 'name'): return True if self.kind == 'name': return self._same_pyname(self.expected, pyname) @@ -161,13 +161,15 @@ def _evaluate(self, code): class _BuiltinsStub(object): def get_attribute(self, name): return builtins.builtins[name] + def __getitem__(self, name): return builtins.builtins[name] + def __contains__(self, name): return name in builtins.builtins pyobject = _BuiltinsStub() else: - pyobject = self.project.pycore.get_module(attributes[0]) + pyobject = self.project.get_module(attributes[0]) for attribute in attributes[1:]: pyname = pyobject[attribute] if pyname is None: diff --git a/pymode/libs3/rope/__init__.py b/pymode/libs3/rope/__init__.py index 451ebe3a..a936fe29 100644 --- a/pymode/libs3/rope/__init__.py +++ b/pymode/libs3/rope/__init__.py @@ -1,7 +1,7 @@ """rope, a python refactoring library""" INFO = __doc__ -VERSION = '0.9.4' +VERSION = '0.9.4-1' COPYRIGHT = """\ Copyright (C) 2006-2010 Ali Gholami Rudi Copyright (C) 2009-2010 Anton Gritsay diff --git a/pymode/libs3/rope/refactor/patchedast.py b/pymode/libs3/rope/refactor/patchedast.py index 034dac35..042b33dd 100644 --- a/pymode/libs3/rope/refactor/patchedast.py +++ b/pymode/libs3/rope/refactor/patchedast.py @@ -1,7 +1,6 @@ import collections import re import warnings -import sys from rope.base import ast, codeanalyze, exceptions @@ -564,19 +563,6 @@ def _TryExcept(self, node): children.extend(['else', ':']) children.extend(node.orelse) self._handle(node, children) - - def _Try(self, node): - children = ['try', ':'] - children.extend(node.body) - children.extend(node.handlers) - if node.orelse: - children.extend(['else', ':']) - children.extend(node.orelse) - if node.finalbody: - children.extend(['finally', ':']) - children.extend(node.finalbody) - - self._handle(node, children) def _ExceptHandler(self, node): self._excepthandler(node) @@ -618,15 +604,9 @@ def _While(self, node): self._handle(node, children) def _With(self, node): - children = [] - if (sys.version_info[1] < 3): - children = ['with', node.context_expr] - if node.optional_vars: - children.extend(['as', node.optional_vars]) - else: - children = ['with', node.items[0].context_expr] - if node.items[0].optional_vars: - children.extend(['as', node.items[0].optional_vars]) + children = ['with', node.context_expr] + if node.optional_vars: + children.extend(['as', node.optional_vars]) children.append(':') children.extend(node.body) self._handle(node, children) diff --git a/pymode/libs3/rope/refactor/suites.py b/pymode/libs3/rope/refactor/suites.py index 041c06a2..d955c819 100644 --- a/pymode/libs3/rope/refactor/suites.py +++ b/pymode/libs3/rope/refactor/suites.py @@ -128,15 +128,6 @@ def _TryExcept(self, node): if node.orelse: self.suites.append(Suite(node.orelse, node.lineno, self.suite)) - def _Try(self, node): - self.suites.append(Suite(node.body, node.lineno, self.suite)) - for handler in node.handlers: - self.suites.append(Suite(handler.body, node.lineno, self.suite)) - if node.orelse: - self.suites.append(Suite(node.orelse, node.lineno, self.suite)) - if node.finalbody: - self.suites.append(Suite(node.finalbody, node.lineno, self.suite)) - def _add_if_like_node(self, node): self.suites.append(Suite(node.body, node.lineno, self.suite)) if node.orelse: