Thank you

On Sat, Sep 25, 2021, at 18:53, Guido van Rossum wrote:
> First you need to fond a core dev to sponsor you (Steven D’A?). That person 
> will guide you through the process. 
> 
> On Sat, Sep 25, 2021 at 08:30 Noam Tenne <n...@10ne.org> wrote:
>> __
>> So should I just scratch this and rewrite a PEP for an extensible assertion 
>> mechanism?
>> 
>> On Fri, Sep 24, 2021, at 14:04, Noam Tenne wrote:
>>> 
>>> Hi All,
>>> 
>>> Following the discussions on "Power Assertions: Is it PEP-able?", I've 
>>> drafted this PEP.
>>> Your comments are most welcome.
>>> 
>>> PEP: 9999
>>> Title: Power Assertion
>>> Author: Noam Tenne <n...@10ne.org>
>>> Status: Draft
>>> Type: Standards Track
>>> Content-Type: text/x-rst
>>> Created: 24-Sep-2021
>>> 
>>> 
>>> Abstract
>>> ========
>>> 
>>> This PEP introduces a language enhancement named "Power Assertion".
>>> 
>>> The Power Assertion is inspired by a similar feature found in the
>>> `Groovy language`_ and is an extension to the core lib's ``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.
>>> 
>>> .. _Groovy language: 
>>> http://docs.groovy-lang.org/next/html/documentation/core-testing-guide.html#_power_assertions
>>> 
>>> 
>>> Motivation
>>> =========
>>> 
>>> 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.
>>> 
>>> 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.
>>> 
>>> 
>>> The Community Wants This
>>> ------------------------
>>> 
>>> As mentioned in the abstract, this feature was borrowed from Groovy.
>>> It is a very popular feature within the Groovy community, also used by
>>> projects such as `Spock`_.
>>> 
>>> On top of that, it is very much needed in the Python community as well:
>>> 
>>> * `Power Assertion was explicitly requested`_ as a feature in the
>>>   `Nimoy`_ testing framework
>>> * There's a `similar feature in pytest`_
>>> 
>>> And when `discussed in the python-ideas`_ mailing list, the responses
>>> were overall positive:
>>> 
>>> * "This is cool." - Guido van Rossum
>>> * "I was actually thinking exactly the opposite: this would more
>>>   useful in production than in testing."
>>>   - 2QdxY4RzWzUUiLuE@potatochowder.com
>>> * "What pytest does is awesome. I though about implementing it in the
>>>   standard compiler since seen it the first time." - Serhiy Storchaka
>>> 
>>> .. _Spock: https://spockframework.org/
>>> .. _Power Assertion was explicitly requested: 
>>> https://stackoverflow.com/a/58536986/198825
>>> .. _similar feature in pytest: 
>>> https://docs.pytest.org/en/latest/how-to/assert.html
>>> .. _discussed in the python-ideas: 
>>> https://mail.python.org/archives/list/python-ideas@python.org/thread/T26DR4BMPG5EOB3A2ELVEWQPYRENRXHM/
>>> 
>>> 
>>> Rational
>>> ========
>>> 
>>> Code Example
>>> ------------
>>> 
>>> ::
>>> 
>>>     class SomeClass:
>>>         def __init__(self):
>>>             self.val = {'d': 'e'}
>>> 
>>>     def __str__(self):
>>>             return str(self.val)
>>> 
>>>     sc = SomeClass()
>>> 
>>>     assert sc.val['d'] == 'f'
>>> 
>>> This routine will result in the output:
>>> 
>>> ::
>>> 
>>>     Assertion failed:
>>> 
>>>     sc.val['d'] == f
>>>     |  |        |
>>>     |  e        False
>>>     |
>>>     {'d': 'e'}
>>> 
>>> 
>>> Display
>>> -------
>>> 
>>> 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.
>>> 
>>> This way of presentation is clearer and more human friendly than the
>>> output offered by pytest's solution.
>>> 
>>> 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.
>>> 
>>> 
>>> Mechanics
>>> ---------
>>> 
>>> Reference Implementation
>>> ''''''''''''''''''''''''
>>> 
>>> The reference implementation uses AST manipulation because this is
>>> the only way that this level of involvement can be achieved by a
>>> third party library.
>>> 
>>> It iterates over every subexpression in the assert statement.
>>> Subexpressions are parts of the expression separated by a lookup
>>> (``map[key]``), an attribute reference (``key.value``) or a binary
>>> comparison operator (``==``).
>>> 
>>> It then builds an AST in the structure of a tree to maintain
>>> the order of the operations in the original code, and tracks the
>>> original code of the subexpression together with the AST code of the
>>> subexpression and the original indices.
>>> 
>>> It then rewrites the AST of the original expression to call a
>>> specialised assertion function, which accepts the tree as a parameter.
>>> 
>>> At runtime the expression is executed. If it fails, a rendering
>>> function is called to render the assertion message as per the example
>>> above.
>>> 
>>> 
>>> Actual Implementation
>>> '''''''''''''''''''''
>>> 
>>> To be discussed.
>>> 
>>> In the python-ideas mailing list, Serhiy Storchaka suggests:
>>> 
>>>     It needs a support in the compiler. The condition expression should be
>>>     compiled to keep all immediate results of subexpressions on the stack.
>>>     If the final result is true, immediate results are dropped. If it is
>>>     false, the second argument of assert is evaluated and its value together
>>>     with all immediate results of the first expression, together with
>>>     references to corresponding subexpressions (as strings, ranges or AST
>>>     nodes) are passed to the special handler. That handler can be
>>>     implemented in a third-party library, because formatting and outputting
>>>     a report is a complex task. The default handler can just raise an
>>>     AttributeError.
>>> 
>>> 
>>> Caveats
>>> -------
>>> 
>>> 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.
>>> 
>>> 
>>> Reference Implementation
>>> ========================
>>> 
>>> There's a `complete implementation`_ of this enhancement in the
>>> `Nimoy`_ testing framework.
>>> 
>>> It uses AST manipulation to remap the expression to a `data structure`_
>>> at compile time, so that it can then be `evaluated and printed`_ at runtime.
>>> 
>>> .. _Nimoy: https://browncoat-ninjas.github.io/nimoy/
>>> .. _complete implementation: 
>>> https://browncoat-ninjas.github.io/nimoy/examples/#power-assertions-beta
>>> .. _data structure: 
>>> https://github.com/browncoat-ninjas/nimoy/blob/develop/nimoy/ast_tools/expression_transformer.py#L77
>>> .. _evaluated and printed: 
>>> https://github.com/browncoat-ninjas/nimoy/blob/develop/nimoy/assertions/power.py
>>> 
>>> 
>>> Copyright
>>> =========
>>> 
>>> This document is placed in the public domain or under the
>>> CC0-1.0-Universal license, whichever is more permissive.
>>> 
>>> 
>>> 
>>> ..
>>>    Local Variables:
>>>    mode: indented-text
>>>    indent-tabs-mode: nil
>>>    sentence-end-double-space: t
>>>    fill-column: 70
>>>    coding: utf-8
>>>    End:
>>> 
>>> *Attachments:*
>>>  * pep-9999.rst
>> _______________________________________________
>> 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/DO3ETJ4COXAFJKNYZP3IAGFX5N64CILD/
>> 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/7C6BWQN6LTPKJJZGEFMPT3TBFHIH3MHW/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to