~ubuntu-branches/debian/experimental/spyder/experimental

« back to all changes in this revision

Viewing changes to spyderlib/rope_patch.py

  • Committer: Package Import Robot
  • Author(s): Picca Frédéric-Emmanuel
  • Date: 2013-01-20 12:19:54 UTC
  • mfrom: (1.1.16)
  • Revision ID: package-import@ubuntu.com-20130120121954-1jt1xa924bshhvh0
Tags: 2.2.0~beta1+dfsg-2
fix typo ipython-qtconsol -> ipython-qtconsole

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# Copyright © 2011 Pierre Raybaut
4
 
# Licensed under the terms of the MIT License
5
 
# (see spyderlib/__init__.py for details)
6
 
 
7
 
"""
8
 
Patching rope:
9
 
 
10
 
[1] For compatibility with Spyder's standalone version, build with py2exe or
11
 
    cx_Freeze
12
 
 
13
 
[2] For better performances, see this thread:
14
 
http://groups.google.com/group/rope-dev/browse_thread/thread/57de5731f202537a
15
 
 
16
 
[3] To avoid considering folders without __init__.py as Python packages, thus
17
 
avoiding side effects as non-working introspection features on a Python module
18
 
or package when a folder in current directory has the same name.
19
 
See this thread:
20
 
http://groups.google.com/group/rope-dev/browse_thread/thread/924c4b5a6268e618
21
 
 
22
 
[4] To avoid rope adding a 2 spaces indent to every docstring it gets, because
23
 
it breaks the work of Sphinx on the Object Inspector.
24
 
"""
25
 
 
26
 
def apply():
27
 
    """Monkey patching rope
28
 
    
29
 
    See [1], [2] and [3] in module docstring."""
30
 
    import rope
31
 
    if rope.VERSION not in ('0.9.4', '0.9.3', '0.9.2'):
32
 
        raise ImportError, "rope %s can't be patched" % rope.VERSION
33
 
 
34
 
    # [1] Patching project.Project for compatibility with py2exe/cx_Freeze
35
 
    #     distributions
36
 
    from spyderlib.baseconfig import is_py2exe_or_cx_Freeze
37
 
    if is_py2exe_or_cx_Freeze():
38
 
        from rope.base import project
39
 
        class PatchedProject(project.Project):
40
 
            def _default_config(self):
41
 
                # py2exe/cx_Freeze distribution
42
 
                from spyderlib.baseconfig import get_module_source_path
43
 
                fname = get_module_source_path('spyderlib',
44
 
                                               'default_config.py')
45
 
                return open(fname, 'rb').read()
46
 
        project.Project = PatchedProject
47
 
    
48
 
    # Patching pycore.PyCore...
49
 
    from rope.base import pycore
50
 
    class PatchedPyCore(pycore.PyCore):
51
 
        # [2] ...so that forced builtin modules (i.e. modules that were 
52
 
        # declared as 'extension_modules' in rope preferences) will be indeed
53
 
        # recognized as builtins by rope, as expected
54
 
        # 
55
 
        # This patch is included in rope 0.9.4+ but applying it anyway is ok
56
 
        def get_module(self, name, folder=None):
57
 
            """Returns a `PyObject` if the module was found."""
58
 
            # check if this is a builtin module
59
 
            pymod = self._builtin_module(name)
60
 
            if pymod is not None:
61
 
                return pymod
62
 
            module = self.find_module(name, folder)
63
 
            if module is None:
64
 
                raise pycore.ModuleNotFoundError(
65
 
                                            'Module %s not found' % name)
66
 
            return self.resource_to_pyobject(module)
67
 
        # [3] ...to avoid considering folders without __init__.py as Python
68
 
        # packages
69
 
        def _find_module_in_folder(self, folder, modname):
70
 
            module = folder
71
 
            packages = modname.split('.')
72
 
            for pkg in packages[:-1]:
