]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Demo/newmetaclasses/Eiffel.py
AppPkg/Applications/Python: Add Python 2.7.2 sources since the release of Python...
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Demo / newmetaclasses / Eiffel.py
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)