[docs]classJSONParser:"""A parser that receives commands and arguments as a JSON string. See :ref:`json-parser` for details on implementation and use-cases. """#: list: Additional arguments to be passed to each command in the parser.#: Note that the command is always passed first.parser_args:List[Any]=[]#: dict: Mapping of command verb to callback coroutine.callbacks:Dict[str,Callable[...,Coroutine]]=DEFAULT_CALLBACKS
[docs]defparse_command(self,command:T)->T:"""Parses a user command. The command string must be a serialised JSON-like string that contains at least a keyword ``command`` with the name of the callback, and any number of additional arguments which will be passed to it. """# This will pass the command as the first argument for each command.# If self.parser_args is defined, those arguments will be passed next.parser_args=[command]parser_args+=self.parser_args# Empty command. Just finish the command.ifnotcommand.body:command.done()returncommandcommand.set_status(command.status.RUNNING)try:payload=json.loads(command.body)exceptjson.JSONDecodeErroraserr:returncommand.fail(error=f"Cannot deserialise command string {command.body!r}: {err}")if"command"notinpayload:returncommand.fail(error=f"Command {command.body!r} does not contain ""a 'command' parameter.")verb=payload.pop("command")ifverbnotinself.callbacks:returncommand.fail(error=f"Cannot find a callback for command {verb!r}.")elifnotasyncio.iscoroutinefunction(self.callbacks[verb]):returncommand.fail(error=f"Callback {verb!r} is not a coroutine function.")try:asyncio.create_task(self.callbacks[verb](*parser_args,payload))exceptExceptionaserr:returncommand.fail(error="Errored scheduling callback coroutine for "f"command {verb!r}: {err}")returncommand