init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
|
|
@ -0,0 +1,7 @@
|
|||
"""rope IDE tools package
|
||||
|
||||
This package contains modules that can be used in IDEs
|
||||
but do not depend on the UI. So these modules will be used
|
||||
by `rope.ui` modules.
|
||||
|
||||
"""
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
226
.venv/lib/python3.8/site-packages/rope/contrib/autoimport.py
Normal file
226
.venv/lib/python3.8/site-packages/rope/contrib/autoimport.py
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
import re
|
||||
|
||||
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
|
||||
|
||||
|
||||
class AutoImport(object):
|
||||
"""A class for finding the module that provides a name
|
||||
|
||||
This class maintains a cache of global names in python modules.
|
||||
Note that this cache is not accurate and might be out of date.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, project, observe=True, underlined=False):
|
||||
"""Construct an AutoImport object
|
||||
|
||||
If `observe` is `True`, listen for project changes and update
|
||||
the cache.
|
||||
|
||||
If `underlined` is `True`, underlined names are cached, too.
|
||||
"""
|
||||
self.project = project
|
||||
self.underlined = underlined
|
||||
self.names = project.data_files.read_data("globalnames")
|
||||
if self.names is None:
|
||||
self.names = {}
|
||||
project.data_files.add_write_hook(self._write)
|
||||
# XXX: using a filtered observer
|
||||
observer = resourceobserver.ResourceObserver(
|
||||
changed=self._changed, moved=self._moved, removed=self._removed
|
||||
)
|
||||
if observe:
|
||||
project.add_observer(observer)
|
||||
|
||||
def import_assist(self, starting):
|
||||
"""Return a list of ``(name, module)`` tuples
|
||||
|
||||
This function tries to find modules that have a global name
|
||||
that starts with `starting`.
|
||||
"""
|
||||
# XXX: breaking if gave up! use generators
|
||||
result = []
|
||||
for module in self.names:
|
||||
for global_name in self.names[module]:
|
||||
if global_name.startswith(starting):
|
||||
result.append((global_name, module))
|
||||
return result
|
||||
|
||||
def get_modules(self, name):
|
||||
"""Return the list of modules that have global `name`"""
|
||||
result = []
|
||||
for module in self.names:
|
||||
if name in self.names[module]:
|
||||
result.append(module)
|
||||
return result
|
||||
|
||||
def get_all_names(self):
|
||||
"""Return the list of all cached global names"""
|
||||
result = set()
|
||||
for module in self.names:
|
||||
result.update(set(self.names[module]))
|
||||
return result
|
||||
|
||||
def get_name_locations(self, name):
|
||||
"""Return a list of ``(resource, lineno)`` tuples"""
|
||||
result = []
|
||||
for module in self.names:
|
||||
if name in self.names[module]:
|
||||
try:
|
||||
pymodule = self.project.get_module(module)
|
||||
if name in pymodule:
|
||||
pyname = pymodule[name]
|
||||
module, lineno = pyname.get_definition_location()
|
||||
if module is not None:
|
||||
resource = module.get_module().get_resource()
|
||||
if resource is not None and lineno is not None:
|
||||
result.append((resource, lineno))
|
||||
except exceptions.ModuleNotFoundError:
|
||||
pass
|
||||
return result
|
||||
|
||||
def generate_cache(
|
||||
self, resources=None, underlined=None, task_handle=taskhandle.NullTaskHandle()
|
||||
):
|
||||
"""Generate global name cache for project files
|
||||
|
||||
If `resources` is a list of `rope.base.resource.File`, only
|
||||
those files are searched; otherwise all python modules in the
|
||||
project are cached.
|
||||
|
||||
"""
|
||||
if resources is None:
|
||||
resources = self.project.get_python_files()
|
||||
job_set = task_handle.create_jobset(
|
||||
"Generating autoimport cache", len(resources)
|
||||
)
|
||||
for file in resources:
|
||||
job_set.started_job("Working on <%s>" % file.path)
|
||||
self.update_resource(file, underlined)
|
||||
job_set.finished_job()
|
||||
|
||||
def generate_modules_cache(
|
||||
self, modules, underlined=None, task_handle=taskhandle.NullTaskHandle()
|
||||
):
|
||||
"""Generate global name cache for modules listed in `modules`"""
|
||||
job_set = task_handle.create_jobset(
|
||||
"Generating autoimport cache for modules", len(modules)
|
||||
)
|
||||
for modname in modules:
|
||||
job_set.started_job("Working on <%s>" % modname)
|
||||
if modname.endswith(".*"):
|
||||
mod = self.project.find_module(modname[:-2])
|
||||
if mod:
|
||||
for sub in submodules(mod):
|
||||
self.update_resource(sub, underlined)
|
||||
else:
|
||||
self.update_module(modname, underlined)
|
||||
job_set.finished_job()
|
||||
|
||||
def clear_cache(self):
|
||||
"""Clear all entries in global-name cache
|
||||
|
||||
It might be a good idea to use this function before
|
||||
regenerating global names.
|
||||
|
||||
"""
|
||||
self.names.clear()
|
||||
|
||||
def find_insertion_line(self, code):
|
||||
"""Guess at what line the new import should be inserted"""
|
||||
match = re.search(r"^(def|class)\s+", code)
|
||||
if match is not None:
|
||||
code = code[: match.start()]
|
||||
try:
|
||||
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, pymodule)
|
||||
module_imports.add_import(importinfo)
|
||||
code = module_imports.get_changed_source()
|
||||
offset = code.index(testmodname)
|
||||
lineno = code.count("\n", 0, offset) + 1
|
||||
return lineno
|
||||
|
||||
def update_resource(self, resource, underlined=None):
|
||||
"""Update the cache for global names in `resource`"""
|
||||
try:
|
||||
pymodule = self.project.get_pymodule(resource)
|
||||
modname = self._module_name(resource)
|
||||
self._add_names(pymodule, modname, underlined)
|
||||
except exceptions.ModuleSyntaxError:
|
||||
pass
|
||||
|
||||
def update_module(self, modname, underlined=None):
|
||||
"""Update the cache for global names in `modname` module
|
||||
|
||||
`modname` is the name of a module.
|
||||
"""
|
||||
try:
|
||||
pymodule = self.project.get_module(modname)
|
||||
self._add_names(pymodule, modname, underlined)
|
||||
except exceptions.ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
def _module_name(self, resource):
|
||||
return libutils.modname(resource)
|
||||
|
||||
def _add_names(self, pymodule, modname, underlined):
|
||||
if underlined is None:
|
||||
underlined = self.underlined
|
||||
globals = []
|
||||
if isinstance(pymodule, pyobjects.PyDefinedObject):
|
||||
attributes = pymodule._get_structural_attributes()
|
||||
else:
|
||||
attributes = pymodule.get_attributes()
|
||||
for name, pyname in attributes.items():
|
||||
if not underlined and name.startswith("_"):
|
||||
continue
|
||||
if isinstance(pyname, (pynames.AssignedName, pynames.DefinedName)):
|
||||
globals.append(name)
|
||||
if isinstance(pymodule, builtins.BuiltinModule):
|
||||
globals.append(name)
|
||||
self.names[modname] = globals
|
||||
|
||||
def _write(self):
|
||||
self.project.data_files.write_data("globalnames", self.names)
|
||||
|
||||
def _changed(self, resource):
|
||||
if not resource.is_folder():
|
||||
self.update_resource(resource)
|
||||
|
||||
def _moved(self, resource, newresource):
|
||||
if not resource.is_folder():
|
||||
modname = self._module_name(resource)
|
||||
if modname in self.names:
|
||||
del self.names[modname]
|
||||
self.update_resource(newresource)
|
||||
|
||||
def _removed(self, resource):
|
||||
if not resource.is_folder():
|
||||
modname = self._module_name(resource)
|
||||
if modname in self.names:
|
||||
del self.names[modname]
|
||||
|
||||
|
||||
def submodules(mod):
|
||||
if isinstance(mod, resources.File):
|
||||
if mod.name.endswith(".py") and mod.name != "__init__.py":
|
||||
return set([mod])
|
||||
return set()
|
||||
if not mod.has_child("__init__.py"):
|
||||
return set()
|
||||
result = set([mod])
|
||||
for child in mod.get_children():
|
||||
result |= submodules(child)
|
||||
return result
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
"""For performing many refactorings as a single command
|
||||
|
||||
`changestack` module can be used to perform many refactorings on top
|
||||
of each other as one bigger command. It can be used like::
|
||||
|
||||
stack = ChangeStack(project, 'my big command')
|
||||
|
||||
#..
|
||||
stack.push(refactoring1.get_changes())
|
||||
#..
|
||||
stack.push(refactoring2.get_changes())
|
||||
#..
|
||||
stack.push(refactoringX.get_changes())
|
||||
|
||||
stack.pop_all()
|
||||
changes = stack.merged()
|
||||
|
||||
Now `changes` can be previewed or performed as before.
|
||||
"""
|
||||
|
||||
from rope.base import change
|
||||
|
||||
|
||||
class ChangeStack(object):
|
||||
def __init__(self, project, description="merged changes"):
|
||||
self.project = project
|
||||
self.description = description
|
||||
self.stack = []
|
||||
|
||||
def push(self, changes):
|
||||
self.stack.append(changes)
|
||||
self.project.do(changes)
|
||||
|
||||
def pop_all(self):
|
||||
for i in range(len(self.stack)):
|
||||
self.project.history.undo(drop=True)
|
||||
|
||||
def merged(self):
|
||||
result = change.ChangeSet(self.description)
|
||||
for changes in self.stack:
|
||||
for c in self._basic_changes(changes):
|
||||
result.add_change(c)
|
||||
return result
|
||||
|
||||
def _basic_changes(self, changes):
|
||||
if isinstance(changes, change.ChangeSet):
|
||||
for child in changes.changes:
|
||||
for atom in self._basic_changes(child):
|
||||
yield atom
|
||||
else:
|
||||
yield changes
|
||||
741
.venv/lib/python3.8/site-packages/rope/contrib/codeassist.py
Normal file
741
.venv/lib/python3.8/site-packages/rope/contrib/codeassist.py
Normal file
|
|
@ -0,0 +1,741 @@
|
|||
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`
|
||||
|
||||
`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`.
|
||||
|
||||
`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)
|
||||
90
.venv/lib/python3.8/site-packages/rope/contrib/finderrors.py
Normal file
90
.venv/lib/python3.8/site-packages/rope/contrib/finderrors.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""Finding bad name and attribute accesses
|
||||
|
||||
`find_errors` function can be used to find possible bad name and
|
||||
attribute accesses. As an example::
|
||||
|
||||
errors = find_errors(project, project.get_resource('mod.py'))
|
||||
for error in errors:
|
||||
print('%s: %s' % (error.lineno, error.error))
|
||||
|
||||
prints possible errors for ``mod.py`` file.
|
||||
|
||||
TODO:
|
||||
|
||||
* use task handles
|
||||
* reporting names at most once
|
||||
* attributes of extension modules that don't appear in
|
||||
extension_modules project config can be ignored
|
||||
* not calling `PyScope.get_inner_scope_for_line()` if it is a
|
||||
bottleneck; needs profiling
|
||||
* not reporting occurrences where rope cannot infer the object
|
||||
* rope saves multiple objects for some of the names in its objectdb
|
||||
use all of them not to give false positives
|
||||
* ... ;-)
|
||||
|
||||
"""
|
||||
from rope.base import ast, evaluate, pyobjects
|
||||
|
||||
|
||||
def find_errors(project, resource):
|
||||
"""Find possible bad name and attribute accesses
|
||||
|
||||
It returns a list of `Error`.
|
||||
"""
|
||||
pymodule = project.get_pymodule(resource)
|
||||
finder = _BadAccessFinder(pymodule)
|
||||
ast.walk(pymodule.get_ast(), finder)
|
||||
return finder.errors
|
||||
|
||||
|
||||
class _BadAccessFinder(object):
|
||||
def __init__(self, pymodule):
|
||||
self.pymodule = pymodule
|
||||
self.scope = pymodule.get_scope()
|
||||
self.errors = []
|
||||
|
||||
def _Name(self, node):
|
||||
if isinstance(node.ctx, (ast.Store, ast.Param)):
|
||||
return
|
||||
scope = self.scope.get_inner_scope_for_line(node.lineno)
|
||||
pyname = scope.lookup(node.id)
|
||||
if pyname is None:
|
||||
self._add_error(node, "Unresolved variable")
|
||||
elif self._is_defined_after(scope, pyname, node.lineno):
|
||||
self._add_error(node, "Defined later")
|
||||
|
||||
def _Attribute(self, node):
|
||||
if not isinstance(node.ctx, ast.Store):
|
||||
scope = self.scope.get_inner_scope_for_line(node.lineno)
|
||||
pyname = evaluate.eval_node(scope, node.value)
|
||||
if pyname is not None and pyname.get_object() != pyobjects.get_unknown():
|
||||
if node.attr not in pyname.get_object():
|
||||
self._add_error(node, "Unresolved attribute")
|
||||
ast.walk(node.value, self)
|
||||
|
||||
def _add_error(self, node, msg):
|
||||
if isinstance(node, ast.Attribute):
|
||||
name = node.attr
|
||||
else:
|
||||
name = node.id
|
||||
if name != "None":
|
||||
error = Error(node.lineno, msg + " " + name)
|
||||
self.errors.append(error)
|
||||
|
||||
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] == self.pymodule
|
||||
and lineno <= location[1] <= scope.get_end()
|
||||
):
|
||||
return True
|
||||
|
||||
|
||||
class Error(object):
|
||||
def __init__(self, lineno, error):
|
||||
self.lineno = lineno
|
||||
self.error = error
|
||||
|
||||
def __str__(self):
|
||||
return "%s: %s" % (self.lineno, self.error)
|
||||
125
.venv/lib/python3.8/site-packages/rope/contrib/findit.py
Normal file
125
.venv/lib/python3.8/site-packages/rope/contrib/findit.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import rope.base.codeanalyze
|
||||
import rope.base.evaluate
|
||||
import rope.base.pyobjects
|
||||
from rope.base import taskhandle, exceptions, worder
|
||||
from rope.contrib import fixsyntax
|
||||
from rope.refactor import occurrences
|
||||
|
||||
|
||||
def find_occurrences(
|
||||
project,
|
||||
resource,
|
||||
offset,
|
||||
unsure=False,
|
||||
resources=None,
|
||||
in_hierarchy=False,
|
||||
task_handle=taskhandle.NullTaskHandle(),
|
||||
):
|
||||
"""Return a list of `Location`
|
||||
|
||||
If `unsure` is `True`, possible matches are returned, too. You
|
||||
can use `Location.unsure` to see which are unsure occurrences.
|
||||
`resources` can be a list of `rope.base.resource.File` that
|
||||
should be searched for occurrences; if `None` all python files
|
||||
in the project are searched.
|
||||
|
||||
"""
|
||||
name = worder.get_name_at(resource, offset)
|
||||
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,
|
||||
name,
|
||||
pyname,
|
||||
unsure=is_match,
|
||||
in_hierarchy=in_hierarchy,
|
||||
instance=primary,
|
||||
)
|
||||
if resources is None:
|
||||
resources = project.get_python_files()
|
||||
job_set = task_handle.create_jobset("Finding Occurrences", count=len(resources))
|
||||
return _find_locations(finder, resources, job_set)
|
||||
|
||||
|
||||
def find_implementations(
|
||||
project, resource, offset, resources=None, task_handle=taskhandle.NullTaskHandle()
|
||||
):
|
||||
"""Find the places a given method is overridden.
|
||||
|
||||
Finds the places a method is implemented. Returns a list of
|
||||
`Location`.
|
||||
"""
|
||||
name = worder.get_name_at(resource, offset)
|
||||
this_pymodule = project.get_pymodule(resource)
|
||||
pyname = rope.base.evaluate.eval_location(this_pymodule, offset)
|
||||
if pyname is not None:
|
||||
pyobject = pyname.get_object()
|
||||
if (
|
||||
not isinstance(pyobject, rope.base.pyobjects.PyFunction)
|
||||
or pyobject.get_kind() != "method"
|
||||
):
|
||||
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, name, filters=filters)
|
||||
if resources is None:
|
||||
resources = project.get_python_files()
|
||||
job_set = task_handle.create_jobset("Finding Implementations", count=len(resources))
|
||||
return _find_locations(finder, resources, job_set)
|
||||
|
||||
|
||||
def find_definition(project, code, offset, resource=None, maxfixes=1):
|
||||
"""Return the definition location of the python name at `offset`
|
||||
|
||||
A `Location` object is returned if the definition location can be
|
||||
determined, otherwise ``None`` is returned.
|
||||
"""
|
||||
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, name, [check_offset, pyname_filter])
|
||||
for occurrence in finder.find_occurrences(pymodule=module):
|
||||
return Location(occurrence)
|
||||
|
||||
|
||||
class Location(object):
|
||||
def __init__(self, occurrence):
|
||||
self.resource = occurrence.resource
|
||||
self.region = occurrence.get_word_range()
|
||||
self.offset = self.region[0]
|
||||
self.unsure = occurrence.is_unsure()
|
||||
self.lineno = occurrence.lineno
|
||||
|
||||
|
||||
def _find_locations(finder, resources, job_set):
|
||||
result = []
|
||||
for resource in resources:
|
||||
job_set.started_job(resource.path)
|
||||
for occurrence in finder.find_occurrences(resource):
|
||||
result.append(Location(occurrence))
|
||||
job_set.finished_job()
|
||||
return result
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
"""Fix the name of modules
|
||||
|
||||
This module is useful when you want to rename many of the modules in
|
||||
your project. That can happen specially when you want to change their
|
||||
naming style.
|
||||
|
||||
For instance::
|
||||
|
||||
fixer = FixModuleNames(project)
|
||||
changes = fixer.get_changes(fixer=str.lower)
|
||||
project.do(changes)
|
||||
|
||||
Here it renames all modules and packages to use lower-cased chars.
|
||||
You can tell it to use any other style by using the ``fixer``
|
||||
argument.
|
||||
|
||||
"""
|
||||
from rope.base import taskhandle
|
||||
from rope.contrib import changestack
|
||||
from rope.refactor import rename
|
||||
|
||||
|
||||
class FixModuleNames(object):
|
||||
def __init__(self, project):
|
||||
self.project = project
|
||||
|
||||
def get_changes(self, fixer=str.lower, task_handle=taskhandle.NullTaskHandle()):
|
||||
"""Fix module names
|
||||
|
||||
`fixer` is a function that takes and returns a `str`. Given
|
||||
the name of a module, it should return the fixed name.
|
||||
|
||||
"""
|
||||
stack = changestack.ChangeStack(self.project, "Fixing module names")
|
||||
jobset = task_handle.create_jobset(
|
||||
"Fixing module names", self._count_fixes(fixer) + 1
|
||||
)
|
||||
try:
|
||||
while True:
|
||||
for resource in self._tobe_fixed(fixer):
|
||||
jobset.started_job(resource.path)
|
||||
renamer = rename.Rename(self.project, resource)
|
||||
changes = renamer.get_changes(fixer(self._name(resource)))
|
||||
stack.push(changes)
|
||||
jobset.finished_job()
|
||||
break
|
||||
else:
|
||||
break
|
||||
finally:
|
||||
jobset.started_job("Reverting to original state")
|
||||
stack.pop_all()
|
||||
jobset.finished_job()
|
||||
return stack.merged()
|
||||
|
||||
def _count_fixes(self, fixer):
|
||||
return len(list(self._tobe_fixed(fixer)))
|
||||
|
||||
def _tobe_fixed(self, fixer):
|
||||
for resource in self.project.get_python_files():
|
||||
modname = self._name(resource)
|
||||
if modname != fixer(modname):
|
||||
yield resource
|
||||
|
||||
def _name(self, resource):
|
||||
modname = resource.name.rsplit(".", 1)[0]
|
||||
if modname == "__init__":
|
||||
modname = resource.parent.name
|
||||
return modname
|
||||
189
.venv/lib/python3.8/site-packages/rope/contrib/fixsyntax.py
Normal file
189
.venv/lib/python3.8/site-packages/rope/contrib/fixsyntax.py
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
import rope.base.codeanalyze
|
||||
import rope.base.evaluate
|
||||
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, project, code, resource, maxfixes=1):
|
||||
self.project = project
|
||||
self.code = code
|
||||
self.resource = resource
|
||||
self.maxfixes = maxfixes
|
||||
|
||||
@utils.saveit
|
||||
def get_pymodule(self):
|
||||
"""Get a `PyModule`"""
|
||||
msg = None
|
||||
code = self.code
|
||||
tries = 0
|
||||
while True:
|
||||
try:
|
||||
if (
|
||||
tries == 0
|
||||
and self.resource is not None
|
||||
and self.resource.read() == code
|
||||
):
|
||||
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 as e:
|
||||
if msg is None:
|
||||
msg = "%s:%s %s" % (e.filename, e.lineno, e.message_)
|
||||
if tries < self.maxfixes:
|
||||
tries += 1
|
||||
self.commenter.comment(e.lineno)
|
||||
code = "\n".join(self.commenter.lines)
|
||||
else:
|
||||
raise exceptions.ModuleSyntaxError(
|
||||
e.filename, e.lineno, "Failed to fix error: {0}".format(msg)
|
||||
)
|
||||
|
||||
@property
|
||||
@utils.saveit
|
||||
def commenter(self):
|
||||
return _Commenter(self.code)
|
||||
|
||||
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)
|
||||
expression = expression.replace("\\\n", " ").replace("\n", " ")
|
||||
lineno = self.code.count("\n", 0, offset)
|
||||
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)
|
||||
|
||||
if new_code.startswith(self.code[: offset + 1]):
|
||||
return new_pyname()
|
||||
result = old_pyname()
|
||||
if result is None:
|
||||
return new_pyname()
|
||||
return result
|
||||
|
||||
|
||||
class _Commenter(object):
|
||||
def __init__(self, code):
|
||||
self.code = code
|
||||
self.lines = self.code.split("\n")
|
||||
self.lines.append("\n")
|
||||
self.origs = list(range(len(self.lines) + 1))
|
||||
self.diffs = [0] * (len(self.lines) + 1)
|
||||
|
||||
def comment(self, lineno):
|
||||
start = _logical_start(self.lines, lineno, check_prev=True) - 1
|
||||
# using self._get_stmt_end() instead of self._get_block_end()
|
||||
# to lower commented lines
|
||||
end = self._get_stmt_end(start)
|
||||
indents = _get_line_indents(self.lines[start])
|
||||
if 0 < start:
|
||||
last_lineno = self._last_non_blank(start - 1)
|
||||
last_line = self.lines[last_lineno]
|
||||
if last_line.rstrip().endswith(":"):
|
||||
indents = _get_line_indents(last_line) + 4
|
||||
self._set(start, " " * indents + "pass")
|
||||
for line in range(start + 1, end + 1):
|
||||
self._set(line, self.lines[start])
|
||||
self._fix_incomplete_try_blocks(lineno, indents)
|
||||
|
||||
def transfered_offset(self, offset):
|
||||
lineno = self.code.count("\n", 0, offset)
|
||||
diff = sum(self.diffs[:lineno])
|
||||
return offset + diff
|
||||
|
||||
def _last_non_blank(self, start):
|
||||
while start > 0 and self.lines[start].strip() == "":
|
||||
start -= 1
|
||||
return start
|
||||
|
||||
def _get_block_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:
|
||||
end_line = i
|
||||
else:
|
||||
break
|
||||
return end_line
|
||||
|
||||
def _get_stmt_end(self, 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:
|
||||
return i - 1
|
||||
return lineno
|
||||
|
||||
def _fix_incomplete_try_blocks(self, lineno, indents):
|
||||
block_start = lineno
|
||||
last_indents = indents
|
||||
while block_start > 0:
|
||||
block_start = (
|
||||
rope.base.codeanalyze.get_block_start(
|
||||
ArrayLinesAdapter(self.lines), block_start
|
||||
)
|
||||
- 1
|
||||
)
|
||||
if self.lines[block_start].strip().startswith("try:"):
|
||||
indents = _get_line_indents(self.lines[block_start])
|
||||
if indents > last_indents:
|
||||
continue
|
||||
last_indents = indents
|
||||
block_end = self._find_matching_deindent(block_start)
|
||||
line = self.lines[block_end].strip()
|
||||
if not (
|
||||
line.startswith("finally:")
|
||||
or line.startswith("except ")
|
||||
or line.startswith("except:")
|
||||
):
|
||||
self._insert(block_end, " " * indents + "finally:")
|
||||
self._insert(block_end + 1, " " * indents + " pass")
|
||||
|
||||
def _find_matching_deindent(self, line_number):
|
||||
indents = _get_line_indents(self.lines[line_number])
|
||||
current_line = line_number + 1
|
||||
while current_line < len(self.lines):
|
||||
line = self.lines[current_line]
|
||||
if not line.strip().startswith("#") and not line.strip() == "":
|
||||
# HACK: We should have used logical lines here
|
||||
if _get_line_indents(self.lines[current_line]) <= indents:
|
||||
return current_line
|
||||
current_line += 1
|
||||
return len(self.lines) - 1
|
||||
|
||||
def _set(self, lineno, line):
|
||||
self.diffs[self.origs[lineno]] += len(line) - len(self.lines[lineno])
|
||||
self.lines[lineno] = line
|
||||
|
||||
def _insert(self, lineno, line):
|
||||
self.diffs[self.origs[lineno]] += len(line) + 1
|
||||
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:
|
||||
prev = lineno - 1
|
||||
while prev > 0:
|
||||
start, end = logical_finder.logical_line_in(prev)
|
||||
if end is None or start <= lineno < end:
|
||||
return start
|
||||
if start <= prev:
|
||||
break
|
||||
prev -= 1
|
||||
return logical_finder.logical_line_in(lineno)[0]
|
||||
|
||||
|
||||
def _get_line_indents(line):
|
||||
return rope.base.codeanalyze.count_line_indents(line)
|
||||
388
.venv/lib/python3.8/site-packages/rope/contrib/generate.py
Normal file
388
.venv/lib/python3.8/site-packages/rope/contrib/generate.py
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
import rope.base.evaluate
|
||||
from rope.base import libutils
|
||||
from rope.base import change, pyobjects, exceptions, pynames, worder, codeanalyze
|
||||
from rope.refactor import sourceutils, importutils, functionutils, suites
|
||||
|
||||
|
||||
def create_generate(kind, project, resource, offset, goal_resource=None):
|
||||
"""A factory for creating `Generate` objects
|
||||
|
||||
`kind` can be 'variable', 'function', 'class', 'module' or
|
||||
'package'.
|
||||
|
||||
"""
|
||||
generate = eval("Generate" + kind.title())
|
||||
return generate(project, resource, offset, goal_resource=goal_resource)
|
||||
|
||||
|
||||
def create_module(project, name, sourcefolder=None):
|
||||
"""Creates a module and returns a `rope.base.resources.File`"""
|
||||
if sourcefolder is None:
|
||||
sourcefolder = project.root
|
||||
packages = name.split(".")
|
||||
parent = sourcefolder
|
||||
for package in packages[:-1]:
|
||||
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:
|
||||
sourcefolder = project.root
|
||||
packages = name.split(".")
|
||||
parent = sourcefolder
|
||||
for package in packages[:-1]:
|
||||
parent = parent.get_child(package)
|
||||
made_packages = parent.create_folder(packages[-1])
|
||||
made_packages.create_file("__init__.py")
|
||||
return made_packages
|
||||
|
||||
|
||||
class _Generate(object):
|
||||
def __init__(self, project, resource, offset, goal_resource=None):
|
||||
self.project = project
|
||||
self.resource = resource
|
||||
self.goal_resource = goal_resource
|
||||
self.info = self._generate_info(project, resource, offset)
|
||||
self.name = self.info.get_name()
|
||||
self._check_exceptional_conditions()
|
||||
|
||||
def _generate_info(self, project, resource, offset):
|
||||
return _GenerationInfo(project.pycore, resource, offset, self.goal_resource)
|
||||
|
||||
def _check_exceptional_conditions(self):
|
||||
if self.info.element_already_exists():
|
||||
raise exceptions.RefactoringError(
|
||||
"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
|
||||
)
|
||||
|
||||
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)
|
||||
definition = "\n" * blanks[0] + base_definition + "\n" * blanks[1]
|
||||
|
||||
resource = self.info.get_insertion_resource()
|
||||
start, end = self.info.get_insertion_offsets()
|
||||
|
||||
collector = codeanalyze.ChangeCollector(resource.read())
|
||||
collector.add_change(start, end, definition)
|
||||
changes.add_change(change.ChangeContents(resource, collector.get_changed()))
|
||||
if self.goal_resource:
|
||||
relative_import = _add_relative_import_to_module(
|
||||
self.project, self.resource, self.goal_resource, self.name
|
||||
)
|
||||
changes.add_change(relative_import)
|
||||
return changes
|
||||
|
||||
def get_location(self):
|
||||
return (self.info.get_insertion_resource(), self.info.get_insertion_lineno())
|
||||
|
||||
def _get_element_kind(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_element(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class GenerateFunction(_Generate):
|
||||
def _generate_info(self, project, resource, offset):
|
||||
return _FunctionGenerationInfo(project.pycore, resource, offset)
|
||||
|
||||
def _get_element(self):
|
||||
decorator = ""
|
||||
args = []
|
||||
if self.info.is_static_method():
|
||||
decorator = "@staticmethod\n"
|
||||
if (
|
||||
self.info.is_method()
|
||||
or self.info.is_constructor()
|
||||
or self.info.is_instance()
|
||||
):
|
||||
args.append("self")
|
||||
args.extend(self.info.get_passed_args())
|
||||
definition = "%sdef %s(%s):\n pass\n" % (
|
||||
decorator,
|
||||
self.name,
|
||||
", ".join(args),
|
||||
)
|
||||
return definition
|
||||
|
||||
def _get_element_kind(self):
|
||||
return "Function"
|
||||
|
||||
|
||||
class GenerateVariable(_Generate):
|
||||
def _get_element(self):
|
||||
return "%s = None\n" % self.name
|
||||
|
||||
def _get_element_kind(self):
|
||||
return "Variable"
|
||||
|
||||
|
||||
class GenerateClass(_Generate):
|
||||
def _get_element(self):
|
||||
return "class %s(object):\n pass\n" % self.name
|
||||
|
||||
def _get_element_kind(self):
|
||||
return "Class"
|
||||
|
||||
|
||||
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))
|
||||
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, self.resource, new_resource)
|
||||
)
|
||||
return changes
|
||||
|
||||
def get_location(self):
|
||||
package = self.info.get_package()
|
||||
return (package.get_child("%s.py" % self.name), 1)
|
||||
|
||||
|
||||
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))
|
||||
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, self.resource, new_resource)
|
||||
)
|
||||
child = self.project.get_folder(package.path + "/" + self.name)
|
||||
changes.add_change(change.CreateFile(child, "__init__.py"))
|
||||
return changes
|
||||
|
||||
def get_location(self):
|
||||
package = self.info.get_package()
|
||||
child = package.get_child(self.name)
|
||||
return (child.get_child("__init__.py"), 1)
|
||||
|
||||
|
||||
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 = 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())
|
||||
|
||||
|
||||
def _add_relative_import_to_module(project, resource, imported, name):
|
||||
pymodule = project.get_pymodule(resource)
|
||||
import_tools = importutils.ImportTools(project)
|
||||
module_imports = import_tools.module_imports(pymodule)
|
||||
new_import = import_tools.get_from_import(imported, name)
|
||||
module_imports.add_import(new_import)
|
||||
return change.ChangeContents(resource, module_imports.get_changed_source())
|
||||
|
||||
|
||||
class _GenerationInfo(object):
|
||||
def __init__(self, pycore, resource, offset, goal_resource=None):
|
||||
self.pycore = pycore
|
||||
self.resource = resource
|
||||
self.offset = offset
|
||||
self.goal_resource = goal_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()
|
||||
|
||||
def _init_fields(self):
|
||||
self.source_scope = self._get_source_scope()
|
||||
self.goal_scope = self._get_goal_scope()
|
||||
self.goal_pymodule = self._get_goal_module(self.goal_scope)
|
||||
|
||||
def _get_goal_scope(self):
|
||||
if self.primary is None:
|
||||
if self.goal_resource:
|
||||
return self.pycore.project.get_pymodule(self.goal_resource).get_scope()
|
||||
else:
|
||||
return self._get_source_scope()
|
||||
pyobject = self.primary.get_object()
|
||||
if isinstance(pyobject, pyobjects.PyDefinedObject):
|
||||
return pyobject.get_scope()
|
||||
elif isinstance(pyobject.get_type(), pyobjects.PyClass):
|
||||
return pyobject.get_type().get_scope()
|
||||
|
||||
def _get_goal_module(self, scope):
|
||||
if scope is None:
|
||||
return
|
||||
while scope.parent is not None:
|
||||
scope = scope.parent
|
||||
return scope.pyobject
|
||||
|
||||
def _get_source_scope(self):
|
||||
module_scope = self.source_pymodule.get_scope()
|
||||
lineno = self.source_pymodule.lines.get_line_number(self.offset)
|
||||
return module_scope.get_inner_scope_for_line(lineno)
|
||||
|
||||
def get_insertion_lineno(self):
|
||||
lines = self.goal_pymodule.lines
|
||||
if self.goal_scope == self.source_scope:
|
||||
line_finder = self.goal_pymodule.logical_lines
|
||||
lineno = lines.get_line_number(self.offset)
|
||||
lineno = line_finder.logical_line_in(lineno)[0]
|
||||
root = suites.ast_suite_tree(self.goal_scope.pyobject.get_ast())
|
||||
suite = root.find_suite(lineno)
|
||||
indents = sourceutils.get_indents(lines, lineno)
|
||||
while self.get_scope_indents() < indents:
|
||||
lineno = suite.get_start()
|
||||
indents = sourceutils.get_indents(lines, lineno)
|
||||
suite = suite.parent
|
||||
return lineno
|
||||
else:
|
||||
return min(self.goal_scope.get_end() + 1, lines.length())
|
||||
|
||||
def get_insertion_resource(self):
|
||||
return self.goal_pymodule.get_resource()
|
||||
|
||||
def get_insertion_offsets(self):
|
||||
if self.goal_scope.get_kind() == "Class":
|
||||
start, end = sourceutils.get_body_region(self.goal_scope.pyobject)
|
||||
if self.goal_pymodule.source_code[start:end].strip() == "pass":
|
||||
return start, end
|
||||
lines = self.goal_pymodule.lines
|
||||
start = lines.get_line_start(self.get_insertion_lineno())
|
||||
return (start, start)
|
||||
|
||||
def get_scope_indents(self):
|
||||
if self.goal_scope.get_kind() == "Module":
|
||||
return 0
|
||||
return (
|
||||
sourceutils.get_indents(
|
||||
self.goal_pymodule.lines, self.goal_scope.get_start()
|
||||
)
|
||||
+ 4
|
||||
)
|
||||
|
||||
def get_blank_lines(self):
|
||||
if self.goal_scope.get_kind() == "Module":
|
||||
base_blanks = 2
|
||||
if self.goal_pymodule.source_code.strip() == "":
|
||||
base_blanks = 0
|
||||
if self.goal_scope.get_kind() == "Class":
|
||||
base_blanks = 1
|
||||
if self.goal_scope.get_kind() == "Function":
|
||||
base_blanks = 0
|
||||
if self.goal_scope == self.source_scope:
|
||||
return (0, base_blanks)
|
||||
return (base_blanks, 0)
|
||||
|
||||
def get_package(self):
|
||||
primary = self.primary
|
||||
if self.primary is None:
|
||||
return self.pycore.project.get_source_folders()[0]
|
||||
if isinstance(primary.get_object(), pyobjects.PyPackage):
|
||||
return primary.get_object().get_resource()
|
||||
raise exceptions.RefactoringError(
|
||||
"A module/package can be only created in a package."
|
||||
)
|
||||
|
||||
def primary_is_found(self):
|
||||
return self.goal_scope is not None
|
||||
|
||||
def element_already_exists(self):
|
||||
if self.pyname is None or isinstance(self.pyname, pynames.UnboundName):
|
||||
return False
|
||||
return self.get_name() in self.goal_scope.get_defined_names()
|
||||
|
||||
def get_name(self):
|
||||
return worder.get_name_at(self.resource, self.offset)
|
||||
|
||||
|
||||
class _FunctionGenerationInfo(_GenerationInfo):
|
||||
def _get_goal_scope(self):
|
||||
if self.is_constructor():
|
||||
return self.pyname.get_object().get_scope()
|
||||
if self.is_instance():
|
||||
return self.pyname.get_object().get_type().get_scope()
|
||||
if self.primary is None:
|
||||
return self._get_source_scope()
|
||||
pyobject = self.primary.get_object()
|
||||
if isinstance(pyobject, pyobjects.PyDefinedObject):
|
||||
return pyobject.get_scope()
|
||||
elif isinstance(pyobject.get_type(), pyobjects.PyClass):
|
||||
return pyobject.get_type().get_scope()
|
||||
|
||||
def element_already_exists(self):
|
||||
if self.pyname is None or isinstance(self.pyname, pynames.UnboundName):
|
||||
return False
|
||||
return self.get_name() in self.goal_scope.get_defined_names()
|
||||
|
||||
def is_static_method(self):
|
||||
return self.primary is not None and 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
|
||||
)
|
||||
|
||||
def is_constructor(self):
|
||||
return self.pyname is not None and isinstance(
|
||||
self.pyname.get_object(), pyobjects.PyClass
|
||||
)
|
||||
|
||||
def is_instance(self):
|
||||
if self.pyname is None:
|
||||
return False
|
||||
pyobject = self.pyname.get_object()
|
||||
return isinstance(pyobject.get_type(), pyobjects.PyClass)
|
||||
|
||||
def get_name(self):
|
||||
if self.is_constructor():
|
||||
return "__init__"
|
||||
if self.is_instance():
|
||||
return "__call__"
|
||||
return worder.get_name_at(self.resource, self.offset)
|
||||
|
||||
def get_passed_args(self):
|
||||
result = []
|
||||
source = self.source_pymodule.source_code
|
||||
finder = worder.Worder(source)
|
||||
if finder.is_a_function_being_called(self.offset):
|
||||
start, end = finder.get_primary_range(self.offset)
|
||||
parens_start, parens_end = finder.get_word_parens_range(end - 1)
|
||||
call = source[start:parens_end]
|
||||
parser = functionutils._FunctionParser(call, False)
|
||||
args, keywords = parser.get_parameters()
|
||||
for arg in args:
|
||||
if self._is_id(arg):
|
||||
result.append(arg)
|
||||
else:
|
||||
result.append("arg%d" % len(result))
|
||||
for name, value in keywords:
|
||||
result.append(name)
|
||||
return result
|
||||
|
||||
def _is_id(self, arg):
|
||||
def id_or_underline(c):
|
||||
return c.isalpha() or c == "_"
|
||||
|
||||
for c in arg:
|
||||
if not id_or_underline(c) and not c.isdigit():
|
||||
return False
|
||||
return id_or_underline(arg[0])
|
||||
Loading…
Add table
Add a link
Reference in a new issue