symbian-qemu-0.9.1-12/python-2.6.1/Demo/metaclasses/Trace.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Tracing metaclass.
       
     2 
       
     3 XXX This is very much a work in progress.
       
     4 
       
     5 """
       
     6 
       
     7 import types, sys
       
     8 
       
     9 class TraceMetaClass:
       
    10     """Metaclass for tracing.
       
    11 
       
    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.
       
    17 
       
    18     """
       
    19 
       
    20     __inited = 0
       
    21 
       
    22     def __init__(self, name, bases, dict):
       
    23         self.__name__ = name
       
    24         self.__bases__ = bases
       
    25         self.__dict = dict
       
    26         # XXX Can't define __dict__, alas
       
    27         self.__inited = 1
       
    28 
       
    29     def __getattr__(self, name):
       
    30         try:
       
    31             return self.__dict[name]
       
    32         except KeyError:
       
    33             for base in self.__bases__:
       
    34                 try:
       
    35                     return base.__getattr__(name)
       
    36                 except AttributeError:
       
    37                     pass
       
    38             raise AttributeError, name
       
    39 
       
    40     def __setattr__(self, name, value):
       
    41         if not self.__inited:
       
    42             self.__dict__[name] = value
       
    43         else:
       
    44             self.__dict[name] = value
       
    45 
       
    46     def __call__(self, *args, **kw):
       
    47         inst = TracingInstance()
       
    48         inst.__meta_init__(self)
       
    49         try:
       
    50             init = inst.__getattr__('__init__')
       
    51         except AttributeError:
       
    52             init = lambda: None
       
    53         apply(init, args, kw)
       
    54         return inst
       
    55 
       
    56     __trace_output__ = None
       
    57 
       
    58 class TracingInstance:
       
    59     """Helper class to represent an instance of a tracing class."""
       
    60 
       
    61     def __trace_call__(self, fp, fmt, *args):
       
    62         fp.write((fmt+'\n') % args)
       
    63 
       
    64     def __meta_init__(self, klass):
       
    65         self.__class = klass
       
    66 
       
    67     def __getattr__(self, name):
       
    68         # Invoked for any attr not in the instance's __dict__
       
    69         try:
       
    70             raw = self.__class.__getattr__(name)
       
    71         except AttributeError:
       
    72             raise AttributeError, name
       
    73         if type(raw) != types.FunctionType:
       
    74             return raw
       
    75         # It's a function
       
    76         fullname = self.__class.__name__ + "." + name
       
    77         if not self.__trace_output__ or name == '__trace_call__':
       
    78             return NotTracingWrapper(fullname, raw, self)
       
    79         else:
       
    80             return TracingWrapper(fullname, raw, self)
       
    81 
       
    82 class NotTracingWrapper:
       
    83     def __init__(self, name, func, inst):
       
    84         self.__name__ = name
       
    85         self.func = func
       
    86         self.inst = inst
       
    87     def __call__(self, *args, **kw):
       
    88         return apply(self.func, (self.inst,) + args, kw)
       
    89 
       
    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)
       
    95         try:
       
    96             rv = apply(self.func, (self.inst,) + args, kw)
       
    97         except:
       
    98             t, v, tb = sys.exc_info()
       
    99             self.inst.__trace_call__(self.inst.__trace_output__,
       
   100                                      "returning from %s with exception %s: %s",
       
   101                                      self.__name__, t, v)
       
   102             raise t, v, tb
       
   103         else:
       
   104             self.inst.__trace_call__(self.inst.__trace_output__,
       
   105                                      "returning from %s with value %s",
       
   106                                      self.__name__, rv)
       
   107             return rv
       
   108 
       
   109 Traced = TraceMetaClass('Traced', (), {'__trace_output__': None})
       
   110 
       
   111 
       
   112 def _test():
       
   113     global C, D
       
   114     class C(Traced):
       
   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
       
   119     class D(C):
       
   120         def m2(self, y): print "D.m2(%r)" % (y,); return C.m2(self, y)
       
   121         __trace_output__ = None
       
   122     x = C(4321)
       
   123     print x
       
   124     print x.x
       
   125     print x.m1(100)
       
   126     print x.m1(10)
       
   127     print x.m2(33)
       
   128     print x.m1(5)
       
   129     print x.m2(4000)
       
   130     print x.x
       
   131 
       
   132     print C.__init__
       
   133     print C.m2
       
   134     print D.__init__
       
   135     print D.m2
       
   136 
       
   137     y = D()
       
   138     print y
       
   139     print y.m1(10)
       
   140     print y.m2(100)
       
   141     print y.x
       
   142 
       
   143 if __name__ == '__main__':
       
   144     _test()