Package rdkit :: Package Logger :: Module Logger
[hide private]
[frames] | no frames]

Source Code for Module rdkit.Logger.Logger

  1  # $Id: Logger.py 997 2009-02-25 06:12:43Z glandrum $ 
  2  #---------------------------------------------------------------------- 
  3  # Name:        Logger.py 
  4  # Purpose:     Provides a Logger class which can be wrapped around another 
  5  #              python class to log method calls and attribute changes. 
  6  # Requires:    Python 2.0 (or higher?) 
  7  # 
  8  # Author:      greg Landrum (Landrum@RationalDiscovery.com) 
  9  # License: 
 10  # 
 11  #       Copyright (c) 2001-2006 Greg Landrum and Rational Discovery LLC, 
 12  # 
 13  #   @@ All Rights Reserved  @@ 
 14  # 
 15  #---------------------------------------------------------------------- 
 16  """ Provides a Logger class which can be wrapped around another 
 17               python class to log method calls and attribute changes. 
 18  """ 
 19   
 20  import types 
 21  import re 
 22   
 23  reType = type(re.compile('f*')) 
 24  stringTypes = [types.StringType,types.UnicodeType,reType] 
 25                  
26 -def isPresent(what,checkList):
27 """ checks to see if any of the regular expressions in a list match a string 28 29 **Arguments** 30 31 - what: the thing to match against 32 33 - checkList: the list of regexps to try the match with 34 35 **Returns** 36 37 1 or 0 depending upon whether or not _what_ was found in checkList 38 39 **Notes** 40 41 - the search is done using _match_, so we match *any* part of _what_ 42 43 """ 44 for entry in checkList: 45 if type(entry) == reType: 46 if entry.match(what) is not None: 47 return 1 48 else: 49 if what == entry: 50 return 1 51 return 0
52
53 -class Callable(object):
54 """ this is just a simple class with a __call__ method we'll use to pass 55 any method invocations back to the caller. 56 57 """
58 - def __init__(self,log,obj,method):
59 """ Constructor 60 61 **Arguments:** 62 63 - log: a python list (or anything else supporting the append method) 64 which is used to log the actual invocation of a method 65 66 - obj: the object which is calling the method 67 68 - method: the *name* of the method to be invoked 69 70 """ 71 self._obj = obj 72 self._log = log 73 self._method = method
74 - def __call__(self,*args,**kwargs):
75 """ logs the method name and arguments and makes the call 76 77 """ 78 self._log.append((self._method,args,kwargs)) 79 return getattr(self._obj,self._method)(*args,**kwargs)
80
81 -class Logger(object):
82 """ This is the actual wrapper class. 83 84 The wrapper is fairly thin; it only has one methods of its own: 85 86 - _LoggerGetLog() 87 88 and then several instance variables: 89 90 - _loggerFlushCommand 91 92 - _loggerClass 93 94 - _loggerObj 95 96 - _loggerCommandLog 97 98 - _loggerIgnore 99 100 These names were chosen to minimize the likelihood of a collision 101 with the attributes of a wrapped class. Obviously... ;-) 102 103 The general idea of using this is that you wrap a class in the logger, 104 and then use the class as you normally would. Whenever you want to 105 get the contents of the log (for example after running your program for 106 a while), you can call _loggerCommandLog. The resulting list can be 107 played back in another (or the same) object using the replay() function 108 defined below. 109 110 The logger can, optionally, be set to flush its log whenever a method with 111 a particular name is invoked. For example, you may want to be wrapping 112 some kind of drawing canvas and want to reset the log whenever the canvas 113 is cleared because there's no point in storing commands which will have 114 no effect on the final drawing. 115 116 **Note** 117 118 because of the way I've worked this, the log will actually be flushed 119 whenever the client program accesses the flush method, it need not be invoked. 120 i.e. if the loggerFlushCommand is 'foo', then doing either wrappedObj.foo() or 121 wrappedObj.foo will reset the log. This is undesirable and will most likely 122 be fixed in a future version 123 124 """
125 - def __init__(self,klass,*args,**kwargs):
126 """ Constructor 127 128 **Arguments** 129 130 The one required argument here is _klass_, which is the class 131 to be wrapped. 132 133 **Optional Keyword Arguments** 134 135 - loggerFlushCommand: the name of the attribute which will flush the log 136 137 - loggerIgnore: a list of regexps defining methods which should not be 138 logged 139 140 **All other arguments are passed to the constructor for _klass_ ** 141 142 """ 143 if kwargs.has_key('loggerFlushCommand'): 144 self.__dict__['_loggerFlushCommand'] = kwargs['loggerFlushCommand'] 145 del kwargs['loggerFlushCommand'] 146 else: 147 self.__dict__['_loggerFlushCommand'] = None 148 if kwargs.has_key('loggerIgnore'): 149 tempL = kwargs['loggerIgnore'] 150 for entry in tempL: 151 if type(entry) not in stringTypes: 152 raise ValueError,'All entries in loggerIgnore must be either strings or regexps' 153 self.__dict__['_loggerIgnore'] = tempL 154 del kwargs['loggerIgnore'] 155 else: 156 self.__dict__['_loggerIgnore'] = [] 157 self.__dict__['_loggerClass'] = klass 158 self.__dict__['_loggerObj'] = klass(*args,**kwargs) 159 self.__dict__['_loggerCommandLog'] = []
160
161 - def _LoggerGetLog(self):
162 """ Returns the contents of the command log as a python list 163 164 """ 165 return self._loggerCommandLog
166
167 - def __getattr__(self,which):
168 """ here's where the logging of method invocations takes place 169 170 """ 171 if hasattr(self._loggerObj,which): 172 tmpAttr = getattr(self._loggerObj,which) 173 if type(tmpAttr) == types.MethodType: 174 loggerFlushCommand = self._loggerFlushCommand 175 if which == loggerFlushCommand: 176 self._loggerCommandLog = [] 177 return Callable([],self._loggerObj,which) 178 elif self._loggerIgnore != [] and isPresent(which,self._loggerIgnore): 179 return Callable([],self._loggerObj,which) 180 else: 181 return Callable(self._loggerCommandLog,self._loggerObj,which) 182 else: 183 return tmpAttr 184 else: 185 raise AttributeError, '%s instance has no attribute %s'%(repr(self._loggerClass.__name__),repr(which))
186
187 - def __setattr__(self,which,val):
188 """ setattr calls (i.e. wrappedObject.foo = 1) are also logged 189 190 """ 191 d = self.__dict__ 192 if d.has_key(which): 193 d[which] = val 194 else: 195 self._loggerCommandLog.append((setattr,which,val)) 196 setattr(self._loggerObj,which,val) 197 return val
198
199 -def replay(logItems,obj):
200 """ loops through the items in a Logger log list and invokes 201 them in obj 202 203 **Arguments** 204 205 - logItems: a list of 3 tuples containing: 206 207 1) method name 208 209 2) tuple of positional arguments 210 211 3) dictionary of keyword arguments 212 213 - obj: the object in which the log should be replayed 214 215 **Returns** 216 217 a list with the the return values of all the method 218 invocations/attribute assignments 219 220 """ 221 if isinstance(logItems,Logger): 222 logItems = logItems._LoggerGetLog() 223 resList = [] 224 for method,a1,a2 in logItems: 225 if callable(method): 226 if method == setattr: 227 method(obj,a1,a2) 228 resList.append(a2) 229 else: 230 resList.append(method(obj,a1,a2)) 231 else: 232 a = getattr(obj,method) 233 resList.append(apply(a,a1,a2)) 234 return resList
235