Skip to content

Commit 88fe9b9

Browse files
author
goodboy
authored
Merge pull request #142 from tgoodlet/doc_self_arg
Document self arg and exception handling
2 parents 119836b + eed63e0 commit 88fe9b9

File tree

2 files changed

+84
-21
lines changed

2 files changed

+84
-21
lines changed

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ A definitive example
5959
6060
.. badges
6161
.. |pypi| image:: https://img.shields.io/pypi/v/pluggy.svg
62-
:target: https://pypi.python.org/pypi/pluggy
62+
:target: https://pypi.org/pypi/pluggy
6363
.. |versions| image:: https://img.shields.io/pypi/pyversions/pluggy.svg
64-
:target: https://pypi.python.org/pypi/pluggy
64+
:target: https://pypi.org/pypi/pluggy
6565
.. |travis| image:: https://img.shields.io/travis/pytest-dev/pluggy/master.svg
6666
:target: https://travis-ci.org/pytest-dev/pluggy
6767
.. |appveyor| image:: https://img.shields.io/appveyor/ci/pytestbot/pluggy/master.svg

docs/index.rst

Lines changed: 82 additions & 19 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
@@ -451,6 +454,11 @@ whereas this is not:
451454
def myhook(config, args, extra_arg):
452455
print(args)
453456
457+
.. note::
458+
The one exception to this rule (that a *hookspec* must have as least as
459+
many arguments as its *hookimpls*) is the conventional `self`_ arg; this
460+
is always ignored when *hookimpls* are defined as `methods`_.
461+
454462
.. _firstresult:
455463

456464
First result only
@@ -509,25 +517,6 @@ if a hookspec specifies a ``warn_on_impl``, pluggy will trigger it for any plugi
509517
def oldhook():
510518
pass
511519
512-
513-
.. links
514-
.. _@contextlib.contextmanager:
515-
https://docs.python.org/3.6/library/contextlib.html#contextlib.contextmanager
516-
.. _pytest_cmdline_main:
517-
https://github.com/pytest-dev/pytest/blob/master/_pytest/hookspec.py#L80
518-
.. _hookspec module:
519-
https://github.com/pytest-dev/pytest/blob/master/_pytest/hookspec.py
520-
.. _Writing hook functions:
521-
http://doc.pytest.org/en/latest/writing_plugins.html#writing-hook-functions
522-
.. _hookwrapper:
523-
http://doc.pytest.org/en/latest/writing_plugins.html#hookwrapper-executing-around-other-hooks
524-
.. _hook function ordering:
525-
http://doc.pytest.org/en/latest/writing_plugins.html#hook-function-ordering-call-example
526-
.. _first result:
527-
http://doc.pytest.org/en/latest/writing_plugins.html#firstresult-stop-at-first-non-none-result
528-
.. _sent:
529-
https://docs.python.org/3/reference/expressions.html#generator.send
530-
531520
.. _manage:
532521

533522
The Plugin registry
@@ -657,18 +646,21 @@ assertion should not error:
657646
hookimpl = HookimplMarker('myproject')
658647
659648
class Plugin1(object):
649+
@hookimpl
660650
def myhook(self, args):
661651
"""Default implementation.
662652
"""
663653
return 1
664654
665655
class Plugin2(object):
656+
@hookimpl
666657
def myhook(self, args):
667658
"""Default implementation.
668659
"""
669660
return 2
670661
671662
class Plugin3(object):
663+
@hookimpl
672664
def myhook(self, args):
673665
"""Default implementation.
674666
"""
@@ -694,6 +686,57 @@ its :ref:`firstresult` in which case only the first single value (which is not
694686

695687
.. _call_historic:
696688

689+
Exception handling
690+
------------------
691+
If any *hookimpl* errors with an exception no further callbacks
692+
are invoked and the exception is packaged up and delivered to
693+
any :ref:`hookwrappers` before being re-raised at the hook invocation
694+
point:
695+
696+
.. code-block:: python
697+
698+
from pluggy import PluginManager, HookimplMarker
699+
700+
hookimpl = HookimplMarker('myproject')
701+
702+
class Plugin1(object):
703+
@hookimpl
704+
def myhook(self, args):
705+
return 1
706+
707+
class Plugin2(object):
708+
@hookimpl
709+
def myhook(self, args):
710+
raise RuntimeError
711+
712+
class Plugin3(object):
713+
@hookimpl
714+
def myhook(self, args):
715+
return 3
716+
717+
@hookimpl(hookwrapper=True)
718+
def myhook(self, args):
719+
outcome = yield
720+
721+
try:
722+
outcome.get_result()
723+
except RuntimeError:
724+
# log the error details
725+
print(outcome.excinfo)
726+
727+
pm = PluginManager('myproject')
728+
729+
# register plugins
730+
pm.register(Plugin1())
731+
pm.register(Plugin2())
732+
pm.register(Plugin3())
733+
734+
# register wrapper
735+
pm.register(sys.modules[__name__])
736+
737+
# this raises RuntimeError due to Plugin2
738+
pm.hook.myhook(args=())
739+
697740
Historic calls
698741
--------------
699742
A *historic call* allows for all newly registered functions to receive all hook
@@ -799,6 +842,22 @@ in your project you should thus use a dependency restriction like
799842

800843

801844
.. hyperlinks
845+
.. _@contextlib.contextmanager:
846+
https://docs.python.org/3.6/library/contextlib.html#contextlib.contextmanager
847+
.. _pytest_cmdline_main:
848+
https://github.com/pytest-dev/pytest/blob/master/_pytest/hookspec.py#L80
849+
.. _hookspec module:
850+
https://github.com/pytest-dev/pytest/blob/master/_pytest/hookspec.py
851+
.. _Writing hook functions:
852+
http://doc.pytest.org/en/latest/writing_plugins.html#writing-hook-functions
853+
.. _hookwrapper:
854+
http://doc.pytest.org/en/latest/writing_plugins.html#hookwrapper-executing-around-other-hooks
855+
.. _hook function ordering:
856+
http://doc.pytest.org/en/latest/writing_plugins.html#hook-function-ordering-call-example
857+
.. _first result:
858+
http://doc.pytest.org/en/latest/writing_plugins.html#firstresult-stop-at-first-non-none-result
859+
.. _sent:
860+
https://docs.python.org/3/reference/expressions.html#generator.send
802861
.. _pytest:
803862
https://pytest.org
804863
.. _request-response pattern:
@@ -823,6 +882,10 @@ in your project you should thus use a dependency restriction like
823882
https://github.com/pytest-dev/pluggy/blob/master/tox.ini#L2
824883
.. _200+ plugins:
825884
http://plugincompat.herokuapp.com/
885+
.. _self:
886+
https://docs.python.org/3.6/tutorial/classes.html#random-remarks
887+
.. _methods:
888+
https://docs.python.org/3.6/tutorial/classes.html#method-objects
826889

827890

828891
.. Indices and tables

0 commit comments

Comments
 (0)