@@ -56,7 +56,7 @@ The remaining hook functions will not be called in this case.
56
56
57
57
.. _`hookwrapper` :
58
58
59
- hookwrapper : executing around other hooks
59
+ hook wrappers : executing around other hooks
60
60
-------------------------------------------------
61
61
62
62
.. currentmodule :: _pytest.core
@@ -69,10 +69,8 @@ which yields exactly once. When pytest invokes hooks it first executes
69
69
hook wrappers and passes the same arguments as to the regular hooks.
70
70
71
71
At 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.
76
74
77
75
Here is an example definition of a hook wrapper:
78
76
@@ -81,26 +79,35 @@ Here is an example definition of a hook wrapper:
81
79
import pytest
82
80
83
81
84
- @pytest.hookimpl (hookwrapper = True )
82
+ @pytest.hookimpl (wrapper = True )
85
83
def pytest_pyfunc_call (pyfuncitem ):
86
84
do_something_before_next_hook_executes()
87
85
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
90
88
91
- res = outcome.get_result() # will raise if outcome was exception
89
+ new_res = post_process_result(res)
92
90
93
- post_process_result(res)
91
+ # Override the return value to the plugin system.
92
+ return new_res
94
93
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.
96
95
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.
101
108
102
109
For more information, consult the
103
- :ref: `pluggy documentation about hookwrappers <pluggy:hookwrappers >`.
110
+ :ref: `pluggy documentation about hook wrappers <pluggy:hookwrappers >`.
104
111
105
112
.. _plugin-hookorder :
106
113
@@ -130,11 +137,14 @@ after others, i.e. the position in the ``N``-sized list of functions:
130
137
131
138
132
139
# Plugin 3
133
- @pytest.hookimpl (hookwrapper = True )
140
+ @pytest.hookimpl (wrapper = True )
134
141
def pytest_collection_modifyitems (items ):
135
142
# 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
+ ...
138
148
139
149
Here is the order of execution:
140
150
@@ -149,12 +159,11 @@ Here is the order of execution:
149
159
Plugin1).
150
160
151
161
4. 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 .
154
164
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.
158
167
159
168
160
169
Declaring new hooks
0 commit comments