AndreaCensi/contracts — pull request #30 by yaniv256 (2014-11-19 00:40:49+00:00)
Title: A descriptor for contract attributes

Hi Andrea,

I wrote a descriptor for enforcing contracts. From the doc string:

_A descriptor for object attributes that enforces a contract
check on whatever object or function the attribute is set
to. For a function, the function would not be passed the self
argument (because that breaks encapsulation - you can still
actively pass self if you want). Setting up an attribute like
this is useful when an API that is expressed as an object
requires a client function to work with. In such cases you
want to both communicate expectations with regards to the
needed function and verify that they are met._

Usage example:

```python

from contracts import ContractAttribute, contract, ContractNotRespected

class spam(object):
f=ContractAttribute(contract(arg='float,>0')) #for functions
x=ContractAttribute('float,>0') #for scalars using string
y=ContractAttribute(float) #for scalars using type

eggs=spam()

from math import log, exp, pi
eggs.f=lambda (arg): log(arg)

print "eggs.f(e)=" + str(eggs.f(exp(1.0)))

try:
print "eggs.f=" + str(eggs.f(-1.0))
except ContractNotRespected as detail:
print detail

print "Attempting eggs.x=pi"
eggs.x=pi
print "eggs.x=" + str(eggs.x)

print "Attempting eggs.x=-pi"
try:
eggs.x=-pi
except ContractNotRespected as detail:
print detail

print "Attempting eggs.y=2*pi"
eggs.y=2*pi
print "eggs.y=" + str(eggs.y)
print "eggs.x=" + str(eggs.x)

print "Attempting eggs.y=3"
try:
eggs.y=3
except ContractNotRespected as detail:
print str(detail)[:180]
```
Output:
```
eggs.f(e)=1.0
Breach for argument 'arg' to ().
Condition -1.0 > 0 not respected
checking: >0 for value: Instance of float: -1.0
checking: float,>0 for value: Instance of float: -1.0
Attempting eggs.x=pi
eggs.x=3.14159265359
Attempting eggs.x=-pi
Condition -3.14159265359 > 0 not respected
checking: >0 for value: Instance of float: -3.141592653589793
checking: float,>0 for value: Instance of float: -3.141592653589793
Attempting eggs.y=2*pi
eggs.y=6.28318530718
eggs.x=3.14159265359
Attempting eggs.y=3
Could not satisfy any of the 3 clauses in Float|np_scalar_float|np_scalar,array(float).
---- Clause #1: Float
| Expected type 'float', got 'int'.
| checking: Float for value
```