import re string = '' def d1(*args): global string string += ' '.join(['d1 outter', str(args)]) + "\n" def inner(*args): global string string += ' '.join(['d1 inner', str(args)]) + "\n" return args[0] return inner def d2(*args): global string string += ' '.join(['d2 outter', str(args)]) + "\n" def inner(*args): global string string += ' '.join(['d2 inner', str(args)]) + "\n" return args[0] return inner def d3(*args): global string string += ' '.join(['d3 outter', str(args)]) + "\n" def inner(*args): global string string += ' '.join(['d3 inner', str(args)]) + "\n" return args[0] return inner def d4(*args): global string string += ' '.join(['d4 outter', str(args)]) + "\n" def inner(*args): global string string += ' '.join(['d4 inner', str(args)]) + "\n" return args[0] return inner @d1() @d2() class Test1(): global string string += 'test1 start\n' @d3() @d4() def test2(_): global string string += 'test2\n' return 'test2 return' string += 'test1 end\n' # todo check function ids expect = re.compile(r''' ^d1 outter \(\) d2 outter \(\) test1 start d3 outter \(\) d4 outter \(\) d4 inner \(,\) d3 inner \(,\) test1 end d2 inner \(,\) d1 inner \(,\) instantiate test1 run test2 method test2 return$ '''.strip()) string += 'instantiate test1\n' test1 = Test1() string += 'run test2 method\n' string += test1.test2() print(string) assert expect.search(string)