[Python-ideas] Contracts in python -- a report & next steps

Marko Ristin-Kaufmann marko.ristin at gmail.com
Wed Oct 24 03:41:34 EDT 2018

P.S. Here is the link to the github repo:

On Wed, 24 Oct 2018 at 09:40, Marko Ristin-Kaufmann <marko.ristin at gmail.com>

> Hi,
> I would like to give you a short report on the development of icontract
> library following the discussion about the introduction of contracts into
> Python (e.g., see [1, 2, 3, 4]).
> *Features*
> The functionality of icontract library is basically on par with Eiffel,
> Cobra and other languages supporting contracts except for loop invariants
> and less readable syntax.
> The features include:
> * "require", "ensure" and "invariant" decorators to define the contracts
> * "snapshot" decorator to capture the values prior to the function
> invocation to allow postconditions to verify the state transitions
> * inheritance of the contracts (with strengthening/weakening)
> * tracing of the argument values on contract violation
> * informative violation messages automatically parsed from the code of the
> condition function
> * The user can specify custom errors to be raised on a specific contract
> violation
> * individual toggling of the contracts
> * linter to check the contract arguments
> * sphinx extension to render the contracts automatically in the
> documentation (including a sophisticated matching of logical implications)
> We covered all the use cases we could find in our code base (at Parquery
> AG) such as:
> * functions
> * instance methods
> * class and static methods
> * property getters, setters and deleters
> * slot wrappers
> *Roadblocks*
> During the development, the following roadblocks were encountered:
> * We wanted to include the contracts in the output of help().
> Unfortunately, help() renders the __doc__ of the class and not of the
> instance. For functions, this is the class "function" which you can not
> inherit from. See [5] for more details.
> * We need to inspect the source code of the condition and error lambdas to
> generate the violation message and infer the error type in the
> documentation, respectively. inspect.getsource(.) is broken on lambdas
> defined in decorators in Python 3.5.2+ (see [6]). We circumvented this bug
> by using inspect.findsource(.), inspect.getsourcefile(.) and examining the
> local source code of the lambda by searching for other decorators above and
> other decorators and a function or class definition below. The decorator
> code is parsed and then we match the condition and error arguments in the
> AST of the decorator. This is brittle as it prevents us from having partial
> definitions of contract functions or from sharing the contracts among
> functions.
> Here is a short code snippet to demonstrate where the current
> implementation fails:
> import icontract
> require_x_positive = icontract.require(
>     lambda x: x > 0, error=lambda: ValueError("x must be positive"))
> @require_x_positive
> def some_func(x: int) -> None:
>     pass
> However, we haven't faced a situation in the code base where we would do
> something like the above, so I am unsure whether this is a big issue. As
> long as decorators are directly applied to functions and classes,
> everything worked fine on our code base.
> *Our Experience*
> We have been using icontract in our team for our production code base
> (~100K LOC) as well as for a couple of open source projects (each <10K LOC)
> since August 1st 2018 (~ 3 months).
> In contrast to points raised during the discussions in [1, 2, 3, 4], we
> did not have issues with readability and modifying contracts. Thus far, we
> have not encountered problems with variable renames and major code
> refactorings. We use Pycharm, so it remains open whether this also applies
> to development environments such as emacs and vim.
> We confirm that contracts help us improve the documentation, keep the
> documentation up-to-date, better reason about the function's input and
> output and catch bugs early and more easily during the unit and integration
> tests.
> *Status*
> The library interface is currently frozen after the version bump to 2.0.0
> and is not expected to change in the next six months. All the reported bugs
> have been fixed and no bug fixes are pending.
> *Next Steps?*
> I personally doubt that we are enough people to form a party to push for a
> change in the language. A standardized library seems to me like a
> realizable compromise given the state of the discussion on this mail list.
> Before we organize a collective to write a proposal to standardize the
> library, I would suggest that a couple of other interested teams adopt
> icontract, apply it to their code bases and report their experiences on
> this mail list. I hope that 2-3 reports would be insightful enough to
> either convince other people that contracts in python are worth
> standardizing (and highlight missing features yet to be implemented) or
> provide solid material to discard the endeavor at the current moment.
> In the meanwhile, it would be of great help if somebody could vet the
> documentation and the code of icontract.
> *Authors*
> The library was mainly written by me (with some help of my colleague Adam
> Radomski). We discussed the features within the dev team at Parquery
> (Zurich, Switzerland) as well as in email correspondence with James Lu.
> [1] https://groups.google.com/forum/#!topic/python-ideas/mvzLsdwGuww
> [2] https://groups.google.com/forum/#!topic/python-ideas/JtMgpSyODTU
> [3] https://groups.google.com/forum/#!topic/python-ideas/mvzLsdwGuww
> [4]
> https://groups.google.com/forum/#!topic/python-ideas/dmXz_7LH4GI%5B1-25%5D
> [5] https://groups.google.com/forum/#!topic/python-ideas/c9ntrVuh6WE
> [6] https://bugs.python.org/issue21217
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20181024/806a8b9f/attachment.html>

More information about the Python-ideas mailing list