Skip to content

Commit e54fc41

Browse files
author
Tyler Goodlet
committed
Document exception handling
Explain how hook calls fail when a hookimpl raises. Resolves #123
1 parent c5a50d6 commit e54fc41

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

docs/index.rst

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ For another example see the `hook function ordering`_ section of the
312312
``tryfirst`` and ``trylast`` hooks are still invoked in LIFO order within
313313
each category.
314314

315+
316+
.. _hookwrappers:
317+
315318
Wrappers
316319
^^^^^^^^
317320
A *hookimpl* can be marked with a ``"hookwrapper"`` option which indicates that
@@ -662,18 +665,21 @@ assertion should not error:
662665
hookimpl = HookimplMarker('myproject')
663666
664667
class Plugin1(object):
668+
@hookimpl
665669
def myhook(self, args):
666670
"""Default implementation.
667671
"""
668672
return 1
669673
670674
class Plugin2(object):
675+
@hookimpl
671676
def myhook(self, args):
672677
"""Default implementation.
673678
"""
674679
return 2
675680
676681
class Plugin3(object):
682+
@hookimpl
677683
def myhook(self, args):
678684
"""Default implementation.
679685
"""
@@ -699,6 +705,57 @@ its :ref:`firstresult` in which case only the first single value (which is not
699705

700706
.. _call_historic:
701707

708+
Exception handling
709+
------------------
710+
If any *hookimpl* errors with an exception no further callbacks
711+
are invoked and the exception is packaged up and delivered to
712+
any :ref:`hookwrappers` before being re-raised at the hook invocation
713+
point:
714+
715+
.. code-block:: python
716+
717+
from pluggy import PluginManager, HookimplMarker
718+
719+
hookimpl = HookimplMarker('myproject')
720+
721+
class Plugin1(object):
722+
@hookimpl
723+
def myhook(self, args):
724+
return 1
725+
726+
class Plugin2(object):
727+
@hookimpl
728+
def myhook(self, args):
729+
raise RunTimeError
730+
731+
class Plugin3(object):
732+
@hookimpl
733+
def myhook(self, args):
734+
return 3
735+
736+
@hookimpl(hookwrapper=True)
737+
def myhook(self, args):
738+
outcome = yield
739+
740+
try:
741+
outcome.get_result()
742+
except RuntimeError:
743+
# log the error details
744+
print(outcome.excinfo)
745+
746+
pm = PluginManager('myproject')
747+
748+
# register plugins
749+
pm.register(Plugin1())
750+
pm.register(Plugin2())
751+
pm.register(Plugin3())
752+
753+
# register wrapper
754+
pm.register(sys.modules[__name__])
755+
756+
# this raises RuntimeError due to Plugin2
757+
pm.hook.myhook(args=())
758+
702759
Historic calls
703760
--------------
704761
A *historic call* allows for all newly registered functions to receive all hook

0 commit comments

Comments
 (0)