From d5b4e556e1a683f7461e8f475851e2181b995712 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Fri, 27 Sep 2013 19:29:50 +0200 Subject: [PATCH] dos2unix'ed for ^M at EOL --- manifold/util/autolog.py | 844 +++++++++++++++++++-------------------- 1 file changed, 422 insertions(+), 422 deletions(-) diff --git a/manifold/util/autolog.py b/manifold/util/autolog.py index 70c5c056..e88b6f33 100644 --- a/manifold/util/autolog.py +++ b/manifold/util/autolog.py @@ -1,422 +1,422 @@ -# Written by Brendan O'Connor, brenocon@gmail.com, www.anyall.org -# * Originally written Aug. 2005 -# * Posted to gist.github.com/16173 on Oct. 2008 - -# Copyright (c) 2003-2006 Open Source Applications Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import re, sys, types - -""" -Have all your function & method calls automatically logged, in indented outline -form - unlike the stack snapshots in an interactive debugger, it tracks call -structure & stack depths across time! - -It hooks into all function calls that you specify, and logs each time they're -called. I find it especially useful when I don't know what's getting called -when, or need to continuously test for state changes. (by hacking this file) - -Originally inspired from the python cookbook: -http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/198078 - -Currently you can - - tag functions or individual methods to be autologged - - tag an entire class's methods to be autologged - - tag an entire module's classes and functions to be autologged - -TODO: - - allow tagging of ALL modules in the program on startup? - -CAVEATS: - - certain classes barf when you logclass() them -- most notably, - SWIG-generated wrappers, and perhaps others. - -USAGE: see examples on the bottom of this file. - - -Viewing tips -============ - -If your terminal can't keep up, try xterm or putty, they seem to be highest -performance. xterm is available for all platforms through X11... - -Also try: (RunChandler > log &); tail -f log - -Also, you can "less -R log" afterward and get the colors correct. - -If you have long lines, less -RS kills wrapping, enhancing readability. Also -can chop at formatAllArgs(). - -If you want long lines to be chopped realtime, try piping through less:: - - RunChandler | less -RS - -but then you have to hit 'space' lots to prevent chandler from freezing. -less's 'F' command is supposed to do this correctly but doesn't work for me. -""" - - -#@@@ should use the standard python logging system? -log = sys.stdout - -# Globally incremented across function calls, so tracks stack depth -indent = 0 -indStr = ' ' - - -# ANSI escape codes for terminals. -# X11 xterm: always works, all platforms -# cygwin dosbox: run through |cat and then colors work -# linux: works on console & gnome-terminal -# mac: untested - - -BLACK = "\033[0;30m" -BLUE = "\033[0;34m" -GREEN = "\033[0;32m" -CYAN = "\033[0;36m" -RED = "\033[0;31m" -PURPLE = "\033[0;35m" -BROWN = "\033[0;33m" -GRAY = "\033[0;37m" -BOLDGRAY = "\033[1;30m" -BOLDBLUE = "\033[1;34m" -BOLDGREEN = "\033[1;32m" -BOLDCYAN = "\033[1;36m" -BOLDRED = "\033[1;31m" -BOLDPURPLE = "\033[1;35m" -BOLDYELLOW = "\033[1;33m" -WHITE = "\033[1;37m" - -NORMAL = "\033[0m" - - -def indentlog(message): - global log, indStr, indent - print >>log, "%s%s" %(indStr*indent, message) - log.flush() - -def shortstr(obj): - """ - Where to put gritty heuristics to make an object appear in most useful - form. defaults to __str__. - """ - if "wx." in str(obj.__class__) or obj.__class__.__name__.startswith("wx"): - shortclassname = obj.__class__.__name__ - ##shortclassname = str(obj.__class__).split('.')[-1] - if hasattr(obj, "blockItem") and hasattr(obj.blockItem, "blockName"): - moreInfo = "block:'%s'" %obj.blockItem.blockName - else: - moreInfo = "at %d" %id(obj) - return "<%s %s>" % (shortclassname, moreInfo) - else: - return str(obj) - -def formatAllArgs(args, kwds): - """ - makes a nice string representation of all the arguments - """ - allargs = [] - for item in args: - allargs.append('%s' % shortstr(item)) - for key,item in kwds.items(): - allargs.append('%s=%s' % (key,shortstr(item))) - formattedArgs = ', '.join(allargs) - if len(formattedArgs) > 150: - return formattedArgs[:146] + " ..." - return formattedArgs - - -def logmodules(listOfModules): - for m in listOfModules: - bindmodule(m) - -def logmodule(module, logMatch=".*", logNotMatch="nomatchasfdasdf"): - """ - WARNING: this seems to break if you import SWIG wrapper classes - directly into the module namespace ... logclass() creates weirdness when - used on them, for some reason. - - @param module: could be either an actual module object, or the string - you can import (which seems to be the same thing as its - __name__). So you can say logmodule(__name__) at the end - of a module definition, to log all of it. - """ - - allow = lambda s: re.match(logMatch, s) and not re.match(logNotMatch, s) - - if isinstance(module, str): - d = {} - exec "import %s" % module in d - import sys - module = sys.modules[module] - - names = module.__dict__.keys() - for name in names: - if not allow(name): continue - - value = getattr(module, name) - if isinstance(value, type): - setattr(module, name, logclass(value)) - print>>log,"autolog.logmodule(): bound %s" %name - elif isinstance(value, types.FunctionType): - setattr(module, name, logfunction(value)) - print>>log,"autolog.logmodule(): bound %s" %name - -def logfunction(theFunction, displayName=None): - """a decorator.""" - if not displayName: displayName = theFunction.__name__ - - def _wrapper(*args, **kwds): - global indent - argstr = formatAllArgs(args, kwds) - - # Log the entry into the function - indentlog("%s%s%s (%s) " % (BOLDRED,displayName,NORMAL, argstr)) - log.flush() - - indent += 1 - returnval = theFunction(*args,**kwds) - indent -= 1 - - # Log return - ##indentlog("return: %s"% shortstr(returnval) - return returnval - return _wrapper - -def logmethod(theMethod, displayName=None): - """use this for class or instance methods, it formats with the object out front.""" - if not displayName: displayName = theMethod.__name__ - def _methodWrapper(self, *args, **kwds): - "Use this one for instance or class methods" - global indent - - argstr = formatAllArgs(args, kwds) - selfstr = shortstr(self) - - #print >> log,"%s%s. %s (%s) " % (indStr*indent,selfstr,methodname,argstr) - indentlog("%s.%s%s%s (%s) " % (selfstr, BOLDRED,theMethod.__name__,NORMAL, argstr)) - log.flush() - - indent += 1 - - if theMethod.__name__ == 'OnSize': - indentlog("position, size = %s%s %s%s" %(BOLDBLUE, self.GetPosition(), self.GetSize(), NORMAL)) - - returnval = theMethod(self, *args,**kwds) - - indent -= 1 - - return returnval - return _methodWrapper - - -def logclass(cls, methodsAsFunctions=False, - logMatch=".*", logNotMatch="asdfnomatch"): - """ - A class "decorator". But python doesn't support decorator syntax for - classes, so do it manually:: - - class C(object): - ... - C = logclass(C) - - @param methodsAsFunctions: set to True if you always want methodname first - in the display. Probably breaks if you're using class/staticmethods? - """ - - allow = lambda s: re.match(logMatch, s) and not re.match(logNotMatch, s) and \ - s not in ('__str__','__repr__') - - namesToCheck = cls.__dict__.keys() - - for name in namesToCheck: - if not allow(name): continue - # unbound methods show up as mere functions in the values of - # cls.__dict__,so we have to go through getattr - value = getattr(cls, name) - - if methodsAsFunctions and callable(value): - setattr(cls, name, logfunction(value)) - elif isinstance(value, types.MethodType): - #a normal instance method - if value.im_self == None: - setattr(cls, name, logmethod(value)) - - #class & static method are more complex. - #a class method - elif value.im_self == cls: - w = logmethod(value.im_func, - displayName="%s.%s" %(cls.__name__, value.__name__)) - setattr(cls, name, classmethod(w)) - else: assert False - - #a static method - elif isinstance(value, types.FunctionType): - w = logfunction(value, - displayName="%s.%s" %(cls.__name__, value.__name__)) - setattr(cls, name, staticmethod(w)) - return cls - -class LogMetaClass(type): - """ - Alternative to logclass(), you set this as a class's __metaclass__. - - It will not work if the metaclass has already been overridden (e.g. - schema.Item or zope.interface (used in Twisted) - - Also, it should fail for class/staticmethods, that hasnt been added here - yet. - """ - - def __new__(cls,classname,bases,classdict): - logmatch = re.compile(classdict.get('logMatch','.*')) - lognotmatch = re.compile(classdict.get('logNotMatch', 'nevermatchthisstringasdfasdf')) - - for attr,item in classdict.items(): - if callable(item) and logmatch.match(attr) and not lognotmatch.match(attr): - classdict['_H_%s'%attr] = item # rebind the method - classdict[attr] = logmethod(item) # replace method by wrapper - - return type.__new__(cls,classname,bases,classdict) - - - -# ---------------------------- Tests and examples ---------------------------- - -if __name__=='__main__': - print; print "------------------- single function logging ---------------" - @logfunction - def test(): - return 42 - - test() - - print; print "------------------- single method logging -----------------" - class Test1(object): - def __init__(self): - self.a = 10 - - @logmethod - def add(self,a,b): return a+b - - @logmethod - def fac(self,val): - if val == 1: - return 1 - else: - return val * self.fac(val-1) - - @logfunction - def fac2(self, val): - if val == 1: - return 1 - else: - return val * self.fac2(val-1) - - t = Test1() - t.add(5,6) - t.fac(4) - print "--- tagged as @logfunction, doesn't understand 'self' is special:" - t.fac2(4) - - - print; print """-------------------- class "decorator" usage ------------------""" - class Test2(object): - #will be ignored - def __init__(self): - self.a = 10 - def ignoreThis(self): pass - - - def add(self,a,b):return a+b - def fac(self,val): - if val == 1: - return 1 - else: - return val * self.fac(val-1) - - Test2 = logclass(Test2, logMatch='fac|add') - - t2 = Test2() - t2.add(5,6) - t2.fac(4) - t2.ignoreThis() - - - print; print "-------------------- metaclass usage ------------------" - class Test3(object): - __metaclass__ = LogMetaClass - logNotMatch = 'ignoreThis' - - def __init__(self): pass - - def fac(self,val): - if val == 1: - return 1 - else: - return val * self.fac(val-1) - def ignoreThis(self): pass - t3 = Test3() - t3.fac(4) - t3.ignoreThis() - - print; print "-------------- testing static & classmethods --------------" - class Test4(object): - @classmethod - def cm(cls, a, b): - print cls - return a+b - - def im(self, a, b): - print self - return a+b - - @staticmethod - def sm(a,b): return a+b - - Test4 = logclass(Test4) - - Test4.cm(4,3) - Test4.sm(4,3) - - t4 = Test4() - t4.im(4,3) - t4.sm(4,3) - t4.cm(4,3) - - #print; print "-------------- static & classmethods: where to put decorators? --------------" - #class Test5(object): - #@classmethod - #@logmethod - #def cm(cls, a, b): - #print cls - #return a+b - #@logmethod - #def im(self, a, b): - #print self - #return a+b - - #@staticmethod - #@logfunction - #def sm(a,b): return a+b - - - #Test5.cm(4,3) - #Test5.sm(4,3) - - #t5 = Test5() - #t5.im(4,3) - #t5.sm(4,3) - #t5.cm(4,3) +# Written by Brendan O'Connor, brenocon@gmail.com, www.anyall.org +# * Originally written Aug. 2005 +# * Posted to gist.github.com/16173 on Oct. 2008 + +# Copyright (c) 2003-2006 Open Source Applications Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re, sys, types + +""" +Have all your function & method calls automatically logged, in indented outline +form - unlike the stack snapshots in an interactive debugger, it tracks call +structure & stack depths across time! + +It hooks into all function calls that you specify, and logs each time they're +called. I find it especially useful when I don't know what's getting called +when, or need to continuously test for state changes. (by hacking this file) + +Originally inspired from the python cookbook: +http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/198078 + +Currently you can + - tag functions or individual methods to be autologged + - tag an entire class's methods to be autologged + - tag an entire module's classes and functions to be autologged + +TODO: + - allow tagging of ALL modules in the program on startup? + +CAVEATS: + - certain classes barf when you logclass() them -- most notably, + SWIG-generated wrappers, and perhaps others. + +USAGE: see examples on the bottom of this file. + + +Viewing tips +============ + +If your terminal can't keep up, try xterm or putty, they seem to be highest +performance. xterm is available for all platforms through X11... + +Also try: (RunChandler > log &); tail -f log + +Also, you can "less -R log" afterward and get the colors correct. + +If you have long lines, less -RS kills wrapping, enhancing readability. Also +can chop at formatAllArgs(). + +If you want long lines to be chopped realtime, try piping through less:: + + RunChandler | less -RS + +but then you have to hit 'space' lots to prevent chandler from freezing. +less's 'F' command is supposed to do this correctly but doesn't work for me. +""" + + +#@@@ should use the standard python logging system? +log = sys.stdout + +# Globally incremented across function calls, so tracks stack depth +indent = 0 +indStr = ' ' + + +# ANSI escape codes for terminals. +# X11 xterm: always works, all platforms +# cygwin dosbox: run through |cat and then colors work +# linux: works on console & gnome-terminal +# mac: untested + + +BLACK = "\033[0;30m" +BLUE = "\033[0;34m" +GREEN = "\033[0;32m" +CYAN = "\033[0;36m" +RED = "\033[0;31m" +PURPLE = "\033[0;35m" +BROWN = "\033[0;33m" +GRAY = "\033[0;37m" +BOLDGRAY = "\033[1;30m" +BOLDBLUE = "\033[1;34m" +BOLDGREEN = "\033[1;32m" +BOLDCYAN = "\033[1;36m" +BOLDRED = "\033[1;31m" +BOLDPURPLE = "\033[1;35m" +BOLDYELLOW = "\033[1;33m" +WHITE = "\033[1;37m" + +NORMAL = "\033[0m" + + +def indentlog(message): + global log, indStr, indent + print >>log, "%s%s" %(indStr*indent, message) + log.flush() + +def shortstr(obj): + """ + Where to put gritty heuristics to make an object appear in most useful + form. defaults to __str__. + """ + if "wx." in str(obj.__class__) or obj.__class__.__name__.startswith("wx"): + shortclassname = obj.__class__.__name__ + ##shortclassname = str(obj.__class__).split('.')[-1] + if hasattr(obj, "blockItem") and hasattr(obj.blockItem, "blockName"): + moreInfo = "block:'%s'" %obj.blockItem.blockName + else: + moreInfo = "at %d" %id(obj) + return "<%s %s>" % (shortclassname, moreInfo) + else: + return str(obj) + +def formatAllArgs(args, kwds): + """ + makes a nice string representation of all the arguments + """ + allargs = [] + for item in args: + allargs.append('%s' % shortstr(item)) + for key,item in kwds.items(): + allargs.append('%s=%s' % (key,shortstr(item))) + formattedArgs = ', '.join(allargs) + if len(formattedArgs) > 150: + return formattedArgs[:146] + " ..." + return formattedArgs + + +def logmodules(listOfModules): + for m in listOfModules: + bindmodule(m) + +def logmodule(module, logMatch=".*", logNotMatch="nomatchasfdasdf"): + """ + WARNING: this seems to break if you import SWIG wrapper classes + directly into the module namespace ... logclass() creates weirdness when + used on them, for some reason. + + @param module: could be either an actual module object, or the string + you can import (which seems to be the same thing as its + __name__). So you can say logmodule(__name__) at the end + of a module definition, to log all of it. + """ + + allow = lambda s: re.match(logMatch, s) and not re.match(logNotMatch, s) + + if isinstance(module, str): + d = {} + exec "import %s" % module in d + import sys + module = sys.modules[module] + + names = module.__dict__.keys() + for name in names: + if not allow(name): continue + + value = getattr(module, name) + if isinstance(value, type): + setattr(module, name, logclass(value)) + print>>log,"autolog.logmodule(): bound %s" %name + elif isinstance(value, types.FunctionType): + setattr(module, name, logfunction(value)) + print>>log,"autolog.logmodule(): bound %s" %name + +def logfunction(theFunction, displayName=None): + """a decorator.""" + if not displayName: displayName = theFunction.__name__ + + def _wrapper(*args, **kwds): + global indent + argstr = formatAllArgs(args, kwds) + + # Log the entry into the function + indentlog("%s%s%s (%s) " % (BOLDRED,displayName,NORMAL, argstr)) + log.flush() + + indent += 1 + returnval = theFunction(*args,**kwds) + indent -= 1 + + # Log return + ##indentlog("return: %s"% shortstr(returnval) + return returnval + return _wrapper + +def logmethod(theMethod, displayName=None): + """use this for class or instance methods, it formats with the object out front.""" + if not displayName: displayName = theMethod.__name__ + def _methodWrapper(self, *args, **kwds): + "Use this one for instance or class methods" + global indent + + argstr = formatAllArgs(args, kwds) + selfstr = shortstr(self) + + #print >> log,"%s%s. %s (%s) " % (indStr*indent,selfstr,methodname,argstr) + indentlog("%s.%s%s%s (%s) " % (selfstr, BOLDRED,theMethod.__name__,NORMAL, argstr)) + log.flush() + + indent += 1 + + if theMethod.__name__ == 'OnSize': + indentlog("position, size = %s%s %s%s" %(BOLDBLUE, self.GetPosition(), self.GetSize(), NORMAL)) + + returnval = theMethod(self, *args,**kwds) + + indent -= 1 + + return returnval + return _methodWrapper + + +def logclass(cls, methodsAsFunctions=False, + logMatch=".*", logNotMatch="asdfnomatch"): + """ + A class "decorator". But python doesn't support decorator syntax for + classes, so do it manually:: + + class C(object): + ... + C = logclass(C) + + @param methodsAsFunctions: set to True if you always want methodname first + in the display. Probably breaks if you're using class/staticmethods? + """ + + allow = lambda s: re.match(logMatch, s) and not re.match(logNotMatch, s) and \ + s not in ('__str__','__repr__') + + namesToCheck = cls.__dict__.keys() + + for name in namesToCheck: + if not allow(name): continue + # unbound methods show up as mere functions in the values of + # cls.__dict__,so we have to go through getattr + value = getattr(cls, name) + + if methodsAsFunctions and callable(value): + setattr(cls, name, logfunction(value)) + elif isinstance(value, types.MethodType): + #a normal instance method + if value.im_self == None: + setattr(cls, name, logmethod(value)) + + #class & static method are more complex. + #a class method + elif value.im_self == cls: + w = logmethod(value.im_func, + displayName="%s.%s" %(cls.__name__, value.__name__)) + setattr(cls, name, classmethod(w)) + else: assert False + + #a static method + elif isinstance(value, types.FunctionType): + w = logfunction(value, + displayName="%s.%s" %(cls.__name__, value.__name__)) + setattr(cls, name, staticmethod(w)) + return cls + +class LogMetaClass(type): + """ + Alternative to logclass(), you set this as a class's __metaclass__. + + It will not work if the metaclass has already been overridden (e.g. + schema.Item or zope.interface (used in Twisted) + + Also, it should fail for class/staticmethods, that hasnt been added here + yet. + """ + + def __new__(cls,classname,bases,classdict): + logmatch = re.compile(classdict.get('logMatch','.*')) + lognotmatch = re.compile(classdict.get('logNotMatch', 'nevermatchthisstringasdfasdf')) + + for attr,item in classdict.items(): + if callable(item) and logmatch.match(attr) and not lognotmatch.match(attr): + classdict['_H_%s'%attr] = item # rebind the method + classdict[attr] = logmethod(item) # replace method by wrapper + + return type.__new__(cls,classname,bases,classdict) + + + +# ---------------------------- Tests and examples ---------------------------- + +if __name__=='__main__': + print; print "------------------- single function logging ---------------" + @logfunction + def test(): + return 42 + + test() + + print; print "------------------- single method logging -----------------" + class Test1(object): + def __init__(self): + self.a = 10 + + @logmethod + def add(self,a,b): return a+b + + @logmethod + def fac(self,val): + if val == 1: + return 1 + else: + return val * self.fac(val-1) + + @logfunction + def fac2(self, val): + if val == 1: + return 1 + else: + return val * self.fac2(val-1) + + t = Test1() + t.add(5,6) + t.fac(4) + print "--- tagged as @logfunction, doesn't understand 'self' is special:" + t.fac2(4) + + + print; print """-------------------- class "decorator" usage ------------------""" + class Test2(object): + #will be ignored + def __init__(self): + self.a = 10 + def ignoreThis(self): pass + + + def add(self,a,b):return a+b + def fac(self,val): + if val == 1: + return 1 + else: + return val * self.fac(val-1) + + Test2 = logclass(Test2, logMatch='fac|add') + + t2 = Test2() + t2.add(5,6) + t2.fac(4) + t2.ignoreThis() + + + print; print "-------------------- metaclass usage ------------------" + class Test3(object): + __metaclass__ = LogMetaClass + logNotMatch = 'ignoreThis' + + def __init__(self): pass + + def fac(self,val): + if val == 1: + return 1 + else: + return val * self.fac(val-1) + def ignoreThis(self): pass + t3 = Test3() + t3.fac(4) + t3.ignoreThis() + + print; print "-------------- testing static & classmethods --------------" + class Test4(object): + @classmethod + def cm(cls, a, b): + print cls + return a+b + + def im(self, a, b): + print self + return a+b + + @staticmethod + def sm(a,b): return a+b + + Test4 = logclass(Test4) + + Test4.cm(4,3) + Test4.sm(4,3) + + t4 = Test4() + t4.im(4,3) + t4.sm(4,3) + t4.cm(4,3) + + #print; print "-------------- static & classmethods: where to put decorators? --------------" + #class Test5(object): + #@classmethod + #@logmethod + #def cm(cls, a, b): + #print cls + #return a+b + #@logmethod + #def im(self, a, b): + #print self + #return a+b + + #@staticmethod + #@logfunction + #def sm(a,b): return a+b + + + #Test5.cm(4,3) + #Test5.sm(4,3) + + #t5 = Test5() + #t5.im(4,3) + #t5.sm(4,3) + #t5.cm(4,3) -- 2.43.0