root/branches/gajim_0.6.1/common/debug.py

Revision 64, 13.2 kB (checked in by asterix86, 5 years ago)

keyboard interrupt
comments

  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
Line 
1##   debug.py
2##
3##   Copyright (C) 2003 Jacob Lundqvist
4##
5##   This program is free software; you can redistribute it and/or modify
6##   it under the terms of the GNU Lesser General Public License as published
7##   by the Free Software Foundation; either version 2, or (at your option)
8##   any later version.
9##
10##   This program is distributed in the hope that it will be useful,
11##   but WITHOUT ANY WARRANTY; without even the implied warranty of
12##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13##   GNU Lesser General Public License for more details.
14
15_version_ = '1.4.0'
16
17"""\
18
19Generic debug class
20
21Other modules can always define extra debug flags for local usage, as long as
22they make sure they append them to debug_flags
23
24Also its always a good thing to prefix local flags with something, to reduce risk
25of coliding flags. Nothing breaks if two flags would be identical, but it might
26activate unintended debugging.
27
28flags can be numeric, but that makes analysing harder, on creation its
29not obvious what is activated, and when flag_show is given, output isnt
30really meaningfull.
31
32This Debug class can either be initialized and used on app level, or used independantly
33by the individual classes.
34
35For samples of usage, see samples subdir in distro source, and selftest
36in this code
37   
38"""
39
40
41
42import sys
43import time
44from string import join
45
46import types
47
48
49debug_flags = []
50
51color_none         = chr(27) + "[0m"
52color_black        = chr(27) + "[30m"
53color_red          = chr(27) + "[31m"
54color_green        = chr(27) + "[32m"
55color_brown        = chr(27) + "[33m"
56color_blue         = chr(27) + "[34m"
57color_magenta      = chr(27) + "[35m"
58color_cyan         = chr(27) + "[36m"
59color_light_gray   = chr(27) + "[37m"
60color_dark_gray    = chr(27) + "[30;1m"
61color_bright_red   = chr(27) + "[31;1m"
62color_bright_green = chr(27) + "[32;1m"
63color_yellow       = chr(27) + "[33;1m"
64color_bright_blue  = chr(27) + "[34;1m"
65color_purple       = chr(27) + "[35;1m"
66color_bright_cyan  = chr(27) + "[36;1m"
67color_white        = chr(27) + "[37;1m"
68
69
70"""
71Define your flags in yor modules like this:
72
73from debug import *
74
75DBG_INIT = 'init'                ; debug_flags.append( DBG_INIT )
76DBG_CONNECTION = 'connection'    ; debug_flags.append( DBG_CONNECTION )
77
78 The reason for having a double statement wis so we can validate params
79 and catch all undefined debug flags
80 
81 This gives us control over all used flags, and makes it easier to allow
82 global debugging in your code, just do something like
83 
84 foo = Debug( debug_flags )
85 
86 group flags, that is a flag in it self containing multiple flags should be
87 defined without the debug_flags.append() sequence, since the parts are already
88 in the list, also they must of course be defined after the flags they depend on ;)
89 example:
90
91DBG_MULTI = [ DBG_INIT, DBG_CONNECTION ]
92
93
94
95  NoDebug
96  -------
97  To speed code up, typically for product releases or such
98  use this class instead if you globaly want to disable debugging
99"""
100DBG_INIT = 'init'        ; debug_flags.append( DBG_INIT )
101DBG_ALWAYS = 'always'    ; debug_flags.append( DBG_ALWAYS )
102
103
104class NoDebug:
105    def __init__( self, *args, **kwargs ):
106        pass
107    def show( self,  *args, **kwargs):
108        pass
109    def is_active( self, flag ):
110        pass
111    def active_set( self, active_flags = None ):
112        return 0
113   
114
115LINE_FEED = '\n'
116
117
118class Debug:     
119    def __init__( self,
120                  #
121                  # active_flags are those that will trigger output
122                  #
123                  active_flags = None, 
124                  #
125                  # Log file should be file object or file namne
126                  #
127                  log_file = sys.stderr,
128                  #
129                  # prefix and sufix can either be set globaly or per call.
130                  # personally I use this to color code debug statements
131                  # with prefix = chr(27) + '[34m'
132                  #      sufix = chr(27) + '[37;1m\n'
133                  #
134                  prefix = color_red + 'DEBUG: ' + color_white, 
135                  sufix = '\n',
136                  #
137                  # If you want unix style timestamps,
138                  #  0 disables timestamps
139                  #  1 before prefix, good when prefix is a string
140                  #  2 after prefix, good when prefix is a color
141                  #
142                  time_stamp = 2,                 
143                  #
144                  # flag_show should normaly be of, but can be turned on to get a
145                  # good view of what flags are actually used for calls,
146                  # if it is not None, it should be a string
147                  # flags for current call will be displayed
148                  # with flag_show as separator                 
149                  # recomended values vould be '-' or ':', but any string goes
150                  #
151                  flag_show = None,
152                  #
153                  # If you dont want to validate flags on each call to
154                  # show(), set this to 0
155                  #
156                  validate_flags = 1,
157                  #
158                  # If you dont want the welcome message, set to 0
159                  # default is to show welcome if any flags are active
160                  welcome = -1,
161                  #
162                  # Non plain-ascii encodings can benefit from it
163                  encoding = None
164                  ):
165
166        if type(active_flags) not in [type([]), type(())]:
167            print  '***' 
168            print  '*** Invalid or oldformat debug param given: %s' % active_flags
169            print  '*** please correct your param, should be of [] type!'
170            print  '*** Due to this, full debuging is enabled'
171            active_flags=[DBG_ALWAYS]
172
173        if welcome == -1:
174            if active_flags and len(active_flags):
175                welcome = 1
176            else:
177                welcome = 0
178           
179        self._remove_dupe_flags()
180        if log_file:
181            if type( log_file ) is type(''):
182                try:
183                    self._fh = open(log_file,'w')
184                except:
185                    print 'ERROR: can open %s for writing'
186                    sys.exit(0)
187            else: ## assume its a stream type object
188                self._fh = log_file
189        else:
190            self._fh = sys.stdout
191         
192        if time_stamp not in (0,1,2):
193            msg2 = '%s' % time_stamp
194            raise 'Invalid time_stamp param', msg2
195        self.prefix = prefix
196        self.sufix = sufix
197        self.time_stamp = time_stamp
198        self.flag_show = None # must be initialised after possible welcome
199        self.validate_flags = validate_flags
200        self.encoding = encoding
201
202        self.active_set( active_flags )
203        if welcome:
204            self.show('')
205            caller = sys._getframe(1) # used to get name of caller
206            try:
207                mod_name= ":%s" % caller.f_locals['__name__']
208            except:
209                mod_name = ""
210            self.show('Debug created for %s%s' % (caller.f_code.co_filename,
211                                                   mod_name ))
212            self.show(' flags defined: %s' % join( self.active ))
213           
214        if type(flag_show) in (type(''), type(None)):
215            self.flag_show = flag_show
216        else:
217            msg2 = '%s' % type(flag_show )
218            raise 'Invalid type for flag_show!', msg2
219
220
221       
222
223
224    def show( self, msg, flag = None, prefix = None, sufix = None,
225              lf = 0 ):
226        """
227        flag can be of folowing types:
228            None - this msg will always be shown if any debugging is on
229            flag - will be shown if flag is active
230            (flag1,flag2,,,) - will be shown if any of the given flags
231                               are active
232
233        if prefix / sufix are not given, default ones from init will be used
234       
235        lf = -1 means strip linefeed if pressent
236        lf = 1 means add linefeed if not pressent
237        """
238       
239        if self.validate_flags:
240            self._validate_flag( flag )
241           
242        if not self.is_active(flag):
243            return
244        if prefix:
245            pre = prefix
246        else:
247            pre = self.prefix
248        if sufix:
249            suf = sufix
250        else:
251            suf = self.sufix
252
253        if self.time_stamp == 2:
254            output = '%s%s ' % ( pre,
255                                 time.strftime('%b %d %H:%M:%S',
256                                 time.localtime(time.time() )),
257                                 )
258        elif self.time_stamp == 1:
259            output = '%s %s' % ( time.strftime('%b %d %H:%M:%S',
260                                 time.localtime(time.time() )),
261                                 pre,
262                                 )
263        else:
264            output = pre
265           
266        if self.flag_show:
267            if flag:
268                output = '%s%s%s' % ( output, flag, self.flag_show )
269            else:
270                # this call uses the global default,
271                # dont print "None", just show the separator
272                output = '%s %s' % ( output, self.flag_show )
273
274        if type(msg)==type(u'') and self.encoding:
275            msg=msg.encode(self.encoding, 'replace')
276
277        output = '%s%s%s' % ( output, msg, suf )
278        if lf:
279            # strip/add lf if needed
280            last_char = output[-1]
281            if lf == 1 and last_char != LINE_FEED:
282                output = output + LINE_FEED
283            elif lf == -1 and last_char == LINE_FEED:
284                output = output[:-1]
285        try:
286            self._fh.write( output )
287        except:
288            # unicode strikes again ;)
289            s=u''
290            for i in range(len(output)):
291                if ord(output[i]) < 128:
292                    c = output[i]
293                else:
294                    c = '?'
295                s=s+c
296            self._fh.write( '%s%s%s' % ( pre, s, suf ))
297        self._fh.flush()
298           
299               
300    def is_active( self, flag ):
301        'If given flag(s) should generate output.'
302
303        # try to abort early to quicken code
304        if not self.active:
305            return 0
306        if not flag or flag in self.active or DBG_ALWAYS in  self.active:
307            return 1
308        else:
309            # check for multi flag type:
310            if type( flag ) in ( type(()), type([]) ):
311                for s in flag:
312                    if s in self.active:
313                        return 1
314        return 0
315
316   
317    def active_set( self, active_flags = None ):
318        "returns 1 if any flags where actually set, otherwise 0."
319        r = 0
320        ok_flags = []
321        if not active_flags:
322            #no debuging at all
323            self.active = []
324        elif type( active_flags ) in ( types.TupleType, types.ListType ):
325            flags = self._as_one_list( active_flags )
326            for t in flags:
327                if t not in debug_flags:
328                    print 'Invalid debugflag given', t
329                else:
330                    ok_flags.append( t )
331               
332            self.active = ok_flags
333            r = 1
334        else:
335            # assume comma string
336            try:
337                flags = active_flags.split(',')
338            except:
339                self.show( '***' )
340                self.show( '*** Invalid debug param given: %s' % active_flags )
341                self.show( '*** please correct your param!' )
342                self.show( '*** due to this, full debuging is enabled' )
343                self.active = debug_flags
344           
345            for f in flags:
346                s = f.strip()
347                ok_flags.append( s )
348            self.active = ok_flags
349
350        self._remove_dupe_flags()
351        return r
352   
353    def active_get( self ):
354        "returns currently active flags."
355        return self.active
356   
357   
358    def _as_one_list( self, items ):
359        """ init param might contain nested lists, typically from group flags.
360       
361        This code organises lst and remves dupes
362        """
363        if type( items ) <> type( [] ) and type( items ) <> type( () ):
364            return [ items ]
365        r = []
366        for l in items:
367            if type( l ) == type([]):
368                lst2 = self._as_one_list( l )
369                for l2 in lst2: 
370                    self._append_unique_str(r, l2 )
371            elif l == None:
372                continue
373            else:
374                self._append_unique_str(r, l )
375        return r
376   
377   
378    def _append_unique_str( self, lst, item ):
379        """filter out any dupes."""
380        if type(item) <> type(''):
381            msg2 = '%s' % item
382            raise 'Invalid item type (should be string)',msg2
383        if item not in lst:
384            lst.append( item )
385        return lst
386
387   
388    def _validate_flag( self, flags ):
389        'verify that flag is defined.'
390        if flags:
391            for f in self._as_one_list( flags ):
392                if not f in debug_flags:
393                    msg2 = '%s' % f
394                    raise 'Invalid debugflag given', msg2
395
396    def _remove_dupe_flags( self ):
397        """
398        if multiple instances of Debug is used in same app,
399        some flags might be created multiple time, filter out dupes
400        """
401        global debug_flags
402       
403        unique_flags = []
404        for f in debug_flags:
405            if f not in unique_flags:
406                unique_flags.append(f)
407        debug_flags = unique_flags
Note: See TracBrowser for help on using the browser.