diff options
| author | Maurits van Rees <maurits@vanrees.org> | 2022-11-08 14:29:53 +0100 |
|---|---|---|
| committer | Maurits van Rees <maurits@vanrees.org> | 2022-11-08 14:36:44 +0100 |
| commit | b7c4196c21b2fe7a2f7b307e1d247c999be1090a (patch) | |
| tree | a3ef281314aa2084a889c248280bd47c8b2f88c1 | |
| parent | 594eee0457cba5d2b93920de15f8f2c6399dd34d (diff) | |
| download | zope-exceptions-b7c4196c21b2fe7a2f7b307e1d247c999be1090a.tar.gz | |
Catch exceptions in formatExceptionOnly.
Getting an exception when reporting about a different exception is not helpful.
On Python 3.11 this is needed for some HTTPErrors.
| -rw-r--r-- | CHANGES.rst | 4 | ||||
| -rw-r--r-- | src/zope/exceptions/exceptionformatter.py | 9 | ||||
| -rw-r--r-- | src/zope/exceptions/tests/test_exceptionformatter.py | 41 |
3 files changed, 53 insertions, 1 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 88f6e1a..5d3521b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,10 @@ 4.6 (unreleased) ================ +- Catch exceptions in ``formatExceptionOnly``. + Getting an exception when reporting about a different exception is not helpful. + On Python 3.11 this is needed for some HTTPErrors. + - Add official support for Python 3.11. diff --git a/src/zope/exceptions/exceptionformatter.py b/src/zope/exceptions/exceptionformatter.py index e6b0314..b61026c 100644 --- a/src/zope/exceptions/exceptionformatter.py +++ b/src/zope/exceptions/exceptionformatter.py @@ -171,7 +171,14 @@ class TextExceptionFormatter(object): return self.line_sep.join(result) def formatExceptionOnly(self, etype, value): - result = ''.join(traceback.format_exception_only(etype, value)) + # We don't want to get an error when we format an error, so we + # compensate in our code. For example, on Python 3.11.0 HTTPError + # gives an unhelpful KeyError in tempfile when Python formats it. + # See https://github.com/python/cpython/issues/90113 + try: + result = ''.join(traceback.format_exception_only(etype, value)) + except Exception: + result = str(value) return result def formatLastLine(self, exc_line): diff --git a/src/zope/exceptions/tests/test_exceptionformatter.py b/src/zope/exceptions/tests/test_exceptionformatter.py index 46eea6d..4d6c6fc 100644 --- a/src/zope/exceptions/tests/test_exceptionformatter.py +++ b/src/zope/exceptions/tests/test_exceptionformatter.py @@ -278,6 +278,47 @@ class TextExceptionFormatterTests(unittest.TestCase): ''.join( traceback.format_exception_only(ValueError, err))) + def test_formatExceptionOnly_httperror(self): + # On Python 3.11.0 HTTPError may behave wrongly, giving a KeyError in + # tempfile when Python tries to format it. + # See https://github.com/python/cpython/issues/90113 + # or examples in Plone tests, especially doctests: + # https://github.com/plone/Products.CMFPlone/issues/3663 + # We don't want to get an error when we format an error, + # so let's compensate in our code. + try: + from urllib.error import HTTPError + except ImportError: + # BBB for Python 2.7 + from urllib2 import HTTPError + fmt = self._makeOne() + err = HTTPError('url', 400, 'oops', [], None) + result = fmt.formatExceptionOnly(HTTPError, err).strip() + # The output can differ too much per Python version, + # but it is just one line when stripped. + self.assertIn("400", result) + self.assertIn("oops", result) + self.assertIn("Error", result) + self.assertEqual(len(result.splitlines()), 1) + + def test_formatException_httperror(self): + # See test_formatExceptionOnly_httperror. + # Here we check that formatException works. + try: + from urllib.error import HTTPError + except ImportError: + # BBB for Python 2.7 + from urllib2 import HTTPError + fmt = self._makeOne() + err = HTTPError('url', 400, 'oops', [], None) + result = fmt.formatException(HTTPError, err, None) + self.assertEqual(result[0], 'Traceback (most recent call last):\n') + last = result[-1] + # The output can differ per Python version. + self.assertIn("400", last) + self.assertIn("oops", last) + self.assertIn("Error", last) + def test_formatLastLine(self): fmt = self._makeOne() self.assertEqual(fmt.formatLastLine('XXX'), 'XXX') |
