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/

Reply via email to