73
 
                if  module.is_folder() and module.has_child(pkg):
74
 
                    module = module.get_child(pkg)
75
 
                else:
76
 
                    return None
77
 
            if module.is_folder():
78
 
                if module.has_child(packages[-1]) and \
79
 
                   module.get_child(packages[-1]).is_folder() and \
80
 
                   module.get_child(packages[-1]).has_child('__init__.py'):
81
 
                    return module.get_child(packages[-1])
82
 
                elif module.has_child(packages[-1] + '.py') and \
83
 
                     not module.get_child(packages[-1] + '.py').is_folder():
84
 
                    return module.get_child(packages[-1] + '.py')
85
 
    pycore.PyCore = PatchedPyCore
86
 
    
87
 
    # [2] Patching BuiltinFunction for the calltip/doc functions to be 
88
 
    # able to retrieve the function signatures with forced builtins
89
 
    from rope.base import builtins, pyobjects
90
 
    from spyderlib.utils.dochelpers import getargs
91
 
    class PatchedBuiltinFunction(builtins.BuiltinFunction):
92
 
        def __init__(self, returned=None, function=None, builtin=None,
93
 
                     argnames=[], parent=None):
94
 
            builtins._BuiltinElement.__init__(self, builtin, parent)
95
 
            pyobjects.AbstractFunction.__init__(self)
96
 
            self.argnames = argnames
97
 
            if not argnames and builtin:
98
 
                self.argnames = getargs(self.builtin)
99
 
            if self.argnames is None:
100
 
                self.argnames = []
101
 
            self.returned = returned
102
 
            self.function = function
103
 
    builtins.BuiltinFunction = PatchedBuiltinFunction
104
 
 
105
 
    # [2] Patching BuiltinName for the go to definition feature to simply work 
106
 
    # with forced builtins
107
 
    from rope.base import libutils
108
 
    import inspect
109
 
    class PatchedBuiltinName(builtins.BuiltinName):
110
 
        def _pycore(self):
111
 
            p = self.pyobject
112
 
            while p.parent is not None:
113
 
                p = p.parent
114
 
            if isinstance(p, builtins.BuiltinModule) and p.pycore is not None:
115
 
                return p.pycore
116
 
        def get_definition_location(self):
117
 
            if not inspect.isbuiltin(self.pyobject):
118
 
                _lines, lineno = inspect.getsourcelines(self.pyobject.builtin)
119
 
                path = inspect.getfile(self.pyobject.builtin)
120
 
                pycore = self._pycore()
121
 
                if pycore and pycore.project:
122
 
                    resource = libutils.path_to_resource(pycore.project, path)
123
 
                    module = pyobjects.PyModule(pycore, None, resource)
124
 
                    return (module, lineno)
125
 
            return (None, None)
126
 
    builtins.BuiltinName = PatchedBuiltinName
127
 
    
128
 
    # [4] Patching PyDocExtractor so that _get_class_docstring and
129
 
    # _get_single_function_docstring don't add a 2 spaces indent to
130
 
    # every docstring. The only value that we are modifying is the indent
131
 
    # keyword, from 2 to 0.
132
 
    from rope.contrib import codeassist
133
 
    class PatchedPyDocExtractor(codeassist.PyDocExtractor):
134
 
        def _get_class_docstring(self, pyclass):
135
 
            contents = self._trim_docstring(pyclass.get_doc(), indents=0)
136
 
            supers = [super.get_name() for super in pyclass.get_superclasses()]
137
 
            doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) + contents
138
 
 
139
 
            if '__init__' in pyclass:
140
 
                init = pyclass['__init__'].get_object()
141
 
                if isinstance(init, pyobjects.AbstractFunction):
142
 
                    doc += '\n\n' + self._get_single_function_docstring(init)
143
 
            return doc
144
 
            
145
 
        def _get_single_function_docstring(self, pyfunction):
146
 
            signature = self._get_function_signature(pyfunction)
