mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-27 13:42:28 -06:00
269 lines
8.4 KiB
Python
269 lines
8.4 KiB
Python
|
#----------------------------------------------------------------------------
|
||
|
# Name: dbg.py
|
||
|
# Author: Will Sadkin
|
||
|
# Email: wsadkin@nameconnector.com
|
||
|
# Created: 07/11/2002
|
||
|
# Copyright: (c) 2002 by Will Sadkin, 2002
|
||
|
# License: wxWindows license
|
||
|
# Tags: phoenix-port
|
||
|
#----------------------------------------------------------------------------
|
||
|
# 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
|
||
|
#
|
||
|
# o V2.5 compatability update
|
||
|
#
|
||
|
|
||
|
"""
|
||
|
This module provides a useful debugging framework that supports
|
||
|
showing nesting of function calls and allows a program to contain
|
||
|
lots of debugging print statements that can easily be turned on
|
||
|
or off to debug the code. It also supports the ability to
|
||
|
have each function indent the debugging statements contained
|
||
|
within it, including those of any other function called within
|
||
|
its scope, thus allowing you to see in what order functions are
|
||
|
being called, and from where.
|
||
|
|
||
|
This capability is particularly useful in wxPython applications,
|
||
|
where exactly events occur that cause functions to be called is
|
||
|
not entirely clear, and because wxPython programs can't be run
|
||
|
from inside other debugging environments that have their own
|
||
|
message loops.
|
||
|
|
||
|
This module defines a Logger class, responsible for managing
|
||
|
debugging output. Each Logger instance can be given a name
|
||
|
at construction; if this is done, '<name>:' will precede each
|
||
|
logging output made by that Logger instance.
|
||
|
|
||
|
The log() function this class provides takes a set of positional
|
||
|
arguments that are printed in order if debugging is enabled
|
||
|
(just like print does), followed by a set of keyword arguments
|
||
|
that control the behavior of the log() function itself on subsequent
|
||
|
calls. The current keyword arguments are:
|
||
|
|
||
|
indent
|
||
|
When set to a value of 1, this increments the current
|
||
|
indentation level, causing all subsequent dbg() outputs to be
|
||
|
indented by 3 more spaces. When set to a value of 0,
|
||
|
this process is reversed, causing the indent to decrease by
|
||
|
3 spaces. The default indentation level is 0.
|
||
|
|
||
|
enable
|
||
|
When set to a value of 1, this turns on dbg() output for
|
||
|
for program importing this module, until told to do otherwise.
|
||
|
When set to a value of 0, dbg output is turned off. (dbg
|
||
|
output is off by default.)
|
||
|
|
||
|
suspend
|
||
|
When set to a value of 1, this increments the current
|
||
|
"suspension" level. This makes it possible for a function
|
||
|
to temporarily suspend its and any of its dependents'
|
||
|
potential outputs that use the same Logger instance.
|
||
|
When set to a value of 0, the suspension level is
|
||
|
decremented. When the value goes back to 0, potential
|
||
|
logging is resumed (actual output depends on the
|
||
|
"enable" status of the Logger instance in question.)
|
||
|
|
||
|
wxlog
|
||
|
When set to a value of 1, the output will be sent to the
|
||
|
active wxLog target.
|
||
|
|
||
|
stream
|
||
|
When set to a non-None value, the current output stream
|
||
|
(default of sys.stdout) is pushed onto a stack of streams,
|
||
|
and is replaced in the dbg system with the specified stream.
|
||
|
When called with a value of None, the previous stream will
|
||
|
be restored (if stacked.) If set to None without previously
|
||
|
changing it will result in no action being taken.
|
||
|
|
||
|
You can also call the log function implicitly on the Logger
|
||
|
instance, ie. you can type::
|
||
|
|
||
|
from wx.tools.dbg import Logger
|
||
|
dbg = Logger()
|
||
|
dbg('something to print')
|
||
|
|
||
|
Using this fairly simple mechanism, it is possible to get fairly
|
||
|
useful debugging output in a program. Consider the following
|
||
|
code example:
|
||
|
|
||
|
>>> d = {1:'a', 2:'dictionary', 3:'of', 4:'words'}
|
||
|
>>> dbg = dbg.Logger('module')
|
||
|
>>> dbg(enable=1)
|
||
|
module: dbg enabled
|
||
|
>>> def foo(d):
|
||
|
... dbg('foo', indent=1)
|
||
|
... bar(d)
|
||
|
... dbg('end of foo', indent=0)
|
||
|
...
|
||
|
>>> def bar(d):
|
||
|
... dbg('bar', indent=1)
|
||
|
... dbg('contents of d:', indent=1)
|
||
|
... l = d.items()
|
||
|
... l.sort()
|
||
|
... for key, value in l:
|
||
|
... dbg('%d =' % key, value)
|
||
|
... dbg(indent=0)
|
||
|
... dbg('end of bar', indent=0)
|
||
|
...
|
||
|
>>> foo(d)
|
||
|
module: foo
|
||
|
module: bar
|
||
|
module: contents of d:
|
||
|
module: 1 = a
|
||
|
module: 2 = dictionary
|
||
|
module: 3 = of
|
||
|
module: 4 = words
|
||
|
module: end of bar
|
||
|
module: end of foo
|
||
|
>>>
|
||
|
|
||
|
"""
|
||
|
|
||
|
|
||
|
class Logger:
|
||
|
def __init__(self, name=None):
|
||
|
import sys
|
||
|
self.name = name
|
||
|
self._indent = 0 # current number of indentations
|
||
|
self._dbg = 0 # enable/disable flag
|
||
|
self._suspend = 0 # allows code to "suspend/resume" potential dbg output
|
||
|
self._wxLog = 0 # use wxLogMessage for debug output
|
||
|
self._outstream = sys.stdout # default output stream
|
||
|
self._outstream_stack = [] # for restoration of streams as necessary
|
||
|
|
||
|
|
||
|
def IsEnabled():
|
||
|
return self._dbg
|
||
|
|
||
|
def IsSuspended():
|
||
|
return _suspend
|
||
|
|
||
|
|
||
|
def log(self, *args, **kwargs):
|
||
|
"""
|
||
|
This function provides a useful framework for generating
|
||
|
optional debugging output that can be displayed at an
|
||
|
arbitrary level of indentation.
|
||
|
"""
|
||
|
if not self._dbg and not 'enable' in kwargs.keys():
|
||
|
return
|
||
|
|
||
|
if self._dbg and len(args) and not self._suspend:
|
||
|
# (emulate print functionality; handle unicode as best as possible:)
|
||
|
strs = []
|
||
|
for arg in args:
|
||
|
try:
|
||
|
strs.append(str(arg))
|
||
|
except:
|
||
|
strs.append(repr(arg))
|
||
|
|
||
|
output = ' '.join(strs)
|
||
|
if self.name: output = self.name+': ' + output
|
||
|
output = ' ' * 3 * self._indent + output
|
||
|
|
||
|
if self._wxLog:
|
||
|
wx.LogMessage(output)
|
||
|
else:
|
||
|
self._outstream.write(output + '\n')
|
||
|
self._outstream.flush()
|
||
|
# else do nothing
|
||
|
|
||
|
# post process args:
|
||
|
for kwarg, value in kwargs.items():
|
||
|
if kwarg == 'indent':
|
||
|
self.SetIndent(value)
|
||
|
elif kwarg == 'enable':
|
||
|
self.SetEnabled(value)
|
||
|
elif kwarg == 'suspend':
|
||
|
self.SetSuspend(value)
|
||
|
elif kwarg == 'wxlog':
|
||
|
self.SetWxLog(value)
|
||
|
elif kwarg == 'stream':
|
||
|
self.SetStream(value)
|
||
|
|
||
|
# aliases for the log function
|
||
|
dbg = log # backwards compatible
|
||
|
msg = log #
|
||
|
__call__ = log # this one lets you 'call' the instance directly
|
||
|
|
||
|
|
||
|
def SetEnabled(self, value):
|
||
|
if value:
|
||
|
old_dbg = self._dbg
|
||
|
self._dbg = 1
|
||
|
if not old_dbg:
|
||
|
self.dbg('dbg enabled')
|
||
|
else:
|
||
|
if self._dbg:
|
||
|
self.dbg('dbg disabled')
|
||
|
self._dbg = 0
|
||
|
|
||
|
|
||
|
def SetSuspend(self, value):
|
||
|
if value:
|
||
|
self._suspend += 1
|
||
|
elif self._suspend > 0:
|
||
|
self._suspend -= 1
|
||
|
|
||
|
|
||
|
def SetIndent(self, value):
|
||
|
if value:
|
||
|
self._indent += 1
|
||
|
elif self._indent > 0:
|
||
|
self._indent -= 1
|
||
|
|
||
|
|
||
|
def SetWxLog(self, value):
|
||
|
self._wxLog = value
|
||
|
|
||
|
|
||
|
def SetStream(self, value):
|
||
|
if value:
|
||
|
self._outstream_stack.append( self._outstream )
|
||
|
self._outstream = value
|
||
|
elif value is None and len(self._outstream_stack) > 0:
|
||
|
self._outstream = self._outstream_stack.pop(-1)
|
||
|
|
||
|
|
||
|
#------------------------------------------------------------
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
import sys
|
||
|
import wx
|
||
|
|
||
|
wx.Log.SetActiveTarget(wx.LogStderr())
|
||
|
logger = Logger('module')
|
||
|
dbg = logger.dbg
|
||
|
dbg(enable=1)
|
||
|
logger('test __call__ interface')
|
||
|
dbg('testing wxLog output to stderr:', wxlog=1, indent=1)
|
||
|
dbg('1,2,3...')
|
||
|
dbg('testing wx.LogNull:')
|
||
|
devnull = wx.LogNull()
|
||
|
dbg('4,5,6...') # shouldn't print, according to doc...
|
||
|
del devnull
|
||
|
dbg('(resuming to wx.LogStdErr)', '7,8,9...', indent=0)
|
||
|
dbg('disabling wx.Log output, switching to stderr:')
|
||
|
dbg(wxlog=0, stream=sys.stderr)
|
||
|
dbg(logger._outstream, 'switching back to stdout:')
|
||
|
dbg(stream=None)
|
||
|
dbg(logger._outstream )
|
||
|
def foo(str):
|
||
|
dbg('foo:', indent=1)
|
||
|
dbg(str, indent=0)
|
||
|
foo('testing dbg inside function')
|
||
|
class bar(Logger):
|
||
|
def __init__(self, name):
|
||
|
Logger.__init__(self, name)
|
||
|
def enable(self, value):
|
||
|
self.dbg(enable=value)
|
||
|
def foo(self, str):
|
||
|
self.dbg('foo:', indent=1)
|
||
|
self.dbg(str, indent=0)
|
||
|
f = bar('class mixin')
|
||
|
f.foo("shouldn't print")
|
||
|
f.enable(1)
|
||
|
f.foo("should print")
|
||
|
dbg('test completed.', enable=0)
|
||
|
dbg('(double-checking ;-)')
|
||
|
|