async-zulip-bot-sdk

Command System API

The SDK provides a flexible command parsing and dispatch system.

CommandParser

Parses commands from messages by prefix or @-mention.

Class: CommandParser

from bot_sdk import CommandParser

Init

parser = CommandParser(
    prefixes=("/", "!"),
    *,
    enable_mentions: bool = True,
    mention_aliases: Iterable[str] | None = None,
    specs: Iterable[CommandSpec] | None = None,
    auto_help: bool = True,
    translator: Callable[[str], str] | None = None,
)

Parameters

Example

parser = CommandParser(prefixes=("/", "!", "#"), enable_mentions=True)

Methods

CommandSpec

Defines a command.

from bot_sdk import CommandSpec

CommandSpec(
    name: str,
    description: str = "",
    args: list[CommandArgument] = [],
    aliases: list[str] = [],
    allow_extra: bool = False,
    handler: Callable | None = None,
    show_in_help: bool = True,
    min_level: int | None = None,
)

Fields

Examples

CommandArgument

Defines an argument.

CommandArgument(
    name: str,
    type: type = str,
    required: bool = True,
    description: str = "",
    multiple: bool = False,
)

Argument description is surfaced in !help <command> detailed output.

Boolean parsing accepts: true/1/yes/y/on and false/0/no/n/off.

CommandInvocation

Result of parsing.

@dataclass
class CommandInvocation:
    name: str
    args: dict[str, Any]
    tokens: list[str]
    spec: CommandSpec

Exceptions

Internationalization (i18n)

When a translator function is provided to CommandParser.__init__, the following strings are localized:

This allows the entire command system to respond in the user’s language.

Full example

from bot_sdk import BaseBot, Message, CommandSpec, CommandArgument, CommandInvocation, run_bot

class CalculatorBot(BaseBot):
    def __init__(self, client):
        super().__init__(client)
        self.command_parser.register_spec(
            CommandSpec(
                name="add",
                description="Add two numbers",
                aliases=["plus", "+"],
                args=[
                    CommandArgument(name="a", type=float, required=True),
                    CommandArgument(name="b", type=float, required=True),
                ],
                handler=self.handle_add,
            )
        )
        self.command_parser.register_spec(
            CommandSpec(
                name="multiply",
                description="Multiply two numbers",
                aliases=["mul", "*"],
                args=[
                    CommandArgument(name="a", type=float, required=True),
                    CommandArgument(name="b", type=float, required=True),
                ],
                handler=self.handle_multiply,
            )
        )
        self.command_parser.register_spec(
            CommandSpec(
                name="power",
                description="a^b",
                aliases=["pow", "**"],
                args=[
                    CommandArgument(name="base", type=float, required=True),
                    CommandArgument(name="exponent", type=float, required=True),
                ],
                handler=self.handle_power,
            )
        )

    async def handle_add(self, inv: CommandInvocation, message, bot):
        await self.send_reply(message, f"{inv.args['a']} + {inv.args['b']} = {inv.args['a'] + inv.args['b']}")

    async def handle_multiply(self, inv: CommandInvocation, message, bot):
        await self.send_reply(message, f"{inv.args['a']} × {inv.args['b']} = {inv.args['a'] * inv.args['b']}")

    async def handle_power(self, inv: CommandInvocation, message, bot):
        await self.send_reply(message, f"{inv.args['base']} ^ {inv.args['exponent']} = {inv.args['base'] ** inv.args['exponent']}")

    async def on_message(self, message: Message) -> None:
        await self.send_reply(message, "I am a calculator bot. Use /help.")

if __name__ == "__main__":
    run_bot(CalculatorBot)

Best practices