Path: blob/master/elisp/emacs-for-python/rope-dist/rope/refactor/functionutils.py
1415 views
import rope.base.exceptions1import rope.base.pyobjects2from rope.base.builtins import Lambda3from rope.base import worder456class DefinitionInfo(object):78def __init__(self, function_name, is_method, args_with_defaults,9args_arg, keywords_arg):10self.function_name = function_name11self.is_method = is_method12self.args_with_defaults = args_with_defaults13self.args_arg = args_arg14self.keywords_arg = keywords_arg1516def to_string(self):17return '%s(%s)' % (self.function_name, self.arguments_to_string())1819def arguments_to_string(self, from_index=0):20params = []21for arg, default in self.args_with_defaults:22if default is not None:23params.append('%s=%s' % (arg, default))24else:25params.append(arg)26if self.args_arg is not None:27params.append('*' + self.args_arg)28if self.keywords_arg:29params.append('**' + self.keywords_arg)30return ', '.join(params[from_index:])3132@staticmethod33def _read(pyfunction, code):34scope = pyfunction.get_scope()35parent = scope.parent36parameter_names = pyfunction.get_param_names()37kind = pyfunction.get_kind()38is_method = kind == 'method'39is_lambda = kind == 'lambda'40info = _FunctionParser(code, is_method, is_lambda)41args, keywords = info.get_parameters()42args_arg = None43keywords_arg = None44if args and args[-1].startswith('**'):45keywords_arg = args[-1][2:]46del args[-1]47if args and args[-1].startswith('*'):48args_arg = args[-1][1:]49del args[-1]50args_with_defaults = [(name, None) for name in args]51args_with_defaults.extend(keywords)52return DefinitionInfo(info.get_function_name(), is_method,53args_with_defaults, args_arg, keywords_arg)5455@staticmethod56def read(pyfunction):57pymodule = pyfunction.get_module()58word_finder = worder.Worder(pymodule.source_code)59lineno = pyfunction.get_ast().lineno60start = pymodule.lines.get_line_start(lineno)61if isinstance(pyfunction, Lambda):62call = word_finder.get_lambda_and_args(start)63else:64call = word_finder.get_function_and_args_in_header(start)65return DefinitionInfo._read(pyfunction, call)666768class CallInfo(object):6970def __init__(self, function_name, args, keywords, args_arg,71keywords_arg, implicit_arg, constructor):72self.function_name = function_name73self.args = args74self.keywords = keywords75self.args_arg = args_arg76self.keywords_arg = keywords_arg77self.implicit_arg = implicit_arg78self.constructor = constructor7980def to_string(self):81function = self.function_name82if self.implicit_arg:83function = self.args[0] + '.' + self.function_name84params = []85start = 086if self.implicit_arg or self.constructor:87start = 188if self.args[start:]:89params.extend(self.args[start:])90if self.keywords:91params.extend(['%s=%s' % (name, value) for name, value in self.keywords])92if self.args_arg is not None:93params.append('*' + self.args_arg)94if self.keywords_arg:95params.append('**' + self.keywords_arg)96return '%s(%s)' % (function, ', '.join(params))9798@staticmethod99def read(primary, pyname, definition_info, code):100is_method_call = CallInfo._is_method_call(primary, pyname)101is_constructor = CallInfo._is_class(pyname)102is_classmethod = CallInfo._is_classmethod(pyname)103info = _FunctionParser(code, is_method_call or is_classmethod)104args, keywords = info.get_parameters()105args_arg = None106keywords_arg = None107if args and args[-1].startswith('**'):108keywords_arg = args[-1][2:]109del args[-1]110if args and args[-1].startswith('*'):111args_arg = args[-1][1:]112del args[-1]113if is_constructor:114args.insert(0, definition_info.args_with_defaults[0][0])115return CallInfo(info.get_function_name(), args, keywords, args_arg,116keywords_arg, is_method_call or is_classmethod,117is_constructor)118119@staticmethod120def _is_method_call(primary, pyname):121return primary is not None and \122isinstance(primary.get_object().get_type(),123rope.base.pyobjects.PyClass) and \124CallInfo._is_method(pyname)125126@staticmethod127def _is_class(pyname):128return pyname is not None and \129isinstance(pyname.get_object(),130rope.base.pyobjects.PyClass)131132@staticmethod133def _is_method(pyname):134if pyname is not None and \135isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction):136return pyname.get_object().get_kind() == 'method'137return False138139@staticmethod140def _is_classmethod(pyname):141if pyname is not None and \142isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction):143return pyname.get_object().get_kind() == 'classmethod'144return False145146147class ArgumentMapping(object):148149def __init__(self, definition_info, call_info):150self.call_info = call_info151self.param_dict = {}152self.keyword_args = []153self.args_arg = []154for index, value in enumerate(call_info.args):155if index < len(definition_info.args_with_defaults):156name = definition_info.args_with_defaults[index][0]157self.param_dict[name] = value158else:159self.args_arg.append(value)160for name, value in call_info.keywords:161index = -1162for pair in definition_info.args_with_defaults:163if pair[0] == name:164self.param_dict[name] = value165break166else:167self.keyword_args.append((name, value))168169def to_call_info(self, definition_info):170args = []171keywords = []172for index in range(len(definition_info.args_with_defaults)):173name = definition_info.args_with_defaults[index][0]174if name in self.param_dict:175args.append(self.param_dict[name])176else:177for i in range(index, len(definition_info.args_with_defaults)):178name = definition_info.args_with_defaults[i][0]179if name in self.param_dict:180keywords.append((name, self.param_dict[name]))181break182args.extend(self.args_arg)183keywords.extend(self.keyword_args)184return CallInfo(self.call_info.function_name, args, keywords,185self.call_info.args_arg, self.call_info.keywords_arg,186self.call_info.implicit_arg, self.call_info.constructor)187188189class _FunctionParser(object):190191def __init__(self, call, implicit_arg, is_lambda=False):192self.call = call193self.implicit_arg = implicit_arg194self.word_finder = worder.Worder(self.call)195if is_lambda:196self.last_parens = self.call.rindex(':')197else:198self.last_parens = self.call.rindex(')')199self.first_parens = self.word_finder._find_parens_start(self.last_parens)200201def get_parameters(self):202args, keywords = self.word_finder.get_parameters(self.first_parens,203self.last_parens)204if self.is_called_as_a_method():205instance = self.call[:self.call.rindex('.', 0, self.first_parens)]206args.insert(0, instance.strip())207return args, keywords208209def get_instance(self):210if self.is_called_as_a_method():211return self.word_finder.get_primary_at(212self.call.rindex('.', 0, self.first_parens) - 1)213214def get_function_name(self):215if self.is_called_as_a_method():216return self.word_finder.get_word_at(self.first_parens - 1)217else:218return self.word_finder.get_primary_at(self.first_parens - 1)219220def is_called_as_a_method(self):221return self.implicit_arg and '.' in self.call[:self.first_parens]222223224