3 XXX This is very much a work in progress.
10 """Metaclass for tracing.
12 Classes defined using this metaclass have an automatic tracing
13 feature -- by setting the __trace_output__ instance (or class)
14 variable to a file object, trace messages about all calls are
15 written to the file. The trace formatting can be changed by
16 defining a suitable __trace_call__ method.
22 def __init__(self
, name
, bases
, dict):
24 self
.__bases
__ = bases
26 # XXX Can't define __dict__, alas
29 def __getattr__(self
, name
):
31 return self
.__dict
[name
]
33 for base
in self
.__bases
__:
35 return base
.__getattr
__(name
)
36 except AttributeError:
38 raise AttributeError, name
40 def __setattr__(self
, name
, value
):
42 self
.__dict
__[name
] = value
44 self
.__dict
[name
] = value
46 def __call__(self
, *args
, **kw
):
47 inst
= TracingInstance()
48 inst
.__meta
_init
__(self
)
50 init
= inst
.__getattr
__('__init__')
51 except AttributeError:
56 __trace_output__
= None
58 class TracingInstance
:
59 """Helper class to represent an instance of a tracing class."""
61 def __trace_call__(self
, fp
, fmt
, *args
):
62 fp
.write((fmt
+'\n') % args
)
64 def __meta_init__(self
, klass
):
67 def __getattr__(self
, name
):
68 # Invoked for any attr not in the instance's __dict__
70 raw
= self
.__class
.__getattr
__(name
)
71 except AttributeError:
72 raise AttributeError, name
73 if type(raw
) != types
.FunctionType
:
76 fullname
= self
.__class
.__name
__ + "." + name
77 if not self
.__trace
_output
__ or name
== '__trace_call__':
78 return NotTracingWrapper(fullname
, raw
, self
)
80 return TracingWrapper(fullname
, raw
, self
)
82 class NotTracingWrapper
:
83 def __init__(self
, name
, func
, inst
):
87 def __call__(self
, *args
, **kw
):
88 return apply(self
.func
, (self
.inst
,) + args
, kw
)
90 class TracingWrapper(NotTracingWrapper
):
91 def __call__(self
, *args
, **kw
):
92 self
.inst
.__trace
_call
__(self
.inst
.__trace
_output
__,
93 "calling %s, inst=%s, args=%s, kw=%s",
94 self
.__name
__, self
.inst
, args
, kw
)
96 rv
= apply(self
.func
, (self
.inst
,) + args
, kw
)
98 t
, v
, tb
= sys
.exc_info()
99 self
.inst
.__trace
_call
__(self
.inst
.__trace
_output
__,
100 "returning from %s with exception %s: %s",
104 self
.inst
.__trace
_call
__(self
.inst
.__trace
_output
__,
105 "returning from %s with value %s",
109 Traced
= TraceMetaClass('Traced', (), {'__trace_output__': None})
115 def __init__(self
, x
=0): self
.x
= x
116 def m1(self
, x
): self
.x
= x
117 def m2(self
, y
): return self
.x
+ y
118 __trace_output__
= sys
.stdout
120 def m2(self
, y
): print "D.m2(%s)" % `y`
; return C
.m2(self
, y
)
121 __trace_output__
= None
143 if __name__
== '__main__':