]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/tools/dbg.py
wx namespace
[wxWidgets.git] / wxPython / wx / tools / dbg.py
CommitLineData
d14a1e28
RD
1#----------------------------------------------------------------------------
2# Name: dbg.py
3# RCS-ID: $Id$
4# Author: Will Sadkin
5# Email: wsadkin@nameconnector.com
6# Created: 07/11/2002
7# Copyright: (c) 2002 by Will Sadkin, 2002
8# License: wxWindows license
9#----------------------------------------------------------------------------
1fded56b 10
d14a1e28
RD
11"""
12This module provides a useful debugging framework that supports
13showing nesting of function calls and allows a program to contain
14lots of debugging print statements that can easily be turned on
15or off to debug the code. It also supports the ability to
16have each function indent the debugging statements contained
17within it, including those of any other function called within
18its scope, thus allowing you to see in what order functions are
19being called, and from where.
20
21This capability is particularly useful in wxPython applications,
22where exactly events occur that cause functions to be called is
23not entirely clear, and because wxPython programs can't be run
24from inside other debugging environments that have their own
25message loops.
26
27This module defines a Logger class, responsible for managing
28debugging output. Each Logger instance can be given a name
29at construction; if this is done, '<name>:' will precede each
30logging output made by that Logger instance.
31
32The log() function this class provides takes a set of positional
33arguments that are printed in order if debugging is enabled
34(just like print does), followed by a set of keyword arguments
35that control the behavior of the log() function itself on subsequent
36calls. The current keyword arguments are:
37
38indent
39 When set to a value of 1, this increments the current
40 indentation level, causing all subsequent dbg() outputs to be
41 indented by 3 more spaces. When set to a value of 0,
42 this process is reversed, causing the indent to decrease by
43 3 spaces. The default indentation level is 0.
44
45enable
46 When set to a value of 1, this turns on dbg() output for
47 for program importing this module, until told to do otherwise.
48 When set to a value of 0, dbg output is turned off. (dbg
49 output is off by default.)
50
51suspend
52 When set to a value of 1, this increments the current
53 "suspension" level. This makes it possible for a function
54 to temporarily suspend its and any of its dependents'
55 potential outputs that use the same Logger instance.
56 When set to a value of 0, the suspension level is
57 decremented. When the value goes back to 0, potential
58 logging is resumed (actual output depends on the
59 "enable" status of the Logger instance in question.)
60
61wxlog
62 When set to a value of 1, the output will be sent to the
63 active wxLog target.
64
65stream
66 When set to a non-None value, the current output stream
67 (default of sys.stdout) is pushed onto a stack of streams,
68 and is replaced in the dbg system with the specified stream.
69 When called with a value of None, the previous stream will
70 be restored (if stacked.) If set to None without previously
71 changing it will result in no action being taken.
72
73You can also call the log function implicitly on the Logger
74instance, ie. you can type:
75 from wxPython.tools.dbg import Logger
76 dbg = Logger()
77 dbg('something to print')
78
79Using this fairly simple mechanism, it is possible to get fairly
80useful debugging output in a program. Consider the following
81code example:
82
83>>> d = {1:'a', 2:'dictionary', 3:'of', 4:'words'}
84>>> dbg = dbg.Logger('module')
85>>> dbg(enable=1)
86module: dbg enabled
87>>> def foo(d):
88... dbg('foo', indent=1)
89... bar(d)
90... dbg('end of foo', indent=0)
91...
92>>> def bar(d):
93... dbg('bar', indent=1)
94... dbg('contents of d:', indent=1)
95... l = d.items()
96... l.sort()
97... for key, value in l:
98... dbg('%d =' % key, value)
99... dbg(indent=0)
100... dbg('end of bar', indent=0)
101...
102>>> foo(d)
103module: foo
104 module: bar
105 module: contents of d:
106 module: 1 = a
107 module: 2 = dictionary
108 module: 3 = of
109 module: 4 = words
110 module: end of bar
111 module: end of foo
112>>>
113
114"""
115
116
117class Logger:
118 def __init__(self, name=None):
119 import sys
120 self.name = name
121 self._indent = 0 # current number of indentations
122 self._dbg = 0 # enable/disable flag
123 self._suspend = 0 # allows code to "suspend/resume" potential dbg output
124 self._wxLog = 0 # use wxLogMessage for debug output
125 self._outstream = sys.stdout # default output stream
126 self._outstream_stack = [] # for restoration of streams as necessary
127
128
129 def IsEnabled():
130 return self._dbg
131
132 def IsSuspended():
133 return _suspend
134
135
136 def log(self, *args, **kwargs):
137 """
138 This function provides a useful framework for generating
139 optional debugging output that can be displayed at an
140 arbitrary level of indentation.
141 """
142 if not self._dbg and not 'enable' in kwargs.keys():
143 return
144
145 if self._dbg and len(args) and not self._suspend:
146 # (emulate print functionality)
147 strs = [str(arg) for arg in args]
148 output = ' '.join(strs)
149 if self.name: output = self.name+': ' + output
150 output = ' ' * 3 * self._indent + output
151
152 if self._wxLog:
153 from wxPython.wx import wxLogMessage # (if not already imported)
154 wxLogMessage(output)
155 else:
156 self._outstream.write(output + '\n')
157 self._outstream.flush()
158 # else do nothing
159
160 # post process args:
161 for kwarg, value in kwargs.items():
162 if kwarg == 'indent':
163 self.SetIndent(value)
164 elif kwarg == 'enable':
165 self.SetEnabled(value)
166 elif kwarg == 'suspend':
167 self.SetSuspend(value)
168 elif kwarg == 'wxlog':
169 self.SetWxLog(value)
170 elif kwarg == 'stream':
171 self.SetStream(value)
172
173 # aliases for the log function
174 dbg = log # backwards compatible
175 msg = log #
176 __call__ = log # this one lets you 'call' the instance directly
177
178
179 def SetEnabled(self, value):
180 if value:
181 old_dbg = self._dbg
182 self._dbg = 1
183 if not old_dbg:
184 self.dbg('dbg enabled')
185 else:
186 if self._dbg:
187 self.dbg('dbg disabled')
188 self._dbg = 0
189
190
191 def SetSuspend(self, value):
192 if value:
193 self._suspend += 1
194 elif self._suspend > 0:
195 self._suspend -= 1
196
197
198 def SetIndent(self, value):
199 if value:
200 self._indent += 1
201 elif self._indent > 0:
202 self._indent -= 1
203
204
205 def SetWxLog(self, value):
206 self._wxLog = value
207
208
209 def SetStream(self, value):
210 if value:
211 self._outstream_stack.append( self._outstream )
212 self._outstream = value
213 elif value is None and len(self._outstream_stack) > 0:
214 self._outstream = self._outstream_stack.pop(-1)
215
216
217#------------------------------------------------------------
218
219if __name__ == "__main__":
220 from wxPython.wx import *
221 wxLog_SetActiveTarget( wxLogStderr() )
222 logger = Logger('module')
223 dbg = logger.dbg
224 dbg(enable=1)
225 logger('test __call__ interface')
226 dbg('testing wxLog output to stderr:', wxlog=1, indent=1)
227 dbg('1,2,3...')
228 dbg('testing wxLogNull:')
229 devnull = wxLogNull()
230 dbg('4,5,6...') # shouldn't print, according to doc...
231 del devnull
232 dbg('(resuming to wxLogStdErr)', '7,8,9...', indent=0)
233 dbg('disabling wxLog output, switching to stderr:')
234 dbg(wxlog=0, stream=sys.stderr)
235 dbg(logger._outstream, 'switching back to stdout:')
236 dbg(stream=None)
237 dbg(logger._outstream )
238 def foo(str):
239 dbg('foo:', indent=1)
240 dbg(str, indent=0)
241 foo('testing dbg inside function')
242 class bar(Logger):
243 def __init__(self, name):
244 Logger.__init__(self, name)
245 def enable(self, value):
246 self.dbg(enable=value)
247 def foo(self, str):
248 self.dbg('foo:', indent=1)
249 self.dbg(str, indent=0)
250 f = bar('class mixin')
251 f.foo("shouldn't print")
252 f.enable(1)
253 f.foo("should print")
254 dbg('test completed.', enable=0)
255 dbg('(double-checking ;-)')
1fded56b 256