X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FcallerName.py;h=9fd0308f8088e21f9afb4a4ac65476a27e174db9;hb=d828b7da029994130b3717855155e49d58ee87ea;hp=6c4140c9b7ffa3d6d22fbb23ffd93cadc52cdf4b;hpb=606f9b6618e0e0659d4029c607eaa04d9b3501cc;p=tools%2Fsat.git diff --git a/src/callerName.py b/src/callerName.py index 6c4140c..9fd0308 100644 --- a/src/callerName.py +++ b/src/callerName.py @@ -5,47 +5,169 @@ # Public Domain, i.e. feel free to copy/paste # Considered a hack in Python 2 +import os +import sys import inspect import logging -import sys +import pprint as PP + + +############################################################################## +def caller_name_simple(skip=1): + """ + Get a name of a caller in the format module.class.method + + 'skip' specifies how many levels of stack to skip while getting caller + name. skip=1 means 'who calls me', skip=2 'who calls my caller' etc. + + An empty string is returned if skipped levels exceed stack height + """ + + def stack_(frame): + framelist = [] + while frame: + framelist.append(frame) + frame = frame.f_back + return framelist + + stack = stack_(sys._getframe(1)) + start = 0 + skip + if len(stack) < start + 1: + return '' + parentframe = stack[start] + + name = [] + module = inspect.getmodule(parentframe) + # `modname` can be None when frame is executed directly in console + # TODO(techtonik): consider using __main__ + if module: + name.append(module.__name__) + # detect classname + if 'self' in parentframe.f_locals: + # I don't know any way to detect call from the object method + # XXX: there seems to be no way to detect static method call - it will + # be just a function call + name.append(parentframe.f_locals['self'].__class__.__name__) + codename = parentframe.f_code.co_name + + fr = inspect.currentframe().f_back + for i in range(skip): # no more 20 for precaution + fr = fr.f_back + if fr is None: + break + lineno = fr.f_lineno + + if codename != '': # top level usually + name.append(codename) + + name[-1] += "[%s]" % str(lineno) # function or a method + del parentframe + return ".".join(name) + + +############################################################################## +def caller_name_stack(skip=1): + """ + Get a name of a caller in the format module[no].class[no].method[no] + where [no] is line nunber in source file(s) + + 'skip' specifies how many levels of stack to skip while getting caller + name. skip=1 means 'who calls me', skip=2 'who calls my caller' etc. + + An empty string is returned if skipped levels exceed stack height + """ + def stack_(frame): + framelist = [] + while frame: + framelist.append(frame) + frame = frame.f_back + return framelist + + stack = stack_(sys._getframe(1)) + start = 0 + skip + if len(stack) < start + 1: + return '' + parentframe = stack[start] + + name = [] + module = inspect.getmodule(parentframe) + # `modname` can be None when frame is executed directly in console + # TODO(techtonik): consider using __main__ + if module: + name.append(module.__name__) + # detect classname + if 'self' in parentframe.f_locals: + # I don't know any way to detect call from the object method + # XXX: there seems to be no way to detect static method call - it will + # be just a function call + name.append(parentframe.f_locals['self'].__class__.__name__) + codename = parentframe.f_code.co_name + + fr = inspect.currentframe().f_back + lineno = [fr.f_lineno] + for i in range(20): # no more 20 for precaution + fr = fr.f_back + if fr is None: + break + #print("*** frame locals %s" % str(fr.f_locals.keys())) + #print("*** frame globals %s" % str(fr.f_globals.keys())) + try: + namesrc = fr.f_globals["__name__"] + if namesrc == "__main__": + namesrc = os.path.basename(fr.f_globals["__file__"]) + lineno.insert(0, (namesrc + "[%s]" % fr.f_lineno)) + except: + lineno.insert(0, ("??", fr.f_lineno)) + + if codename != '': # top level usually + name.append(codename) # function or a method + + #print("lineno", lineno) + #print("name", name) + + name[-1] += " // STACK: %s" % " ".join(lineno[0:-1]) + + del parentframe + return ".".join(name) + + +############################################################################## +def example_of_use(toCall): + """ + example of use caller_name_simple, or else + """ + class Dummy: + def one_method(self): + print("4- call in class %s" % toCall(0)) + + print("1- call in %s" % toCall(0)) # output from main to here + print("2- call in %s" % toCall(0)) + print("3- call in %s" % toCall(1)) # output from main to caller + tmp = Dummy() + tmp.one_method() + + +############################################################################## +# main as an example +############################################################################## +if __name__ == "__main__": + example_of_use(caller_name_simple) + example_of_use(caller_name_stack) + +""" +example of output + +1- call in __main__.example_of_use[143] +2- call in __main__.example_of_use[144] +3- call in __main__[154] +4- call in class __main__.Dummy.one_method[141] +1- call in __main__.example_of_use // STACK: callerName.py[155] +2- call in __main__.example_of_use // STACK: callerName.py[155] +3- call in __main__ // STACK: callerName.py[155] +4- call in class __main__.Dummy.one_method // STACK: callerName.py[155] callerName.py[147] +""" -def caller_name(skip=1): - """Get a name of a caller in the format module.class.method - - `skip` specifies how many levels of stack to skip while getting caller - name. skip=1 means "who calls me", skip=2 "who calls my caller" etc. - - An empty string is returned if skipped levels exceed stack height - """ - def stack_(frame): - framelist = [] - while frame: - framelist.append(frame) - frame = frame.f_back - return framelist - - stack = stack_(sys._getframe(1)) - start = 0 + skip - if len(stack) < start + 1: - return '' - parentframe = stack[start] - - name = [] - module = inspect.getmodule(parentframe) - # `modname` can be None when frame is executed directly in console - # TODO(techtonik): consider using __main__ - if module: - name.append(module.__name__) - # detect classname - if 'self' in parentframe.f_locals: - # I don't know any way to detect call from the object method - # XXX: there seems to be no way to detect static method call - it will - # be just a function call - name.append(parentframe.f_locals['self'].__class__.__name__) - codename = parentframe.f_code.co_name - lineno = inspect.currentframe().f_back.f_back.f_lineno - if codename != '': # top level usually - name.append(codename + "[%s]" % str(lineno)) # function or a method - del parentframe - return ".".join(name) \ No newline at end of file +# here default caller_name is user choice... +caller_name = caller_name_simple # not so verbose +# caller_name = caller_name_stack # more verbose, with stack