> 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 <f...@devork.be> 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 pytest-dev@python.org https://mail.python.org/mailman/listinfo/pytest-dev