@@ -56,7 +56,7 @@ The remaining hook functions will not be called in this case.
5656
5757.. _`hookwrapper` :
5858
59- hookwrapper : executing around other hooks
59+ hook wrappers : executing around other hooks
6060-------------------------------------------------
6161
6262.. currentmodule :: _pytest.core
@@ -69,10 +69,8 @@ which yields exactly once. When pytest invokes hooks it first executes
6969hook wrappers and passes the same arguments as to the regular hooks.
7070
7171At the yield point of the hook wrapper pytest will execute the next hook
72- implementations and return their result to the yield point in the form of
73- a :py:class: `Result <pluggy._Result> ` instance which encapsulates a result or
74- exception info. The yield point itself will thus typically not raise
75- exceptions (unless there are bugs).
72+ implementations and return their result to the yield point, or will
73+ propagate an exception if they raised.
7674
7775Here is an example definition of a hook wrapper:
7876
@@ -81,26 +79,35 @@ Here is an example definition of a hook wrapper:
8179 import pytest
8280
8381
84- @pytest.hookimpl (hookwrapper = True )
82+ @pytest.hookimpl (wrapper = True )
8583 def pytest_pyfunc_call (pyfuncitem ):
8684 do_something_before_next_hook_executes()
8785
88- outcome = yield
89- # outcome.excinfo may be None or a (cls, val, tb) tuple
86+ # If the outcome is an exception, will raise the exception.
87+ res = yield
9088
91- res = outcome.get_result() # will raise if outcome was exception
89+ new_res = post_process_result(res)
9290
93- post_process_result(res)
91+ # Override the return value to the plugin system.
92+ return new_res
9493
95- outcome.force_result(new_res) # to override the return value to the plugin system
94+ The hook wrapper needs to return a result for the hook, or raise an exception.
9695
97- Note that hook wrappers don't return results themselves, they merely
98- perform tracing or other side effects around the actual hook implementations.
99- If the result of the underlying hook is a mutable object, they may modify
100- that result but it's probably better to avoid it.
96+ In many cases, the wrapper only needs to perform tracing or other side effects
97+ around the actual hook implementations, in which case it can return the result
98+ value of the ``yield ``. The simplest (though useless) hook wrapper is
99+ ``return (yield) ``.
100+
101+ In other cases, the wrapper wants the adjust or adapt the result, in which case
102+ it can return a new value. If the result of the underlying hook is a mutable
103+ object, the wrapper may modify that result, but it's probably better to avoid it.
104+
105+ If the hook implementation failed with an exception, the wrapper can handle that
106+ exception using a ``try-catch-finally `` around the ``yield ``, by propagating it,
107+ supressing it, or raising a different exception entirely.
101108
102109For more information, consult the
103- :ref: `pluggy documentation about hookwrappers <pluggy:hookwrappers >`.
110+ :ref: `pluggy documentation about hook wrappers <pluggy:hookwrappers >`.
104111
105112.. _plugin-hookorder :
106113
@@ -130,11 +137,14 @@ after others, i.e. the position in the ``N``-sized list of functions:
130137
131138
132139 # Plugin 3
133- @pytest.hookimpl (hookwrapper = True )
140+ @pytest.hookimpl (wrapper = True )
134141 def pytest_collection_modifyitems (items ):
135142 # will execute even before the tryfirst one above!
136- outcome = yield
137- # will execute after all non-hookwrappers executed
143+ try :
144+ return (yield )
145+ finally :
146+ # will execute after all non-wrappers executed
147+ ...
138148
139149 Here is the order of execution:
140150
@@ -149,12 +159,11 @@ Here is the order of execution:
149159 Plugin1).
150160
1511614. Plugin3's pytest_collection_modifyitems then executing the code after the yield
152- point. The yield receives a :py:class: ` Result <pluggy._Result> ` instance which encapsulates
153- the result from calling the non-wrappers. Wrappers shall not modify the result .
162+ point. The yield receives the result from calling the non-wrappers, or raises
163+ an exception if the non-wrappers raised .
154164
155- It's possible to use ``tryfirst `` and ``trylast `` also in conjunction with
156- ``hookwrapper=True `` in which case it will influence the ordering of hookwrappers
157- among each other.
165+ It's possible to use ``tryfirst `` and ``trylast `` also on hook wrappers
166+ in which case it will influence the ordering of hook wrappers among each other.
158167
159168
160169Declaring new hooks
0 commit comments