[Python-ideas] Re: PEP Draft: Power Assertion

2021-09-25 Thread Noam Tenne
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  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: 
>>> Title: Power Assertion
>>> Author: Noam Tenne 
>>> 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:
>

[Python-ideas] Re: PEP Draft: Power Assertion

2021-09-25 Thread Noam Tenne
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: 
> Title: Power Assertion
> Author: Noam Tenne 
> 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
> |  ||
> |  eFalse
> |
> {'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.
> 
> 
>

[Python-ideas] Re: PEP Draft: Power Assertion

2021-09-25 Thread Noam Tenne
>Is there no room for making it easier to do this with less invasive
changes to the stdlib, or are Steven d'A's "heroic measures in an
import hook" the right way to go?

I'm not familiar with this, can you please elaborate?

>From what I understand we can change stdlib to the point of manipulating the 
>AST, and leave rendering to 3rd parties?

On Sat, Sep 25, 2021, at 09:23, Guido van Rossum wrote:
> On Fri, Sep 24, 2021 at 22:07 Stephen J. Turnbull 
>  wrote:
>> Guido van Rossum writes:
>> 
>>  > I think this is by far the best option. Pytest can evolve much faster than
>>  > the stdlib.
>> 
>> Is there no room for making it easier to do this with less invasive
>> changes to the stdlib, or are Steven d'A's "heroic measures in an
>> import hook" the right way to go?
>> 
>> Other Steve
> 
> There’s room for that, but that’s not what’s being proposed (yet :-).
> 
> —Guido
>> 
> -- 
> --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/4ZM7KYC6FZITLRN366FRP4CXXWHPYPPU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP Draft: Power Assertion

2021-09-25 Thread Noam Tenne
>So maybe what we should do now, rather than add one feature, is propose a  new 
>test framework/test runner for the stdlib, inspired by pytest.

I'd actually avoid reinventing a test framework as I think this has proven to 
be futile. I'm of the opinion that the language should provide a lean infra for 
useful testing and have libraries take it from there.

I don't think this is exclusively testing related, as it can be useful as a 
debugging mechanism for things that shouldn't happen, but happen in production.

>Alternatively, take the approach taken with distutils and setuptools— 
>officially accept that a full featured test framework will be left to third 
>parties.

I'm not sure I'm familiar with this. Can you please elaborate?

>NOTE: if the proposal does require actual language changes beyond the current 
>introspection options, that should be made clear.

Note taken. I'm not very familiar with the internals, so I hesitated to write 
this in the PEP, but from what I understand we can make a language change that 
will take care of the AST side of things so that 3rd party libraries can focus 
on the rendering. This way the 3rd party libraries don't have to act as 
executors. Does that make sense?

On Sat, Sep 25, 2021, at 05:45, Christopher Barker wrote:
> My first thought when reading this (and the recent discussion on Python 
> ideas) was that pytest already does this. 
> 
> Then I see in the PEP:   "What pytest does is awesome“
> 
> So what? 
> 
> Well,  two points:
> 
> 1) this should be part of a test framework, not something built in to 
> exceptions. Pytest has shown that it can be done without any language 
> changes. 
> 
> 2) there are a lot of things in Pytest that are very useful. And a lot of 
> problems with unittest. 
> 
> So maybe what we should do now, rather than add one feature, is propose a  
> new test framework/test runner for the stdlib, inspired by pytest. 
> 
> Alternatively, take the approach taken with distutils and setuptools— 
> officially accept that a full featured test framework will be left to third 
> parties.
> 
> NOTE: if the proposal does require actual language changes beyond the current 
>  introspection options, that should be made clear.
> 
> -CHB 
> 
> 
> On Fri, Sep 24, 2021 at 4:12 AM Paul Moore  wrote:
>> On Fri, 24 Sept 2021 at 12:05, Noam Tenne  wrote:
>> 
>> > 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.
>> 
>> One immediate thought. You should give examples of the sort of
>> expressions that are affected, and precisely what the effect is. It's
>> impossible to judge the importance of this point without details.
>> 
>> Paul
>> ___
>> 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/JJ2CT4FYFHJOOSABQOD6KRKCQ22FJ2BI/
>> Code of Conduct: http://python.org/psf/codeofconduct/
> -- 
> Christopher Barker, PhD (Chris)
> 
> Python Language Consulting
>   - Teaching
>   - Scientific Software Development
>   - Desktop GUI and Web Development
>   - wxPython, numpy, scipy, Cython
___
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/7VZLMHZPJCV35UWZRQMKU74DQHFUH7OA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP Draft: Power Assertion

