Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: third_party/logilab/logilab/common/debugger.py

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 #
4 # This file is part of logilab-common.
5 #
6 # logilab-common is free software: you can redistribute it and/or modify it unde r
7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation, either version 2.1 of the License, or (at your option) an y
9 # later version.
10 #
11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 # details.
15 #
16 # You should have received a copy of the GNU Lesser General Public License along
17 # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
18 """Customized version of pdb's default debugger.
19
20 - sets up a history file
21 - uses ipython if available to colorize lines of code
22 - overrides list command to search for current block instead
23 of using 5 lines of context
24
25
26
27
28 """
29
30 from __future__ import print_function
31
32 __docformat__ = "restructuredtext en"
33
34 try:
35 import readline
36 except ImportError:
37 readline = None
38 import os
39 import os.path as osp
40 import sys
41 from pdb import Pdb
42 import inspect
43
44 from logilab.common.compat import StringIO
45
46 try:
47 from IPython import PyColorize
48 except ImportError:
49 def colorize(source, *args):
50 """fallback colorize function"""
51 return source
52 def colorize_source(source, *args):
53 return source
54 else:
55 def colorize(source, start_lineno, curlineno):
56 """colorize and annotate source with linenos
57 (as in pdb's list command)
58 """
59 parser = PyColorize.Parser()
60 output = StringIO()
61 parser.format(source, output)
62 annotated = []
63 for index, line in enumerate(output.getvalue().splitlines()):
64 lineno = index + start_lineno
65 if lineno == curlineno:
66 annotated.append('%4s\t->\t%s' % (lineno, line))
67 else:
68 annotated.append('%4s\t\t%s' % (lineno, line))
69 return '\n'.join(annotated)
70
71 def colorize_source(source):
72 """colorize given source"""
73 parser = PyColorize.Parser()
74 output = StringIO()
75 parser.format(source, output)
76 return output.getvalue()
77
78
79 def getsource(obj):
80 """Return the text of the source code for an object.
81
82 The argument may be a module, class, method, function, traceback, frame,
83 or code object. The source code is returned as a single string. An
84 IOError is raised if the source code cannot be retrieved."""
85 lines, lnum = inspect.getsourcelines(obj)
86 return ''.join(lines), lnum
87
88
89 ################################################################
90 class Debugger(Pdb):
91 """custom debugger
92
93 - sets up a history file
94 - uses ipython if available to colorize lines of code
95 - overrides list command to search for current block instead
96 of using 5 lines of context
97 """
98 def __init__(self, tcbk=None):
99 Pdb.__init__(self)
100 self.reset()
101 if tcbk:
102 while tcbk.tb_next is not None:
103 tcbk = tcbk.tb_next
104 self._tcbk = tcbk
105 self._histfile = os.path.expanduser("~/.pdbhist")
106
107 def setup_history_file(self):
108 """if readline is available, read pdb history file
109 """
110 if readline is not None:
111 try:
112 # XXX try..except shouldn't be necessary
113 # read_history_file() can accept None
114 readline.read_history_file(self._histfile)
115 except IOError:
116 pass
117
118 def start(self):
119 """starts the interactive mode"""
120 self.interaction(self._tcbk.tb_frame, self._tcbk)
121
122 def setup(self, frame, tcbk):
123 """setup hook: set up history file"""
124 self.setup_history_file()
125 Pdb.setup(self, frame, tcbk)
126
127 def set_quit(self):
128 """quit hook: save commands in the history file"""
129 if readline is not None:
130 readline.write_history_file(self._histfile)
131 Pdb.set_quit(self)
132
133 def complete_p(self, text, line, begin_idx, end_idx):
134 """provide variable names completion for the ``p`` command"""
135 namespace = dict(self.curframe.f_globals)
136 namespace.update(self.curframe.f_locals)
137 if '.' in text:
138 return self.attr_matches(text, namespace)
139 return [varname for varname in namespace if varname.startswith(text)]
140
141
142 def attr_matches(self, text, namespace):
143 """implementation coming from rlcompleter.Completer.attr_matches
144 Compute matches when text contains a dot.
145
146 Assuming the text is of the form NAME.NAME....[NAME], and is
147 evaluatable in self.namespace, it will be evaluated and its attributes
148 (as revealed by dir()) are used as possible completions. (For class
149 instances, class members are also considered.)
150
151 WARNING: this can still invoke arbitrary C code, if an object
152 with a __getattr__ hook is evaluated.
153
154 """
155 import re
156 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
157 if not m:
158 return
159 expr, attr = m.group(1, 3)
160 object = eval(expr, namespace)
161 words = dir(object)
162 if hasattr(object, '__class__'):
163 words.append('__class__')
164 words = words + self.get_class_members(object.__class__)
165 matches = []
166 n = len(attr)
167 for word in words:
168 if word[:n] == attr and word != "__builtins__":
169 matches.append("%s.%s" % (expr, word))
170 return matches
171
172 def get_class_members(self, klass):
173 """implementation coming from rlcompleter.get_class_members"""
174 ret = dir(klass)
175 if hasattr(klass, '__bases__'):
176 for base in klass.__bases__:
177 ret = ret + self.get_class_members(base)
178 return ret
179
180 ## specific / overridden commands
181 def do_list(self, arg):
182 """overrides default list command to display the surrounding block
183 instead of 5 lines of context
184 """
185 self.lastcmd = 'list'
186 if not arg:
187 try:
188 source, start_lineno = getsource(self.curframe)
189 print(colorize(''.join(source), start_lineno,
190 self.curframe.f_lineno))
191 except KeyboardInterrupt:
192 pass
193 except IOError:
194 Pdb.do_list(self, arg)
195 else:
196 Pdb.do_list(self, arg)
197 do_l = do_list
198
199 def do_open(self, arg):
200 """opens source file corresponding to the current stack level"""
201 filename = self.curframe.f_code.co_filename
202 lineno = self.curframe.f_lineno
203 cmd = 'emacsclient --no-wait +%s %s' % (lineno, filename)
204 os.system(cmd)
205
206 do_o = do_open
207
208 def pm():
209 """use our custom debugger"""
210 dbg = Debugger(sys.last_traceback)
211 dbg.start()
212
213 def set_trace():
214 Debugger().set_trace(sys._getframe().f_back)
OLDNEW
« no previous file with comments | « third_party/logilab/logilab/common/dbf.py ('k') | third_party/logilab/logilab/common/decorators.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698