147
 
            docs = pyfunction.get_doc()
148
 
            docs = self._trim_docstring(pyfunction.get_doc(), indents=0)
149
 
            return docs
150
 
            return signature + ':\n\n' + docs
151
 
    codeassist.PyDocExtractor = PatchedPyDocExtractor 
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Copyright © 2011 Pierre Raybaut
 
4
# Licensed under the terms of the MIT License
 
5
# (see spyderlib/__init__.py for details)
 
6
 
 
7
"""
 
8
Patching rope:
 
9
 
 
10
[1] For compatibility with Spyder's standalone version, build with py2exe or
 
11
    cx_Freeze
 
12
 
 
13
[2] For better performances, see this thread:
 
14
http://groups.google.com/group/rope-dev/browse_thread/thread/57de5731f202537a
 
15
 
 
16
[3] To avoid considering folders without __init__.py as Python packages, thus
 
17
avoiding side effects as non-working introspection features on a Python module
 
18
or package when a folder in current directory has the same name.
 
19
See this thread:
 
20
http://groups.google.com/group/rope-dev/browse_thread/thread/924c4b5a6268e618
 
21
 
 
22
[4] To avoid rope adding a 2 spaces indent to every docstring it gets, because
 
23
it breaks the work of Sphinx on the Object Inspector.
 
24
"""
 
25
 
 
26
def apply():
 
27
    """Monkey patching rope
 
28
    
 
29
    See [1], [2] and [3] in module docstring."""
 
30
    import rope
 
31
    if rope.VERSION not in ('0.9.4', '0.9.3', '0.9.2'):
 
32
        raise ImportError, "rope %s can't be patched" % rope.VERSION
 
33
 
 
34
    # [1] Patching project.Project for compatibility with py2exe/cx_Freeze
 
35
    #     distributions
 
36
    from spyderlib.baseconfig import is_py2exe_or_cx_Freeze
 
37
    if is_py2exe_or_cx_Freeze():
 
38
        from rope.base import project
 
39
        class PatchedProject(project.Project):
 
40
            def _default_config(self):
 
41
                # py2exe/cx_Freeze distribution
 
42
                from spyderlib.baseconfig import get_module_source_path
 
43
                fname = get_module_source_path('spyderlib',
 
44
                                               'default_config.py')
 
45
                return open(fname, 'rb').read()
 
46
        project.Project = PatchedProject
 
47
    
 
48
    # Patching pycore.PyCore...
 
49
    from rope.base import pycore
 
50
    class PatchedPyCore(pycore.PyCore):
 
51
        # [2] ...so that forced builtin modules (i.e. modules that were 
 
52
        # declared as 'extension_modules' in rope preferences) will be indeed
 
53
        # recognized as builtins by rope, as expected
 
54
        # 
 
55
        # This patch is included in rope 0.9.4+ but applying it anyway is ok
 
56
        def get_module(self, name, folder=None):
 
57
            """Returns a `PyObject` if the module was found."""
 
58
            # check if this is a builtin module
 
59
            pymod = self._builtin_module(name)
 
60
            if pymod is not None:
 
61
                return pymod
 
62
            module = self.find_module(name, folder)
 
63
            if module is None:
 
64
                raise pycore.ModuleNotFoundError(
 
65
                                            'Module %s not found' % name)
 
66
            return self.resource_to_pyobject(module)
 
67
        # [3] ...to avoid considering folders without __init__.py as Python
 
68
        # packages
 
69
        def _find_module_in_folder(self, folder, modname):
 
70
            module = folder
 
71
            packages = modname.split('.')
 
72
            for pkg in packages[:-1]:
 
73
                if  module.is_folder() and module.has_child(pkg):
 
74
                    module = module.get_child(pkg)
 
75
                else:
 
76
                    return None
 
77
            if module.is_folder():
 
78
                if module.has_child(packages[-1]) and \
 
79
                   module.get_child(packages[-1]).is_folder() and \
 
