1 """Support Eiffel-style preconditions and postconditions."""
3 from new
import function
5 class EiffelBaseMetaClass(type):
7 def __new__(meta
, name
, bases
, dict):
8 meta
.convert_methods(dict)
9 return super(EiffelBaseMetaClass
, meta
).__new
__(meta
, name
, bases
,
12 def convert_methods(cls
, dict):
13 """Replace functions in dict with EiffelMethod wrappers.
15 The dict is modified in place.
17 If a method ends in _pre or _post, it is removed from the dict
18 regardless of whether there is a corresponding method.
20 # find methods with pre or post conditions
22 for k
, v
in dict.iteritems():
23 if k
.endswith('_pre') or k
.endswith('_post'):
24 assert isinstance(v
, function
)
25 elif isinstance(v
, function
):
28 pre
= dict.get("%s_pre" % m
)
29 post
= dict.get("%s_post" % m
)
31 dict[k
] = cls
.make_eiffel_method(dict[m
], pre
, post
)
33 convert_methods
= classmethod(convert_methods
)
35 class EiffelMetaClass1(EiffelBaseMetaClass
):
36 # an implementation of the "eiffel" meta class that uses nested functions
38 def make_eiffel_method(func
, pre
, post
):
39 def method(self
, *args
, **kwargs
):
41 pre(self
, *args
, **kwargs
)
42 x
= func(self
, *args
, **kwargs
)
44 post(self
, x
, *args
, **kwargs
)
48 method
.__doc
__ = func
.__doc
__
52 make_eiffel_method
= staticmethod(make_eiffel_method
)
54 class EiffelMethodWrapper
:
56 def __init__(self
, inst
, descr
):
60 def __call__(self
, *args
, **kwargs
):
61 return self
._descr
.callmethod(self
._inst
, args
, kwargs
)
63 class EiffelDescriptor(object):
65 def __init__(self
, func
, pre
, post
):
70 self
.__name
__ = func
.__name
__
71 self
.__doc
__ = func
.__doc
__
73 def __get__(self
, obj
, cls
):
74 return EiffelMethodWrapper(obj
, self
)
76 def callmethod(self
, inst
, args
, kwargs
):
78 self
._pre
(inst
, *args
, **kwargs
)
79 x
= self
._func
(inst
, *args
, **kwargs
)
81 self
._post
(inst
, x
, *args
, **kwargs
)
84 class EiffelMetaClass2(EiffelBaseMetaClass
):
85 # an implementation of the "eiffel" meta class that uses descriptors
87 make_eiffel_method
= EiffelDescriptor
91 __metaclass__
= metaclass
96 """Make it a little larger"""
100 """Make it a little larger"""
103 def m2_pre(self
, arg
):
106 def m2_post(self
, result
, arg
):
112 def m2_post(self
, Result
, arg
):
113 super(Sub
, self
).m2_post(Result
, arg
)
121 except AssertionError:
129 except AssertionError:
135 except AssertionError:
141 if __name__
== "__main__":
142 _test(EiffelMetaClass1
)
143 _test(EiffelMetaClass2
)