Usage¶
Importing the right module¶
code-contracts is split into two different modules: contract
and assertion
.
To use contracts, just import the following module:
>>> from contracts import contract
To use assertions, import the following module:
>>> from contracts import assertion
Expected behavior¶
When a contract or an assertion fails, you can expect it to raise an exception as follows:
Entity | Exception(s) raised |
---|---|
contract |
TypeError , ValueError or AttributeError |
assertion |
AssertionError |
The contracts provided are intended to be used as preconditions, meaning that requirements will be checked before executing a function.
Contracts’ behavior¶
Here’s what happens when a contract fails:
1 2 3 4 5 6 7 8 9 10 | from contracts import contract
def build_rocket(name):
contract.is_not_empty(name)
print("You built a {0} rocket".format(name))
if __name__ == "__main__":
build_rocket(None)
|
Traceback (most recent call last):
File "/contracts/samples/contract_failure_example.py", line 14, in <module>
build_rocket(None, 9, "SpaceX")
File "/contracts/samples/contract_failure_example.py", line 7, in build_rocket
contract.is_not_empty(name)
File /contracts/contracts/contract.py", line 37, in is_not_empty
raise ValueError("{0} was empty.".format(_get_parameter_name()))
ValueError: name was empty.
So when you run this script, the contract raises a ValueError
indicating that the name parameter is empty.
Typically, you want this error to bubble up and crash your program as demonstrated. This way, you can more easily
track the error and fix the calling code accordingly.
Assertions’ behavior¶
Here’s what happens when an assertion fails:
1 2 3 4 5 | from contracts import assertion
if __name__ == "__main__":
assertion.does_not_raise(ValueError, build_rocket, None)
|
Traceback (most recent call last):
File "/contracts/contracts/assertion.py", line 21, in does_not_raise
callable_obj(*args, **kwargs)
File "/contracts/samples/contract_failure_example.py", line 7, in build_rocket
contract.is_not_empty(name)
File "/contracts/contracts/contract.py", line 37, in is_not_empty
raise ValueError("{0} was empty.".format(_get_parameter_name()))
ValueError: name was empty.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/contracts/samples/assertion_failure_example.py", line 8, in <module>
assertion.does_not_raise(ValueError, build_rocket, None)
File "/contracts/contracts/assertion.py", line 25, in does_not_raise
raise AssertionError("{0} raised by {1}().".format(exception_cls.__name__, callable_obj.__name__))
AssertionError: ValueError raised by build_rocket().
So when you run this script, the assertion raises an AssertionError
indicating that
build_rocket()
itself raises a ValueError
. Again, this is because the
name parameter is empty.
As you can see, assertions are very handy to validate the expected behavior of a function or method. Note that it’s a
bit more common to use assertions in the context of more formal unit tests, like when using the unittest
module,
as it handles AssertionError
a little bit more gracefully.
Available contracts¶
code-contracts contains the following contract functions:
Function | Description | Example |
---|---|---|
is_not_none() |
Checks that the specified value is not equal to None. | def contract_is_not_none_demo(a):
contract.is_not_none(a)
contract_is_not_none_demo("abc")
|
is_not_empty() |
Checks that the specified value is not empty. | def contract_is_not_empty_demo(a):
contract.is_not_empty(a)
contract_is_not_empty_demo("abc")
|
is_equal_to_any() |
Checks that the specified value is equal to at least one of the expected values. | def contract_is_equal_to_any_demo(a):
contract.is_equal_to_any(a, [1, 2, 3])
contract_is_equal_to_any_demo(1)
|
is_true() |
Checks that the specified value is equal to True. | def contract_is_true_demo(a):
contract.is_true(a)
contract_is_true_demo(2 > 1)
|
is_false() |
Checks that the specified value is equal to False. | def contract_is_false_demo(a):
contract.is_false(a)
contract_is_false_demo(1 > 2)
|
is_equal() |
Checks that the specified value is strictly equal to the expected value. | def contract_is_equal_demo(a):
contract.is_equal(a, 1)
contract_is_equal_demo(1)
|
is_greater_than() |
Checks that the specified value is greater than the expected value. | def contract_is_greater_than_demo(a):
contract.is_greater_than(a, 1)
contract_is_greater_than_demo(2)
|
is_greater_than_or_equal() |
Checks that the specified value is greater than or strictly equal to the expected value. | def contract_is_greater_than_or_equal(a):
contract.is_greater_than_or_equal(a, 1)
contract_is_greater_than_or_equal(2)
|
all_have_attribute() |
Checks that all objects contained in value - be it a single object or an Iterable of objects - have the specified attribute. |
class ClassA:
abc = 1
class ClassB:
abc = 1
xyz = 2
def contract_all_have_attribute(a):
contract.all_have_attribute(a, "abc")
contract_all_have_attribute([ClassA(), ClassB()])
|
all_have_method() |
Checks that all objects contained in value - be it a single object or an Iterable of objects have the specified method. |
class ClassC:
def my_method(self):
pass
def contract_all_have_method(a):
contract.all_have_method(a, "my_method")
contract_all_have_method(ClassC())
|
is_callable() |
Checks that the specified value is a callable object (i.e. has a ‘__call__’ attribute). | def contract_is_callable(a):
contract.is_callable(a)
contract_is_callable(ClassC().my_method)
|
is_instance() |
Checks that the specified value is an instance of the given class. | def contract_is_instance(a):
contract.is_instance(a, int)
contract_is_instance(1)
|
Note
Some of these contract functions contain an optional parameter named expression_str. Its purpose is to allow you to pass a string representation of the value passed to the function. This is especially useful if, for example, the value isn’t a single, discrete value, but a boolean expression such as x > y. In such a case, you can pass ‘x > y’ in expression_str. This expression will be used to create a more meaningful error message if the contract fails.
Available assertions¶
code-contracts contains the following assertion functions:
Function | Description | Example |
---|---|---|
does_not_raise() |
Asserts that the specified callable object does not raise an exception of the specified class when called. | assertion.does_not_raise(ValueError, lambda: None)
|
raises() |
Asserts that the specified callable object raises an exception of the specified class when called. | def raises():
raise ValueError("Error!")
assertion.raises(ValueError, raises)
|
raises_with_msg() |
Asserts that the specified callable object raises an exception of the specified type with the specified message when called. | def raises():
raise ValueError("Error!")
assertion.raises_with_msg(ValueError, raises, "Error!")
|
not_called_with() |
Asserts that the specified mock object was never called with a specific sequence of arguments. | mock = Mock()
mock.my_method.side_effect = lambda a: a + 1
assertion.not_called_with(mock.my_method, 123)
|
contains_one_element_of_class() |
Asserts that the specified iterable object contains one and only one element of the specified class. | assertion.contains_one_element_of_class(int, [1])
|