80
                   module.get_child(packages[-1]).has_child('__init__.py'):
 
81
                    return module.get_child(packages[-1])
 
82
                elif module.has_child(packages[-1] + '.py') and \
 
83
                     not module.get_child(packages[-1] + '.py').is_folder():
 
84
                    return module.get_child(packages[-1] + '.py')
 
85
    pycore.PyCore = PatchedPyCore
 
86
    
 
87
    # [2] Patching BuiltinFunction for the calltip/doc functions to be 
 
88
    # able to retrieve the function signatures with forced builtins
 
89
    from rope.base import builtins, pyobjects
 
90
    from spyderlib.utils.dochelpers import getargs
 
91
    class PatchedBuiltinFunction(builtins.BuiltinFunction):
 
92
        def __init__(self, returned=None, function=None, builtin=None,
 
93
                     argnames=[], parent=None):
 
94
            builtins._BuiltinElement.__init__(self, builtin, parent)
 
95
            pyobjects.AbstractFunction.__init__(self)
 
96
            self.argnames = argnames
 
97
            if not argnames and builtin:
 
98
                self.argnames = getargs(self.builtin)
 
99
            if self.argnames is None:
 
100
                self.argnames = []
 
101
            self.returned = returned
 
102
            self.function = function
 
103
    builtins.BuiltinFunction = PatchedBuiltinFunction
 
104
 
 
105
    # [2] Patching BuiltinName for the go to definition feature to simply work 
 
106
    # with forced builtins
 
107
    from rope.base import libutils
 
108
    import inspect
 
109
    class PatchedBuiltinName(builtins.BuiltinName):
 
110
        def _pycore(self):
 
111
            p = self.pyobject
 
112
            while p.parent is not None:
 
113
                p = p.parent
 
114
            if isinstance(p, builtins.BuiltinModule) and p.pycore is not None:
 
115
                return p.pycore
 
116
        def get_definition_location(self):
 
117
            if not inspect.isbuiltin(self.pyobject):
 
118
                _lines, lineno = inspect.getsourcelines(self.pyobject.builtin)
 
119
                path = inspect.getfile(self.pyobject.builtin)
 
120
                pycore = self._pycore()
 
121
                if pycore and pycore.project:
 
122
                    resource = libutils.path_to_resource(pycore.project, path)
 
123
                    module = pyobjects.PyModule(pycore, None, resource)
 
124
                    return (module, lineno)
 
125
            return (None, None)
 
126
    builtins.BuiltinName = PatchedBuiltinName
 
127
    
 
128
    # [4] Patching PyDocExtractor so that _get_class_docstring and
 
129
    # _get_single_function_docstring don't add a 2 spaces indent to
 
130
    # every docstring. The only value that we are modifying is the indent
 
131
    # keyword, from 2 to 0.
 
132
    from rope.contrib import codeassist
 
133
    class PatchedPyDocExtractor(codeassist.PyDocExtractor):
 
134
        def _get_class_docstring(self, pyclass):
 
135
            contents = self._trim_docstring(pyclass.get_doc(), indents=0)
 
136
            supers = [super.get_name() for super in pyclass.get_superclasses()]
 
137
            doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) + contents
 
138
 
 
139
            if '__init__' in pyclass:
 
140
                init = pyclass['__init__'].get_object()
 
141
                if isinstance(init, pyobjects.AbstractFunction):
 
142
                    doc += '\n\n' + self._get_single_function_docstring(init)
 
143
            return doc
 
144
            
 
145
        def _get_single_function_docstring(self, pyfunction):
 
146
            signature = self._get_function_signature(pyfunction)
 
147
            docs = pyfunction.get_doc()
 
148
            docs = self._trim_docstring(pyfunction.get_doc(), indents=0)
 
149
            return docs
 
150
            return signature + ':\n\n' + docs
 
151
    codeassist.PyDocExtractor = PatchedPyDocExtractor