symbian-qemu-0.9.1-12/python-2.6.1/Demo/newmetaclasses/Eiffel.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Support Eiffel-style preconditions and postconditions."""
       
     2 
       
     3 from types import FunctionType as function
       
     4 
       
     5 class EiffelBaseMetaClass(type):
       
     6 
       
     7     def __new__(meta, name, bases, dict):
       
     8         meta.convert_methods(dict)
       
     9         return super(EiffelBaseMetaClass, meta).__new__(meta, name, bases,
       
    10                                                         dict)
       
    11 
       
    12     @classmethod
       
    13     def convert_methods(cls, dict):
       
    14         """Replace functions in dict with EiffelMethod wrappers.
       
    15 
       
    16         The dict is modified in place.
       
    17 
       
    18         If a method ends in _pre or _post, it is removed from the dict
       
    19         regardless of whether there is a corresponding method.
       
    20         """
       
    21         # find methods with pre or post conditions
       
    22         methods = []
       
    23         for k, v in dict.iteritems():
       
    24             if k.endswith('_pre') or k.endswith('_post'):
       
    25                 assert isinstance(v, function)
       
    26             elif isinstance(v, function):
       
    27                 methods.append(k)
       
    28         for m in methods:
       
    29             pre = dict.get("%s_pre" % m)
       
    30             post = dict.get("%s_post" % m)
       
    31             if pre or post:
       
    32                 dict[k] = cls.make_eiffel_method(dict[m], pre, post)
       
    33 
       
    34 class EiffelMetaClass1(EiffelBaseMetaClass):
       
    35     # an implementation of the "eiffel" meta class that uses nested functions
       
    36 
       
    37     @staticmethod
       
    38     def make_eiffel_method(func, pre, post):
       
    39         def method(self, *args, **kwargs):
       
    40             if pre:
       
    41                 pre(self, *args, **kwargs)
       
    42             x = func(self, *args, **kwargs)
       
    43             if post:
       
    44                 post(self, x, *args, **kwargs)
       
    45             return x
       
    46 
       
    47         if func.__doc__:
       
    48             method.__doc__ = func.__doc__
       
    49 
       
    50         return method
       
    51 
       
    52 class EiffelMethodWrapper:
       
    53 
       
    54     def __init__(self, inst, descr):
       
    55         self._inst = inst
       
    56         self._descr = descr
       
    57 
       
    58     def __call__(self, *args, **kwargs):
       
    59         return self._descr.callmethod(self._inst, args, kwargs)
       
    60 
       
    61 class EiffelDescriptor(object):
       
    62 
       
    63     def __init__(self, func, pre, post):
       
    64         self._func = func
       
    65         self._pre = pre
       
    66         self._post = post
       
    67 
       
    68         self.__name__ = func.__name__
       
    69         self.__doc__ = func.__doc__
       
    70 
       
    71     def __get__(self, obj, cls):
       
    72         return EiffelMethodWrapper(obj, self)
       
    73 
       
    74     def callmethod(self, inst, args, kwargs):
       
    75         if self._pre:
       
    76             self._pre(inst, *args, **kwargs)
       
    77         x = self._func(inst, *args, **kwargs)
       
    78         if self._post:
       
    79             self._post(inst, x, *args, **kwargs)
       
    80         return x
       
    81 
       
    82 class EiffelMetaClass2(EiffelBaseMetaClass):
       
    83     # an implementation of the "eiffel" meta class that uses descriptors
       
    84 
       
    85     make_eiffel_method = EiffelDescriptor
       
    86 
       
    87 def _test(metaclass):
       
    88     class Eiffel:
       
    89         __metaclass__ = metaclass
       
    90 
       
    91     class Test(Eiffel):
       
    92 
       
    93         def m(self, arg):
       
    94             """Make it a little larger"""
       
    95             return arg + 1
       
    96 
       
    97         def m2(self, arg):
       
    98             """Make it a little larger"""
       
    99             return arg + 1
       
   100 
       
   101         def m2_pre(self, arg):
       
   102             assert arg > 0
       
   103 
       
   104         def m2_post(self, result, arg):
       
   105             assert result > arg
       
   106 
       
   107     class Sub(Test):
       
   108         def m2(self, arg):
       
   109             return arg**2
       
   110         def m2_post(self, Result, arg):
       
   111             super(Sub, self).m2_post(Result, arg)
       
   112             assert Result < 100
       
   113 
       
   114     t = Test()
       
   115     t.m(1)
       
   116     t.m2(1)
       
   117     try:
       
   118         t.m2(0)
       
   119     except AssertionError:
       
   120         pass
       
   121     else:
       
   122         assert False
       
   123 
       
   124     s = Sub()
       
   125     try:
       
   126         s.m2(1)
       
   127     except AssertionError:
       
   128         pass # result == arg
       
   129     else:
       
   130         assert False
       
   131     try:
       
   132         s.m2(10)
       
   133     except AssertionError:
       
   134         pass # result ==  100
       
   135     else:
       
   136         assert False
       
   137     s.m2(5)
       
   138 
       
   139 if __name__ == "__main__":
       
   140     _test(EiffelMetaClass1)
       
   141     _test(EiffelMetaClass2)