<div dir="ltr"><div dir="ltr">P.S. Here is the link to the github repo: <a href="https://github.com/Parquery/icontract">https://github.com/Parquery/icontract</a><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, 24 Oct 2018 at 09:40, Marko Ristin-Kaufmann <<a href="mailto:marko.ristin@gmail.com">marko.ristin@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>Hi,<br></div>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]). <br><br></div><div><b>Features</b><br></div><div>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.<br><br></div><div>The features include:<br></div><div>* "require", "ensure" and "invariant" decorators to define the contracts<br></div><div>* "snapshot" decorator to capture the values prior to the function invocation to allow postconditions to verify the state transitions<br></div><div>* inheritance of the contracts (with strengthening/weakening)<br></div><div>* tracing of the argument values on contract violation<br></div><div>* informative violation messages automatically parsed from the code of the condition function<br></div><div>* The user can specify custom errors to be raised on a specific contract violation<br></div><div>* individual toggling of the contracts<br></div><div>* linter to check the contract arguments<br></div><div>* sphinx extension to render the contracts automatically in the documentation (including a sophisticated matching of logical implications)<br><br></div><div>We covered all the use cases we could find in our code base (at Parquery AG) such as:<br></div><div>* functions<br></div><div>* instance methods<br></div><div>* class and static methods<br></div><div>* property getters, setters and deleters<br></div><div>* slot wrappers<br><br></div><div><b>Roadblocks</b><br></div><div>During the development, the following roadblocks were encountered:<br><br></div><div>* 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.<br><br></div><div>* 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.<br><br></div><div>Here is a short code snippet to demonstrate where the current implementation fails:<br></div><font size="2"><span style="color:rgb(0,0,128);font-weight:bold">import </span>icontract</font><br><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"DejaVu Sans Mono""><font size="2">require_x_positive = icontract.require(<br>    <span style="color:rgb(0,0,128);font-weight:bold">lambda </span>x: x > <span style="color:rgb(0,0,255)">0</span>, <span style="color:rgb(102,0,153)">error</span>=<span style="color:rgb(0,0,128);font-weight:bold">lambda</span>: <span style="color:rgb(0,0,128)">ValueError</span>(<span style="color:rgb(0,128,128);font-weight:bold">"x must be positive"</span>))<br><br><span style="color:rgb(0,0,178)">@require_x_positive<br></span><span style="color:rgb(0,0,128);font-weight:bold">def </span>some_func(<span style="color:rgb(128,128,128)">x: int</span>) -> <span style="color:rgb(0,0,128);font-weight:bold">None</span>:<br>    <span style="color:rgb(0,0,128);font-weight:bold">pass</span></font></pre><div>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.<br></div><div><br></div><div><b>Our Experience<br></b></div><div>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). <br><br>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.<br><br></div><div>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.<br></div><div><br></div><div><b>Status<br></b></div><div>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.<br></div><div><br></div><div><b>Next Steps?</b><br></div><div>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.<br><br></div><div>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.<br><br></div><div>In the meanwhile, it would be of great help if somebody could vet the documentation and the code of icontract.<br> </div><div><br></div><div><b>Authors</b><br>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.<br></div><div dir="ltr"><br>[1] <a href="https://groups.google.com/forum/#!topic/python-ideas/mvzLsdwGuww" target="_blank">https://groups.google.com/forum/#!topic/python-ideas/mvzLsdwGuww</a><br>[2] <a href="https://groups.google.com/forum/#!topic/python-ideas/JtMgpSyODTU" target="_blank">https://groups.google.com/forum/#!topic/python-ideas/JtMgpSyODTU</a><br>[3] <a href="https://groups.google.com/forum/#!topic/python-ideas/mvzLsdwGuww" target="_blank">https://groups.google.com/forum/#!topic/python-ideas/mvzLsdwGuww</a><br>[4] <a href="https://groups.google.com/forum/#!topic/python-ideas/dmXz_7LH4GI%5B1-25%5D" target="_blank">https://groups.google.com/forum/#!topic/python-ideas/dmXz_7LH4GI%5B1-25%5D</a><br>[5] <a href="https://groups.google.com/forum/#!topic/python-ideas/c9ntrVuh6WE" target="_blank">https://groups.google.com/forum/#!topic/python-ideas/c9ntrVuh6WE</a><br>[6] <a href="https://bugs.python.org/issue21217" target="_blank">https://bugs.python.org/issue21217</a><br></div></div></div></div></div></div></div></div></div></div></div></div>
</blockquote></div>