mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #7684 from tk0miya/7683_allowed_exceptions
Add allowed_exceptions parameter to Sphinx.emit() (refs: #7683)
This commit is contained in:
commit
da88a8234d
2
CHANGES
2
CHANGES
@ -73,6 +73,8 @@ Features added
|
|||||||
:rst:dir:`py:exception:` and :rst:dir:`py:method:` directives
|
:rst:dir:`py:exception:` and :rst:dir:`py:method:` directives
|
||||||
* #7596: py domain: Change a type annotation for variables to a hyperlink
|
* #7596: py domain: Change a type annotation for variables to a hyperlink
|
||||||
* #7582: napoleon: a type for attribute are represented like type annotation
|
* #7582: napoleon: a type for attribute are represented like type annotation
|
||||||
|
* #7683: Add ``allowed_exceptions`` parameter to ``Sphinx.emit()`` to allow
|
||||||
|
handlers to raise specified exceptions
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
@ -436,22 +436,32 @@ class Sphinx:
|
|||||||
logger.debug('[app] disconnecting event: [id=%s]', listener_id)
|
logger.debug('[app] disconnecting event: [id=%s]', listener_id)
|
||||||
self.events.disconnect(listener_id)
|
self.events.disconnect(listener_id)
|
||||||
|
|
||||||
def emit(self, event: str, *args: Any) -> List:
|
def emit(self, event: str, *args: Any,
|
||||||
|
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List:
|
||||||
"""Emit *event* and pass *arguments* to the callback functions.
|
"""Emit *event* and pass *arguments* to the callback functions.
|
||||||
|
|
||||||
Return the return values of all callbacks as a list. Do not emit core
|
Return the return values of all callbacks as a list. Do not emit core
|
||||||
Sphinx events in extensions!
|
Sphinx events in extensions!
|
||||||
"""
|
|
||||||
return self.events.emit(event, *args)
|
|
||||||
|
|
||||||
def emit_firstresult(self, event: str, *args: Any) -> Any:
|
.. versionchanged:: 3.1
|
||||||
|
|
||||||
|
Added *allowed_exceptions* to specify path-through exceptions
|
||||||
|
"""
|
||||||
|
return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions)
|
||||||
|
|
||||||
|
def emit_firstresult(self, event: str, *args: Any,
|
||||||
|
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any:
|
||||||
"""Emit *event* and pass *arguments* to the callback functions.
|
"""Emit *event* and pass *arguments* to the callback functions.
|
||||||
|
|
||||||
Return the result of the first callback that doesn't return ``None``.
|
Return the result of the first callback that doesn't return ``None``.
|
||||||
|
|
||||||
.. versionadded:: 0.5
|
.. versionadded:: 0.5
|
||||||
|
.. versionchanged:: 3.1
|
||||||
|
|
||||||
|
Added *allowed_exceptions* to specify path-through exceptions
|
||||||
"""
|
"""
|
||||||
return self.events.emit_firstresult(event, *args)
|
return self.events.emit_firstresult(event, *args,
|
||||||
|
allowed_exceptions=allowed_exceptions)
|
||||||
|
|
||||||
# registering addon parts
|
# registering addon parts
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import warnings
|
import warnings
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from typing import Any, Callable, Dict, List, NamedTuple
|
from typing import Any, Callable, Dict, List, NamedTuple, Tuple
|
||||||
|
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||||
from sphinx.errors import ExtensionError, SphinxError
|
from sphinx.errors import ExtensionError, SphinxError
|
||||||
@ -22,6 +22,7 @@ from sphinx.util import logging
|
|||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
|
from typing import Type # for python3.5.1
|
||||||
from sphinx.application import Sphinx
|
from sphinx.application import Sphinx
|
||||||
|
|
||||||
|
|
||||||
@ -88,7 +89,8 @@ class EventManager:
|
|||||||
if listener.id == listener_id:
|
if listener.id == listener_id:
|
||||||
listeners.remove(listener)
|
listeners.remove(listener)
|
||||||
|
|
||||||
def emit(self, name: str, *args: Any) -> List:
|
def emit(self, name: str, *args: Any,
|
||||||
|
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List:
|
||||||
"""Emit a Sphinx event."""
|
"""Emit a Sphinx event."""
|
||||||
try:
|
try:
|
||||||
logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
|
logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
|
||||||
@ -106,6 +108,9 @@ class EventManager:
|
|||||||
results.append(listener.handler(*args))
|
results.append(listener.handler(*args))
|
||||||
else:
|
else:
|
||||||
results.append(listener.handler(self.app, *args))
|
results.append(listener.handler(self.app, *args))
|
||||||
|
except allowed_exceptions:
|
||||||
|
# pass through the errors specified as *allowed_exceptions*
|
||||||
|
raise
|
||||||
except SphinxError:
|
except SphinxError:
|
||||||
raise
|
raise
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@ -113,12 +118,13 @@ class EventManager:
|
|||||||
(listener.handler, name)) from exc
|
(listener.handler, name)) from exc
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def emit_firstresult(self, name: str, *args: Any) -> Any:
|
def emit_firstresult(self, name: str, *args: Any,
|
||||||
|
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any:
|
||||||
"""Emit a Sphinx event and returns first result.
|
"""Emit a Sphinx event and returns first result.
|
||||||
|
|
||||||
This returns the result of the first handler that doesn't return ``None``.
|
This returns the result of the first handler that doesn't return ``None``.
|
||||||
"""
|
"""
|
||||||
for result in self.emit(name, *args):
|
for result in self.emit(name, *args, allowed_exceptions=allowed_exceptions):
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
return None
|
return None
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from sphinx.errors import ExtensionError
|
||||||
from sphinx.events import EventManager
|
from sphinx.events import EventManager
|
||||||
|
|
||||||
|
|
||||||
@ -22,3 +25,19 @@ def test_event_priority():
|
|||||||
|
|
||||||
events.emit('builder-inited')
|
events.emit('builder-inited')
|
||||||
assert result == [3, 1, 2, 5, 4]
|
assert result == [3, 1, 2, 5, 4]
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_allowed_exceptions():
|
||||||
|
def raise_error(app):
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
events = EventManager(object()) # pass an dummy object as an app
|
||||||
|
events.connect('builder-inited', raise_error, priority=500)
|
||||||
|
|
||||||
|
# all errors are conveted to ExtensionError
|
||||||
|
with pytest.raises(ExtensionError):
|
||||||
|
events.emit('builder-inited')
|
||||||
|
|
||||||
|
# Allow RuntimeError (pass-through)
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
events.emit('builder-inited', allowed_exceptions=(RuntimeError,))
|
||||||
|
Loading…
Reference in New Issue
Block a user