AndreaCensi / contracts

PyContracts is a Python package that allows to declare constraints on function parameters and return values. Contracts can be specified using Python3 annotations, or inside a docstring. PyContracts supports a basic type system, variables binding, arithmetic constraints, and has several specialized contracts and an extension API.
http://andreacensi.github.io/contracts/
Other
398 stars 62 forks source link

Support for calllable objects and bound functions #29

Open yaniv256 opened 9 years ago

yaniv256 commented 9 years ago

Hi Andrea,

Love the project. This is my first pull request on Github, and note that I am also new to Python in general. I fixed a bug I was getting with bound methods that originated from the imported decorator module. I also added support to callable objects by replacing them with their call. This now runs on 2.7:

from contracts import contract, ContractNotRespected

class eggs(object):
    def __init__(self,x):
        self.x=x
    def __call__(self,kw1,kw2):
        print str(self.x) + ': kw1='+ str(kw1) + ', kw2=' + str(kw2)
    def bound_func(self,kw1,kw2):
        print str(self.x) + ': kw1='+ str(kw1) + ', kw2=' + str(kw2)

spam=eggs('Hello from within the instance')            
fish=contract(kw1=float,kw2=int)(spam)

print "\nCalling a proper fish"
fish(6.0,5)

print "\nCalling an improper fish"
try:
    fish(6,5.0)
except ContractNotRespected as detail:
    print detail

dead=eggs("And now ...")    
parrot=contract(kw1=float,kw2=int)(dead.bound_func)

print "\nCalling a proper parrot"
parrot(600.0,500)

print "\nCalling an improper parrot"
try:
    parrot(600,500.0)
except ContractNotRespected as detail:
    print detail

The output is:

Calling a proper fish
Hello from within the instance: kw1=6.0, kw2=5

Calling an improper fish
Breach for argument 'kw1' to __call__().
Expected type 'float', got 'int'.
checking: float   for value: Instance of int: 6   

Calling a proper parrot
And now ...: kw1=600.0, kw2=500

Calling an improper parrot
Breach for argument 'kw1' to bound_func().
Expected type 'float', got 'int'.
checking: float   for value: Instance of int: 600   

BTW, I have a branch, ContractAttribute, with a working descriptor for enforcing a contract on an object's static function attribute. Let me know if you are interested.

AndreaCensi commented 9 years ago

Hi Yaniv,

When merging this I get some regressions on tests. Could you have a look at those by running nosetests contracts?

A.

yaniv256 commented 9 years ago

I don't know how to work with nosetest, and I have to get back to my main project. I apologize.

Best, Yaniv