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

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

Issue 10447014: Add pylint to depot_tools. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Fix unittests. Created 8 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « third_party/logilab/common/dbf.py ('k') | third_party/logilab/common/decorators.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 __docformat__ = "restructuredtext en"
30
31 try:
32 import readline
33 except ImportError:
34 readline = None
35 import os
36 import os.path as osp
37 import sys
38 from pdb import Pdb
39 from cStringIO import StringIO
40 import inspect
41
42 try:
43 from IPython import PyColorize
44 except ImportError:
45 def colorize(source, *args):
46 """fallback colorize function"""
47 return source
48 def colorize_source(source, *args):
49 return source
50 else:
51 def colorize(source, start_lineno, curlineno):
52 """colorize and annotate source with linenos
53 (as in pdb's list command)
54 """
55 parser = PyColorize.Parser()
56 output = StringIO()
57 parser.format(source, output)
58 annotated = []
59 for index, line in enumerate(output.getvalue().splitlines()):
60 lineno = index + start_lineno
61 if lineno == curlineno:
62 annotated.append('%4s\t->\t%s' % (lineno, line))
63 else:
64 annotated.append('%4s\t\t%s' % (lineno, line))
65 return '\n'.join(annotated)
66
67 def colorize_source(source):
68 """colorize given source"""
69 parser = PyColorize.Parser()
70 output = StringIO()
71 parser.format(source, output)
72 return output.getvalue()
73
74
75 def getsource(obj):
76 """Return the text of the source code for an object.
77
78 The argument may be a module, class, method, function, traceback, frame,
79 or code object. The source code is returned as a single string. An
80 IOError is raised if the source code cannot be retrieved."""
81 lines, lnum = inspect.getsourcelines(obj)
82 return ''.join(lines), lnum
83
84
85 ################################################################
86 class Debugger(Pdb):
87 """custom debugger
88
89 - sets up a history file
90 - uses ipython if available to colorize lines of code
91 - overrides list command to search for current block instead
92 of using 5 lines of context
93 """
94 def __init__(self, tcbk=None):
95 Pdb.__init__(self)
96 self.reset()
97 if tcbk:
98 while tcbk.tb_next is not None:
99 tcbk = tcbk.tb_next
100 self._tcbk = tcbk
101 self._histfile = os.path.expanduser("~/.pdbhist")
102
103 def setup_history_file(self):
104 """if readline is available, read pdb history file
105 """
106 if readline is not None:
107 try:
108 # XXX try..except shouldn't be necessary
109 # read_history_file() can accept None
110 readline.read_history_file(self._histfile)
111 except IOError:
112 pass
113
114 def start(self):
115 """starts the interactive mode"""
116 self.interaction(self._tcbk.tb_frame, self._tcbk)
117
118 def setup(self, frame, tcbk):
119 """setup hook: set up history file"""
120 self.setup_history_file()
121 Pdb.setup(self, frame, tcbk)
122
123 def set_quit(self):
124 """quit hook: save commands in the history file"""
125 if readline is not None:
126 readline.write_history_file(self._histfile)
127 Pdb.set_quit(self)
128
129 def complete_p(self, text, line, begin_idx, end_idx):
130 """provide variable names completion for the ``p`` command"""
131 namespace = dict(self.curframe.f_globals)
132 namespace.update(self.curframe.f_locals)
133 if '.' in text:
134 return self.attr_matches(text, namespace)
135 return [varname for varname in namespace if varname.startswith(text)]
136
137
138 def attr_matches(self, text, namespace):
139 """implementation coming from rlcompleter.Completer.attr_matches
140 Compute matches when text contains a dot.
141
142 Assuming the text is of the form NAME.NAME....[NAME], and is
143 evaluatable in self.namespace, it will be evaluated and its attributes
144 (as revealed by dir()) are used as possible completions. (For class
145 instances, class members are also considered.)
146
147 WARNING: this can still invoke arbitrary C code, if an object
148 with a __getattr__ hook is evaluated.
149
150 """
151 import re
152 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
153 if not m:
154 return
155 expr, attr = m.group(1, 3)
156 object = eval(expr, namespace)
157 words = dir(object)
158 if hasattr(object, '__class__'):
159 words.append('__class__')
160 words = words + self.get_class_members(object.__class__)
161 matches = []
162 n = len(attr)
163 for word in words:
164 if word[:n] == attr and word != "__builtins__":
165 matches.append("%s.%s" % (expr, word))
166 return matches
167
168 def get_class_members(self, klass):
169 """implementation coming from rlcompleter.get_class_members"""
170 ret = dir(klass)
171 if hasattr(klass, '__bases__'):
172 for base in klass.__bases__:
173 ret = ret + self.get_class_members(base)
174 return ret
175
176 ## specific / overridden commands
177 def do_list(self, arg):
178 """overrides default list command to display the surrounding block
179 instead of 5 lines of context
180 """
181 self.lastcmd = 'list'
182 if not arg:
183 try:
184 source, start_lineno = getsource(self.curframe)
185 print colorize(''.join(source), start_lineno,
186 self.curframe.f_lineno)
187 except KeyboardInterrupt:
188 pass
189 except IOError:
190 Pdb.do_list(self, arg)
191 else:
192 Pdb.do_list(self, arg)
193 do_l = do_list
194
195 def do_open(self, arg):
196 """opens source file corresponding to the current stack level"""
197 filename = self.curframe.f_code.co_filename
198 lineno = self.curframe.f_lineno
199 cmd = 'emacsclient --no-wait +%s %s' % (lineno, filename)
200 os.system(cmd)
201
202 do_o = do_open
203
204 def pm():
205 """use our custom debugger"""
206 dbg = Debugger(sys.last_traceback)
207 dbg.start()
208
209 def set_trace():
210 Debugger().set_trace(sys._getframe().f_back)
OLDNEW
« no previous file with comments | « third_party/logilab/common/dbf.py ('k') | third_party/logilab/common/decorators.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698