| Index: tools/telemetry/third_party/rope/rope/contrib/codeassist.py
|
| diff --git a/tools/telemetry/third_party/rope/rope/contrib/codeassist.py b/tools/telemetry/third_party/rope/rope/contrib/codeassist.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..92c1bfc275c77c0b2985545426f736a5ed37dfde
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/rope/contrib/codeassist.py
|
| @@ -0,0 +1,695 @@
|
| +import keyword
|
| +import sys
|
| +import warnings
|
| +
|
| +import rope.base.codeanalyze
|
| +import rope.base.evaluate
|
| +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
|
| +
|
| +
|
| +def code_assist(project, source_code, offset, resource=None,
|
| + templates=None, maxfixes=1, later_locals=True):
|
| + """Return python code completions as a list of `CodeAssistProposal`\s
|
| +
|
| + `resource` is a `rope.base.resources.Resource` object. If
|
| + provided, relative imports are handled.
|
| +
|
| + `maxfixes` is the maximum number of errors to fix if the code has
|
| + errors in it.
|
| +
|
| + If `later_locals` is `False` names defined in this scope and after
|
| + this line is ignored.
|
| +
|
| + """
|
| + if templates is not None:
|
| + warnings.warn('Codeassist no longer supports templates',
|
| + DeprecationWarning, stacklevel=2)
|
| + assist = _PythonCodeAssist(
|
| + project, source_code, offset, resource=resource,
|
| + maxfixes=maxfixes, later_locals=later_locals)
|
| + return assist()
|
| +
|
| +
|
| +def starting_offset(source_code, offset):
|
| + """Return the offset in which the completion should be inserted
|
| +
|
| + Usually code assist proposals should be inserted like::
|
| +
|
| + completion = proposal.name
|
| + result = (source_code[:starting_offset] +
|
| + completion + source_code[offset:])
|
| +
|
| + Where starting_offset is the offset returned by this function.
|
| +
|
| + """
|
| + word_finder = worder.Worder(source_code, True)
|
| + expression, starting, starting_offset = \
|
| + word_finder.get_splitted_primary_before(offset)
|
| + return starting_offset
|
| +
|
| +
|
| +def get_doc(project, source_code, offset, resource=None, maxfixes=1):
|
| + """Get the pydoc"""
|
| + fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes)
|
| + pyname = fixer.pyname_at(offset)
|
| + if pyname is None:
|
| + return None
|
| + pyobject = pyname.get_object()
|
| + return PyDocExtractor().get_doc(pyobject)
|
| +
|
| +
|
| +def get_calltip(project, source_code, offset, resource=None,
|
| + maxfixes=1, ignore_unknown=False, remove_self=False):
|
| + """Get the calltip of a function
|
| +
|
| + The format of the returned string is
|
| + ``module_name.holding_scope_names.function_name(arguments)``. For
|
| + classes `__init__()` and for normal objects `__call__()` function
|
| + is used.
|
| +
|
| + Note that the offset is on the function itself *not* after the its
|
| + open parenthesis. (Actually it used to be the other way but it
|
| + was easily confused when string literals were involved. So I
|
| + decided it is better for it not to try to be too clever when it
|
| + cannot be clever enough). You can use a simple search like::
|
| +
|
| + offset = source_code.rindex('(', 0, offset) - 1
|
| +
|
| + to handle simple situations.
|
| +
|
| + If `ignore_unknown` is `True`, `None` is returned for functions
|
| + without source-code like builtins and extensions.
|
| +
|
| + If `remove_self` is `True`, the first parameter whose name is self
|
| + will be removed for methods.
|
| + """
|
| + fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes)
|
| + pyname = fixer.pyname_at(offset)
|
| + if pyname is None:
|
| + return None
|
| + pyobject = pyname.get_object()
|
| + return PyDocExtractor().get_calltip(pyobject, ignore_unknown, remove_self)
|
| +
|
| +
|
| +def get_definition_location(project, source_code, offset,
|
| + resource=None, maxfixes=1):
|
| + """Return the definition location of the python name at `offset`
|
| +
|
| + Return a (`rope.base.resources.Resource`, lineno) tuple. If no
|
| + `resource` is given and the definition is inside the same module,
|
| + the first element of the returned tuple would be `None`. If the
|
| + location cannot be determined ``(None, None)`` is returned.
|
| +
|
| + """
|
| + fixer = fixsyntax.FixSyntax(project, source_code, resource, maxfixes)
|
| + pyname = fixer.pyname_at(offset)
|
| + if pyname is not None:
|
| + module, lineno = pyname.get_definition_location()
|
| + if module is not None:
|
| + return module.get_module().get_resource(), lineno
|
| + return (None, None)
|
| +
|
| +
|
| +def find_occurrences(*args, **kwds):
|
| + import rope.contrib.findit
|
| + warnings.warn('Use `rope.contrib.findit.find_occurrences()` instead',
|
| + DeprecationWarning, stacklevel=2)
|
| + 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
|
| +
|
| + The `scope` instance variable shows where proposed name came from
|
| + and can be 'global', 'local', 'builtin', 'attribute', 'keyword',
|
| + 'imported', 'parameter_keyword'.
|
| +
|
| + The `type` instance variable shows the approximate type of the
|
| + proposed object and can be 'instance', 'class', 'function', 'module',
|
| + and `None`.
|
| +
|
| + All possible relations between proposal's `scope` and `type` are shown
|
| + in the table below (different scopes in rows and types in columns):
|
| +
|
| + | instance | class | function | module | None
|
| + local | + | + | + | + |
|
| + global | + | + | + | + |
|
| + builtin | + | + | + | |
|
| + attribute | + | + | + | + |
|
| + imported | + | + | + | + |
|
| + keyword | | | | | +
|
| + parameter_keyword | | | | | +
|
| +
|
| + """
|
| +
|
| + def __init__(self, name, scope, pyname=None):
|
| + self.name = name
|
| + self.pyname = pyname
|
| + self.scope = self._get_scope(scope)
|
| +
|
| + def __str__(self):
|
| + return '%s (%s, %s)' % (self.name, self.scope, self.type)
|
| +
|
| + def __repr__(self):
|
| + return str(self)
|
| +
|
| + @property
|
| + def parameters(self):
|
| + """The names of the parameters the function takes.
|
| +
|
| + Returns None if this completion is not a function.
|
| + """
|
| + pyname = self.pyname
|
| + if isinstance(pyname, pynames.ImportedName):
|
| + pyname = pyname._get_imported_pyname()
|
| + if isinstance(pyname, pynames.DefinedName):
|
| + pyobject = pyname.get_object()
|
| + if isinstance(pyobject, pyobjects.AbstractFunction):
|
| + return pyobject.get_param_names()
|
| +
|
| + @property
|
| + def type(self):
|
| + pyname = self.pyname
|
| + if isinstance(pyname, builtins.BuiltinName):
|
| + pyobject = pyname.get_object()
|
| + if isinstance(pyobject, builtins.BuiltinFunction):
|
| + return 'function'
|
| + elif isinstance(pyobject, builtins.BuiltinClass):
|
| + return 'class'
|
| + elif isinstance(pyobject, builtins.BuiltinObject) or \
|
| + isinstance(pyobject, builtins.BuiltinName):
|
| + return 'instance'
|
| + elif isinstance(pyname, pynames.ImportedModule):
|
| + return 'module'
|
| + elif isinstance(pyname, pynames.ImportedName) or \
|
| + isinstance(pyname, pynames.DefinedName):
|
| + pyobject = pyname.get_object()
|
| + if isinstance(pyobject, pyobjects.AbstractFunction):
|
| + return 'function'
|
| + if isinstance(pyobject, pyobjects.AbstractClass):
|
| + return 'class'
|
| + return 'instance'
|
| +
|
| + def _get_scope(self, scope):
|
| + if isinstance(self.pyname, builtins.BuiltinName):
|
| + return 'builtin'
|
| + if isinstance(self.pyname, pynames.ImportedModule) or \
|
| + isinstance(self.pyname, pynames.ImportedName):
|
| + return 'imported'
|
| + return scope
|
| +
|
| + def get_doc(self):
|
| + """Get the proposed object's docstring.
|
| +
|
| + Returns None if it can not be get.
|
| + """
|
| + if not self.pyname:
|
| + return None
|
| + pyobject = self.pyname.get_object()
|
| + if not hasattr(pyobject, 'get_doc'):
|
| + return None
|
| + return self.pyname.get_object().get_doc()
|
| +
|
| + @property
|
| + def kind(self):
|
| + warnings.warn("the proposal's `kind` property is deprecated, "
|
| + "use `scope` instead")
|
| + return self.scope
|
| +
|
| +
|
| +# leaved for backward compatibility
|
| +CodeAssistProposal = CompletionProposal
|
| +
|
| +
|
| +class NamedParamProposal(CompletionProposal):
|
| + """A parameter keyword completion proposal
|
| +
|
| + Holds reference to ``_function`` -- the function which
|
| + parameter ``name`` belongs to. This allows to determine
|
| + default value for this parameter.
|
| + """
|
| + def __init__(self, name, function):
|
| + self.argname = name
|
| + name = '%s=' % name
|
| + super(NamedParamProposal, self).__init__(name, 'parameter_keyword')
|
| + self._function = function
|
| +
|
| + def get_default(self):
|
| + """Get a string representation of a param's default value.
|
| +
|
| + Returns None if there is no default value for this param.
|
| + """
|
| + definfo = functionutils.DefinitionInfo.read(self._function)
|
| + for arg, default in definfo.args_with_defaults:
|
| + if self.argname == arg:
|
| + return default
|
| + return None
|
| +
|
| +
|
| +def sorted_proposals(proposals, scopepref=None, typepref=None):
|
| + """Sort a list of proposals
|
| +
|
| + Return a sorted list of the given `CodeAssistProposal`\s.
|
| +
|
| + `scopepref` can be a list of proposal scopes. Defaults to
|
| + ``['parameter_keyword', 'local', 'global', 'imported',
|
| + 'attribute', 'builtin', 'keyword']``.
|
| +
|
| + `typepref` can be a list of proposal types. Defaults to
|
| + ``['class', 'function', 'instance', 'module', None]``.
|
| + (`None` stands for completions with no type like keywords.)
|
| + """
|
| + sorter = _ProposalSorter(proposals, scopepref, typepref)
|
| + return sorter.get_sorted_proposal_list()
|
| +
|
| +
|
| +def starting_expression(source_code, offset):
|
| + """Return the expression to complete"""
|
| + word_finder = worder.Worder(source_code, True)
|
| + expression, starting, starting_offset = \
|
| + word_finder.get_splitted_primary_before(offset)
|
| + if expression:
|
| + return expression + '.' + starting
|
| + return starting
|
| +
|
| +
|
| +def default_templates():
|
| + warnings.warn('default_templates() is deprecated.',
|
| + DeprecationWarning, stacklevel=2)
|
| + return {}
|
| +
|
| +
|
| +class _PythonCodeAssist(object):
|
| +
|
| + def __init__(self, project, source_code, offset, resource=None,
|
| + maxfixes=1, later_locals=True):
|
| + self.project = project
|
| + self.code = source_code
|
| + self.resource = resource
|
| + self.maxfixes = maxfixes
|
| + self.later_locals = later_locals
|
| + self.word_finder = worder.Worder(source_code, True)
|
| + self.expression, self.starting, self.offset = \
|
| + self.word_finder.get_splitted_primary_before(offset)
|
| +
|
| + keywords = keyword.kwlist
|
| +
|
| + 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
|
| + return current_offset + 1
|
| +
|
| + def _matching_keywords(self, starting):
|
| + result = []
|
| + for kw in self.keywords:
|
| + if kw.startswith(starting):
|
| + result.append(CompletionProposal(kw, 'keyword'))
|
| + return result
|
| +
|
| + def __call__(self):
|
| + if self.offset > len(self.code):
|
| + return []
|
| + completions = list(self._code_completions().values())
|
| + if self.expression.strip() == '' and self.starting.strip() != '':
|
| + completions.extend(self._matching_keywords(self.starting))
|
| + return completions
|
| +
|
| + def _dotted_completions(self, module_scope, holding_scope):
|
| + result = {}
|
| + found_pyname = rope.base.evaluate.eval_str(holding_scope,
|
| + self.expression)
|
| + if found_pyname is not None:
|
| + element = found_pyname.get_object()
|
| + compl_scope = 'attribute'
|
| + if isinstance(element, (pyobjectsdef.PyModule,
|
| + pyobjectsdef.PyPackage)):
|
| + compl_scope = 'imported'
|
| + for name, pyname in element.get_attributes().items():
|
| + if name.startswith(self.starting):
|
| + result[name] = CompletionProposal(name, compl_scope,
|
| + pyname)
|
| + return result
|
| +
|
| + def _undotted_completions(self, scope, result, lineno=None):
|
| + if scope.parent is not None:
|
| + self._undotted_completions(scope.parent, result)
|
| + if lineno is None:
|
| + names = scope.get_propagated_names()
|
| + else:
|
| + names = scope.get_names()
|
| + for name, pyname in names.items():
|
| + if name.startswith(self.starting):
|
| + compl_scope = 'local'
|
| + if scope.get_kind() == 'Module':
|
| + compl_scope = 'global'
|
| + if lineno is None or self.later_locals or \
|
| + not self._is_defined_after(scope, pyname, lineno):
|
| + result[name] = CompletionProposal(name, compl_scope,
|
| + pyname)
|
| +
|
| + def _from_import_completions(self, pymodule):
|
| + module_name = self.word_finder.get_from_module(self.offset)
|
| + if module_name is None:
|
| + return {}
|
| + pymodule = self._find_module(pymodule, module_name)
|
| + result = {}
|
| + for name in pymodule:
|
| + if name.startswith(self.starting):
|
| + result[name] = CompletionProposal(name, scope='global',
|
| + pyname=pymodule[name])
|
| + return result
|
| +
|
| + def _find_module(self, pymodule, module_name):
|
| + dots = 0
|
| + while module_name[dots] == '.':
|
| + dots += 1
|
| + pyname = pynames.ImportedModule(pymodule,
|
| + module_name[dots:], dots)
|
| + return pyname.get_object()
|
| +
|
| + def _is_defined_after(self, scope, pyname, lineno):
|
| + location = pyname.get_definition_location()
|
| + if location is not None and location[1] is not None:
|
| + if location[0] == scope.pyobject.get_module() and \
|
| + lineno <= location[1] <= scope.get_end():
|
| + return True
|
| +
|
| + def _code_completions(self):
|
| + lineno = self.code.count('\n', 0, self.offset) + 1
|
| + fixer = fixsyntax.FixSyntax(self.project, self.code,
|
| + self.resource, self.maxfixes)
|
| + pymodule = fixer.get_pymodule()
|
| + module_scope = pymodule.get_scope()
|
| + code = pymodule.source_code
|
| + lines = code.split('\n')
|
| + result = {}
|
| + start = fixsyntax._logical_start(lines, lineno)
|
| + indents = fixsyntax._get_line_indents(lines[start - 1])
|
| + inner_scope = module_scope.get_inner_scope_for_line(start, indents)
|
| + if self.word_finder.is_a_name_after_from_import(self.offset):
|
| + return self._from_import_completions(pymodule)
|
| + if self.expression.strip() != '':
|
| + result.update(self._dotted_completions(module_scope, inner_scope))
|
| + else:
|
| + result.update(self._keyword_parameters(module_scope.pyobject,
|
| + inner_scope))
|
| + self._undotted_completions(inner_scope, result, lineno=lineno)
|
| + return result
|
| +
|
| + def _keyword_parameters(self, pymodule, scope):
|
| + offset = self.offset
|
| + if offset == 0:
|
| + return {}
|
| + word_finder = worder.Worder(self.code, True)
|
| + if word_finder.is_on_function_call_keyword(offset - 1):
|
| + 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:
|
| + 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:
|
| + pyobject = pyobject['__init__'].get_object()
|
| + elif '__call__' in pyobject:
|
| + pyobject = pyobject['__call__'].get_object()
|
| + if isinstance(pyobject, pyobjects.AbstractFunction):
|
| + param_names = []
|
| + param_names.extend(
|
| + pyobject.get_param_names(special_args=False))
|
| + result = {}
|
| + for name in param_names:
|
| + if name.startswith(self.starting):
|
| + result[name + '='] = NamedParamProposal(
|
| + name, pyobject
|
| + )
|
| + return result
|
| + return {}
|
| +
|
| +
|
| +class _ProposalSorter(object):
|
| + """Sort a list of code assist proposals"""
|
| +
|
| + 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']
|
| + self.scopepref = scopepref
|
| + if typepref is None:
|
| + typepref = ['class', 'function', 'instance', 'module', None]
|
| + self.typerank = dict((type, index)
|
| + for index, type in enumerate(typepref))
|
| +
|
| + def get_sorted_proposal_list(self):
|
| + """Return a list of `CodeAssistProposal`"""
|
| + proposals = {}
|
| + for proposal in self.proposals:
|
| + proposals.setdefault(proposal.scope, []).append(proposal)
|
| + result = []
|
| + for scope in self.scopepref:
|
| + scope_proposals = proposals.get(scope, [])
|
| + scope_proposals = [proposal for proposal in scope_proposals
|
| + if proposal.type in self.typerank]
|
| + scope_proposals.sort(key=self._proposal_key)
|
| + result.extend(scope_proposals)
|
| + return result
|
| +
|
| + def _proposal_key(self, proposal1):
|
| + def _underline_count(name):
|
| + return sum(1 for c in name if c == "_")
|
| + return (self.typerank.get(proposal1.type, 100),
|
| + _underline_count(proposal1.name),
|
| + proposal1.name)
|
| + #if proposal1.type != proposal2.type:
|
| + # return cmp(self.typerank.get(proposal1.type, 100),
|
| + # self.typerank.get(proposal2.type, 100))
|
| + #return self._compare_underlined_names(proposal1.name,
|
| + # proposal2.name)
|
| +
|
| +
|
| +class PyDocExtractor(object):
|
| +
|
| + def get_doc(self, pyobject):
|
| + if isinstance(pyobject, pyobjects.AbstractFunction):
|
| + return self._get_function_docstring(pyobject)
|
| + elif isinstance(pyobject, pyobjects.AbstractClass):
|
| + return self._get_class_docstring(pyobject)
|
| + elif isinstance(pyobject, pyobjects.AbstractModule):
|
| + return self._trim_docstring(pyobject.get_doc())
|
| + return None
|
| +
|
| + def get_calltip(self, pyobject, ignore_unknown=False, remove_self=False):
|
| + try:
|
| + if isinstance(pyobject, pyobjects.AbstractClass):
|
| + pyobject = pyobject['__init__'].get_object()
|
| + if not isinstance(pyobject, pyobjects.AbstractFunction):
|
| + pyobject = pyobject['__call__'].get_object()
|
| + except exceptions.AttributeNotFoundError:
|
| + return None
|
| + if ignore_unknown and not isinstance(pyobject, pyobjects.PyFunction):
|
| + return
|
| + if isinstance(pyobject, pyobjects.AbstractFunction):
|
| + result = self._get_function_signature(pyobject, add_module=True)
|
| + if remove_self and self._is_method(pyobject):
|
| + return result.replace('(self)', '()').replace('(self, ', '(')
|
| + return result
|
| +
|
| + 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
|
| +
|
| + if '__init__' in pyclass:
|
| + init = pyclass['__init__'].get_object()
|
| + if isinstance(init, pyobjects.AbstractFunction):
|
| + doc += '\n\n' + self._get_single_function_docstring(init)
|
| + return doc
|
| +
|
| + def _get_function_docstring(self, pyfunction):
|
| + functions = [pyfunction]
|
| + if self._is_method(pyfunction):
|
| + functions.extend(self._get_super_methods(pyfunction.parent,
|
| + pyfunction.get_name()))
|
| + return '\n\n'.join([self._get_single_function_docstring(function)
|
| + for function in functions])
|
| +
|
| + def _is_method(self, pyfunction):
|
| + return isinstance(pyfunction, pyobjects.PyFunction) and \
|
| + isinstance(pyfunction.parent, pyobjects.PyClass)
|
| +
|
| + def _get_single_function_docstring(self, pyfunction):
|
| + signature = self._get_function_signature(pyfunction)
|
| + docs = self._trim_docstring(pyfunction.get_doc(), indents=2)
|
| + return signature + ':\n\n' + docs
|
| +
|
| + def _get_super_methods(self, pyclass, name):
|
| + result = []
|
| + for super_class in pyclass.get_superclasses():
|
| + if name in super_class:
|
| + function = super_class[name].get_object()
|
| + if isinstance(function, pyobjects.AbstractFunction):
|
| + result.append(function)
|
| + result.extend(self._get_super_methods(super_class, name))
|
| + return result
|
| +
|
| + def _get_function_signature(self, pyfunction, add_module=False):
|
| + location = self._location(pyfunction, add_module)
|
| + if isinstance(pyfunction, pyobjects.PyFunction):
|
| + info = functionutils.DefinitionInfo.read(pyfunction)
|
| + return location + info.to_string()
|
| + else:
|
| + return '%s(%s)' % (location + pyfunction.get_name(),
|
| + ', '.join(pyfunction.get_param_names()))
|
| +
|
| + def _location(self, pyobject, add_module=False):
|
| + location = []
|
| + parent = pyobject.parent
|
| + while parent and not isinstance(parent, pyobjects.AbstractModule):
|
| + location.append(parent.get_name())
|
| + location.append('.')
|
| + parent = parent.parent
|
| + if add_module:
|
| + if isinstance(pyobject, pyobjects.PyFunction):
|
| + location.insert(0, self._get_module(pyobject))
|
| + if isinstance(parent, builtins.BuiltinModule):
|
| + location.insert(0, parent.get_name() + '.')
|
| + return ''.join(location)
|
| +
|
| + def _get_module(self, pyfunction):
|
| + module = pyfunction.get_module()
|
| + if module is not None:
|
| + resource = module.get_resource()
|
| + if resource is not None:
|
| + return libutils.modname(resource) + '.'
|
| + return ''
|
| +
|
| + def _trim_docstring(self, docstring, indents=0):
|
| + """The sample code from :PEP:`257`"""
|
| + if not docstring:
|
| + return ''
|
| + # Convert tabs to spaces (following normal Python rules)
|
| + # and split into a list of lines:
|
| + lines = docstring.expandtabs().splitlines()
|
| + # Determine minimum indentation (first line doesn't count):
|
| + indent = sys.maxsize
|
| + for line in lines[1:]:
|
| + stripped = line.lstrip()
|
| + if stripped:
|
| + indent = min(indent, len(line) - len(stripped))
|
| + # Remove indentation (first line is special):
|
| + trimmed = [lines[0].strip()]
|
| + if indent < sys.maxsize:
|
| + for line in lines[1:]:
|
| + trimmed.append(line[indent:].rstrip())
|
| + # Strip off trailing and leading blank lines:
|
| + while trimmed and not trimmed[-1]:
|
| + trimmed.pop()
|
| + while trimmed and not trimmed[0]:
|
| + trimmed.pop(0)
|
| + # Return a single string:
|
| + return '\n'.join((' ' * indents + line for line in trimmed))
|
| +
|
| +
|
| +# Deprecated classes
|
| +
|
| +class TemplateProposal(CodeAssistProposal):
|
| + def __init__(self, name, template):
|
| + warnings.warn('TemplateProposal is deprecated.',
|
| + DeprecationWarning, stacklevel=2)
|
| + super(TemplateProposal, self).__init__(name, 'template')
|
| + self.template = template
|
| +
|
| +
|
| +class Template(object):
|
| +
|
| + def __init__(self, template):
|
| + self.template = template
|
| + warnings.warn('Template is deprecated.',
|
| + DeprecationWarning, stacklevel=2)
|
| +
|
| + def variables(self):
|
| + return []
|
| +
|
| + def substitute(self, mapping):
|
| + return self.template
|
| +
|
| + def get_cursor_location(self, mapping):
|
| + return len(self.template)
|
|
|