1 """Support Eiffel-style preconditions and postconditions."""
3 from types
import FunctionType
as 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
,
13 def convert_methods(cls
, dict):
14 """Replace functions in dict with EiffelMethod wrappers.
16 The dict is modified in place.
18 If a method ends in _pre or _post, it is removed from the dict
19 regardless of whether there is a corresponding method.
21 # find methods with pre or post conditions
23 for k
, v
in dict.items():
24 if k
.endswith('_pre') or k
.endswith('_post'):
25 assert isinstance(v
, function
)
26 elif isinstance(v
, function
):
29 pre
= dict.get("%s_pre" % m
)
30 post
= dict.get("%s_post" % m
)
32 dict[k
] = cls
.make_eiffel_method(dict[m
], pre
, post
)
34 class EiffelMetaClass1(EiffelBaseMetaClass
):
35 # 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 class EiffelMethodWrapper
:
54 def __init__(self
, inst
, descr
):
58 def __call__(self
, *args
, **kwargs
):
59 return self
._descr
.callmethod(self
._inst
, args
, kwargs
)
61 class EiffelDescriptor(object):
63 def __init__(self
, func
, pre
, post
):
68 self
.__name
__ = func
.__name
__
69 self
.__doc
__ = func
.__doc
__
71 def __get__(self
, obj
, cls
):
72 return EiffelMethodWrapper(obj
, self
)
74 def callmethod(self
, inst
, args
, kwargs
):
76 self
._pre
(inst
, *args
, **kwargs
)
77 x
= self
._func
(inst
, *args
, **kwargs
)
79 self
._post
(inst
, x
, *args
, **kwargs
)
82 class EiffelMetaClass2(EiffelBaseMetaClass
):
83 # an implementation of the "eiffel" meta class that uses descriptors
85 make_eiffel_method
= EiffelDescriptor
89 __metaclass__
= metaclass
94 """Make it a little larger"""
98 """Make it a little larger"""
101 def m2_pre(self
, arg
):
104 def m2_post(self
, result
, arg
):
110 def m2_post(self
, Result
, arg
):
111 super(Sub
, self
).m2_post(Result
, arg
)
119 except AssertionError:
127 except AssertionError:
133 except AssertionError:
139 if __name__
== "__main__":
140 _test(EiffelMetaClass1
)
141 _test(EiffelMetaClass2
)