Comment 1 for bug 804127

Revision history for this message
Jonathan Lange (jml) wrote : Re: assertThat sometimes generates unprintable AssertionErrors

This test seems to reproduce:

    def test_assertThat_unicode(self):
        crazy_char = _u("\xa7")
        e = self.assertRaises(
            self.assertThat, crazy_char, Equals(_u("a")), verbose=True)
        str_exception = _exception_to_text(e)

Also, see this discussion:

<jml> mgz: around?
<mgz> aha, I was considering pinging you
<mgz> I've got an idea that might help some of the assertThat issues
<mgz> how about just putting the Mismatch object in the AssertionError rather than stringifying it? avoids a bunch of __str__ vs __unicode__ issues
<mgz> also puts the formatting entirely in the hands of the Mismatch rather than printing the Matcher at all
<mgz> I don't think there are any bad side effects from having a non-string type argument to an exception
<mgz> jml: anything in particular?
<jml> mgz: oh huh
<jml> mgz: just wanted your feedback on a bug
<jml> mgz:
<ubot5> Ubuntu bug 675323 in testtools "assertThat style gives overly verbose output" [Wishlist,Triaged]
<mgz> how would you feel about just printing the "Difference" portion and none of the rest?
<mgz> in cases like assertThat(something_long, DoctestMatches(pattern, doctest.REPORT_UDIFF)) that'll be much better anyway
<mgz> and trivial things like assertEqual(1, 2) are clear anyway without being explicit about what the Matcher and matchee are
<jml> mgz: basically, that's my plan.
<jml> mgz: maybe adding a verbose option to assertThat to print its current output
<jml> mgz: patch up.
<jml> mgz: regarding your earlier comment, you mean doing something like 'raise AssertionError(mismatch)' and relying on AssertionError to call __str__ (and thus, describe)
<mgz> I do.
<mgz> Then we can get the logic right on the Mismatch classes, and avoid the python version variations on exception instances
<jml> Hmm.
<jml> mgz: That would change the API for mismatches, not sure that would be a problem.
<mgz> In which respect?
<jml> we don't currently insist on inheriting from Mismatch
<jml> and we don't currently use mismatch.__str__
<jml> so third-party mismatches that don't inherit will break
<mgz> hm.
<jml> where 'break' means, "<testtools.matchers.Mismatch object at %x attributes=%r>" % (id(self), self.__dict__)
<mgz> the other option is raising an AssertionError subclass on some python versions.
<mgz> which is also a tricky api change.
<jml> well, we could _always_ raise an AssertionError subclass
<jml> that would only break people who were expecting an exact class
<jml> but would still go alright w/ 'except AssertionError' or isinstance() checks
<jml> mgz: in some ways, I wouldn't mind raising a specialized exception for assertThat anyway. I think it would be nice to attach the matchee & matcher objects explictly and make them programatically available
<mgz> that sounds reasonable.
<jml> hmm.
<jml> I guess the break there is that if someone sets failureException, assertThat failures become errors.
<jml> I think that's as unlikely to be a problem in practice as third-party mismatches that don't inherit from Mismatch.