/usr/share/pyshared/spyderlib/rope_patch.py is in python-spyderlib 2.1.9-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | # -*- coding: utf-8 -*-
#
# Copyright © 2011 Pierre Raybaut
# Licensed under the terms of the MIT License
# (see spyderlib/__init__.py for details)
"""
Patching rope:
[1] For compatibility with Spyder's standalone version, build with py2exe or
cx_Freeze
[2] For better performances, see this thread:
http://groups.google.com/group/rope-dev/browse_thread/thread/57de5731f202537a
[3] To avoid considering folders without __init__.py as Python packages, thus
avoiding side effects as non-working introspection features on a Python module
or package when a folder in current directory has the same name.
See this thread:
http://groups.google.com/group/rope-dev/browse_thread/thread/924c4b5a6268e618
[4] To avoid rope adding a 2 spaces indent to every docstring it gets, because
it breaks the work of Sphinx on the Object Inspector.
"""
def apply():
"""Monkey patching rope
See [1], [2] and [3] in module docstring."""
import rope
if rope.VERSION not in ('0.9.3', '0.9.2'):
raise ImportError, "rope %s can't be patched" % rope.VERSION
# [1] Patching project.Project for compatibility with py2exe/cx_Freeze
# distributions
from spyderlib.baseconfig import is_py2exe_or_cx_Freeze
if is_py2exe_or_cx_Freeze():
from rope.base import project
class PatchedProject(project.Project):
def _default_config(self):
# py2exe/cx_Freeze distribution
from spyderlib.baseconfig import get_module_source_path
fname = get_module_source_path('spyderlib',
'default_config.py')
return open(fname, 'rb').read()
project.Project = PatchedProject
# Patching pycore.PyCore...
from rope.base import pycore
class PatchedPyCore(pycore.PyCore):
# [2] ...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
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)
# [3] ...to avoid considering folders without __init__.py as Python
# packages
def _find_module_in_folder(self, folder, modname):
module = folder
packages = modname.split('.')
for pkg in packages[:-1]:
if module.is_folder() and module.has_child(pkg):
module = module.get_child(pkg)
else:
return None
if module.is_folder():
if module.has_child(packages[-1]) and \
module.get_child(packages[-1]).is_folder() and \
module.get_child(packages[-1]).has_child('__init__.py'):
return module.get_child(packages[-1])
elif module.has_child(packages[-1] + '.py') and \
not module.get_child(packages[-1] + '.py').is_folder():
return module.get_child(packages[-1] + '.py')
pycore.PyCore = PatchedPyCore
# [2] 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
# [2] 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
# [4] Patching PyDocExtractor so that _get_class_docstring and
# _get_single_function_docstring don't add a 2 spaces indent to
# every docstring. The only value that we are modifying is the indent
# keyword, from 2 to 0.
from rope.contrib import codeassist
class PatchedPyDocExtractor(codeassist.PyDocExtractor):
def _get_class_docstring(self, pyclass):
contents = self._trim_docstring(pyclass.get_doc(), indents=0)
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_single_function_docstring(self, pyfunction):
signature = self._get_function_signature(pyfunction)
docs = pyfunction.get_doc()
docs = self._trim_docstring(pyfunction.get_doc(), indents=0)
return docs
return signature + ':\n\n' + docs
codeassist.PyDocExtractor = PatchedPyDocExtractor
|