+++ /dev/null
-#----------------------------------------------------------------------------
-# Name: dbg.py
-# RCS-ID: $Id$
-# Author: Will Sadkin
-# Email: wsadkin@nameconnector.com
-# Created: 07/11/2002
-# Copyright: (c) 2002 by Will Sadkin, 2002
-# License: wxWindows license
-#----------------------------------------------------------------------------
-# 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 wxPython.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:
- from wxPython.wx import wxLogMessage # (if not already imported)
- wxLogMessage(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 ;-)')
-