diff --git a/CHANGES b/CHANGES index a4ab8bd51be..9e3e29fe06e 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,7 @@ Features added dedent via no-argument ``:dedent:`` option * C++, also hyperlink operator overloads in expressions and alias declarations. * #8247: Allow production lists to refer to tokens from other production groups +* #8813: Show what extension (or module) caused it on errors on event handler Bugs fixed ---------- diff --git a/sphinx/errors.py b/sphinx/errors.py index c632d8dbc86..3e84b6b88b8 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -47,12 +47,19 @@ class ApplicationError(SphinxError): class ExtensionError(SphinxError): """Extension error.""" - category = 'Extension error' - def __init__(self, message: str, orig_exc: Exception = None) -> None: + def __init__(self, message: str, orig_exc: Exception = None, modname: str = None) -> None: super().__init__(message) self.message = message self.orig_exc = orig_exc + self.modname = modname + + @property + def category(self) -> str: # type: ignore + if self.modname: + return 'Extension error (%s)' % self.modname + else: + return 'Extension error' def __repr__(self) -> str: if self.orig_exc: diff --git a/sphinx/events.py b/sphinx/events.py index 806a6e55dbe..e3a3b964f1d 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -19,6 +19,7 @@ from sphinx.errors import ExtensionError, SphinxError from sphinx.locale import __ from sphinx.util import logging +from sphinx.util.inspect import safe_getattr if False: # For type annotation @@ -114,8 +115,9 @@ def emit(self, name: str, *args: Any, except SphinxError: raise except Exception as exc: + modname = safe_getattr(listener.handler, '__module__', None) raise ExtensionError(__("Handler %r for event %r threw an exception") % - (listener.handler, name), exc) from exc + (listener.handler, name), exc, modname=modname) from exc return results def emit_firstresult(self, name: str, *args: Any,