Skip to content

Commit

Permalink
Editor's rope-based introspection features (code completion, calltips…
Browse files Browse the repository at this point in the history
…, go to definition): new rope monkey-patch providing major performance improvements
  • Loading branch information
PierreRaybaut committed Mar 7, 2011
1 parent 9f9f2f2 commit 35d0e47
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 22 deletions.
4 changes: 4 additions & 0 deletions rope_profiling/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def get_calltip_from_pyobject(pyobject,
def get_doc_from_pyobject(pyobject):
return pydocextractor.get_doc(pyobject)


from spyderlib import rope_patch
rope_patch.apply()

def other_features():
project = rope.base.project.Project('src', **ROPE_PREFS)
project.validate(project.root)
Expand Down
76 changes: 76 additions & 0 deletions spyderlib/rope_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
#
# Copyright © 2011 Pierre Raybaut
# Licensed under the terms of the MIT License
# (see spyderlib/__init__.py for details)

"""
Patching rope for better performances
See this thread:
http://groups.google.com/group/rope-dev/browse_thread/thread/57de5731f202537a
"""

def apply():
"""Monkey patching rope for better performances"""
import rope
if rope.VERSION not in ('0.9.3', '0.9.2'):
raise ImportError, "rope %s can't be patched" % rope.VERSION

# Patching pycore.PyCore, so that forced builtin modules (i.e. modules
# that were declared as 'extension_modules' in rope preferences)
# will be indeed recognized as builtins by rope, as expected
from rope.base import pycore
class PatchedPyCore(pycore.PyCore):
def get_module(self, name, folder=None):
"""Returns a `PyObject` if the module was found."""
# check if this is a builtin module
pymod = self._builtin_module(name)
if pymod is not None:
return pymod
module = self.find_module(name, folder)
if module is None:
raise pycore.ModuleNotFoundError(
'Module %s not found' % name)
return self.resource_to_pyobject(module)
pycore.PyCore = PatchedPyCore

# Patching BuiltinFunction for the calltip/doc functions to be
# able to retrieve the function signatures with forced builtins
from rope.base import builtins, pyobjects
from spyderlib.utils.dochelpers import getargs
class PatchedBuiltinFunction(builtins.BuiltinFunction):
def __init__(self, returned=None, function=None, builtin=None,
argnames=[], parent=None):
builtins._BuiltinElement.__init__(self, builtin, parent)
pyobjects.AbstractFunction.__init__(self)
self.argnames = argnames
if not argnames and builtin:
self.argnames = getargs(self.builtin)
if self.argnames is None:
self.argnames = []
self.returned = returned
self.function = function
builtins.BuiltinFunction = PatchedBuiltinFunction

# Patching BuiltinName for the go to definition feature to simply work
# with forced builtins
from rope.base import libutils
import inspect
class PatchedBuiltinName(builtins.BuiltinName):
def _pycore(self):
p = self.pyobject
while p.parent is not None:
p = p.parent
if isinstance(p, builtins.BuiltinModule) and p.pycore is not None:
return p.pycore
def get_definition_location(self):
if not inspect.isbuiltin(self.pyobject):
_lines, lineno = inspect.getsourcelines(self.pyobject.builtin)
path = inspect.getfile(self.pyobject.builtin)
pycore = self._pycore()
if pycore and pycore.project:
resource = libutils.path_to_resource(pycore.project, path)
module = pyobjects.PyModule(pycore, None, resource)
return (module, lineno)
return (None, None)
builtins.BuiltinName = PatchedBuiltinName
8 changes: 8 additions & 0 deletions spyderlib/spyder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1368,6 +1368,14 @@ def exec_():
from spyderlib.qt import QtGui
QtGui.QApplication = FakeQApplication

#----Monkey patching rope
try:
from spyderlib import rope_patch
rope_patch.apply()
except ImportError:
# rope 0.9.2/0.9.3 is not installed
pass

#----Monkey patching sys.exit
def fake_sys_exit(arg=[]):
pass
Expand Down
26 changes: 4 additions & 22 deletions spyderlib/widgets/projectexplorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,6 @@
try:
import rope.base.libutils
import rope.contrib.codeassist
pydocextractor = rope.contrib.codeassist.PyDocExtractor()

def get_pyobject(project, source_code, offset, resource=None, maxfixes=1):
fixer = rope.contrib.codeassist.fixsyntax.FixSyntax(project.pycore,
source_code, resource, maxfixes)
pyname = fixer.pyname_at(offset)
if pyname is None:
return None
return pyname.get_object()

def get_calltip_from_pyobject(pyobject,
ignore_unknown=False, remove_self=False):
return pydocextractor.get_calltip(pyobject, ignore_unknown, remove_self)

def get_doc_from_pyobject(pyobject):
return pydocextractor.get_doc(pyobject)

except ImportError:
pass

Expand Down Expand Up @@ -270,17 +253,16 @@ def get_calltip_text(self, source_code, offset, filename):
try:
if DEBUG:
t0 = time.time()
pyobject = get_pyobject(self.rope_project, source_code, offset,
resource)
cts = get_calltip_from_pyobject(pyobject, ignore_unknown=True,
remove_self=True)
cts = rope.contrib.codeassist.get_calltip(
self.rope_project, source_code, offset, resource)
if DEBUG:
log_dt(LOG_FILENAME, "get_calltip", t0)
if cts is not None:
while '..' in cts:
cts = cts.replace('..', '.')
try:
doc_text = get_doc_from_pyobject(pyobject)
doc_text = rope.contrib.codeassist.get_doc(
self.rope_project, source_code, offset, resource)
if DEBUG:
log_dt(LOG_FILENAME, "get_doc", t0)
except Exception, _error:
Expand Down

0 comments on commit 35d0e47

Please sign in to comment.