> > What about asserts that are not used for testing, but as classic “unless > there’s a bug, this should hold”?
To me this relates to the thread about having a structured *assert* that doesn't go away with *-O*. My purpose when addressing *assert* was precisely the *“unless there’s a bug, this should hold”* kind of assertions. In that context, introducing additional yet known costs (as in this "power" idea), providing for different exception types (maybe all descending from AssertError?), and allowing for a block to prepare the exception, are all worth it. Introducing the new syntax for *assert* would imply zero cost for existing assertions. On Sun, Sep 12, 2021 at 10:28 AM Guido van Rossum <gu...@python.org> wrote: > This is cool. > > AFAIK pytest does something like this. How does your implementation differ? > > What is your argument for making this part of the language? Why not a 3rd > party library? > > What about asserts that are not used for testing, but as classic “unless > there’s a bug, this should hold”? Those may not want to incur the extra > cost. > > —Guido > > On Sun, Sep 12, 2021 at 07:09 <n...@10ne.org> wrote: > >> Hi all, >> >> I’d like your comments and feedback on an enhancement that introduces >> power assertions to the Python language. >> >> Proposal >> -------- >> This feature is inspired by a similar feature of the Groovy language[1], >> and is effectively a variant of the `assert` keyword. >> When an assertion expression evaluates to `False`, the output shows not >> only the failure, but also a breakdown of the evaluated expression from the >> inner part to the outer part. >> >> For example, a procedure like: >> ```python >> class SomeClass: >> def __init__(self): >> self.val = {'d': 'e'} >> >> def __str__(self): >> return str(self.val) >> >> sc = SomeClass() >> >> assert sc.val['d'] == 'f' >> ``` >> >> Will result in the output: >> >> ```python >> Assertion failed: >> >> sc.val['d'] == f >> | | | >> | e False >> | >> {'d': 'e'} >> ``` >> See link [2] if the formatting above is screwed up. >> >> In the output above we can see the value of every part of the expression >> from left to right, mapped to their expression fragment with the pipe (`|`). >> The number of rows that are printed depend on the value of each fragment >> of the expression. >> If the value of a fragment is longer than the actual fragment (`{'d': >> 'e'}` is longer than `sc`), then the next value (`e`) will be printed on a >> new line which will appear above. >> Values are appended to the same line until it overflows in length to >> horizontal position of the next fragment. >> >> The information that’s displayed is dictated by the type. >> If the type is a constant value, it will be displayed as is. >> If the type implements `__str__`, then the return value of that will be >> displayed. >> >> It is important to note that expressions with side effects are affected >> by this feature. This is because in order to display this information, we >> must store references to the instances and not just the values. >> >> Rational >> -------- >> Every test boils down to the binary statement "Is this true or false?", >> whether you use the built-in assert keyword or a more advanced assertion >> method provided by a testing framework. >> When an assertion fails, the output is binary too — "Expected x, but got >> y". >> >> There are helpful libraries like Hamcrest which give you a more verbose >> breakdown of the difference and answer the question "What exactly is the >> difference between x and y?". >> This is extremely helpful, but it still focuses on the difference between >> the values. >> >> We need to keep in mind that a given state is normally an outcome of a >> series of states, that is, one outcome is a result of multiple conditions >> and causes. >> This is where power assertion comes in. It allows us to better understand >> what led to the failure. >> >> Implementation >> -------- >> I’ve already built a fully functional implementation[2] of this feature >> as part of my Python testing framework - Nimoy[3]. >> The current implementation uses AST manipulation to remap the expression >> to a data structure[4] at compile time, so that it can then be evaluated >> and printed[5] at runtime. >> >> >> [1] >> http://docs.groovy-lang.org/next/html/documentation/core-testing-guide.html#_power_assertions >> [2] >> https://browncoat-ninjas.github.io/nimoy/examples/#power-assertions-beta >> [3] https://github.com/browncoat-ninjas/nimoy/ >> [4] >> https://github.com/browncoat-ninjas/nimoy/blob/develop/nimoy/ast_tools/expression_transformer.py#L77 >> [5] >> https://github.com/browncoat-ninjas/nimoy/blob/develop/nimoy/assertions/power.py >> _______________________________________________ >> Python-ideas mailing list -- python-ideas@python.org >> To unsubscribe send an email to python-ideas-le...@python.org >> https://mail.python.org/mailman3/lists/python-ideas.python.org/ >> Message archived at >> https://mail.python.org/archives/list/python-ideas@python.org/message/T26DR4BMPG5EOB3A2ELVEWQPYRENRXHM/ >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -- > --Guido (mobile) > _______________________________________________ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/EEVHXKWUMVSEPAR73WOBQM3BO7NESPBZ/ > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Juancarlo *Añez*
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/RHXMGHUXNSHJTDBNAI3ZQGWZXN2TDFLN/ Code of Conduct: http://python.org/psf/codeofconduct/