> I still think the most sane approach is to let pytest show
> the repr of failing objects [0]. This would allow you to
> write objects with a .__bool__() and a .__repr__() where
> pytest would show the repr if it's false.
Don't get me wrong--I fully agree that the approach you're describing. And
I'm not advocating for that AST example at all (it's just all I could
cobble together because I didn't see an appropriate place to hack on the
repr handling).
> And if you really want to have the dual behaviour, make
> it explicit...
The dual behavior was an implementation detail of the hacked experiment I
was playing with. My interest was in having something like
pytest_assertrepr_compare() but for single-values rather than just
comparisons.
> [0] I don't think it currently does this, so this would
> be a feature request AFAIK.
Here's an example of Pytest's current behavior using a falsey value with a
repr:
import pytest
# Test helpers.
def myfunc(x):
if x == 42:
return True
msg = 'custom report\nmulti-line output\nmyfunc({0}) failed'
return FalsyValue(msg.format(x))
class FalsyValue(object):
def __init__(self, repr_string):
self.repr_string = repr_string
def __bool__(self):
return False
def __nonzero__(self): # <- for py 2
return False
def __eq__(self, other):
return other == False
def __repr__(self):
return self.repr_string
# Test cases.
def test_passing():
assert myfunc(42)
def test_failing():
assert myfunc(41)
Running this gives the following failure message:
============================ FAILURES ============================
__________________________ test_failing __________________________
def test_failing():
> assert myfunc(41)
E assert custom report\nmulti-line output\nmyfunc(41) failed
E + where custom report\nmulti-line output\nmyfunc(41) fai
led = myfunc(41)
test_falsey_object.py:31: AssertionError
=============== 1 failed, 1 passed in 0.22 seconds ===============
So this does sort-of work although the repr is duplicated and newlines are
being escaped.
On thing that's important to mention: If there's a feature request based on
anything in this discussion thread, it should not be made for my case.
After giving it more thought, I think I'll need to raise my own errors
directly so I'm not sure I would be able to use the feature.
On Thu, Mar 22, 2018 at 5:46 PM, Floris Bruynooghe <[email protected]> wrote:
> On Thu, Mar 22 2018, Shawn Brown wrote:
>
> > Would a return value helper--as you are thinking about it--be able to
> > handle cases like test_3passing()?
> >
> > def test_3passing():
> > with pytest.raises(AssertionError) as excinfo:
> > assert myfunc(41)
> > assert 'custom report' in str(excinfo.value)
>
> I agree with Ronny here and do think you're trying to design a very
> weird and unnatural API for Python. The function should either return
> an object or raise an exception, you can't have both. Well, you can as
> you've show, but this is very brittle and your users will be thoroughly
> confused about what is going on. So you shouldn't have both.
>
> Having followed this discussion so far I still think the most sane
> approach is to let pytest show the repr of failing objects [0]. This would
> allow you to write objects with a .__bool__() and a .__repr__() where
> pytest would show the repr if it's false. And if you really want to
> have the dual behaviour, make it explicit to the user with a signature
> like myfunc(value, raising=False) so they can invoke the raising
> behaviour when desired.
>
>
> [0] I don't think it currently does this, so this would be a feature
> request AFAIK.
>
_______________________________________________
pytest-dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pytest-dev