def test_command_completed(): with pytest.raises(TypeError): events.CommandCompleted() assert repr(events.HookCompleted(Mock(), None)) class FooCommand(commands.Command): pass with pytest.raises(RuntimeError, match="properly annotated"): class FooCompleted(events.CommandCompleted): pass class FooCompleted1(events.CommandCompleted): command: FooCommand with pytest.warns(RuntimeWarning, match="conflicting subclasses"): class FooCompleted2(events.CommandCompleted): command: FooCommand
async def hook_task(self, hook: commands.StartHook) -> None: await self.handle_hook(hook) if hook.blocking: self.server_event(events.HookCompleted(hook))
def __bool__(self): """Determine if playbook is correct.""" already_asserted = len(self.actual) i = already_asserted while i < len(self.expected): x = self.expected[i] if isinstance(x, commands.Command): pass else: if hasattr(x, "playbook_eval"): try: x = self.expected[i] = x.playbook_eval(self) except Exception: self.actual.append(_TracebackInPlaybook(traceback.format_exc())) break for name, value in vars(x).items(): if isinstance(value, _Placeholder): setattr(x, name, value()) if isinstance(x, events.OpenConnectionCompleted) and not x.reply: x.command.connection.state = ConnectionState.OPEN elif isinstance(x, events.ConnectionClosed): x.connection.state &= ~ConnectionState.CAN_READ self.actual.append(x) try: cmds: typing.List[commands.Command] = list(self.layer.handle_event(x)) except Exception: self.actual.append(_TracebackInPlaybook(traceback.format_exc())) break cmds = list(_merge_sends(cmds, ignore_hooks=not self.hooks, ignore_logs=not self.logs)) self.actual.extend(cmds) pos = len(self.actual) - len(cmds) - 1 hook_replies = [] for cmd in cmds: pos += 1 assert self.actual[pos] == cmd if isinstance(cmd, commands.CloseConnection): if cmd.half_close: cmd.connection.state &= ~ConnectionState.CAN_WRITE else: cmd.connection.state = ConnectionState.CLOSED elif isinstance(cmd, commands.Log): need_to_emulate_log = ( not self.logs and cmd.level in ("debug", "info") and ( pos >= len(self.expected) or not isinstance(self.expected[pos], commands.Log) ) ) if need_to_emulate_log: self.expected.insert(pos, cmd) elif isinstance(cmd, commands.StartHook) and not self.hooks: need_to_emulate_hook = ( not self.hooks and ( pos >= len(self.expected) or (not ( isinstance(self.expected[pos], commands.StartHook) and self.expected[pos].name == cmd.name )) ) ) if need_to_emulate_hook: self.expected.insert(pos, cmd) if cmd.blocking: # the current event may still have yielded more events, so we need to insert # the reply *after* those additional events. hook_replies.append(events.HookCompleted(cmd)) self.expected = self.expected[:pos + 1] + hook_replies + self.expected[pos + 1:] eq(self.expected[i:], self.actual[i:]) # compare now already to set placeholders i += 1 if not eq(self.expected, self.actual): self._errored = True diffs = list(difflib.ndiff( [_fmt_entry(x) for x in self.expected], [_fmt_entry(x) for x in self.actual] )) if already_asserted: diffs.insert(already_asserted, "==== asserted until here ====") diff = "\n".join(diffs) raise AssertionError(f"Playbook mismatch!\n{diff}") else: return True