Record all hooks called in a plugin manager. Hook recorders are created by :class:`Pytester`. This wraps all the hook calls in the plugin manager, recording each call before propagating the normal calls.
| 248 | |
| 249 | @final |
| 250 | class HookRecorder: |
| 251 | """Record all hooks called in a plugin manager. |
| 252 | |
| 253 | Hook recorders are created by :class:`Pytester`. |
| 254 | |
| 255 | This wraps all the hook calls in the plugin manager, recording each call |
| 256 | before propagating the normal calls. |
| 257 | """ |
| 258 | |
| 259 | def __init__( |
| 260 | self, pluginmanager: PytestPluginManager, *, _ispytest: bool = False |
| 261 | ) -> None: |
| 262 | check_ispytest(_ispytest) |
| 263 | |
| 264 | self._pluginmanager = pluginmanager |
| 265 | self.calls: list[RecordedHookCall] = [] |
| 266 | self.ret: int | ExitCode | None = None |
| 267 | |
| 268 | def before(hook_name: str, hook_impls, kwargs) -> None: |
| 269 | self.calls.append(RecordedHookCall(hook_name, kwargs)) |
| 270 | |
| 271 | def after(outcome, hook_name: str, hook_impls, kwargs) -> None: |
| 272 | pass |
| 273 | |
| 274 | self._undo_wrapping = pluginmanager.add_hookcall_monitoring(before, after) |
| 275 | |
| 276 | def finish_recording(self) -> None: |
| 277 | self._undo_wrapping() |
| 278 | |
| 279 | def getcalls(self, names: str | Iterable[str]) -> list[RecordedHookCall]: |
| 280 | """Get all recorded calls to hooks with the given names (or name).""" |
| 281 | if isinstance(names, str): |
| 282 | names = names.split() |
| 283 | return [call for call in self.calls if call._name in names] |
| 284 | |
| 285 | def assert_contains(self, entries: Sequence[tuple[str, str]]) -> None: |
| 286 | __tracebackhide__ = True |
| 287 | i = 0 |
| 288 | entries = list(entries) |
| 289 | # Since Python 3.13, f_locals is not a dict, but eval requires a dict. |
| 290 | backlocals = dict(sys._getframe(1).f_locals) |
| 291 | while entries: |
| 292 | name, check = entries.pop(0) |
| 293 | for ind, call in enumerate(self.calls[i:]): |
| 294 | if call._name == name: |
| 295 | print("NAMEMATCH", name, call) |
| 296 | if eval(check, backlocals, call.__dict__): |
| 297 | print("CHECKERMATCH", repr(check), "->", call) |
| 298 | else: |
| 299 | print("NOCHECKERMATCH", repr(check), "-", call) |
| 300 | continue |
| 301 | i += ind + 1 |
| 302 | break |
| 303 | print("NONAMEMATCH", name, "with", call) |
| 304 | else: |
| 305 | fail(f"could not find {name!r} check {check!r}") |
| 306 | |
| 307 | def popcall(self, name: str) -> RecordedHookCall: |
no outgoing calls