2021-09-25 Thread Noam Tenne
Will do!

On Fri, Sep 24, 2021, at 14:10, Paul Moore wrote:
> On Fri, 24 Sept 2021 at 12:05, Noam Tenne  wrote:
> 
> > 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.
> 
> One immediate thought. You should give examples of the sort of
> expressions that are affected, and precisely what the effect is. It's
> impossible to judge the importance of this point without details.
> 
> Paul
> ___
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/B5XXYI435LXPPYTSVNT3COY5CMG2PCDR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] PEP Draft: Power Assertion

2021-09-24 Thread Noam Tenne
Hi All,

Following the discussions on "Power Assertions: Is it PEP-able?", I've drafted 
this PEP.
Your comments are most welcome.

PEP: 
Title: Power Assertion
Author: Noam Tenne 
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
|  ||
|  eFalse
|
{'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 execu

[Python-ideas] Re: Power Assertions: Is it PEP-able?

2021-09-12 Thread noam
> Maybe you all could collaborate on a PEP? This sounds a worthy topic.
.
Yes, I would love that please.
___
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/IEXGEPLU5SAINPV3RQIFBZYNYRUIVNWP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Power Assertions: Is it PEP-able?

2021-09-12 Thread noam
2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> On 2021-09-12 at 07:28:53 -0700,
> Guido van Rossum gu...@python.org wrote:
> > 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.
> > I was actually thinking exactly the opposite:  this would more useful in
> production than in testing.
> When I'm testing, tests build on each other.  I should know that the
> inner parts work, and I should be testing specific aspects of the outer
> parts.  If I don't have confidence in those inner parts, then I need to
> write more tests against them.  If I don't "know" where the data comes
> from in my assertions, then my tests are trying to test too much at
> once.
> On the other hand, weird things happen in production, and my first
> reaction to "this shouldn't happen unless there's a bug" are is to start
> looking in the logs at how we got there.  These power assertions are
> like a retroactive or JIT logging mechanism (in the sense that I may not
> have logged enough detail), or a sort of first order run-time debugger
> that shows me what's relevant at the point of the failure.
> As far as the extra cost goes, how does that cost compare to the full
> stack trace I already get from the exception being raised?

That's an interesting observation. I haven't thought of that.
Regarding cost - I haven't profiled my implementation, so I'll have to get back 
to you on that one.
___
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/6F7MAI5TI6CIESDPOJTGCAYVIZARK23A/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Power Assertions: Is it PEP-able?

2021-09-12 Thread noam
> This is cool.
Thank you. Much appreciated.

> AFAIK pytest does something like this. How does your implementation differ?
The pytest implementation is very powerful in the way of hints and suggestions 
that point to the difference and source, but when the asserted expression has 
more than one sub-expression, the thread-style breakdown is unreadable. I 
believe my chart-style implementation offers better readability.

> What is your argument for making this part of the language? Why not a 3rd 
> party library?
The first argument is that asserts are fundamental, which is why they are a 
core part of the language in the first place. If they're already part of the 
core, we can improve them to provide more constructive feedback, without having 
to pull in mammoth testing frameworks, which brings me to my second argument.

My understanding of the compiler is that a 3rd party library can't simply 
rewrite AST during the standard compilation. If one wants to intervene with the 
AST phase, one must rewrite and execute the python files. This is a very 
intrusive and impractical process for a scope of a 3rd party library. It's 
definitely more fitting for frameworks that act as executers such as pytest and 
my framework Nimoy. 
Please correct me if I'm mistaken.

> 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.
Correct. I believe that the proper way to handle this is a switch much like 
`-O`. The feature will be opt-in, and one can opt-in using that switch.
___
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/SPUISYVZWRAHJMY5IP5AZ42SDQKW6E6D/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Power Assertions: Is it PEP-able?

2021-09-12 Thread noam
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
|  ||
|  eFalse
|
{'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/


[Python-ideas] Re: Function suggestion: itertools.one()

2020-07-28 Thread Noam Yorav-Raphael
Thanks! It's good to hear that you too find it useful.

Since adding methods to built-in types is much heavier than adding one
function to a module, l suggest keeping this discussion focused on adding
just the one() function to itertools, and see if there is enough support
for this.

Cheers,
Noam

On Tue, Jul 28, 2020 at 10:47 PM Alex Hall  wrote:

> In my personal toolbox of utility functions, this is by far the function I
> use most often, although it's implemented slightly differently and I call
> it `only`. I think it's very useful and it would be great to have in the
> standard library to encourage people to write safer code.
>
> Often this is part of a larger expression, especially if I'm drilling into
> some nested data structure. This can lead to having a prefix operation (the
> function call) breaking a chain of postfix operations (attributes, method
> calls, subscripting...) which is ugly and less readable. It would be nice
> if this could also be available as a method on lists, tuples, and sets to
> keep the data flowing left to right. Plus it would save an import.
>
> On Tue, Jul 28, 2020 at 9:29 PM Noam Yorav-Raphael 
> wrote:
>
>> Hello,
>>
>> There's a simple function that I use many times, and I think may be a
>> good fit to be added to itertools. A function that gets an iterator, and if
>> it has exactly one element returns it, and otherwise raises an exception.
>> This is very useful for cases where I do some sort of query that I expect
>> to get exactly one result, and I want an exception to be raised if I'm
>> wrong. For example:
>>
>> jack = one(p for p in people if p.id == '1234')
>>
>> sqlalchemy already has such a function for queries:
>> https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one
>>
>> more-itertools has this exact function:
>>
>> https://more-itertools.readthedocs.io/en/latest/api.html#more_itertools.one
>>
>> Here is a simple implementation:
>>
>> def one(iterable):
>> it = iter(iterable)
>> try:
>> first = next(it)
>> except StopIteration:
>> raise ValueError("Iterator is empty")
>> try:
>> second = next(it)
>> except StopIteration:
>> return first
>> else:
>> raise ValueError("Iterator has more than one item")
>>
>> I brought this up on python-dev, but it should be discussed here.
>> Here is the discussion:
>>
>> https://mail.python.org/archives/list/python-...@python.org/thread/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/
>>
>> Brett Cannon said that this idea has been brought up at least twice
>> before. I found:
>>
>> https://mail.python.org/archives/list/python-ideas@python.org/thread/FTJ6JRDTZ57HUVZ3PVIZV2NHU2NLAC4X/#RMWV3SNZ2N4KZLPKPIDE42H46QDEIVHE
>>
>>
>> https://mail.python.org/archives/list/python-ideas@python.org/thread/REYDJFCXQNQG4SAWKELQMCGM77IZG47Q/#ITR2ILPVCKYR52U2D7RHGENASZTNVDHN
>>
>> The first thread hasn't reached any operative conclusion. The second
>> thread was very long, and seemed to focus mostly on another function,
>> first(), that doesn't check if there is more than one item. Joao S. O Bueno
>> said that it passed "general approval". I think that perhaps a new
>> discussion, focused just on one (no pun intended) function in the itertools
>> module may reach a conclusion.
>>
>> It was suggested that instead of an additional function, one can use
>> iterator unpacking:
>>
>> jack, = (p for p in people if p.id == '1234')
>> or
>> [jack] = (p for p in people if p.id == '1234')
>>
>> I still think that having a one() function would be useful, since:
>> 1. I think it spells the intention more clearly. It is not symbols that
>> you need to understand their meaning in order to understand that I expect
>> the iterable to have exactly one item, it's spelled in code.
>> 2. The exception would be easier to understand, since errors in tuple
>> unpacking usually mean something else.
>> 3. The one() function allows you to use the result inside an expression
>> without assigning it to a variable. Therefore, I think it encourages
>> writing better code. It's very easy to write:
>> print([p for p in people if p.id == '1234][0])
>> (which has the problem of not verifying the assumption that there's no
>> more than one result), and I find it easier to replace _[0] with one(_)
>> than to be required to name a new variable, and instead of having an
>> operation on the iterable, change the way I'm assigning to it.
>>
>> WDYT?
>>
>> Cheers,
&g

[Python-ideas] Function suggestion: itertools.one()

2020-07-28 Thread Noam Yorav-Raphael
Hello,

There's a simple function that I use many times, and I think may be a good
fit to be added to itertools. A function that gets an iterator, and if it
has exactly one element returns it, and otherwise raises an exception. This
is very useful for cases where I do some sort of query that I expect to get
exactly one result, and I want an exception to be raised if I'm wrong. For
example:

jack = one(p for p in people if p.id == '1234')

sqlalchemy already has such a function for queries:
https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one

more-itertools has this exact function:
https://more-itertools.readthedocs.io/en/latest/api.html#more_itertools.one

Here is a simple implementation:

def one(iterable):
it = iter(iterable)
try:
first = next(it)
except StopIteration:
raise ValueError("Iterator is empty")
try:
second = next(it)
except StopIteration:
return first
else:
raise ValueError("Iterator has more than one item")

I brought this up on python-dev, but it should be discussed here.
Here is the discussion:
https://mail.python.org/archives/list/python-...@python.org/thread/D52MPKLIN4VEXBOCKVMTWAK66MAOEINY/

Brett Cannon said that this idea has been brought up at least twice before.
I found:
https://mail.python.org/archives/list/python-ideas@python.org/thread/FTJ6JRDTZ57HUVZ3PVIZV2NHU2NLAC4X/#RMWV3SNZ2N4KZLPKPIDE42H46QDEIVHE

https://mail.python.org/archives/list/python-ideas@python.org/thread/REYDJFCXQNQG4SAWKELQMCGM77IZG47Q/#ITR2ILPVCKYR52U2D7RHGENASZTNVDHN

The first thread hasn't reached any operative conclusion. The second thread
was very long, and seemed to focus mostly on another function, first(),
that doesn't check if there is more than one item. Joao S. O Bueno said
that it passed "general approval". I think that perhaps a new discussion,
focused just on one (no pun intended) function in the itertools module may
reach a conclusion.

It was suggested that instead of an additional function, one can use
iterator unpacking:

jack, = (p for p in people if p.id == '1234')
or
[jack] = (p for p in people if p.id == '1234')

I still think that having a one() function would be useful, since:
1. I think it spells the intention more clearly. It is not symbols that you
need to understand their meaning in order to understand that I expect the
iterable to have exactly one item, it's spelled in code.
2. The exception would be easier to understand, since errors in tuple
unpacking usually mean something else.
3. The one() function allows you to use the result inside an expression
without assigning it to a variable. Therefore, I think it encourages
writing better code. It's very easy to write:
print([p for p in people if p.id == '1234][0])
(which has the problem of not verifying the assumption that there's no more
than one result), and I find it easier to replace _[0] with one(_) than to
be required to name a new variable, and instead of having an operation on
the iterable, change the way I'm assigning to it.

WDYT?

Cheers,
Noam
___
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/6OLEL4XTUWXRI7ENODKEDOYFBRVDYKI7/
Code of Conduct: http://python.org/psf/codeofconduct/