If assertions have an associated block, then `pdb` can be invoked within. I
almost never use debuggers, so I don't remember, but I think a recent
Python version introduced the likes of `debug()` to step into the
pre-configured debugger.

About the "power assertions" proposal in this thread, once everything is in
place to produce the output as proposed, then libraries may come in to
produce different output formats.

My personal preference is for a form of assertions that don't go away, ever.

Regarding the syntax, I think that should be the last part of the design.
If you think about it, a block associated with the assert should execute
when the assertion fails, so maybe it should be something like:

*assert* *cond* *else:* *block*


with an AssertionError raised if *"block"* does not raise.

Another proposal out there that has the same semantics is:

*unless* *cond*: *block*


Yet I find that using a negative keyword makes things ugly. I'd rather
stick to "*assert*", or maybe go for "*invariant*" statement,  to be rid of
the legacy of the meaning of *"assert"* in Python's history.

*invariant* *cond*: *block*


After all, I think it's invariants what I've been after in my recent posts.
It's easy to document that the *"cond"* must be cheap because it will
*_always_* be executed, and that the *"block"* can be as complex as
required by the severity of the failure.

I still think that there's different levels of criticality to failed
assertions, and that an exception hierarchy that has levels can help build
more reliable systems.

On Tue, Sep 14, 2021 at 5:52 PM Finn Mason <finnjavie...@gmail.com> wrote:

> I think that this is a great idea. However, pipes only point to one
> character, which can be confusing. (Citation: many tracebacks before 3.10.)
>
> I'm wondering: Could failed assertions step you into `pdb`, if they are
> used for testing purposes? Could there be a way to specify different levels
> of assertions? For example, maybe certain assertions are turned off with -O
> or -OO, others turned off only with -O, and some that never are?
> There are lots of ways `assert` could be improved, and the question is
> how? What is/are the best way(s)?
>
> --
> Finn Mason
>
> On Mon, Sep 13, 2021, 5:36 AM Juancarlo Añez <apal...@gmail.com> wrote:
>
>> 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/
>>
>

-- 
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/RADNF5VWZ7DBDOYZVWJR424D64V7LVRM/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to