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

Custom exception messages on breach of contract #17

Open szaydel opened 10 years ago

szaydel commented 10 years ago

@AndreaCensi, contracts is an awesome library, but I think one thing that would make it better, at least to me, is ability to define custom exceptions. For example, say I define a custom Type and then I want a specific error to be raised, ideally being able to pass parameters to that error, which would then allow me to do try/except and have a typical error object with .args and .message elements.

I have not really looked at implementation details, but seems it should be doable.

AndreaCensi commented 10 years ago

That's an interesting idea. Do you mean something like this?

 @contract(a='>0', exception=ValueError)
 def f(a):
    ....

Though there are some details to be figured out... for example, how should one define how the exception be constructed? Should PyContracts do the equivalent of raise ValueError(a)?

szaydel commented 10 years ago

Yeah, but more along the lines of:

class MySpecialException(Exception):
    do stuff here

 @contract(a='>0', exception=MySpecialException)
 def f(a):
    ....

I mean this would be same functionality, but the ability to raise your own exceptions would go hand-in-hand with writing your own validation functions.

What I am doing is I am creating custom validators like so, and then just import that dict on the bottom into different parts of the app. It would be nice to actually raise a custom exception which along with custom validators could make this very extensible.

new_contract("smf_fmri", validate_fmri)

DATATYPES = {  
               "smf_fmri"     :     new_contract,
}

=== some module ===
from moduleX import DATATYPES
AndreaCensi commented 10 years ago

I don't fully understand the example--- especially this part:

 DATATYPES = {  
                "smf_fmri"     :     new_contract,
 }

but I believe the feature that you propose might be useful.

szaydel commented 10 years ago

Maybe this was a poor example. It is just how I implemented contracts, which allows me to organize "custom types" into dicts that I can later import into multiple modules in my project. Anyway, ignoring this example, it would really be nice to raise a custom exception from pycontracts. I think your point about construction of exception is very good, and I am not sure I have a good answer. I suspect having custom messages and such may be a bit tough. Or at least will contribute to a much more verbose declaration.

szaydel commented 10 years ago

I thought about this a bit and I think what would really make this very useful is some ability to raise not only a custom Exception, but one that already has a message and arguments optionally. I think this will make it a lot easier to properly inform the user when a breach occurs on a custom type.

@contract(a='>0', exception=ValueError, exc_msg='Undefined value for blah...')
def f(a):
    <body>